This is a hands-on tutorial, so please switch to the corresponding code branch before reading.
- Repo:
https://github.com/jacob-chia/tinychain.git- Branch:
git fetch && git switch 05-cmd-configImportant crates used in this lesson:
In this lesson, we will add two commands:
new-account: create an account and return the address. The account storage path can be specified by parameters.run: run the tinychain node service. The running parameters are passed in through the configuration file.
Define the Opts and SubCommand according to the requirements of clap. Let's look at the code directly.
// src/main.rs
/// The command of tinychain
#[derive(Debug, Parser)]
struct Opts {
#[command(subcommand)]
subcmd: SubCommand,
}
#[derive(Debug, Subcommand)]
enum SubCommand {
/// Create a new account for signing transactions
NewAccount {
/// the keystore directory, default is `./db/keystore/`
#[arg(short, long, default_value_t = String::from("./db/keystore/"))]
keystore_dir: String,
},
/// Run the node
Run {
/// the config file path, default is `config.toml`
#[arg(short, long, default_value_t = String::from("config.toml"))]
config: String,
},
}// src/main.rs
#[tokio::main]
async fn main() {
pretty_env_logger::init();
let opts = Opts::parse();
match opts.subcmd {
SubCommand::NewAccount { keystore_dir } => new_account(&keystore_dir),
SubCommand::Run { config } => run(&config).await,
}
}
fn new_account(keystore_dir: &str) {
let wallet = Wallet::new(keystore_dir);
let acc = wallet.new_account().unwrap();
info!("📣 New account: {:?}", acc);
}
async fn run(config_file: &str) {
let cfg = Config::load(config_file).unwrap();
info!("📣 Config loaded: {:?}", cfg);
// ...
}When it comes to SubCommand::Run, we need to specify a configuration file, and here is a template: ./config-template.toml.
Accordingly, a struct should be defined to deserialize the configuration file. The code is as follows:
// src/config.rs
#[derive(Clone, Debug, Default, Deserialize)]
pub struct Config {
/// The path to the data directory.
pub data_dir: String,
/// The path to the genesis file.
pub genesis_file: String,
/// The address to listen on for HTTP Server.
pub http_addr: String,
/// The miner account to receive mining rewards.
pub author: String,
/// Wallet configuration.
pub wallet: WalletConfig,
}
impl Config {
/// Load the configuration from the given path.
pub fn load(path: &str) -> Result<Self, Error> {
let content =
fs::read_to_string(path).map_err(|_| Error::ConfigNotExist(path.to_string()))?;
let config: Config = toml::from_str(&content)?;
Ok(config)
}
}Note: The log level in the code is
info, so we need to add theRUST_LOG=infoparameter when running.
-
Build:
cargo build; -
Check the commands:
RUST_LOG=info ./target/debug/tinychain: -
Create an account:
RUST_LOG=info ./target/debug/tinychain new-account: -
Run the service:
RUST_LOG=info ./target/debug/tinychain run -c ./config-template.toml:
There is no difficulty in this lesson. It mainly demonstrates two functions:
- Parsing command line arguments
- Reading configuration files
| < 04-Wallet: Sign & Verify | 06-Thinking in Libp2p > |
|---|


