Skip to content

Commit

Permalink
feat: add init commands to node and faucet binaries (#392)
Browse files Browse the repository at this point in the history
  • Loading branch information
tomyrd authored Jun 28, 2024
1 parent efa1137 commit ce4422a
Show file tree
Hide file tree
Showing 17 changed files with 301 additions and 49 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Changelog

* Add `init` command for node and faucet (#392).
* Added crate to distribute node RPC protobuf files (#391).
* Changed state sync endpoint to return a list of `TransactionSummary` objects instead of just transaction IDs (#386).
* Fixed faucet note script so that it uses the `aux` input (#387).
Expand Down
3 changes: 3 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions bin/faucet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ actix-cors = "0.7.0"
actix-files = "0.6.5"
actix-web = "4"
async-mutex = "1.4.0"
clap = { version = "4.3", features = ["derive"] }
derive_more = "0.99.17"
figment = { version = "0.10", features = ["toml", "env"] }
miden-lib = { workspace = true, features = ["concurrent"] }
Expand All @@ -32,5 +33,6 @@ rand = { version = "0.8.5" }
rand_chacha = "0.3"
serde = { version = "1.0", features = ["derive"] }
thiserror = { workspace = true }
toml = { version = "0.8" }
tonic = { workspace = true }
tracing = { workspace = true }
18 changes: 14 additions & 4 deletions bin/faucet/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,23 @@ This crate contains a binary for running a Miden rollup faucet.
## Running the faucet
1. Run a local node, for example using the docker image. From the "miden-node" repo root run the following commands:
```bash
cargo make docker-build-node
cargo make docker-run-node
make docker-build-node
make docker-run-node
```

2. From the "miden-node" repo root run the faucet:
2. Install the faucet (with the "testing" feature):
```bash
cargo run --bin miden-faucet --features testing --release
make install-faucet-testing
```

3. Create the default faucet configuration file:
```bash
miden-faucet init
```

4. Start the faucet server:
```bash
miden-faucet start
```

After a few seconds you may go to `http://localhost:8080` and see the faucet UI.
Expand Down
17 changes: 16 additions & 1 deletion bin/faucet/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::{
path::PathBuf,
};

use miden_node_utils::config::Endpoint;
use miden_node_utils::config::{Endpoint, DEFAULT_FAUCET_SERVER_PORT, DEFAULT_NODE_RPC_PORT};
use serde::{Deserialize, Serialize};

// Faucet config
Expand Down Expand Up @@ -43,3 +43,18 @@ impl Display for FaucetConfig {
))
}
}

impl Default for FaucetConfig {
fn default() -> Self {
Self {
endpoint: Endpoint::localhost(DEFAULT_FAUCET_SERVER_PORT),
node_url: Endpoint::localhost(DEFAULT_NODE_RPC_PORT).to_string(),
timeout_ms: 10000,
database_filepath: PathBuf::from("store.sqlite3"),
asset_amount_options: vec![100, 500, 1000],
token_symbol: "POL".to_string(),
decimals: 8,
max_supply: 1000000,
}
}
}
123 changes: 90 additions & 33 deletions bin/faucet/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ mod errors;
mod handlers;
mod state;

use std::path::PathBuf;
use std::{fs::File, io::Write, path::PathBuf};

use actix_cors::Cors;
use actix_files::Files;
use actix_web::{
middleware::{DefaultHeaders, Logger},
web, App, HttpServer,
};
use clap::{Parser, Subcommand};
use errors::FaucetError;
use miden_node_utils::config::load_config;
use state::FaucetState;
Expand All @@ -26,8 +27,32 @@ use crate::{
// =================================================================================================

const COMPONENT: &str = "miden-faucet";
const FAUCET_CONFIG_FILE_PATH: &str = "miden-faucet.toml";

const FAUCET_CONFIG_FILE_PATH: &str = "config/miden-faucet.toml";
// COMMANDS
// ================================================================================================

#[derive(Parser)]
#[command(version, about, long_about = None)]
pub struct Cli {
#[command(subcommand)]
pub command: Command,
}

#[derive(Subcommand)]
pub enum Command {
/// Start the faucet server
Start {
#[arg(short, long, value_name = "FILE", default_value = FAUCET_CONFIG_FILE_PATH)]
config: PathBuf,
},

/// Generates default configuration file for the faucet
Init {
#[arg(short, long, default_value = FAUCET_CONFIG_FILE_PATH)]
config_path: String,
},
}

// MAIN
// =================================================================================================
Expand All @@ -37,37 +62,69 @@ async fn main() -> Result<(), FaucetError> {
miden_node_utils::logging::setup_logging()
.map_err(|err| FaucetError::StartError(err.to_string()))?;

let config: FaucetConfig = load_config(PathBuf::from(FAUCET_CONFIG_FILE_PATH).as_path())
.extract()
.map_err(|err| FaucetError::ConfigurationError(err.to_string()))?;

let faucet_state = FaucetState::new(config.clone()).await?;

info!(target: COMPONENT, %config, "Initializing server");

info!("Server is now running on: {}", config.endpoint_url());

HttpServer::new(move || {
let cors = Cors::default().allow_any_origin().allow_any_method();
App::new()
.app_data(web::Data::new(faucet_state.clone()))
.wrap(cors)
.wrap(Logger::default())
.wrap(DefaultHeaders::new().add(("Cache-Control", "no-cache")))
.service(get_metadata)
.service(get_tokens)
.service(
Files::new("/", "bin/faucet/src/static")
.use_etag(false)
.use_last_modified(false)
.index_file("index.html"),
)
})
.bind((config.endpoint.host, config.endpoint.port))
.map_err(|err| FaucetError::StartError(err.to_string()))?
.run()
.await
.map_err(|err| FaucetError::StartError(err.to_string()))?;
let cli = Cli::parse();

match &cli.command {
Command::Start { config } => {
let config: FaucetConfig = load_config(config.as_path())
.extract()
.map_err(|err| FaucetError::ConfigurationError(err.to_string()))?;

let faucet_state = FaucetState::new(config.clone()).await?;

info!(target: COMPONENT, %config, "Initializing server");

info!("Server is now running on: {}", config.endpoint_url());

HttpServer::new(move || {
let cors = Cors::default().allow_any_origin().allow_any_method();
App::new()
.app_data(web::Data::new(faucet_state.clone()))
.wrap(cors)
.wrap(Logger::default())
.wrap(DefaultHeaders::new().add(("Cache-Control", "no-cache")))
.service(get_metadata)
.service(get_tokens)
.service(
Files::new("/", "bin/faucet/src/static")
.use_etag(false)
.use_last_modified(false)
.index_file("index.html"),
)
})
.bind((config.endpoint.host, config.endpoint.port))
.map_err(|err| FaucetError::StartError(err.to_string()))?
.run()
.await
.map_err(|err| FaucetError::StartError(err.to_string()))?;
},
Command::Init { config_path } => {
let current_dir = std::env::current_dir().map_err(|err| {
FaucetError::ConfigurationError(format!("failed to open current directory: {err}"))
})?;

let mut config_file_path = current_dir.clone();
config_file_path.push(config_path);

let config = FaucetConfig::default();
let config_as_toml_string = toml::to_string(&config).map_err(|err| {
FaucetError::ConfigurationError(format!(
"Failed to serialize default config: {err}"
))
})?;

let mut file_handle =
File::options().write(true).create_new(true).open(&config_file_path).map_err(
|err| FaucetError::ConfigurationError(format!("Error opening the file: {err}")),
)?;

file_handle.write(config_as_toml_string.as_bytes()).map_err(|err| {
FaucetError::ConfigurationError(format!("Error writing to file: {err}"))
})?;

println!("Config file successfully created at: {:?}", config_file_path);
},
}

Ok(())
}
1 change: 1 addition & 0 deletions bin/node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ miden-objects = { workspace = true }
rand_chacha = "0.3"
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1.29", features = ["rt-multi-thread", "net", "macros"] }
toml = { version = "0.8" }
tracing = { workspace = true }
tracing-subscriber = { workspace = true }

Expand Down
47 changes: 41 additions & 6 deletions bin/node/src/commands/genesis/inputs.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,36 @@
use serde::Deserialize;
use std::time::{SystemTime, UNIX_EPOCH};

use serde::{Deserialize, Serialize};

// INPUT HELPER STRUCTS
// ================================================================================================

/// Input types are helper structures designed for parsing and deserializing genesis input files.
/// They serve as intermediary representations, facilitating the conversion from
/// placeholder types (like `GenesisInput`) to internal types (like `GenesisState`).
#[derive(Debug, Clone, Deserialize)]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct GenesisInput {
pub version: u32,
pub timestamp: u32,
pub accounts: Vec<AccountInput>,
}

#[derive(Debug, Clone, Deserialize)]
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(tag = "type")]
pub enum AccountInput {
BasicWallet(BasicWalletInputs),
BasicFungibleFaucet(BasicFungibleFaucetInputs),
}

#[derive(Debug, Clone, Deserialize)]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct BasicWalletInputs {
pub init_seed: String,
pub auth_scheme: AuthSchemeInput,
pub auth_seed: String,
pub storage_mode: String,
}

#[derive(Debug, Clone, Deserialize)]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct BasicFungibleFaucetInputs {
pub init_seed: String,
pub auth_scheme: AuthSchemeInput,
Expand All @@ -39,7 +41,40 @@ pub struct BasicFungibleFaucetInputs {
pub storage_mode: String,
}

#[derive(Debug, Clone, Copy, Deserialize)]
#[derive(Debug, Clone, Copy, Deserialize, Serialize)]
pub enum AuthSchemeInput {
RpoFalcon512,
}

impl Default for GenesisInput {
fn default() -> Self {
Self {
version: 1,
timestamp: SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Current timestamp should be greater than unix epoch")
.as_secs() as u32,
accounts: vec![
AccountInput::BasicWallet(BasicWalletInputs {
init_seed: "0xa123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
.to_string(),
auth_scheme: AuthSchemeInput::RpoFalcon512,
auth_seed: "0xb123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
.to_string(),
storage_mode: "off-chain".to_string(),
}),
AccountInput::BasicFungibleFaucet(BasicFungibleFaucetInputs {
init_seed: "0xc123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
.to_string(),
auth_scheme: AuthSchemeInput::RpoFalcon512,
auth_seed: "0xd123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
.to_string(),
token_symbol: "POL".to_string(),
decimals: 12,
max_supply: 1000000,
storage_mode: "on-chain".to_string(),
}),
],
}
}
}
2 changes: 1 addition & 1 deletion bin/node/src/commands/genesis/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::{
};

use anyhow::{anyhow, Result};
use inputs::{AccountInput, AuthSchemeInput, GenesisInput};
pub use inputs::{AccountInput, AuthSchemeInput, GenesisInput};
use miden_lib::{
accounts::{faucets::create_basic_fungible_faucet, wallets::create_basic_wallet},
AuthScheme,
Expand Down
42 changes: 42 additions & 0 deletions bin/node/src/commands/init.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use std::{fs::File, io::Write, path::PathBuf};

use anyhow::{anyhow, Result};

use crate::{commands::genesis::GenesisInput, config::NodeConfig};

// INIT
// ===================================================================================================

pub fn init_config_files(config_file_path: PathBuf, genesis_file_path: PathBuf) -> Result<()> {
let config = NodeConfig::default();
let config_as_toml_string = toml::to_string(&config)
.map_err(|err| anyhow!("Failed to serialize default config: {}", err))?;

write_string_in_file(config_as_toml_string, &config_file_path)?;

println!("Config file successfully created at: {:?}", config_file_path);

let genesis = GenesisInput::default();
let genesis_as_toml_string = toml::to_string(&genesis)
.map_err(|err| anyhow!("Failed to serialize default config: {}", err))?;

write_string_in_file(genesis_as_toml_string, &genesis_file_path)?;

println!("Genesis config file successfully created at: {:?}", genesis_file_path);

Ok(())
}

fn write_string_in_file(content: String, path: &PathBuf) -> Result<()> {
let mut file_handle = File::options()
.write(true)
.create_new(true)
.open(path)
.map_err(|err| anyhow!("Error opening the file: {err}"))?;

file_handle
.write(content.as_bytes())
.map_err(|err| anyhow!("Error writing to file: {err}"))?;

Ok(())
}
Loading

0 comments on commit ce4422a

Please sign in to comment.