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
This commit is contained in:
Yeastplume 2018-08-30 10:10:40 +01:00 committed by GitHub
parent 471e80e69e
commit 1ded3f3972
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 955 additions and 381 deletions

469
config/src/comments.rs Normal file
View file

@ -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()
}

View file

@ -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 Default for GlobalWalletConfigMembers {
fn default() -> GlobalWalletConfigMembers {
GlobalWalletConfigMembers {
logging: Some(LoggingConfig::default()),
wallet: WalletConfig::default(),
}
}
}
impl Default for GlobalWalletConfig {
fn default() -> GlobalWalletConfig {
GlobalWalletConfig {
config_file_path: None,
members: Some(GlobalWalletConfigMembers::default()),
}
}
}
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(());
}
// 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> {
/// 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;
}*/
/// 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(())
}
}
/// Enable mining
pub fn stratum_enabled(&mut self) -> bool {
return self
.members
/// 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()
.mining_server
.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()
.enable_stratum_server
.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(())
}
}

View file

@ -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};

View file

@ -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>,
}

View file

@ -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
);
}

183
grin.toml
View file

@ -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

View file

@ -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 {

View file

@ -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(),
}
}

View file

@ -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()),
}
}

View file

@ -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(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(mining_config.clone().unwrap());
serv.start_stratum_server(c.clone());
}
}
}

71
src/bin/cmd/config.rs Normal file
View file

@ -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(),
);
}

View file

@ -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};

View file

@ -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 {

View file

@ -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();

View file

@ -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")
@ -105,6 +109,8 @@ fn main() {
.long("wallet_url")
.help("The wallet listener to which mining rewards will be sent")
.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;
}
init_logger(Some(log_conf));
global::set_mining_mode(
global_config
.members
.as_mut()
.unwrap()
.server
.clone()
.chain_type,
}
("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()
);
log_build_info();
if let Some(file_path) = &global_config.config_file_path {
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,
"Found configuration file at {}",
"Using configuration file at {}",
file_path.to_str().unwrap()
);
} else {
info!(LOGGER, "configuration file not found, using default");
info!(LOGGER, "Node configuration file not found, using default");
}
node_config = Some(s);
}
}
log_build_info();
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());
}
}
}

View file

@ -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;

View file

@ -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};

View file

@ -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(());
}

View file

@ -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;