Skip to content

Commit

Permalink
Merge pull request #210 from subspace/farmer-identity-management
Browse files Browse the repository at this point in the history
Farmer identity management
  • Loading branch information
nazar-pc authored Dec 20, 2021
2 parents 8364438 + 07615ed commit 7b05d4a
Show file tree
Hide file tree
Showing 8 changed files with 274 additions and 49 deletions.
4 changes: 4 additions & 0 deletions Cargo.lock

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

4 changes: 4 additions & 0 deletions crates/subspace-farmer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,16 @@ rayon = "1.5.1"
schnorrkel = "0.9.1"
serde = { version = "1.0.131", features = ["derive"] }
serde_json = "1.0.73"
sp-core = { version = "4.1.0-dev", git = "https://github.com/paritytech/substrate", rev = "5bd5b842d4ea520d281b1398e1f54907c9862fcd" }
ss58-registry = "1.10.0"
subspace-archiving = { version = "0.1.0", path = "../subspace-archiving" }
subspace-solving = { version = "0.1.0", path = "../subspace-solving" }
subspace-core-primitives = { version = "0.1.0", path = "../subspace-core-primitives" }
subspace-rpc-primitives = { version = "0.1.0", path = "../subspace-rpc-primitives" }
thiserror = "1.0.24"
tiny-bip39 = "0.8.2"
tokio = { version = "1.15.0", features = ["macros", "rt-multi-thread"] }
zeroize = "1.4.3"

[dependencies.rocksdb]
# This disables compression algorithms that cause issues during linking due to
Expand Down
38 changes: 38 additions & 0 deletions crates/subspace-farmer/src/bin/subspace-farmer/commands.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,41 @@
mod farm;
mod identity;

pub(crate) use farm::farm;
pub(crate) use identity::identity;
use log::info;
use std::path::Path;
use std::{fs, io};

/// Helper function for ignoring the error that given file/directory does not exist.
fn try_remove<P: AsRef<Path>>(
path: P,
remove: impl FnOnce(P) -> std::io::Result<()>,
) -> io::Result<()> {
if path.as_ref().exists() {
remove(path)?;
}
Ok(())
}

pub(crate) fn erase_plot<P: AsRef<Path>>(path: P) -> io::Result<()> {
info!("Erasing the plot");
try_remove(path.as_ref().join("plot.bin"), fs::remove_file)?;
info!("Erasing plot metadata");
try_remove(path.as_ref().join("plot-metadata"), fs::remove_dir_all)?;
info!("Erasing plot commitments");
try_remove(path.as_ref().join("commitments"), fs::remove_dir_all)?;
info!("Erasing object mappings");
try_remove(path.as_ref().join("object-mappings"), fs::remove_dir_all)?;

Ok(())
}

pub(crate) fn wipe<P: AsRef<Path>>(path: P) -> io::Result<()> {
erase_plot(path.as_ref())?;

info!("Erasing identity");
try_remove(path.as_ref().join("identity.bin"), fs::remove_file)?;

Ok(())
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pub(crate) async fn farm(

let identity = Identity::open_or_create(&base_directory)?;

let subspace_codec = SubspaceCodec::new(&identity.public_key());
let subspace_codec = SubspaceCodec::new(identity.public_key());

// Start RPC server
let ws_server = WsServerBuilder::default()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
use crate::{utils, IdentityCommand};
use anyhow::bail;
use bip39::{Language, Mnemonic};
use sp_core::crypto::{Ss58AddressFormatRegistry, Ss58Codec, UncheckedFrom};
use sp_core::sr25519::Public;
use std::path::Path;
use subspace_farmer::Identity;
use zeroize::Zeroize;

pub(crate) fn identity(identity_command: IdentityCommand) -> anyhow::Result<()> {
match identity_command {
IdentityCommand::View {
address,
public_key,
mnemonic,
custom_path,
} => {
let path = utils::get_path(custom_path);
view(&path, address, public_key, mnemonic)
}
IdentityCommand::ImportFromMnemonic {
mut phrase,
custom_path,
} => {
let path = utils::get_path(custom_path);
if Identity::open(&path)?.is_some() {
bail!("Identity already exists, can't import!");
}

let result = Identity::import_from_mnemonic(path, &phrase).map(|_identity| ());
phrase.zeroize();
result
}
}
}

fn view<P: AsRef<Path>>(
path: P,
address: bool,
public_key: bool,
mnemonic: bool,
) -> anyhow::Result<()> {
let identity = match Identity::open(&path)? {
Some(identity) => identity,
None => {
bail!("Identity doesn't exist");
}
};

let public = Public::unchecked_from(identity.public_key().to_bytes());

if (false, false, false) == (address, public_key, mnemonic) || address {
eprint!("Address (SS58 format):\n ");

println!(
"{}",
public.to_ss58check_with_version(
Ss58AddressFormatRegistry::SubspaceTestnetAccount.into()
)
);
}

if public_key {
eprint!("Public key (hex format):\n ");

println!("0x{}", hex::encode(public));
}

if mnemonic {
eprint!("Mnemonic (NOTE: never share this with anyone!):\n ");

println!(
"{}",
Mnemonic::from_entropy(identity.entropy(), Language::English).unwrap()
);
}

Ok(())
}
80 changes: 51 additions & 29 deletions crates/subspace-farmer/src/bin/subspace-farmer/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,62 +5,84 @@ use anyhow::Result;
use clap::{Parser, ValueHint};
use env_logger::Env;
use log::info;
use std::fs;
use std::net::SocketAddr;
use std::path::{Path, PathBuf};
use std::path::PathBuf;

#[derive(Debug, Parser)]
enum IdentityCommand {
/// View identity information
View {
/// Print SS58 address [default if no other option is specified]
#[clap(long, short)]
address: bool,
/// Print public key (hex)
#[clap(long, short)]
public_key: bool,
/// Print mnemonic (NOTE: never share this with anyone!)
#[clap(long, short)]
mnemonic: bool,
/// Use custom path for data storage instead of platform-specific default
#[clap(long, short, value_hint = ValueHint::FilePath)]
custom_path: Option<PathBuf>,
},
/// Import identity from BIP39 mnemonic phrase
ImportFromMnemonic {
/// BIP39 mnemonic phrase to import identity from
phrase: String,
/// Use custom path for data storage instead of platform-specific default
#[clap(long, short, value_hint = ValueHint::FilePath)]
custom_path: Option<PathBuf>,
},
}

// TODO: Separate commands for erasing the plot and wiping everything
#[derive(Debug, Parser)]
#[clap(about, version)]
enum Command {
/// Erase existing plot (including identity)
/// Identity management
#[clap(subcommand)]
Identity(IdentityCommand),
/// Erase existing plot (doesn't touch identity)
ErasePlot {
/// Use custom path for data storage instead of platform-specific default
#[clap(long, value_hint = ValueHint::FilePath)]
#[clap(long, short, value_hint = ValueHint::FilePath)]
custom_path: Option<PathBuf>,
},
/// Wipes plot and identity
Wipe {
/// Use custom path for data storage instead of platform-specific default
#[clap(long, short, value_hint = ValueHint::FilePath)]
custom_path: Option<PathBuf>,
},
/// Start a farmer using previously created plot
Farm {
/// Custom path for data storage instead of platform-specific default
#[clap(long, value_hint = ValueHint::FilePath)]
#[clap(long, short, value_hint = ValueHint::FilePath)]
custom_path: Option<PathBuf>,
/// WebSocket RPC URL of the Subspace node to connect to
#[clap(long, value_hint = ValueHint::Url, default_value = "ws://127.0.0.1:9944")]
#[clap(long, short, value_hint = ValueHint::Url, default_value = "ws://127.0.0.1:9944")]
node_rpc_url: String,
/// Host and port where built-in WebSocket RPC server should listen for incoming connections
#[clap(long, default_value = "127.0.0.1:9955")]
#[clap(long, short, default_value = "127.0.0.1:9955")]
ws_server_listen_addr: SocketAddr,
},
}

/// Helper function for ignoring the error that given file/directory does not exist.
fn try_remove<P: AsRef<Path>>(
path: P,
remove: impl FnOnce(P) -> std::io::Result<()>,
) -> Result<()> {
if path.as_ref().exists() {
remove(path)?;
}
Ok(())
}

#[tokio::main]
async fn main() -> Result<()> {
env_logger::init_from_env(Env::new().default_filter_or("info"));
let command: Command = Command::parse();
match command {
Command::Identity(identity_command) => {
commands::identity(identity_command)?;
}
Command::ErasePlot { custom_path } => {
let path = utils::get_path(custom_path);
info!("Erasing the plot");
try_remove(path.join("plot.bin"), fs::remove_file)?;
info!("Erasing plot metadata");
try_remove(path.join("plot-metadata"), fs::remove_dir_all)?;
info!("Erasing plot commitments");
try_remove(path.join("commitments"), fs::remove_dir_all)?;
info!("Erasing object mappings");
try_remove(path.join("object-mappings"), fs::remove_dir_all)?;
info!("Erasing identity");
try_remove(path.join("identity.bin"), fs::remove_file)?;
commands::erase_plot(&path)?;
info!("Done");
}
Command::Wipe { custom_path } => {
let path = utils::get_path(custom_path);
commands::wipe(&path)?;
info!("Done");
}
Command::Farm {
Expand Down
Loading

0 comments on commit 7b05d4a

Please sign in to comment.