From 1ded3f39727b19f003542191ed8dab7b2e70bcd0 Mon Sep 17 00:00:00 2001
From: Yeastplume <yeastplume@gmail.com>
Date: Thu, 30 Aug 2018 10:10:40 +0100
Subject: [PATCH] Config + Default directories (#1433)

* config file can now be generated by executable

* rustfmt

* remove now-unnecessary config defaults test

* set up paths and config file creation in user's home directory

* rustfmt

* remove default grin.toml

* add grin configuration command to spit out config file

* Split configuration into wallet and server

* rustfmt

* Restore logging to wallet configurations

* rustfmt
---
 config/src/comments.rs                   | 469 +++++++++++++++++++++++
 config/src/config.rs                     | 321 ++++++++++++----
 config/src/lib.rs                        |   5 +-
 config/src/types.rs                      |  23 +-
 config/tests/config.rs                   |  19 -
 grin.toml                                | 183 ---------
 p2p/src/types.rs                         |   2 +-
 servers/src/common/stats.rs              |   4 +-
 servers/src/common/types.rs              |  41 +-
 servers/src/grin/server.rs               |  18 +-
 src/bin/cmd/config.rs                    |  71 ++++
 src/bin/cmd/mod.rs                       |   4 +-
 src/bin/cmd/server.rs                    |   4 +-
 src/bin/cmd/wallet.rs                    |  21 +-
 src/bin/grin.rs                          | 143 ++++---
 wallet/src/db_migrate.rs                 |   2 +-
 wallet/src/lib.rs                        |   2 +-
 wallet/src/libwallet/internal/restore.rs |   2 +-
 wallet/src/lmdb_wallet.rs                |   2 +-
 19 files changed, 955 insertions(+), 381 deletions(-)
 create mode 100644 config/src/comments.rs
 delete mode 100644 config/tests/config.rs
 delete mode 100644 grin.toml
 create mode 100644 src/bin/cmd/config.rs

diff --git a/config/src/comments.rs b/config/src/comments.rs
new file mode 100644
index 000000000..8050fd5f6
--- /dev/null
+++ b/config/src/comments.rs
@@ -0,0 +1,469 @@
+// Copyright 2018 The Grin Developers
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Comments for configuration + injection into output .toml
+use std::collections::HashMap;
+
+/// maps entries to Comments that should preceed them
+fn comments() -> HashMap<String, String> {
+	let mut retval = HashMap::new();
+	retval.insert(
+		"[server]".to_string(),
+		"
+# Sample Server Configuration File for Grin
+#
+# When running the grin executable without specifying any command line
+# arguments, it will look for this file in three places, in the following
+# order:
+#
+# -The working directory
+# -The directory in which the executable resides
+# -[user home]/.grin
+#
+
+#########################################
+### SERVER CONFIGURATION              ###
+#########################################
+
+#Server connection details
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"api_http_addr".to_string(),
+		"
+#the address on which services will listen, e.g. Transaction Pool
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"db_root".to_string(),
+		"
+#the directory, relative to current, in which the grin blockchain
+#is stored
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"chain_type".to_string(),
+		"
+#The chain type, which defines the genesis block and the set of cuckoo
+#parameters used for mining. Can be:
+#AutomatedTesting - For CI builds and instant blockchain creation
+#UserTesting - For regular user testing (cuckoo 16)
+#Testnet1 - Testnet1 genesis block (cuckoo 16)
+#Testnet2 - Testnet2 genesis block (cuckoo 30)
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"chain_validation_mode".to_string(),
+		"
+#The chain validation mode, defines how often (if at all) we
+#want to run a full chain validation. Can be:
+#\"EveryBlock\" - run full chain validation when processing each block (except during sync)
+#\"Disabled\" - disable full chain validation (just run regular block validation)
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"archive_mode".to_string(),
+		"
+#run the node in \"full archive\" mode (default is fast-sync, pruned node)
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"skip_sync_wait".to_string(),
+		"
+#skip waiting for sync on startup, (optional param, mostly for testing)
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"run_tui".to_string(),
+		"
+#whether to run the ncurses TUI. Ncurses must be installed and this
+#will also disable logging to stdout
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"run_wallet_listener".to_string(),
+		"
+#Whether to run the wallet listener with the server by default
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"run_wallet_owner_api".to_string(),
+		"
+# Whether to run the web-wallet API (will only run on localhost)
+# grin wallet web will run this automatically, so this should
+# only be set to true for test/development purposes
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"run_test_miner".to_string(),
+		"
+#Whether to run a test miner. This is only for developer testing (chaintype
+#usertesting) at cuckoo 16, and will only mine into the default wallet port.
+#real mining should use the standalone grin-miner
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"[server.dandelion_config]".to_string(),
+		"
+#########################################
+### DANDELION CONFIGURATION           ###
+#########################################
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"relay_secs".to_string(),
+		"
+#dandelion relay time (choose new relay peer every n secs)
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"embargo_secs".to_string(),
+		"
+#fluff and broadcast after embargo expires if tx not seen on network
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"patience_secs".to_string(),
+		"
+#run dandelion stem/fluff processing every n secs (stem tx aggregation in this window)
+"
+			.to_string(),
+	);
+	retval.insert(
+		"stem_probability".to_string(),
+		"
+#dandelion stem probability (stem 90% of the time, fluff 10% of the time)
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"[server.p2p_config]".to_string(),
+		"#test miner wallet URL (burns if this doesn't exist)
+#test_miner_wallet_url = \"http://127.0.0.1:13415\"
+
+#########################################
+### SERVER P2P CONFIGURATION          ###
+#########################################
+#The P2P server details (i.e. the server that communicates with other
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"host".to_string(),
+		"
+#The interface on which to listen. 
+#0.0.0.0 will listen on all interfaces, alowing others to interact
+#127.0.0.1 will listen on the local machine only
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"port".to_string(),
+		"
+#The port on which to listen.
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"seeding_type".to_string(),
+		"
+#How to seed this server, can be None, List, WebStatic or DNSSeed
+#If the seeding type is List, the list of peers to connect to can
+#be specified as follows:
+#seeds = [\"192.168.0.1:13414\",\"192.168.0.2:13414\"]
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"seeds".to_string(),
+		"
+#If seeding_type = List, the list of peers to connect to.
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"[server.p2p_config.capabilities]".to_string(),
+		"#7 = Bit flags for FULL_NODE, this structure needs to be changed
+#internally to make it more configurable
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"[server.pool_config]".to_string(),
+		"#hardcoded peer lists for allow/deny
+#will *only* connect to peers in allow list
+#peers_allow = [\"192.168.0.1:13414\", \"192.168.0.2:13414\"]
+#will *never* connect to peers in deny list
+#peers_deny = [\"192.168.0.3:13414\", \"192.168.0.4:13414\"]
+#a list of preferred peers to connect to
+#peers_preferred = [\"192.168.0.1:13414\",\"192.168.0.2:13414\"]
+
+#how long a banned peer should stay banned
+#ban_window = 10800
+
+#maximum number of peers
+#peer_max_count = 25
+
+#preferred minimum number of peers (we'll actively keep trying to add peers
+#until we get to at least this number
+#peer_min_preferred_count = 8
+
+#########################################
+### MEMPOOL CONFIGURATION             ###
+#########################################
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"accept_fee_base".to_string(),
+		"
+#Base fee that's accepted into the pool
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"max_pool_size".to_string(),
+		"
+#Maximum number of transactions allowed in the pool
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"[server.stratum_mining_config]".to_string(),
+		"
+################################################
+### STRATUM MINING SERVER CONFIGURATION      ###
+################################################
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"enable_stratum_server".to_string(),
+		"
+#whether stratum server is enabled
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"stratum_server_addr".to_string(),
+		"
+#what port and address for the stratum server to listen on
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"attempt_time_per_block".to_string(),
+		"
+#The amount of time, in seconds, to attempt to mine on a particular
+#header before stopping and re-collecting transactions from the pool
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"minimum_share_difficulty".to_string(),
+		"
+#The minimum acceptable share difficulty to request from miners
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"wallet_listener_url".to_string(),
+		"
+#the wallet receiver to which coinbase rewards will be sent
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"burn_reward".to_string(),
+		"
+#whether to ignore the reward (mostly for testing)
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"[wallet]".to_string(),
+		"
+#########################################
+### WALLET CONFIGURATION              ###
+#########################################
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"api_listen_interface".to_string(),
+		"
+# Host IP for wallet listener, change to \"0.0.0.0\" to receive grins
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"api_listen_port".to_string(),
+		"
+# Port for wallet listener
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"check_node_api_http_addr".to_string(),
+		"
+# Where the wallet should find a running node
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"data_file_dir".to_string(),
+		"
+# Where to find wallet files (seed, data, etc)
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"[logging]".to_string(),
+		"
+#########################################
+### LOGGING CONFIGURATION             ###
+#########################################
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"log_to_stdout".to_string(),
+		"
+# Whether to log to stdout
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"stdout_log_level".to_string(),
+		"
+# Log level for stdout: Critical, Error, Warning, Info, Debug, Trace
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"log_to_file".to_string(),
+		"
+# Whether to log to a file
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"file_log_level".to_string(),
+		"
+# Log level for file: Critical, Error, Warning, Info, Debug, Trace
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"log_file_path".to_string(),
+		"
+# Log file path
+"
+			.to_string(),
+	);
+
+	retval.insert(
+		"log_file_append".to_string(),
+		"
+# Whether to append to the log file (true), or replace it on every run (false)
+"
+			.to_string(),
+	);
+
+	retval
+}
+
+fn get_key(line: &str) -> String {
+	if line.contains("[") && line.contains("]") {
+		return line.to_owned();
+	} else if line.contains("=") {
+		return line.split("=").collect::<Vec<&str>>()[0].trim().to_owned();
+	} else {
+		return "NOT_FOUND".to_owned();
+	}
+}
+
+pub fn insert_comments(orig: String) -> String {
+	let comments = comments();
+	let lines: Vec<&str> = orig.split("\n").collect();
+	let mut out_lines = vec![];
+	for l in lines {
+		let key = get_key(l);
+		if let Some(v) = comments.get(&key) {
+			out_lines.push(v.to_owned());
+		}
+		out_lines.push(l.to_owned());
+		out_lines.push("\n".to_owned());
+	}
+	let mut ret_val = String::from("");
+	for l in out_lines {
+		ret_val.push_str(&l);
+	}
+	ret_val.to_owned()
+}
diff --git a/config/src/config.rs b/config/src/config.rs
index 85329c9de..36bf7933f 100644
--- a/config/src/config.rs
+++ b/config/src/config.rs
@@ -14,33 +14,123 @@
 
 //! Configuration file management
 
-use dirs;
 use std::env;
-use std::fs::File;
+use std::fs::{self, File};
+use std::io::prelude::*;
 use std::io::Read;
 use std::path::PathBuf;
 use toml;
 
-use servers::{ServerConfig, StratumServerConfig};
-use types::{ConfigError, ConfigMembers, GlobalConfig};
+use comments::insert_comments;
+use servers::ServerConfig;
+use types::{
+	ConfigError, ConfigMembers, GlobalConfig, GlobalWalletConfig, GlobalWalletConfigMembers,
+};
 use util::LoggingConfig;
 use wallet::WalletConfig;
 
 /// The default file name to use when trying to derive
-/// the config file location
-
-const CONFIG_FILE_NAME: &'static str = "grin.toml";
+/// the node config file location
+pub const SERVER_CONFIG_FILE_NAME: &'static str = "grin-server.toml";
+/// And a wallet configuration file name
+pub const WALLET_CONFIG_FILE_NAME: &'static str = "grin-wallet.toml";
+const SERVER_LOG_FILE_NAME: &'static str = "grin-server.log";
+const WALLET_LOG_FILE_NAME: &'static str = "grin-wallet.log";
 const GRIN_HOME: &'static str = ".grin";
+const GRIN_CHAIN_DIR: &'static str = "chain_data";
+const GRIN_WALLET_DIR: &'static str = "wallet_data";
+
+fn get_grin_path() -> Result<PathBuf, ConfigError> {
+	// Check if grin dir exists
+	let grin_path = {
+		match env::home_dir() {
+			Some(mut p) => {
+				p.push(GRIN_HOME);
+				p
+			}
+			None => {
+				let mut pb = PathBuf::new();
+				pb.push(GRIN_HOME);
+				pb
+			}
+		}
+	};
+	// Create if the default path doesn't exist
+	if !grin_path.exists() {
+		fs::create_dir_all(grin_path.clone())?;
+	}
+	Ok(grin_path)
+}
+
+fn check_config_current_dir(path: &str) -> Option<PathBuf> {
+	let p = env::current_dir();
+	let mut c = match p {
+		Ok(c) => c,
+		Err(_) => {
+			return None;
+		}
+	};
+	c.push(path);
+	if c.exists() {
+		return Some(c);
+	}
+	None
+}
+
+/// Handles setup and detection of paths for node
+pub fn initial_setup_server() -> Result<GlobalConfig, ConfigError> {
+	// Use config file if current directory if it exists, .grin home otherwise
+	if let Some(p) = check_config_current_dir(SERVER_CONFIG_FILE_NAME) {
+		GlobalConfig::new(p.to_str().unwrap())
+	} else {
+		// Check if grin dir exists
+		let grin_path = get_grin_path()?;
+
+		// Get path to default config file
+		let mut config_path = grin_path.clone();
+		config_path.push(SERVER_CONFIG_FILE_NAME);
+
+		// Spit it out if it doesn't exist
+		if !config_path.exists() {
+			let mut default_config = GlobalConfig::default();
+			// update paths relative to current dir
+			default_config.update_paths(&grin_path);
+			default_config.write_to_file(config_path.to_str().unwrap())?;
+		}
+		GlobalConfig::new(config_path.to_str().unwrap())
+	}
+}
+
+/// Handles setup and detection of paths for wallet
+pub fn initial_setup_wallet() -> Result<GlobalWalletConfig, ConfigError> {
+	// Use config file if current directory if it exists, .grin home otherwise
+	if let Some(p) = check_config_current_dir(WALLET_CONFIG_FILE_NAME) {
+		GlobalWalletConfig::new(p.to_str().unwrap())
+	} else {
+		// Check if grin dir exists
+		let grin_path = get_grin_path()?;
+
+		// Get path to default config file
+		let mut config_path = grin_path.clone();
+		config_path.push(WALLET_CONFIG_FILE_NAME);
+
+		// Spit it out if it doesn't exist
+		if !config_path.exists() {
+			let mut default_config = GlobalWalletConfig::default();
+			// update paths relative to current dir
+			default_config.update_paths(&grin_path);
+			default_config.write_to_file(config_path.to_str().unwrap())?;
+		}
+		GlobalWalletConfig::new(config_path.to_str().unwrap())
+	}
+}
 
 /// Returns the defaults, as strewn throughout the code
-
 impl Default for ConfigMembers {
 	fn default() -> ConfigMembers {
 		ConfigMembers {
 			server: ServerConfig::default(),
-			mining_server: Some(StratumServerConfig::default()),
 			logging: Some(LoggingConfig::default()),
-			wallet: WalletConfig::default(),
 		}
 	}
 }
@@ -54,55 +144,29 @@ impl Default for GlobalConfig {
 	}
 }
 
-impl GlobalConfig {
-	/// Need to decide on rules where to read the config file from,
-	/// but will take a stab at logic for now
-
-	fn derive_config_location(&mut self) -> Result<(), ConfigError> {
-		// First, check working directory
-		let mut config_path = env::current_dir().unwrap();
-		config_path.push(CONFIG_FILE_NAME);
-		if config_path.exists() {
-			self.config_file_path = Some(config_path);
-			return Ok(());
+impl Default for GlobalWalletConfigMembers {
+	fn default() -> GlobalWalletConfigMembers {
+		GlobalWalletConfigMembers {
+			logging: Some(LoggingConfig::default()),
+			wallet: WalletConfig::default(),
 		}
-		// Next, look in directory of executable
-		let mut config_path = env::current_exe().unwrap();
-		config_path.pop();
-		config_path.push(CONFIG_FILE_NAME);
-		if config_path.exists() {
-			self.config_file_path = Some(config_path);
-			return Ok(());
-		}
-		// Then look in {user_home}/.grin
-		let config_path = dirs::home_dir();
-		if let Some(mut p) = config_path {
-			p.push(GRIN_HOME);
-			p.push(CONFIG_FILE_NAME);
-			if p.exists() {
-				self.config_file_path = Some(p);
-				return Ok(());
-			}
-		}
-
-		// Give up
-		Err(ConfigError::FileNotFoundError(String::from("")))
 	}
+}
 
-	/// Takes the path to a config file, or if NONE, tries to determine a config
-	/// file based on rules in derive_config_location
-	pub fn new(file_path: Option<&str>) -> Result<GlobalConfig, ConfigError> {
+impl Default for GlobalWalletConfig {
+	fn default() -> GlobalWalletConfig {
+		GlobalWalletConfig {
+			config_file_path: None,
+			members: Some(GlobalWalletConfigMembers::default()),
+		}
+	}
+}
+
+impl GlobalConfig {
+	/// Requires the path to a config file
+	pub fn new(file_path: &str) -> Result<GlobalConfig, ConfigError> {
 		let mut return_value = GlobalConfig::default();
-		if let Some(fp) = file_path {
-			return_value.config_file_path = Some(PathBuf::from(&fp));
-		} else {
-			let _result = return_value.derive_config_location();
-		}
-
-		// No attempt at a config file, just return defaults
-		if let None = return_value.config_file_path {
-			return Ok(return_value);
-		}
+		return_value.config_file_path = Some(PathBuf::from(&file_path));
 
 		// Config file path is given but not valid
 		let config_file = return_value.config_file_path.clone().unwrap();
@@ -124,10 +188,7 @@ impl GlobalConfig {
 		file.read_to_string(&mut contents)?;
 		let decoded: Result<ConfigMembers, toml::de::Error> = toml::from_str(&contents);
 		match decoded {
-			Ok(mut gc) => {
-				// Put the struct back together, because the config
-				// file was flattened a bit
-				gc.server.stratum_mining_config = gc.mining_server.clone();
+			Ok(gc) => {
 				self.members = Some(gc);
 				return Ok(self);
 			}
@@ -147,6 +208,37 @@ impl GlobalConfig {
 		}
 	}
 
+	/// Update paths
+	pub fn update_paths(&mut self, grin_home: &PathBuf) {
+		// need to update server chain path
+		let mut chain_path = grin_home.clone();
+		chain_path.push(GRIN_CHAIN_DIR);
+		self.members.as_mut().unwrap().server.db_root = chain_path.to_str().unwrap().to_owned();
+		let mut log_path = grin_home.clone();
+		log_path.push(SERVER_LOG_FILE_NAME);
+		self.members
+			.as_mut()
+			.unwrap()
+			.logging
+			.as_mut()
+			.unwrap()
+			.log_file_path = log_path.to_str().unwrap().to_owned();
+	}
+
+	/// Enable mining
+	pub fn stratum_enabled(&mut self) -> bool {
+		return self
+			.members
+			.as_mut()
+			.unwrap()
+			.server
+			.stratum_mining_config
+			.as_mut()
+			.unwrap()
+			.enable_stratum_server
+			.unwrap();
+	}
+
 	/// Serialize config
 	pub fn ser_config(&mut self) -> Result<String, ConfigError> {
 		let encoded: Result<String, toml::ser::Error> =
@@ -162,20 +254,101 @@ impl GlobalConfig {
 		}
 	}
 
-	/*pub fn wallet_enabled(&mut self) -> bool {
-        return self.members.as_mut().unwrap().wallet.as_mut().unwrap().enable_wallet;
-    }*/
-
-	/// Enable mining
-	pub fn stratum_enabled(&mut self) -> bool {
-		return self
-			.members
-			.as_mut()
-			.unwrap()
-			.mining_server
-			.as_mut()
-			.unwrap()
-			.enable_stratum_server
-			.unwrap();
+	/// Write configuration to a file
+	pub fn write_to_file(&mut self, name: &str) -> Result<(), ConfigError> {
+		let conf_out = self.ser_config()?;
+		let conf_out = insert_comments(conf_out);
+		let mut file = File::create(name)?;
+		file.write_all(conf_out.as_bytes())?;
+		Ok(())
+	}
+}
+
+/// TODO: Properly templatize these structs (if it's worth the effort)
+impl GlobalWalletConfig {
+	/// Requires the path to a config file
+	pub fn new(file_path: &str) -> Result<GlobalWalletConfig, ConfigError> {
+		let mut return_value = GlobalWalletConfig::default();
+		return_value.config_file_path = Some(PathBuf::from(&file_path));
+
+		// Config file path is given but not valid
+		let config_file = return_value.config_file_path.clone().unwrap();
+		if !config_file.exists() {
+			return Err(ConfigError::FileNotFoundError(String::from(
+				config_file.to_str().unwrap(),
+			)));
+		}
+
+		// Try to parse the config file if it exists, explode if it does exist but
+		// something's wrong with it
+		return_value.read_config()
+	}
+
+	/// Read config
+	fn read_config(mut self) -> Result<GlobalWalletConfig, ConfigError> {
+		let mut file = File::open(self.config_file_path.as_mut().unwrap())?;
+		let mut contents = String::new();
+		file.read_to_string(&mut contents)?;
+		let decoded: Result<GlobalWalletConfigMembers, toml::de::Error> = toml::from_str(&contents);
+		match decoded {
+			Ok(gc) => {
+				self.members = Some(gc);
+				return Ok(self);
+			}
+			Err(e) => {
+				return Err(ConfigError::ParseError(
+					String::from(
+						self.config_file_path
+							.as_mut()
+							.unwrap()
+							.to_str()
+							.unwrap()
+							.clone(),
+					),
+					String::from(format!("{}", e)),
+				));
+			}
+		}
+	}
+
+	/// Update paths
+	pub fn update_paths(&mut self, wallet_home: &PathBuf) {
+		let mut wallet_path = wallet_home.clone();
+		wallet_path.push(GRIN_WALLET_DIR);
+		self.members.as_mut().unwrap().wallet.data_file_dir =
+			wallet_path.to_str().unwrap().to_owned();
+		let mut log_path = wallet_home.clone();
+		log_path.push(WALLET_LOG_FILE_NAME);
+		self.members
+			.as_mut()
+			.unwrap()
+			.logging
+			.as_mut()
+			.unwrap()
+			.log_file_path = log_path.to_str().unwrap().to_owned();
+	}
+
+	/// Serialize config
+	pub fn ser_config(&mut self) -> Result<String, ConfigError> {
+		let encoded: Result<String, toml::ser::Error> =
+			toml::to_string(self.members.as_mut().unwrap());
+		match encoded {
+			Ok(enc) => return Ok(enc),
+			Err(e) => {
+				return Err(ConfigError::SerializationError(String::from(format!(
+					"{}",
+					e
+				))));
+			}
+		}
+	}
+
+	/// Write configuration to a file
+	pub fn write_to_file(&mut self, name: &str) -> Result<(), ConfigError> {
+		let conf_out = self.ser_config()?;
+		let conf_out = insert_comments(conf_out);
+		let mut file = File::create(name)?;
+		file.write_all(conf_out.as_bytes())?;
+		Ok(())
 	}
 }
diff --git a/config/src/lib.rs b/config/src/lib.rs
index bc1840cc9..63e93005d 100644
--- a/config/src/lib.rs
+++ b/config/src/lib.rs
@@ -20,7 +20,6 @@
 #![deny(unused_mut)]
 #![warn(missing_docs)]
 
-extern crate serde;
 #[macro_use]
 extern crate serde_derive;
 extern crate dirs;
@@ -31,7 +30,9 @@ extern crate grin_servers as servers;
 extern crate grin_util as util;
 extern crate grin_wallet as wallet;
 
+mod comments;
 pub mod config;
 pub mod types;
 
-pub use types::{ConfigError, ConfigMembers, GlobalConfig};
+pub use config::{initial_setup_server, initial_setup_wallet};
+pub use types::{ConfigError, ConfigMembers, GlobalConfig, GlobalWalletConfig};
diff --git a/config/src/types.rs b/config/src/types.rs
index ad88826df..56a10408b 100644
--- a/config/src/types.rs
+++ b/config/src/types.rs
@@ -18,7 +18,7 @@ use std::fmt;
 use std::io;
 use std::path::PathBuf;
 
-use servers::{ServerConfig, StratumServerConfig};
+use servers::ServerConfig;
 use util::LoggingConfig;
 use wallet::WalletConfig;
 
@@ -92,14 +92,25 @@ pub struct ConfigMembers {
 	/// Server config
 	#[serde(default)]
 	pub server: ServerConfig,
-	/// Mining config
-	pub mining_server: Option<StratumServerConfig>,
 	/// Logging config
 	pub logging: Option<LoggingConfig>,
+}
 
-	/// Wallet config. May eventually need to be moved to its own thing. Or not.
-	/// Depends on whether we end up starting the wallet in its own process but
-	/// with the same lifecycle as the server.
+/// Wallet should be split into a separate configuration file
+#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+pub struct GlobalWalletConfig {
+	/// Keep track of the file we've read
+	pub config_file_path: Option<PathBuf>,
+	/// Wallet members
+	pub members: Option<GlobalWalletConfigMembers>,
+}
+
+/// Wallet internal members
+#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+pub struct GlobalWalletConfigMembers {
+	/// Wallet configuration
 	#[serde(default)]
 	pub wallet: WalletConfig,
+	/// Logging config
+	pub logging: Option<LoggingConfig>,
 }
diff --git a/config/tests/config.rs b/config/tests/config.rs
deleted file mode 100644
index 86dd66271..000000000
--- a/config/tests/config.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-#[macro_use]
-extern crate pretty_assertions;
-extern crate grin_config as config;
-
-use config::GlobalConfig;
-
-#[test]
-fn file_config_equal_to_defaults() {
-	let global_config_without_file = GlobalConfig::default();
-
-	let global_config_with_file = GlobalConfig::new(Some("../grin.toml")).unwrap_or_else(|e| {
-		panic!("Error parsing config file: {}", e);
-	});
-
-	assert_eq!(
-		global_config_without_file.members,
-		global_config_with_file.members
-	);
-}
diff --git a/grin.toml b/grin.toml
deleted file mode 100644
index 876a7b52e..000000000
--- a/grin.toml
+++ /dev/null
@@ -1,183 +0,0 @@
-# Sample Server Configuration File for Grin
-#
-# When running the grin executable without specifying any command line
-# arguments, it will look for this file in three places, in the following
-# order:
-#
-# -The working directory
-# -The directory in which the executable resides
-# -[user home]/.grin
-#
-
-#########################################
-### SERVER CONFIGURATION              ###
-#########################################
-
-#Server connection details
-[server]
-
-#the address on which services will listen, e.g. Transaction Pool
-
-api_http_addr = "127.0.0.1:13413"
-
-#the directory, relative to current, in which the grin blockchain
-#is stored
-
-db_root = ".grin"
-
-#The chain type, which defines the genesis block and the set of cuckoo
-#parameters used for mining. Can be:
-#AutomatedTesting - For CI builds and instant blockchain creation
-#UserTesting - For regular user testing (cuckoo 16)
-#Testnet1 - Testnet1 genesis block (cuckoo 16)
-#Testnet2 - Testnet2 genesis block (cuckoo 30)
-
-chain_type = "Testnet3"
-
-#The chain validation mode, defines how often (if at all) we
-#want to run a full chain validation. Can be:
-#"EveryBlock" - run full chain validation when processing each block (except during sync)
-#"Disabled" - disable full chain validation (just run regular block validation)
-#chain_validation_mode = "Disabled"
-
-#run the node in "full archive" mode (default is fast-sync, pruned node)
-#archive_mode = false
-
-#skip waiting for sync on startup, (optional param, mostly for testing)
-skip_sync_wait = false
-
-#whether to run the ncurses TUI. Ncurses must be installed and this
-#will also disable logging to stdout
-run_tui = true
-
-#Whether to run the wallet listener with the server by default
-run_wallet_listener = true
-
-# Whether to run the web-wallet API (will only run on localhost)
-# grin wallet web will run this automatically, so this should
-# only be set to true for test/development purposes
-run_wallet_owner_api = false
-
-#Whether to run a test miner. This is only for developer testing (chaintype
-#usertesting) at cuckoo 16, and will only mine into the default wallet port.
-#real mining should use the standalone grin-miner
-run_test_miner = false
-
-#test miner wallet URL (burns if this doesn't exist)
-#test_miner_wallet_url = "http://127.0.0.1:13415"
-
-[server.dandelion_config]
-#dandelion relay time (choose new relay peer every n secs)
-relay_secs = 600
-
-#fluff and broadcast after embargo expires if tx not seen on network
-embargo_secs = 180
-
-#run dandelion stem/fluff processing every n secs (stem tx aggregation in this window)
-patience_secs = 10
-
-#dandelion stem probability (stem 90% of the time, fluff 10% of the time)
-stem_probability = 90
-
-#The P2P server details (i.e. the server that communicates with other
-#grin server nodes
-[server.p2p_config]
-
-host = "0.0.0.0"
-port = 13414
-
-#How to seed this server, can be None, List, WebStatic or DNSSeed
-#
-#seeding_type = "None"
-
-#If seeding_type = List, the list of peers to connect to.
-#
-#seeds = ["192.168.0.1:13414","192.168.0.2:13414"]
-
-#7 = Bit flags for FULL_NODE, this structure needs to be changed
-#internally to make it more configurable
-capabilities = [7]
-
-#hardcoded peer lists for allow/deny
-#will *only* connect to peers in allow list
-#peers_allow = ["192.168.0.1:13414", "192.168.0.2:13414"]
-#will *never* connect to peers in deny list
-#peers_deny = ["192.168.0.3:13414", "192.168.0.4:13414"]
-#a list of preferred peers to connect to
-#peers_preferred = ["192.168.0.1:13414","192.168.0.2:13414"]
-
-#how long a banned peer should stay banned
-#ban_window = 10800
-
-#maximum number of peers
-#peer_max_count = 25
-
-#preferred minimum number of peers (we'll actively keep trying to add peers
-#until we get to at least this number
-#peer_min_preferred_count = 8
-
-###########################################
-### STRATUM MINING SERVER CONFIGURATION ###
-###########################################
-[mining_server]
-
-#flag whether stratum server is enabled
-enable_stratum_server = true
-
-#what port and address for the stratum server to listen on
-stratum_server_addr = "127.0.0.1:13416"
-
-#The amount of time, in seconds, to attempt to mine on a particular
-#header before stopping and re-collecting transactions from the pool
-attempt_time_per_block = 15
-
-#The minimum acceptable share difficulty to request from miners
-minimum_share_difficulty = 1
-
-#the wallet receiver to which coinbase rewards will be sent
-wallet_listener_url = "http://127.0.0.1:13415"
-
-#whether to ignore the reward (mostly for testing)
-burn_reward = false
-
-#########################################
-### WALLET CONFIGURATION              ###
-#########################################
-
-[wallet]
-
-# Host IP for wallet listener, change to "0.0.0.0" to receive grins
-api_listen_interface = "127.0.0.1"
-
-# Port for wallet listener
-api_listen_port = 13415
-
-# Where the wallet should find a running node
-check_node_api_http_addr = "http://127.0.0.1:13413"
-
-# Where to find wallet files (seed, data, etc)
-data_file_dir = "."
-
-#########################################
-### LOGGING CONFIGURATION             ###
-#########################################
-
-[logging]
-
-# Whether to log to stdout
-log_to_stdout = true
-
-# Log level for stdout: Critical, Error, Warning, Info, Debug, Trace
-stdout_log_level = "Warning"
-
-# Whether to log to a file
-log_to_file = true
-
-# Log level for file: Critical, Error, Warning, Info, Debug, Trace
-file_log_level = "Debug"
-
-# Log file path
-log_file_path = "grin.log"
-
-# Whether to append to the log file (true), or replace it on every run (false)
-log_file_append = true
diff --git a/p2p/src/types.rs b/p2p/src/types.rs
index e37c751c7..69245cbe0 100644
--- a/p2p/src/types.rs
+++ b/p2p/src/types.rs
@@ -142,7 +142,7 @@ impl Default for P2PConfig {
 }
 
 /// Note certain fields are options just so they don't have to be
-/// included in grin.toml, but we don't want them to ever return none
+/// included in grin-server.toml, but we don't want them to ever return none
 impl P2PConfig {
 	/// return ban window
 	pub fn ban_window(&self) -> i64 {
diff --git a/servers/src/common/stats.rs b/servers/src/common/stats.rs
index 896b9ef0c..6c9368aea 100644
--- a/servers/src/common/stats.rs
+++ b/servers/src/common/stats.rs
@@ -201,8 +201,8 @@ impl Default for StratumStats {
 			is_running: false,
 			num_workers: 0,
 			block_height: 0,
-			network_difficulty: 0,
-			cuckoo_size: 0,
+			network_difficulty: 1000,
+			cuckoo_size: 30,
 			worker_stats: Vec::new(),
 		}
 	}
diff --git a/servers/src/common/types.rs b/servers/src/common/types.rs
index 0111e7fe3..26729f458 100644
--- a/servers/src/common/types.rs
+++ b/servers/src/common/types.rs
@@ -117,26 +117,12 @@ pub struct ServerConfig {
 	#[serde(default)]
 	pub chain_type: ChainTypes,
 
-	/// Whether this node is a full archival node or a fast-sync, pruned node
-	pub archive_mode: Option<bool>,
-
 	/// Automatically run full chain validation during normal block processing?
 	#[serde(default)]
 	pub chain_validation_mode: ChainValidationMode,
 
-	/// Configuration for the peer-to-peer server
-	pub p2p_config: p2p::P2PConfig,
-
-	/// Configuration for the mining daemon
-	pub stratum_mining_config: Option<StratumServerConfig>,
-
-	/// Transaction pool configuration
-	#[serde(default)]
-	pub pool_config: pool::PoolConfig,
-
-	/// Dandelion configuration
-	#[serde(default)]
-	pub dandelion_config: pool::DandelionConfig,
+	/// Whether this node is a full archival node or a fast-sync, pruned node
+	pub archive_mode: Option<bool>,
 
 	/// Whether to skip the sync timeout on startup
 	/// (To assist testing on solo chains)
@@ -160,23 +146,38 @@ pub struct ServerConfig {
 
 	/// Test miner wallet URL
 	pub test_miner_wallet_url: Option<String>,
+
+	/// Configuration for the peer-to-peer server
+	pub p2p_config: p2p::P2PConfig,
+
+	/// Transaction pool configuration
+	#[serde(default)]
+	pub pool_config: pool::PoolConfig,
+
+	/// Dandelion configuration
+	#[serde(default)]
+	pub dandelion_config: pool::DandelionConfig,
+
+	/// Configuration for the mining daemon
+	#[serde(default)]
+	pub stratum_mining_config: Option<StratumServerConfig>,
 }
 
 impl Default for ServerConfig {
 	fn default() -> ServerConfig {
 		ServerConfig {
-			db_root: ".grin".to_string(),
+			db_root: "grin_chain".to_string(),
 			api_http_addr: "127.0.0.1:13413".to_string(),
 			p2p_config: p2p::P2PConfig::default(),
 			dandelion_config: pool::DandelionConfig::default(),
 			stratum_mining_config: Some(StratumServerConfig::default()),
 			chain_type: ChainTypes::default(),
-			archive_mode: None,
+			archive_mode: Some(false),
 			chain_validation_mode: ChainValidationMode::default(),
 			pool_config: pool::PoolConfig::default(),
 			skip_sync_wait: Some(false),
 			run_tui: Some(true),
-			run_wallet_listener: Some(true),
+			run_wallet_listener: Some(false),
 			run_wallet_owner_api: Some(false),
 			use_db_wallet: None,
 			run_test_miner: Some(false),
@@ -217,7 +218,7 @@ impl Default for StratumServerConfig {
 			burn_reward: false,
 			attempt_time_per_block: 15,
 			minimum_share_difficulty: 1,
-			enable_stratum_server: Some(true),
+			enable_stratum_server: Some(false),
 			stratum_server_addr: Some("127.0.0.1:13416".to_string()),
 		}
 	}
diff --git a/servers/src/grin/server.rs b/servers/src/grin/server.rs
index 23f95ab3c..705a5bd0b 100644
--- a/servers/src/grin/server.rs
+++ b/servers/src/grin/server.rs
@@ -65,19 +65,21 @@ impl Server {
 	where
 		F: FnMut(Arc<Server>),
 	{
-		let mut mining_config = config.stratum_mining_config.clone();
+		let mining_config = config.stratum_mining_config.clone();
 		let enable_test_miner = config.run_test_miner;
 		let test_miner_wallet_url = config.test_miner_wallet_url.clone();
 		let serv = Arc::new(Server::new(config)?);
 
-		let enable_stratum_server = mining_config.as_mut().unwrap().enable_stratum_server;
-		if let Some(s) = enable_stratum_server {
-			if s {
-				{
-					let mut stratum_stats = serv.state_info.stratum_stats.write().unwrap();
-					stratum_stats.is_enabled = true;
+		if let Some(c) = mining_config {
+			let enable_stratum_server = c.enable_stratum_server;
+			if let Some(s) = enable_stratum_server {
+				if s {
+					{
+						let mut stratum_stats = serv.state_info.stratum_stats.write().unwrap();
+						stratum_stats.is_enabled = true;
+					}
+					serv.start_stratum_server(c.clone());
 				}
-				serv.start_stratum_server(mining_config.clone().unwrap());
 			}
 		}
 
diff --git a/src/bin/cmd/config.rs b/src/bin/cmd/config.rs
new file mode 100644
index 000000000..3e993244f
--- /dev/null
+++ b/src/bin/cmd/config.rs
@@ -0,0 +1,71 @@
+// Copyright 2018 The Grin Developers
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/// Grin configuation file output command
+use config::{GlobalConfig, GlobalWalletConfig};
+use std::env;
+
+/// Create a config file in the current directory
+pub fn config_command_server(file_name: &str) {
+	let mut default_config = GlobalConfig::default();
+	let current_dir = env::current_dir().unwrap_or_else(|e| {
+		panic!("Error creating config file: {}", e);
+	});
+	let mut config_file_name = current_dir.clone();
+	config_file_name.push(file_name);
+	if config_file_name.exists() {
+		panic!(
+			"{} already exists in the current directory. Please remove it first",
+			file_name
+		);
+	}
+	default_config.update_paths(&current_dir);
+	default_config
+		.write_to_file(config_file_name.to_str().unwrap())
+		.unwrap_or_else(|e| {
+			panic!("Error creating config file: {}", e);
+		});
+
+	println!(
+		"{} file configured and created in current directory",
+		file_name
+	);
+}
+
+/// Create a config file in the current directory
+pub fn config_command_wallet(file_name: &str) {
+	let mut default_config = GlobalWalletConfig::default();
+	let current_dir = env::current_dir().unwrap_or_else(|e| {
+		panic!("Error creating config file: {}", e);
+	});
+	let mut config_file_name = current_dir.clone();
+	config_file_name.push(file_name);
+	if config_file_name.exists() {
+		panic!(
+			"{} already exists in the target directory. Please remove it first",
+			file_name
+		);
+	}
+	default_config.update_paths(&current_dir);
+	default_config
+		.write_to_file(config_file_name.to_str().unwrap())
+		.unwrap_or_else(|e| {
+			panic!("Error creating config file: {}", e);
+		});
+
+	println!(
+		"File {} configured and created",
+		config_file_name.to_str().unwrap(),
+	);
+}
diff --git a/src/bin/cmd/mod.rs b/src/bin/cmd/mod.rs
index 801dcc36b..510df4f3c 100644
--- a/src/bin/cmd/mod.rs
+++ b/src/bin/cmd/mod.rs
@@ -13,9 +13,11 @@
 // limitations under the License.
 
 mod client;
+mod config;
 mod server;
 mod wallet;
 
 pub use self::client::client_command;
+pub use self::config::{config_command_server, config_command_wallet};
 pub use self::server::server_command;
-pub use self::wallet::wallet_command;
+pub use self::wallet::{seed_exists, wallet_command};
diff --git a/src/bin/cmd/server.rs b/src/bin/cmd/server.rs
index dd0195d04..6525feca0 100644
--- a/src/bin/cmd/server.rs
+++ b/src/bin/cmd/server.rs
@@ -123,7 +123,7 @@ pub fn server_command(server_args: Option<&ArgMatches>, mut global_config: Globa
 		}
 	}
 
-	if let Some(true) = server_config.run_wallet_listener {
+	/*if let Some(true) = server_config.run_wallet_listener {
 		let mut wallet_config = global_config.members.as_ref().unwrap().wallet.clone();
 		wallet::init_wallet_seed(wallet_config.clone());
 		let wallet = wallet::instantiate_wallet(wallet_config.clone(), "");
@@ -155,7 +155,7 @@ pub fn server_command(server_args: Option<&ArgMatches>, mut global_config: Globa
 					)
 				});
 			});
-	}
+	}*/
 
 	// start the server in the different run modes (interactive or daemon)
 	if let Some(a) = server_args {
diff --git a/src/bin/cmd/wallet.rs b/src/bin/cmd/wallet.rs
index 27f093714..0444e819e 100644
--- a/src/bin/cmd/wallet.rs
+++ b/src/bin/cmd/wallet.rs
@@ -12,6 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+use std::path::PathBuf;
 /// Wallet commands processing
 use std::process::exit;
 use std::sync::{Arc, Mutex};
@@ -20,7 +21,7 @@ use std::time::Duration;
 
 use clap::ArgMatches;
 
-use config::GlobalConfig;
+use config::GlobalWalletConfig;
 use core::core;
 use grin_wallet::{self, controller, display, libwallet};
 use grin_wallet::{HTTPWalletClient, LMDBBackend, WalletConfig, WalletInst, WalletSeed};
@@ -28,12 +29,22 @@ use keychain;
 use servers::start_webwallet_server;
 use util::LOGGER;
 
-pub fn init_wallet_seed(wallet_config: WalletConfig) {
+pub fn _init_wallet_seed(wallet_config: WalletConfig) {
 	if let Err(_) = WalletSeed::from_file(&wallet_config) {
 		WalletSeed::init_file(&wallet_config).expect("Failed to create wallet seed file.");
 	};
 }
 
+pub fn seed_exists(wallet_config: WalletConfig) -> bool {
+	let mut data_file_dir = PathBuf::new();
+	data_file_dir.push(wallet_config.data_file_dir);
+	data_file_dir.push(grin_wallet::SEED_FILE);
+	if data_file_dir.exists() {
+		true
+	} else {
+		false
+	}
+}
 pub fn instantiate_wallet(
 	wallet_config: WalletConfig,
 	passphrase: &str,
@@ -49,7 +60,7 @@ pub fn instantiate_wallet(
 			warn!(LOGGER, "Migration successful. Using LMDB Wallet backend");
 		}
 		warn!(LOGGER, "Please check the results of the migration process using `grin wallet info` and `grin wallet outputs`");
-		warn!(LOGGER, "If anything went wrong, you can try again by deleting the `wallet_data` directory and running a wallet command");
+		warn!(LOGGER, "If anything went wrong, you can try again by deleting the `db` directory and running a wallet command");
 		warn!(LOGGER, "If all is okay, you can move/backup/delete all files in the wallet directory EXCEPT FOR wallet.seed");
 	}
 	let client = HTTPWalletClient::new(&wallet_config.check_node_api_http_addr);
@@ -63,9 +74,9 @@ pub fn instantiate_wallet(
 	Box::new(db_wallet)
 }
 
-pub fn wallet_command(wallet_args: &ArgMatches, global_config: GlobalConfig) {
+pub fn wallet_command(wallet_args: &ArgMatches, config: GlobalWalletConfig) {
 	// just get defaults from the global config
-	let mut wallet_config = global_config.members.unwrap().wallet;
+	let mut wallet_config = config.members.unwrap().wallet;
 
 	if wallet_args.is_present("external") {
 		wallet_config.api_listen_interface = "0.0.0.0".to_string();
diff --git a/src/bin/grin.rs b/src/bin/grin.rs
index e653e4855..2bc216f1a 100644
--- a/src/bin/grin.rs
+++ b/src/bin/grin.rs
@@ -41,7 +41,7 @@ pub mod tui;
 
 use clap::{App, Arg, SubCommand};
 
-use config::GlobalConfig;
+use config::config::{SERVER_CONFIG_FILE_NAME, WALLET_CONFIG_FILE_NAME};
 use core::global;
 use util::{init_logger, LOGGER};
 
@@ -81,10 +81,14 @@ fn main() {
 		.version(crate_version!())
 		.author("The Grin Team")
 		.about("Lightweight implementation of the MimbleWimble protocol.")
-
     // specification of all the server commands and options
     .subcommand(SubCommand::with_name("server")
                 .about("Control the Grin server")
+                .arg(Arg::with_name("config_file")
+                     .short("c")
+                     .long("config_file")
+                     .help("Path to a grin-server.toml configuration file")
+                     .takes_value(true))
                 .arg(Arg::with_name("port")
                      .short("p")
                      .long("port")
@@ -104,7 +108,9 @@ fn main() {
                      .short("w")
                      .long("wallet_url")
                      .help("The wallet listener to which mining rewards will be sent")
-                	.takes_value(true))
+                     .takes_value(true))
+                .subcommand(SubCommand::with_name("config")
+                            .about("Generate a configuration grin-server.toml file in the current directory"))
                 .subcommand(SubCommand::with_name("start")
                             .about("Start the Grin server as a daemon"))
                 .subcommand(SubCommand::with_name("stop")
@@ -274,85 +280,114 @@ fn main() {
 			.about("basic wallet contents summary"))
 
 		.subcommand(SubCommand::with_name("init")
-			.about("Initialize a new wallet seed file and database."))
+			.about("Initialize a new wallet seed file and database.")
+			.arg(Arg::with_name("here")
+				.short("h")
+				.long("here")
+				.help("Create wallet files in the current directory instead of the default ~/.grin directory")
+				.takes_value(false)))
 
 		.subcommand(SubCommand::with_name("restore")
 			.about("Attempt to restore wallet contents from the chain using seed and password. \
 				NOTE: Backup wallet.* and run `wallet listen` before running restore.")))
 
 	.get_matches();
+	let mut wallet_config = None;
+	let mut node_config = None;
 
-	// load a global config object,
-	// then modify that object with any switches
-	// found so that the switches override the
-	// global config file
-
-	// This will return a global config object,
-	// which will either contain defaults for all // of the config structures or a
-	// configuration
-	// read from a config file
-
-	let mut global_config = GlobalConfig::new(None).unwrap_or_else(|e| {
-		panic!("Error parsing config file: {}", e);
-	});
-
-	// initialize the logger
-	let mut log_conf = global_config
-		.members
-		.as_mut()
-		.unwrap()
-		.logging
-		.clone()
-		.unwrap();
-	let run_tui = global_config.members.as_mut().unwrap().server.run_tui;
-	if run_tui.is_some() && run_tui.unwrap() && args.subcommand().0 != "wallet" {
-		log_conf.log_to_stdout = false;
-		log_conf.tui_running = Some(true);
+	// Deal with configuration file creation
+	match args.subcommand() {
+		("server", Some(server_args)) => {
+			// If it's just a server config command, do it and exit
+			if let ("config", Some(_)) = server_args.subcommand() {
+				cmd::config_command_server(SERVER_CONFIG_FILE_NAME);
+				return;
+			}
+		}
+		("wallet", Some(wallet_args)) => {
+			// wallet init command should spit out its config file then continue
+			// (if desired)
+			if let ("init", Some(init_args)) = wallet_args.subcommand() {
+				if init_args.is_present("here") {
+					cmd::config_command_wallet(WALLET_CONFIG_FILE_NAME);
+				}
+			}
+		}
+		_ => {}
+	}
+
+	match args.subcommand() {
+		// If it's a wallet command, try and load a wallet config file
+		("wallet", Some(wallet_args)) => {
+			let mut w = config::initial_setup_wallet().unwrap_or_else(|e| {
+				panic!("Error loading wallet configuration: {}", e);
+			});
+			if !cmd::seed_exists(w.members.as_ref().unwrap().wallet.clone()) {
+				if let ("init", Some(_)) = wallet_args.subcommand() {
+				} else {
+					println!("Wallet seed file doesn't exist. Run `grin wallet -p [password] init` first");
+					return;
+				}
+			}
+			let mut l = w.members.as_mut().unwrap().logging.clone().unwrap();
+			l.tui_running = Some(false);
+			init_logger(Some(l));
+			warn!(
+				LOGGER,
+				"Using wallet configuration file at {}",
+				w.config_file_path.as_ref().unwrap().to_str().unwrap()
+			);
+			wallet_config = Some(w);
+		}
+		// Otherwise load up the node config as usual
+		_ => {
+			let mut s = config::initial_setup_server().unwrap_or_else(|e| {
+				panic!("Error loading server configuration: {}", e);
+			});
+			let mut l = s.members.as_mut().unwrap().logging.clone().unwrap();
+			let run_tui = s.members.as_mut().unwrap().server.run_tui;
+			if let Some(true) = run_tui {
+				l.log_to_stdout = false;
+				l.tui_running = Some(true);
+			}
+			init_logger(Some(l));
+			global::set_mining_mode(s.members.as_mut().unwrap().server.clone().chain_type);
+			if let Some(file_path) = &s.config_file_path {
+				info!(
+					LOGGER,
+					"Using configuration file at {}",
+					file_path.to_str().unwrap()
+				);
+			} else {
+				info!(LOGGER, "Node configuration file not found, using default");
+			}
+			node_config = Some(s);
+		}
 	}
-	init_logger(Some(log_conf));
-	global::set_mining_mode(
-		global_config
-			.members
-			.as_mut()
-			.unwrap()
-			.server
-			.clone()
-			.chain_type,
-	);
 
 	log_build_info();
 
-	if let Some(file_path) = &global_config.config_file_path {
-		info!(
-			LOGGER,
-			"Found configuration file at {}",
-			file_path.to_str().unwrap()
-		);
-	} else {
-		info!(LOGGER, "configuration file not found, using default");
-	}
-
 	match args.subcommand() {
 		// server commands and options
 		("server", Some(server_args)) => {
-			cmd::server_command(Some(server_args), global_config);
+			cmd::server_command(Some(server_args), node_config.unwrap());
 		}
 
 		// client commands and options
 		("client", Some(client_args)) => {
-			cmd::client_command(client_args, global_config);
+			cmd::client_command(client_args, node_config.unwrap());
 		}
 
 		// client commands and options
 		("wallet", Some(wallet_args)) => {
-			cmd::wallet_command(wallet_args, global_config);
+			cmd::wallet_command(wallet_args, wallet_config.unwrap());
 		}
 
 		// If nothing is specified, try to just use the config file instead
 		// this could possibly become the way to configure most things
 		// with most command line options being phased out
 		_ => {
-			cmd::server_command(None, global_config);
+			cmd::server_command(None, node_config.unwrap());
 		}
 	}
 }
diff --git a/wallet/src/db_migrate.rs b/wallet/src/db_migrate.rs
index f0ad39634..a5cff059b 100644
--- a/wallet/src/db_migrate.rs
+++ b/wallet/src/db_migrate.rs
@@ -36,7 +36,7 @@ use store::{self, to_key};
 const DETAIL_FILE: &'static str = "wallet.det";
 const DAT_FILE: &'static str = "wallet.dat";
 const SEED_FILE: &'static str = "wallet.seed";
-const DB_DIR: &'static str = "wallet_data";
+const DB_DIR: &'static str = "db";
 const OUTPUT_PREFIX: u8 = 'o' as u8;
 const DERIV_PREFIX: u8 = 'd' as u8;
 const CONFIRMED_HEIGHT_PREFIX: u8 = 'c' as u8;
diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs
index acb7a6564..7f8487d44 100644
--- a/wallet/src/lib.rs
+++ b/wallet/src/lib.rs
@@ -63,7 +63,7 @@ pub use libwallet::types::{
 	BlockFees, CbData, WalletBackend, WalletClient, WalletInfo, WalletInst,
 };
 pub use lmdb_wallet::{wallet_db_exists, LMDBBackend};
-pub use types::{WalletConfig, WalletSeed};
+pub use types::{WalletConfig, WalletSeed, SEED_FILE};
 
 // temporary
 pub use db_migrate::{migrate, needs_migrate};
diff --git a/wallet/src/libwallet/internal/restore.rs b/wallet/src/libwallet/internal/restore.rs
index 658efd3ed..82c3a2ef9 100644
--- a/wallet/src/libwallet/internal/restore.rs
+++ b/wallet/src/libwallet/internal/restore.rs
@@ -159,7 +159,7 @@ where
 	if !is_empty {
 		error!(
 			LOGGER,
-			"Not restoring. Please back up and remove existing wallet_data directory first."
+			"Not restoring. Please back up and remove existing db directory first."
 		);
 		return Ok(());
 	}
diff --git a/wallet/src/lmdb_wallet.rs b/wallet/src/lmdb_wallet.rs
index 4287e96da..00d6e3311 100644
--- a/wallet/src/lmdb_wallet.rs
+++ b/wallet/src/lmdb_wallet.rs
@@ -27,7 +27,7 @@ use libwallet::{internal, Error, ErrorKind};
 use types::{WalletConfig, WalletSeed};
 use util::secp::pedersen;
 
-pub const DB_DIR: &'static str = "wallet_data";
+pub const DB_DIR: &'static str = "db";
 
 const COMMITMENT_PREFIX: u8 = 'C' as u8;
 const OUTPUT_PREFIX: u8 = 'o' as u8;