diff --git a/alert/alert.go b/alert/alert.go index 959e81459..d761da2a9 100644 --- a/alert/alert.go +++ b/alert/alert.go @@ -15,16 +15,16 @@ var alertCountSince int = 0 func Alert(message string) { log.Error(" ALERT \n" + message) now := time.Now().Unix() - if now-lastAlertUnix > int64(config.App.GetInt("Alert.MinInterval")) { - message = fmt.Sprintf("%v:%v", config.App.GetString("Network"), message) + if now-lastAlertUnix > int64(config.App().GetInt("Alert.MinInterval")) { + message = fmt.Sprintf("%v:%v", config.App().GetString("Network"), message) if alertCountSince > 0 { message = fmt.Sprintf("%v (+%v more since)", message, alertCountSince) alertCountSince = 0 } - if len(config.App.GetString("Alert.TwilioSid")) > 0 { + if len(config.App().GetString("Alert.TwilioSid")) > 0 { go sendTwilio(message) } - if len(config.App.GetString("Alert.EmailRecipients")) > 0 { + if len(config.App().GetString("Alert.EmailRecipients")) > 0 { go sendEmail(message) } } else { @@ -41,8 +41,8 @@ func sendTwilio(message string) { if len(message) > 50 { message = message[:50] } - twilio := gotwilio.NewTwilioClient(config.App.GetString("Alert.TwilioSid"), config.App.GetString("Alert.TwilioToken")) - res, exp, err := twilio.SendSMS(config.App.GetString("Alert.TwilioFrom"), config.App.GetString("Alert.TwilioTo"), message, "", "") + twilio := gotwilio.NewTwilioClient(config.App().GetString("Alert.TwilioSid"), config.App().GetString("Alert.TwilioToken")) + res, exp, err := twilio.SendSMS(config.App().GetString("Alert.TwilioFrom"), config.App().GetString("Alert.TwilioTo"), message, "", "") if exp != nil || err != nil { log.Error("sendTwilio error", "res", res, "exp", exp, "error", err) } @@ -58,7 +58,7 @@ func sendEmail(message string) { if len(subject) > 80 { subject = subject[:80] } - err := SendEmail(subject, message, config.App.GetStringSlice("Alert.EmailRecipients")) + err := SendEmail(subject, message, config.App().GetStringSlice("Alert.EmailRecipients")) if err != nil { log.Error("sendEmail error", "error", err, "message", message) } diff --git a/alert/email.go b/alert/email.go index 0a7102234..d484f6f26 100644 --- a/alert/email.go +++ b/alert/email.go @@ -19,7 +19,7 @@ import ( // Convenience function func SendEmail(subject, body string, tos []string) error { email := Compose(subject, body) - email.From = config.App.GetString("SMTP.User") + email.From = config.App().GetString("SMTP.User") email.ContentType = "text/html; charset=utf-8" email.AddRecipients(tos...) err := email.Send() @@ -86,12 +86,12 @@ func (e *Email) Send() error { auth := smtp.PlainAuth( "", - config.App.GetString("SMTP.User"), - config.App.GetString("SMTP.Password"), - config.App.GetString("SMTP.Host"), + config.App().GetString("SMTP.User"), + config.App().GetString("SMTP.Password"), + config.App().GetString("SMTP.Host"), ) - conn, err := smtp.Dial(fmt.Sprintf("%v:%v", config.App.GetString("SMTP.Host"), config.App.GetString("SMTP.Port"))) + conn, err := smtp.Dial(fmt.Sprintf("%v:%v", config.App().GetString("SMTP.Host"), config.App().GetString("SMTP.Port"))) if err != nil { return err } diff --git a/block/block.go b/block/block.go index 9b2d35f5d..bfa8c28f4 100644 --- a/block/block.go +++ b/block/block.go @@ -24,7 +24,7 @@ type Block struct { // Basic validation that doesn't involve state data. func (b *Block) ValidateBasic(lastBlockHeight uint, lastBlockHash []byte, lastBlockParts PartSetHeader, lastBlockTime time.Time) error { - if b.Network != config.App.GetString("Network") { + if b.Network != config.App().GetString("Network") { return errors.New("Wrong Block.Header.Network") } if b.Height != lastBlockHeight+1 { diff --git a/cmd/gen_validator.go b/cmd/gen_validator.go index f2777e557..1d3af701e 100644 --- a/cmd/gen_validator.go +++ b/cmd/gen_validator.go @@ -18,7 +18,7 @@ Paste the following JSON into your %v file %v `, - config.App.GetString("PrivValidatorFile"), + config.App().GetString("PrivValidatorFile"), string(privValidatorJSONBytes), ) } diff --git a/config/config.go b/config/config.go index e102972ea..2910a2f46 100644 --- a/config/config.go +++ b/config/config.go @@ -7,13 +7,23 @@ import ( "path" "path/filepath" "strings" + "sync" flag "github.com/spf13/pflag" "github.com/tendermint/confer" ) -var rootDir string -var App *confer.Config +var app *confer.Config +var appMtx sync.Mutex + +func App() *confer.Config { + appMtx.Lock() + defer appMtx.Unlock() + if app == nil { + Init("") + } + return app +} // NOTE: If you change this, maybe also change initDefaults() var defaultConfig = `# This is a TOML config file. @@ -75,44 +85,27 @@ var defaultGenesis = ` ` // NOTE: If you change this, maybe also change defaultConfig -func initDefaults() { - App.SetDefault("Network", "tendermint_testnet0") - App.SetDefault("ListenAddr", "0.0.0.0:8080") - App.SetDefault("DB.Backend", "leveldb") - App.SetDefault("DB.Dir", rootDir+"/data") - App.SetDefault("Log.Stdout.Level", "info") - App.SetDefault("Log.File.Dir", rootDir+"/log") - App.SetDefault("Log.File.Level", "debug") - App.SetDefault("RPC.HTTP.ListenAddr", "127.0.0.1:8081") - - App.SetDefault("GenesisFile", rootDir+"/genesis.json") - App.SetDefault("AddrBookFile", rootDir+"/addrbook.json") - App.SetDefault("PrivValidatorfile", rootDir+"/priv_validator.json") -} - -// Check if a file exists; if not, ensure the directory is made and write the file -func checkWriteFile(configFile, contents string) { - if _, err := os.Stat(configFile); os.IsNotExist(err) { - if strings.Index(configFile, "/") != -1 { - err := os.MkdirAll(filepath.Dir(configFile), 0700) - if err != nil { - fmt.Printf("Could not create directory: %v", err) - os.Exit(1) - } - } - err := ioutil.WriteFile(configFile, []byte(contents), 0600) - if err != nil { - fmt.Printf("Could not write config file: %v", err) - os.Exit(1) - } - fmt.Printf("Config file written to %v.\n", configFile) - } +func initDefaults(rootDir string) { + app.SetDefault("Network", "tendermint_testnet0") + app.SetDefault("ListenAddr", "0.0.0.0:8080") + app.SetDefault("DB.Backend", "leveldb") + app.SetDefault("DB.Dir", rootDir+"/data") + app.SetDefault("Log.Stdout.Level", "info") + app.SetDefault("Log.File.Dir", rootDir+"/log") + app.SetDefault("Log.File.Level", "debug") + app.SetDefault("RPC.HTTP.ListenAddr", "0.0.0.0:8081") + + app.SetDefault("GenesisFile", rootDir+"/genesis.json") + app.SetDefault("AddrBookFile", rootDir+"/addrbook.json") + app.SetDefault("PrivValidatorfile", rootDir+"/priv_validator.json") } -func init() { +func Init(rootDir string) { // Get RootDir - rootDir = os.Getenv("TMROOT") + if rootDir == "" { + rootDir = os.Getenv("TMROOT") + } if rootDir == "" { rootDir = os.Getenv("HOME") + "/.tendermint" } @@ -124,15 +117,34 @@ func init() { checkWriteFile(genesisFile, defaultGenesis) // Initialize Config - App = confer.NewConfig() - initDefaults() + app = confer.NewConfig() + initDefaults(rootDir) paths := []string{configFile} - if err := App.ReadPaths(paths...); err != nil { + if err := app.ReadPaths(paths...); err != nil { log.Warn("Error reading configuration", "paths", paths, "error", err) } // Confused? - // App.Debug() + // app.Debug() +} + +// Check if a file exists; if not, ensure the directory is made and write the file +func checkWriteFile(configFile, contents string) { + if _, err := os.Stat(configFile); os.IsNotExist(err) { + if strings.Index(configFile, "/") != -1 { + err := os.MkdirAll(filepath.Dir(configFile), 0700) + if err != nil { + fmt.Printf("Could not create directory: %v", err) + os.Exit(1) + } + } + err := ioutil.WriteFile(configFile, []byte(contents), 0600) + if err != nil { + fmt.Printf("Could not write config file: %v", err) + os.Exit(1) + } + fmt.Printf("Config file written to %v.\n", configFile) + } } func ParseFlags(args []string) { @@ -141,20 +153,20 @@ func ParseFlags(args []string) { // Declare flags flags.BoolVar(&printHelp, "help", false, "Print this help message.") - flags.String("listen_addr", App.GetString("ListenAddr"), "Listen address. (0.0.0.0:0 means any interface, any port)") - flags.String("seed_node", App.GetString("SeedNode"), "Address of seed node") - flags.String("rpc_http_listen_addr", App.GetString("RPC.HTTP.ListenAddr"), "RPC listen address. Port required") + flags.String("listen_addr", app.GetString("ListenAddr"), "Listen address. (0.0.0.0:0 means any interface, any port)") + flags.String("seed_node", app.GetString("SeedNode"), "Address of seed node") + flags.String("rpc_http_listen_addr", app.GetString("RPC.HTTP.ListenAddr"), "RPC listen address. Port required") flags.Parse(args) if printHelp { flags.PrintDefaults() os.Exit(0) } - // Merge parsed flag values onto App. - App.BindPFlag("ListenAddr", flags.Lookup("listen_addr")) - App.BindPFlag("SeedNode", flags.Lookup("seed_node")) - App.BindPFlag("RPC.HTTP.ListenAddr", flags.Lookup("rpc_http_listen_addr")) + // Merge parsed flag values onto app. + app.BindPFlag("ListenAddr", flags.Lookup("listen_addr")) + app.BindPFlag("SeedNode", flags.Lookup("seed_node")) + app.BindPFlag("RPC.HTTP.ListenAddr", flags.Lookup("rpc_http_listen_addr")) // Confused? - //App.Debug() + //app.Debug() } diff --git a/consensus/state.go b/consensus/state.go index 010e8b6e4..24f32aa12 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -619,7 +619,7 @@ func (cs *ConsensusState) RunActionPropose(height uint, round uint) { txs := cs.mempoolReactor.Mempool.GetProposalTxs() block = &blk.Block{ Header: &blk.Header{ - Network: config.App.GetString("Network"), + Network: config.App().GetString("Network"), Height: cs.Height, Time: time.Now(), Fees: 0, // TODO fees diff --git a/daemon/daemon.go b/daemon/daemon.go index c57d5c0ca..a9928dccf 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -36,21 +36,21 @@ func NewNode() *Node { stateDB := dbm.GetDB("state") state := sm.LoadState(stateDB) if state == nil { - state = sm.MakeGenesisStateFromFile(stateDB, config.App.GetString("GenesisFile")) + state = sm.MakeGenesisStateFromFile(stateDB, config.App().GetString("GenesisFile")) state.Save() } // Get PrivValidator var privValidator *sm.PrivValidator - if _, err := os.Stat(config.App.GetString("PrivValidatorFile")); err == nil { - privValidator = sm.LoadPrivValidator(config.App.GetString("PrivValidatorFile")) - log.Info("Loaded PrivValidator", "file", config.App.GetString("PrivValidatorFile"), "privValidator", privValidator) + if _, err := os.Stat(config.App().GetString("PrivValidatorFile")); err == nil { + privValidator = sm.LoadPrivValidator(config.App().GetString("PrivValidatorFile")) + log.Info("Loaded PrivValidator", "file", config.App().GetString("PrivValidatorFile"), "privValidator", privValidator) } else { - log.Info("No PrivValidator found", "file", config.App.GetString("PrivValidatorFile")) + log.Info("No PrivValidator found", "file", config.App().GetString("PrivValidatorFile")) } // Get PEXReactor - book := p2p.NewAddrBook(config.App.GetString("AddrBookFile")) + book := p2p.NewAddrBook(config.App().GetString("AddrBookFile")) pexReactor := p2p.NewPEXReactor(book) // Get MempoolReactor @@ -126,13 +126,13 @@ func Daemon() { // Create & start node n := NewNode() - l := p2p.NewDefaultListener("tcp", config.App.GetString("ListenAddr"), false) + l := p2p.NewDefaultListener("tcp", config.App().GetString("ListenAddr"), false) n.AddListener(l) n.Start() // If seedNode is provided by config, dial out. - if config.App.GetString("SeedNode") != "" { - addr := p2p.NewNetAddressString(config.App.GetString("SeedNode")) + if config.App().GetString("SeedNode") != "" { + addr := p2p.NewNetAddressString(config.App().GetString("SeedNode")) peer, err := n.sw.DialPeerWithAddress(addr) if err != nil { log.Error("Error dialing seed", "error", err) @@ -145,7 +145,7 @@ func Daemon() { } // Run the RPC server. - if config.App.GetString("RPC.HTTP.ListenAddr") != "" { + if config.App().GetString("RPC.HTTP.ListenAddr") != "" { rpc.SetRPCBlockStore(n.blockStore) rpc.SetRPCConsensusState(n.consensusState) rpc.SetRPCMempoolReactor(n.mempoolReactor) diff --git a/db/db.go b/db/db.go index afdea3da8..86d1bec3c 100644 --- a/db/db.go +++ b/db/db.go @@ -31,19 +31,19 @@ func GetDB(name string) DB { if db != nil { return db.(DB) } - switch config.App.GetString("DB.Backend") { + switch config.App().GetString("DB.Backend") { case DBBackendMemDB: db := NewMemDB() dbs.Set(name, db) return db case DBBackendLevelDB: - db, err := NewLevelDB(path.Join(config.App.GetString("DB.Dir"), name+".db")) + db, err := NewLevelDB(path.Join(config.App().GetString("DB.Dir"), name+".db")) if err != nil { panic(err) } dbs.Set(name, db) return db default: - panic(Fmt("Unknown DB backend: %v", config.App.GetString("DB.Backend"))) + panic(Fmt("Unknown DB backend: %v", config.App().GetString("DB.Backend"))) } } diff --git a/logger/log.go b/logger/log.go index 6ea35954f..d37fd67e2 100644 --- a/logger/log.go +++ b/logger/log.go @@ -24,12 +24,12 @@ func init() { // By default, there's a stdout terminal format handler. handlers = append(handlers, log15.LvlFilterHandler( - getLevel(config.App.GetString("Log.Stdout.Level")), + getLevel(config.App().GetString("Log.Stdout.Level")), log15.StreamHandler(os.Stdout, log15.TerminalFormat()), )) // Maybe also write to a file. - if _logFileDir := config.App.GetString("Log.File.Dir"); _logFileDir != "" { + if _logFileDir := config.App().GetString("Log.File.Dir"); _logFileDir != "" { // Create log dir if it doesn't exist err := os.MkdirAll(_logFileDir, 0700) if err != nil { @@ -38,7 +38,7 @@ func init() { } // File handler handlers = append(handlers, log15.LvlFilterHandler( - getLevel(config.App.GetString("Log.File.Level")), + getLevel(config.App().GetString("Log.File.Level")), log15.Must.FileHandler(_logFileDir+"/tendermint.log", log15.LogfmtFormat()), )) } diff --git a/rpc/http_server.go b/rpc/http_server.go index 2c195373c..17d157fb9 100644 --- a/rpc/http_server.go +++ b/rpc/http_server.go @@ -17,9 +17,9 @@ import ( func StartHTTPServer() { initHandlers() - log.Info(Fmt("Starting RPC HTTP server on %s", config.App.GetString("RPC.HTTP.ListenAddr"))) + log.Info(Fmt("Starting RPC HTTP server on %s", config.App().GetString("RPC.HTTP.ListenAddr"))) go func() { - log.Crit("RPC HTTPServer stopped", "result", http.ListenAndServe(config.App.GetString("RPC.HTTP.ListenAddr"), RecoverAndLogHandler(http.DefaultServeMux))) + log.Crit("RPC HTTPServer stopped", "result", http.ListenAndServe(config.App().GetString("RPC.HTTP.ListenAddr"), RecoverAndLogHandler(http.DefaultServeMux))) }() } diff --git a/rpc/net.go b/rpc/net.go index f805cbadf..ae187e1ab 100644 --- a/rpc/net.go +++ b/rpc/net.go @@ -17,14 +17,14 @@ func StatusHandler(w http.ResponseWriter, r *http.Request) { LatestBlockHeight uint LatestBlockTime int64 // nano Network string - }{genesisHash, latestBlockHash, latestHeight, latestBlockTime, config.App.GetString("Network")}) + }{genesisHash, latestBlockHash, latestHeight, latestBlockTime, config.App().GetString("Network")}) } func NetInfoHandler(w http.ResponseWriter, r *http.Request) { o, i, _ := p2pSwitch.NumPeers() numPeers := o + i listening := p2pSwitch.IsListening() - network := config.App.GetString("Network") + network := config.App().GetString("Network") WriteAPIResponse(w, API_OK, struct { NumPeers int Listening bool diff --git a/state/priv_validator.go b/state/priv_validator.go index c7afe63bd..854df45a7 100644 --- a/state/priv_validator.go +++ b/state/priv_validator.go @@ -68,7 +68,7 @@ func GenPrivValidator() *PrivValidator { LastHeight: 0, LastRound: 0, LastStep: stepNone, - filename: config.App.GetString("PrivValidatorFile"), + filename: config.App().GetString("PrivValidatorFile"), } } diff --git a/state/state_test.go b/state/state_test.go index bb2859b98..f719df075 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -55,7 +55,7 @@ func TestCopyState(t *testing.T) { func makeBlock(t *testing.T, state *State, commits []blk.Commit, txs []blk.Tx) *blk.Block { block := &blk.Block{ Header: &blk.Header{ - Network: config.App.GetString("Network"), + Network: config.App().GetString("Network"), Height: state.LastBlockHeight + 1, Time: state.LastBlockTime.Add(time.Minute), Fees: 0,