Config is passed into each module. Remove tendermint/confer

This commit is contained in:
Jae Kwon 2015-05-15 18:05:09 -07:00
parent 183fa85cae
commit 75ef479547
41 changed files with 710 additions and 372 deletions

View File

@ -5,7 +5,6 @@ import (
"time" "time"
"github.com/sfreiberg/gotwilio" "github.com/sfreiberg/gotwilio"
"github.com/tendermint/tendermint/config"
) )
var lastAlertUnix int64 = 0 var lastAlertUnix int64 = 0
@ -15,16 +14,16 @@ var alertCountSince int = 0
func Alert(message string) { func Alert(message string) {
log.Error("<!> ALERT <!>\n" + message) log.Error("<!> ALERT <!>\n" + message)
now := time.Now().Unix() now := time.Now().Unix()
if now-lastAlertUnix > int64(config.App().GetInt("alert_min_interval")) { if now-lastAlertUnix > int64(config.GetInt("alert_min_interval")) {
message = fmt.Sprintf("%v:%v", config.App().GetString("network"), message) message = fmt.Sprintf("%v:%v", config.GetString("network"), message)
if alertCountSince > 0 { if alertCountSince > 0 {
message = fmt.Sprintf("%v (+%v more since)", message, alertCountSince) message = fmt.Sprintf("%v (+%v more since)", message, alertCountSince)
alertCountSince = 0 alertCountSince = 0
} }
if len(config.App().GetString("alert_twilio_sid")) > 0 { if len(config.GetString("alert_twilio_sid")) > 0 {
go sendTwilio(message) go sendTwilio(message)
} }
if len(config.App().GetString("alert_email_recipients")) > 0 { if len(config.GetString("alert_email_recipients")) > 0 {
go sendEmail(message) go sendEmail(message)
} }
} else { } else {
@ -41,8 +40,8 @@ func sendTwilio(message string) {
if len(message) > 50 { if len(message) > 50 {
message = message[:50] message = message[:50]
} }
twilio := gotwilio.NewTwilioClient(config.App().GetString("alert_twilio_sid"), config.App().GetString("alert_twilio_token")) twilio := gotwilio.NewTwilioClient(config.GetString("alert_twilio_sid"), config.GetString("alert_twilio_token"))
res, exp, err := twilio.SendSMS(config.App().GetString("alert_twilio_from"), config.App().GetString("alert_twilio_to"), message, "", "") res, exp, err := twilio.SendSMS(config.GetString("alert_twilio_from"), config.GetString("alert_twilio_to"), message, "", "")
if exp != nil || err != nil { if exp != nil || err != nil {
log.Error("sendTwilio error", "res", res, "exp", exp, "error", err) log.Error("sendTwilio error", "res", res, "exp", exp, "error", err)
} }
@ -58,7 +57,7 @@ func sendEmail(message string) {
if len(subject) > 80 { if len(subject) > 80 {
subject = subject[:80] subject = subject[:80]
} }
err := SendEmail(subject, message, config.App().GetStringSlice("alert_email_recipients")) err := SendEmail(subject, message, config.GetStringSlice("alert_email_recipients"))
if err != nil { if err != nil {
log.Error("sendEmail error", "error", err, "message", message) log.Error("sendEmail error", "error", err, "message", message)
} }

13
alert/config.go Normal file
View File

@ -0,0 +1,13 @@
package alert
import (
cfg "github.com/tendermint/tendermint/config"
)
var config cfg.Config = nil
func init() {
cfg.OnConfig(func(newConfig cfg.Config) {
config = newConfig
})
}

View File

@ -12,14 +12,12 @@ import (
"path/filepath" "path/filepath"
"regexp" "regexp"
"strings" "strings"
"github.com/tendermint/tendermint/config"
) )
// Convenience function // Convenience function
func SendEmail(subject, body string, tos []string) error { func SendEmail(subject, body string, tos []string) error {
email := Compose(subject, body) email := Compose(subject, body)
email.From = config.App().GetString("smtp_user") email.From = config.GetString("smtp_user")
email.ContentType = "text/html; charset=utf-8" email.ContentType = "text/html; charset=utf-8"
email.AddRecipients(tos...) email.AddRecipients(tos...)
err := email.Send() err := email.Send()
@ -86,12 +84,12 @@ func (e *Email) Send() error {
auth := smtp.PlainAuth( auth := smtp.PlainAuth(
"", "",
config.App().GetString("smtp_user"), config.GetString("smtp_user"),
config.App().GetString("smtp_password"), config.GetString("smtp_password"),
config.App().GetString("smtp_host"), config.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.GetString("smtp_host"), config.GetString("smtp_port")))
if err != nil { if err != nil {
return err return err
} }

View File

@ -118,7 +118,7 @@ func main() {
} }
// Write pid to file. This should be the last thing before TrapSignal. // Write pid to file. This should be the last thing before TrapSignal.
err = AtomicWriteFile(barak.rootDir+"/pidfile", []byte(Fmt("%v", barak.pid))) err = WriteFileAtomic(barak.rootDir+"/pidfile", []byte(Fmt("%v", barak.pid)))
if err != nil { if err != nil {
panic(Fmt("Error writing pidfile: %v", err)) panic(Fmt("Error writing pidfile: %v", err))
} }

13
cmd/tendermint/config.go Normal file
View File

@ -0,0 +1,13 @@
package main
import (
cfg "github.com/tendermint/tendermint/config"
)
var config cfg.Config = nil
func init() {
cfg.OnConfig(func(newConfig cfg.Config) {
config = newConfig
})
}

43
cmd/tendermint/flags.go Normal file
View File

@ -0,0 +1,43 @@
package main
import (
flag "github.com/spf13/pflag"
"os"
cfg "github.com/tendermint/tendermint/config"
)
func parseFlags(config cfg.Config, args []string) {
var (
printHelp bool
moniker string
nodeLaddr string
seeds string
fastSync bool
rpcLaddr string
logLevel string
)
// Declare flags
var flags = flag.NewFlagSet("main", flag.ExitOnError)
flags.BoolVar(&printHelp, "help", false, "Print this help message.")
flags.StringVar(&moniker, "moniker", config.GetString("moniker"), "Node Name")
flags.StringVar(&nodeLaddr, "node_laddr", config.GetString("node_laddr"), "Node listen address. (0.0.0.0:0 means any interface, any port)")
flags.StringVar(&seeds, "seeds", config.GetString("seeds"), "Comma delimited seed nodes")
flags.BoolVar(&fastSync, "fast_sync", config.GetBool("fast_sync"), "Fast blockchain syncing")
flags.StringVar(&rpcLaddr, "rpc_laddr", config.GetString("rpc_laddr"), "RPC listen address. Port required")
flags.StringVar(&logLevel, "log_level", config.GetString("log_level"), "Log level")
flags.Parse(args)
if printHelp {
flags.PrintDefaults()
os.Exit(0)
}
// Merge parsed flag values onto app.
config.Set("moniker", moniker)
config.Set("node_laddr", nodeLaddr)
config.Set("seeds", seeds)
config.Set("fast_sync", fastSync)
config.Set("rpc_laddr", rpcLaddr)
config.Set("log_level", logLevel)
}

View File

@ -4,7 +4,6 @@ import (
"fmt" "fmt"
"github.com/tendermint/tendermint/binary" "github.com/tendermint/tendermint/binary"
"github.com/tendermint/tendermint/config"
sm "github.com/tendermint/tendermint/state" sm "github.com/tendermint/tendermint/state"
) )
@ -18,7 +17,7 @@ Paste the following JSON into your %v file
%v %v
`, `,
config.App().GetString("priv_validator_file"), config.GetString("priv_validator_file"),
string(privValidatorJSONBytes), string(privValidatorJSONBytes),
) )
} }

View File

@ -4,8 +4,8 @@ import (
"fmt" "fmt"
"os" "os"
"github.com/tendermint/tendermint/config" cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/logger" tmcfg "github.com/tendermint/tendermint/config/tendermint"
"github.com/tendermint/tendermint/node" "github.com/tendermint/tendermint/node"
) )
@ -25,18 +25,19 @@ Commands:
return return
} }
// Get configuration
config := tmcfg.GetConfig("")
parseFlags(config, args[1:]) // Command line overrides
cfg.ApplyConfig(config) // Notify modules of new config
switch args[0] { switch args[0] {
case "node": case "node":
config.ParseFlags(args[1:])
logger.Reset()
node.RunNode() node.RunNode()
case "gen_account": case "gen_account":
gen_account() gen_account()
case "gen_validator": case "gen_validator":
gen_validator() gen_validator()
case "gen_tx": case "gen_tx":
config.ParseFlags(args[1:])
logger.Reset()
gen_tx() gen_tx()
case "probe_upnp": case "probe_upnp":
probe_upnp() probe_upnp()

View File

@ -3,7 +3,6 @@ package main
import ( import (
"os" "os"
"github.com/tendermint/tendermint/config"
sm "github.com/tendermint/tendermint/state" sm "github.com/tendermint/tendermint/state"
) )
@ -12,7 +11,7 @@ import (
func reset_priv_validator() { func reset_priv_validator() {
// Get PrivValidator // Get PrivValidator
var privValidator *sm.PrivValidator var privValidator *sm.PrivValidator
privValidatorFile := config.App().GetString("priv_validator_file") privValidatorFile := config.GetString("priv_validator_file")
if _, err := os.Stat(privValidatorFile); err == nil { if _, err := os.Stat(privValidatorFile); err == nil {
privValidator = sm.LoadPrivValidator(privValidatorFile) privValidator = sm.LoadPrivValidator(privValidatorFile)
privValidator.LastHeight = 0 privValidator.LastHeight = 0

View File

@ -28,31 +28,6 @@ func Exit(s string) {
os.Exit(1) os.Exit(1)
} }
// Writes to newBytes to filePath.
// Guaranteed not to lose *both* oldBytes and newBytes,
// (assuming that the OS is perfect)
func AtomicWriteFile(filePath string, newBytes []byte) error {
// If a file already exists there, copy to filePath+".bak" (overwrite anything)
if _, err := os.Stat(filePath); !os.IsNotExist(err) {
fileBytes, err := ioutil.ReadFile(filePath)
if err != nil {
return fmt.Errorf("Failed to read file %v. %v", filePath, err)
}
err = ioutil.WriteFile(filePath+".bak", fileBytes, 0600)
if err != nil {
return fmt.Errorf("Failed to write file %v. %v", filePath+".bak", err)
}
}
// Write newBytes to filePath.new
err := ioutil.WriteFile(filePath+".new", newBytes, 0600)
if err != nil {
return fmt.Errorf("Failed to write file %v. %v", filePath+".new", err)
}
// Move filePath.new to filePath
err = os.Rename(filePath+".new", filePath)
return err
}
func EnsureDir(dir string) error { func EnsureDir(dir string) error {
if _, err := os.Stat(dir); os.IsNotExist(err) { if _, err := os.Stat(dir); os.IsNotExist(err) {
err := os.MkdirAll(dir, 0700) err := os.MkdirAll(dir, 0700)
@ -62,3 +37,62 @@ func EnsureDir(dir string) error {
} }
return nil return nil
} }
func FileExists(filePath string) bool {
_, err := os.Stat(filePath)
return !os.IsNotExist(err)
}
func ReadFile(filePath string) ([]byte, error) {
return ioutil.ReadFile(filePath)
}
func MustReadFile(filePath string) []byte {
fileBytes, err := ioutil.ReadFile(filePath)
if err != nil {
Exit(Fmt("MustReadFile failed: %v", err))
return nil
}
return fileBytes
}
func WriteFile(filePath string, contents []byte) error {
err := ioutil.WriteFile(filePath, contents, 0600)
if err != nil {
return err
}
fmt.Printf("File written to %v.\n", filePath)
return nil
}
func MustWriteFile(filePath string, contents []byte) {
err := WriteFile(filePath, contents)
if err != nil {
Exit(Fmt("MustWriteFile failed: %v", err))
}
}
// Writes to newBytes to filePath.
// Guaranteed not to lose *both* oldBytes and newBytes,
// (assuming that the OS is perfect)
func WriteFileAtomic(filePath string, newBytes []byte) error {
// If a file already exists there, copy to filePath+".bak" (overwrite anything)
if _, err := os.Stat(filePath); !os.IsNotExist(err) {
fileBytes, err := ioutil.ReadFile(filePath)
if err != nil {
return fmt.Errorf("Could not read file %v. %v", filePath, err)
}
err = ioutil.WriteFile(filePath+".bak", fileBytes, 0600)
if err != nil {
return fmt.Errorf("Could not write file %v. %v", filePath+".bak", err)
}
}
// Write newBytes to filePath.new
err := ioutil.WriteFile(filePath+".new", newBytes, 0600)
if err != nil {
return fmt.Errorf("Could not write file %v. %v", filePath+".new", err)
}
// Move filePath.new to filePath
err = os.Rename(filePath+".new", filePath)
return err
}

View File

@ -3,186 +3,13 @@ package config
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"path"
"path/filepath"
"strings" "strings"
"sync" "sync"
"time"
flag "github.com/spf13/pflag"
"github.com/tendermint/confer"
) )
var app *confer.Config func Prompt(prompt string, defaultValue string) string {
var appMtx sync.Mutex
func App() *confer.Config {
appMtx.Lock()
defer appMtx.Unlock()
if app == nil {
Init("")
}
return app
}
func SetApp(a *confer.Config) {
appMtx.Lock()
defer appMtx.Unlock()
app = a
}
// NOTE: If you change this, maybe also change initDefaults()
var defaultConfigTmpl = `# This is a TOML config file.
# For more information, see https://github.com/toml-lang/toml
network = "tendermint_testnet_5"
moniker = "__MONIKER__"
node_laddr = "0.0.0.0:46656"
seeds = "goldenalchemist.chaintest.net:46656"
fast_sync = true
db_backend = "leveldb"
log_level = "debug"
rpc_laddr = "0.0.0.0:46657"
`
var DefaultGenesis = `{
"accounts": [
{
"address": "F81CB9ED0A868BD961C4F5BBC0E39B763B89FCB6",
"amount": 690000000000
},
{
"address": "0000000000000000000000000000000000000002",
"amount": 565000000000
},
{
"address": "9E54C9ECA9A3FD5D4496696818DA17A9E17F69DA",
"amount": 525000000000
},
{
"address": "0000000000000000000000000000000000000004",
"amount": 110000000000
}
],
"validators": [
{
"pub_key": [1, "178EC6008A4364508979C70CBF100BD4BCBAA12DDE6251F5F486B4FD09014F06"],
"amount": 5000000000,
"unbond_to": [
{
"address": "93E243AC8A01F723DE353A4FA1ED911529CCB6E5",
"amount": 5000000000
}
]
},
{
"pub_key": [1, "2A77777CC51467DE42350D4A8F34720D527734189BE64C7A930DD169E1FED3C6"],
"amount": 5000000000,
"unbond_to": [
{
"address": "93E243AC8A01F723DE353A4FA1ED911529CCB6E5",
"amount": 5000000000
}
]
},
{
"pub_key": [1, "3718E69D09B11B3AD3FA31AEF07EC416D2AEED241CACE7B0F30AE9803FFB0F08"],
"amount": 5000000000,
"unbond_to": [
{
"address": "93E243AC8A01F723DE353A4FA1ED911529CCB6E5",
"amount": 5000000000
}
]
},
{
"pub_key": [1, "C6B0440DEACD1E4CF1C736CEB8E38E788B700BA2B2045A55CB657A455CF5F889"],
"amount": 5000000000,
"unbond_to": [
{
"address": "93E243AC8A01F723DE353A4FA1ED911529CCB6E5",
"amount": 5000000000
}
]
},
{
"pub_key": [1, "3BA1190D54F91EFBF8B0125F7EC116AD4BA2894B6EE38564A5D5FD3230D91F7B"],
"amount": 5000000000,
"unbond_to": [
{
"address": "93E243AC8A01F723DE353A4FA1ED911529CCB6E5",
"amount": 5000000000
}
]
},
{
"pub_key": [1, "E56663353D01C58A1D4CDB4D14B70C2E3335BE1EBB6C3F697AF7882C03837962"],
"amount": 5000000000,
"unbond_to": [
{
"address": "9E54C9ECA9A3FD5D4496696818DA17A9E17F69DA",
"amount": 5000000000
}
]
}
]
}`
// If not defined in the process args nor config file, then use these defaults.
// NOTE: If you change this, maybe also change defaultConfig
func initDefaults(rootDir string) {
app.SetDefault("network", "tendermint_testnet0")
app.SetDefault("version", "0.2.1")
app.SetDefault("genesis_file", rootDir+"/genesis.json")
app.SetDefault("moniker", "anonymous")
app.SetDefault("node_laddr", "0.0.0.0:46656")
app.SetDefault("seeds", "goldenalchemist.chaintest.net:46656")
app.SetDefault("fast_sync", true)
app.SetDefault("addrbook_file", rootDir+"/addrbook.json")
app.SetDefault("priv_validator_file", rootDir+"/priv_validator.json")
app.SetDefault("db_backend", "leveldb")
app.SetDefault("db_dir", rootDir+"/data")
app.SetDefault("log_level", "info")
app.SetDefault("rpc_laddr", "0.0.0.0:46657")
}
func Init(rootDir string) {
// Get rootdir
if rootDir == "" {
rootDir = os.Getenv("TMROOT")
}
if rootDir == "" {
rootDir = os.Getenv("HOME") + "/.tendermint"
}
configFile := path.Join(rootDir, "config.toml")
genesisFile := path.Join(rootDir, "genesis.json")
// Write default config file if missing.
if !fileExists(configFile) {
// Ask user for moniker
moniker := getInput("Type hostname: ", "anonymous")
defaultConfig := strings.Replace(defaultConfigTmpl, "__MONIKER__", moniker, -1)
writeFile(configFile, defaultConfig)
}
if !fileExists(genesisFile) {
writeFile(genesisFile, DefaultGenesis)
}
// Initialize Config
app = confer.NewConfig()
initDefaults(rootDir)
paths := []string{configFile}
if err := app.ReadPaths(paths...); err != nil {
log.Warn("Error reading configuration", "paths", paths, "error", err)
}
// Confused?
//app.Debug()
}
func getInput(prompt string, defaultValue string) string {
fmt.Print(prompt) fmt.Print(prompt)
reader := bufio.NewReader(os.Stdin) reader := bufio.NewReader(os.Stdin)
line, err := reader.ReadString('\n') line, err := reader.ReadString('\n')
@ -198,55 +25,71 @@ func getInput(prompt string, defaultValue string) string {
} }
} }
func fileExists(file string) bool { type Config interface {
_, err := os.Stat(file) Get(key string) interface{}
return !os.IsNotExist(err) GetBool(key string) bool
GetFloat64(key string) float64
GetInt(key string) int
GetString(key string) string
GetStringMap(key string) map[string]interface{}
GetStringMapString(key string) map[string]string
GetStringSlice(key string) []string
GetTime(key string) time.Time
IsSet(key string) bool
Set(key string, value interface{})
} }
func writeFile(file, contents string) { type MapConfig map[string]interface{}
if _, err := os.Stat(file); os.IsNotExist(err) {
if strings.Index(file, "/") != -1 { func (cfg MapConfig) Get(key string) interface{} { return cfg[key] }
err := os.MkdirAll(filepath.Dir(file), 0700) func (cfg MapConfig) GetBool(key string) bool { return cfg[key].(bool) }
if err != nil { func (cfg MapConfig) GetFloat64(key string) float64 { return cfg[key].(float64) }
fmt.Printf("Could not create directory: %v", err) func (cfg MapConfig) GetInt(key string) int { return cfg[key].(int) }
os.Exit(1) func (cfg MapConfig) GetString(key string) string { return cfg[key].(string) }
} func (cfg MapConfig) GetStringMap(key string) map[string]interface{} {
} return cfg[key].(map[string]interface{})
err := ioutil.WriteFile(file, []byte(contents), 0600) }
if err != nil { func (cfg MapConfig) GetStringMapString(key string) map[string]string {
fmt.Printf("Could not write file: %v", err) return cfg[key].(map[string]string)
os.Exit(1) }
} func (cfg MapConfig) GetStringSlice(key string) []string { return cfg[key].([]string) }
fmt.Printf("File written to %v.\n", file) func (cfg MapConfig) GetTime(key string) time.Time { return cfg[key].(time.Time) }
func (cfg MapConfig) IsSet(key string) bool { _, ok := cfg[key]; return ok }
func (cfg MapConfig) Set(key string, value interface{}) { cfg[key] = value }
func (cfg MapConfig) SetDefault(key string, value interface{}) {
if cfg.IsSet(key) {
return
}
cfg[key] = value
}
//--------------------------------------------------------------------------------
// A little convenient hack to notify listeners upon config changes.
type Configurable func(Config)
var mtx sync.Mutex
var globalConfig Config
var confs []Configurable
func OnConfig(conf func(Config)) {
mtx.Lock()
defer mtx.Unlock()
confs = append(confs, conf)
if globalConfig != nil {
conf(globalConfig)
} }
} }
func ParseFlags(args []string) { func ApplyConfig(config Config) {
var flags = flag.NewFlagSet("main", flag.ExitOnError) mtx.Lock()
var printHelp = false globalConfig = config
confsCopy := make([]Configurable, len(confs))
copy(confsCopy, confs)
mtx.Unlock()
// Declare flags for _, conf := range confsCopy {
flags.BoolVar(&printHelp, "help", false, "Print this help message.") conf(config)
flags.String("moniker", app.GetString("moniker"), "Node Name")
flags.String("node_laddr", app.GetString("node_laddr"), "Node listen address. (0.0.0.0:0 means any interface, any port)")
flags.String("seeds", app.GetString("seeds"), "Comma delimited seed nodes")
flags.Bool("fast_sync", app.GetBool("fast_sync"), "Fast blockchain syncing")
flags.String("rpc_laddr", app.GetString("rpc_laddr"), "RPC listen address. Port required")
flags.String("log_level", app.GetString("log_level"), "Log level")
flags.Parse(args)
if printHelp {
flags.PrintDefaults()
os.Exit(0)
} }
// Merge parsed flag values onto app.
app.BindPFlag("moniker", flags.Lookup("moniker"))
app.BindPFlag("node_laddr", flags.Lookup("node_laddr"))
app.BindPFlag("seeds", flags.Lookup("seeds"))
app.BindPFlag("fast_sync", flags.Lookup("fast_sync"))
app.BindPFlag("rpc_laddr", flags.Lookup("rpc_laddr"))
app.BindPFlag("log_level", flags.Lookup("log_level"))
// Confused?
//app.Debug()
} }

181
config/tendermint/config.go Normal file
View File

@ -0,0 +1,181 @@
package tendermint
import (
"github.com/naoina/toml"
"os"
"path"
"strings"
. "github.com/tendermint/tendermint/common"
cfg "github.com/tendermint/tendermint/config"
)
func getTMRoot(rootDir string) string {
if rootDir == "" {
rootDir = os.Getenv("TMROOT")
}
if rootDir == "" {
rootDir = os.Getenv("HOME") + "/.tendermint"
}
return rootDir
}
func initTMRoot(rootDir string) {
rootDir = getTMRoot(rootDir)
EnsureDir(rootDir)
configFilePath := path.Join(rootDir, "config.toml")
genesisFilePath := path.Join(rootDir, "genesis.json")
// Write default config file if missing.
if !FileExists(configFilePath) {
// Ask user for moniker
moniker := cfg.Prompt("Type hostname: ", "anonymous")
MustWriteFile(configFilePath, []byte(defaultConfig(moniker)))
}
if !FileExists(genesisFilePath) {
MustWriteFile(genesisFilePath, []byte(defaultGenesis))
}
}
func GetConfig(rootDir string) cfg.Config {
rootDir = getTMRoot(rootDir)
initTMRoot(rootDir)
var mapConfig = cfg.MapConfig(make(map[string]interface{}))
configFilePath := path.Join(rootDir, "config.toml")
configFileBytes := MustReadFile(configFilePath)
err := toml.Unmarshal(configFileBytes, mapConfig)
if err != nil {
Exit(Fmt("Could not read config: %v", err))
}
// Set defaults or panic
if !mapConfig.IsSet("network") {
Exit("Must set 'network'")
}
if mapConfig.IsSet("version") {
Exit("Cannot set 'version' via config.toml")
}
// mapConfig.SetDefault("network", "tendermint_testnet0")
mapConfig.SetDefault("version", "0.2.1")
mapConfig.SetDefault("genesis_file", rootDir+"/genesis.json")
mapConfig.SetDefault("moniker", "anonymous")
mapConfig.SetDefault("node_laddr", "0.0.0.0:46656")
// mapConfig.SetDefault("seeds", "goldenalchemist.chaintest.net:46656")
mapConfig.SetDefault("fast_sync", true)
mapConfig.SetDefault("addrbook_file", rootDir+"/addrbook.json")
mapConfig.SetDefault("priv_validator_file", rootDir+"/priv_validator.json")
mapConfig.SetDefault("db_backend", "leveldb")
mapConfig.SetDefault("db_dir", rootDir+"/data")
mapConfig.SetDefault("log_level", "info")
mapConfig.SetDefault("rpc_laddr", "0.0.0.0:46657")
return mapConfig
}
func ensureDefault(mapConfig cfg.MapConfig, key string, value interface{}) {
if !mapConfig.IsSet(key) {
mapConfig[key] = value
}
}
var defaultConfigTmpl = `# This is a TOML config file.
# For more information, see https://github.com/toml-lang/toml
network = "tendermint_testnet_5"
moniker = "__MONIKER__"
node_laddr = "0.0.0.0:46656"
seeds = "goldenalchemist.chaintest.net:46656"
fast_sync = true
db_backend = "leveldb"
log_level = "debug"
rpc_laddr = "0.0.0.0:46657"
`
func defaultConfig(moniker string) (defaultConfig string) {
defaultConfig = strings.Replace(defaultConfigTmpl, "__MONIKER__", moniker, -1)
return
}
var defaultGenesis = `{
"accounts": [
{
"address": "F81CB9ED0A868BD961C4F5BBC0E39B763B89FCB6",
"amount": 690000000000
},
{
"address": "0000000000000000000000000000000000000002",
"amount": 565000000000
},
{
"address": "9E54C9ECA9A3FD5D4496696818DA17A9E17F69DA",
"amount": 525000000000
},
{
"address": "0000000000000000000000000000000000000004",
"amount": 110000000000
}
],
"validators": [
{
"pub_key": [1, "178EC6008A4364508979C70CBF100BD4BCBAA12DDE6251F5F486B4FD09014F06"],
"amount": 5000000000,
"unbond_to": [
{
"address": "93E243AC8A01F723DE353A4FA1ED911529CCB6E5",
"amount": 5000000000
}
]
},
{
"pub_key": [1, "2A77777CC51467DE42350D4A8F34720D527734189BE64C7A930DD169E1FED3C6"],
"amount": 5000000000,
"unbond_to": [
{
"address": "93E243AC8A01F723DE353A4FA1ED911529CCB6E5",
"amount": 5000000000
}
]
},
{
"pub_key": [1, "3718E69D09B11B3AD3FA31AEF07EC416D2AEED241CACE7B0F30AE9803FFB0F08"],
"amount": 5000000000,
"unbond_to": [
{
"address": "93E243AC8A01F723DE353A4FA1ED911529CCB6E5",
"amount": 5000000000
}
]
},
{
"pub_key": [1, "C6B0440DEACD1E4CF1C736CEB8E38E788B700BA2B2045A55CB657A455CF5F889"],
"amount": 5000000000,
"unbond_to": [
{
"address": "93E243AC8A01F723DE353A4FA1ED911529CCB6E5",
"amount": 5000000000
}
]
},
{
"pub_key": [1, "3BA1190D54F91EFBF8B0125F7EC116AD4BA2894B6EE38564A5D5FD3230D91F7B"],
"amount": 5000000000,
"unbond_to": [
{
"address": "93E243AC8A01F723DE353A4FA1ED911529CCB6E5",
"amount": 5000000000
}
]
},
{
"pub_key": [1, "E56663353D01C58A1D4CDB4D14B70C2E3335BE1EBB6C3F697AF7882C03837962"],
"amount": 5000000000,
"unbond_to": [
{
"address": "9E54C9ECA9A3FD5D4496696818DA17A9E17F69DA",
"amount": 5000000000
}
]
}
]
}`

View File

@ -0,0 +1,132 @@
package tendermint_test
import (
"github.com/naoina/toml"
"os"
"path"
"strings"
. "github.com/tendermint/tendermint/common"
cfg "github.com/tendermint/tendermint/config"
)
func getTMRoot(rootDir string) string {
if rootDir == "" {
rootDir = os.Getenv("HOME") + "/.tendermint_test"
}
return rootDir
}
func initTMRoot(rootDir string) {
rootDir = getTMRoot(rootDir)
EnsureDir(rootDir)
configFilePath := path.Join(rootDir, "config.toml")
genesisFilePath := path.Join(rootDir, "genesis.json")
privValFilePath := path.Join(rootDir, "priv_validator.json")
// Write default config file if missing.
if !FileExists(configFilePath) {
// Ask user for moniker
moniker := cfg.Prompt("Type hostname: ", "anonymous")
MustWriteFile(configFilePath, []byte(defaultConfig(moniker)))
}
if !FileExists(genesisFilePath) {
MustWriteFile(genesisFilePath, []byte(defaultGenesis))
}
if !FileExists(privValFilePath) {
MustWriteFile(privValFilePath, []byte(privValFilePath))
}
}
func GetConfig(rootDir string) cfg.Config {
rootDir = getTMRoot(rootDir)
initTMRoot(rootDir)
var mapConfig = cfg.MapConfig(make(map[string]interface{}))
configFilePath := path.Join(rootDir, "config.toml")
configFileBytes := MustReadFile(configFilePath)
err := toml.Unmarshal(configFileBytes, mapConfig)
if err != nil {
Exit(Fmt("Could not read config: %v", err))
}
// Set defaults or panic
if !mapConfig.IsSet("network") {
Exit("Must set 'network'")
}
if mapConfig.IsSet("version") {
Exit("Cannot set 'version' via config.toml")
}
// mapConfig.SetDefault("network", "tendermint_testnet0")
mapConfig.SetDefault("version", "0.2.1")
mapConfig.SetDefault("genesis_file", rootDir+"/genesis.json")
mapConfig.SetDefault("moniker", "anonymous")
mapConfig.SetDefault("node_laddr", "0.0.0.0:36656")
mapConfig.SetDefault("fast_sync", true)
mapConfig.SetDefault("addrbook_file", rootDir+"/addrbook.json")
mapConfig.SetDefault("priv_validator_file", rootDir+"/priv_validator.json")
mapConfig.SetDefault("db_backend", "memdb")
mapConfig.SetDefault("db_dir", rootDir+"/data")
mapConfig.SetDefault("log_level", "debug")
mapConfig.SetDefault("rpc_laddr", "0.0.0.0:36657")
return mapConfig
}
func ensureDefault(mapConfig cfg.MapConfig, key string, value interface{}) {
if !mapConfig.IsSet(key) {
mapConfig[key] = value
}
}
var defaultConfigTmpl = `# This is a TOML config file.
# For more information, see https://github.com/toml-lang/toml
network = "tendermint_test"
moniker = "__MONIKER__"
node_laddr = "0.0.0.0:36656"
seeds = ""
fast_sync = true
db_backend = "memdb"
log_level = "debug"
rpc_laddr = "0.0.0.0:36657"
`
func defaultConfig(moniker string) (defaultConfig string) {
defaultConfig = strings.Replace(defaultConfigTmpl, "__MONIKER__", moniker, -1)
return
}
var defaultGenesis = `{
"accounts": [
{
"address": "1D7A91CB32F758A02EBB9BE1FB6F8DEE56F90D42",
"amount": 200000000
},
{
"address": "AC89A6DDF4C309A89A2C4078CE409A5A7B282270",
"amount": 200000000
}
],
"validators": [
{
"pub_key": [1, "06FBAC4E285285D1D91FCBC7E91C780ADA11516F67462340B3980CE2B94940E8"],
"amount": 1000000,
"unbond_to": [
{
"address": "1D7A91CB32F758A02EBB9BE1FB6F8DEE56F90D42",
"amount": 100000
}
]
}
]
}`
var defaultPrivValidator = `{
"address": "1D7A91CB32F758A02EBB9BE1FB6F8DEE56F90D42",
"pub_key": [1,"06FBAC4E285285D1D91FCBC7E91C780ADA11516F67462340B3980CE2B94940E8"],
"priv_key": [1,"C453604BD6480D5538B4C6FD2E3E314B5BCE518D75ADE4DA3DA85AB8ADFD819606FBAC4E285285D1D91FCBC7E91C780ADA11516F67462340B3980CE2B94940E8"],
"last_height":0,
"last_round":0,
"last_step":0
}`

13
consensus/config.go Normal file
View File

@ -0,0 +1,13 @@
package consensus
import (
cfg "github.com/tendermint/tendermint/config"
)
var config cfg.Config = nil
func init() {
cfg.OnConfig(func(newConfig cfg.Config) {
config = newConfig
})
}

View File

@ -4,6 +4,7 @@ import (
"github.com/tendermint/tendermint/binary" "github.com/tendermint/tendermint/binary"
. "github.com/tendermint/tendermint/common" . "github.com/tendermint/tendermint/common"
sm "github.com/tendermint/tendermint/state" sm "github.com/tendermint/tendermint/state"
_ "github.com/tendermint/tendermint/test"
"github.com/tendermint/tendermint/types" "github.com/tendermint/tendermint/types"
"bytes" "bytes"

View File

@ -69,7 +69,6 @@ import (
"github.com/tendermint/tendermint/binary" "github.com/tendermint/tendermint/binary"
bc "github.com/tendermint/tendermint/blockchain" bc "github.com/tendermint/tendermint/blockchain"
. "github.com/tendermint/tendermint/common" . "github.com/tendermint/tendermint/common"
"github.com/tendermint/tendermint/config"
. "github.com/tendermint/tendermint/consensus/types" . "github.com/tendermint/tendermint/consensus/types"
"github.com/tendermint/tendermint/events" "github.com/tendermint/tendermint/events"
mempl "github.com/tendermint/tendermint/mempool" mempl "github.com/tendermint/tendermint/mempool"
@ -657,7 +656,7 @@ func (cs *ConsensusState) RunActionPropose(height uint, round uint) {
txs := cs.mempoolReactor.Mempool.GetProposalTxs() txs := cs.mempoolReactor.Mempool.GetProposalTxs()
block = &types.Block{ block = &types.Block{
Header: &types.Header{ Header: &types.Header{
Network: config.App().GetString("network"), Network: config.GetString("network"),
Height: cs.Height, Height: cs.Height,
Time: time.Now(), Time: time.Now(),
Fees: 0, // TODO fees Fees: 0, // TODO fees

View File

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"testing" "testing"
_ "github.com/tendermint/tendermint/test"
"github.com/tendermint/tendermint/types" "github.com/tendermint/tendermint/types"
) )

13
consensus/types/config.go Normal file
View File

@ -0,0 +1,13 @@
package consensus
import (
cfg "github.com/tendermint/tendermint/config"
)
var config cfg.Config = nil
func init() {
cfg.OnConfig(func(newConfig cfg.Config) {
config = newConfig
})
}

View File

@ -8,7 +8,6 @@ import (
"github.com/tendermint/tendermint/account" "github.com/tendermint/tendermint/account"
"github.com/tendermint/tendermint/binary" "github.com/tendermint/tendermint/binary"
. "github.com/tendermint/tendermint/common" . "github.com/tendermint/tendermint/common"
"github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/types" "github.com/tendermint/tendermint/types"
) )
@ -41,7 +40,7 @@ func (p *Proposal) String() string {
func (p *Proposal) WriteSignBytes(w io.Writer, n *int64, err *error) { func (p *Proposal) WriteSignBytes(w io.Writer, n *int64, err *error) {
// We hex encode the network name so we don't deal with escaping issues. // We hex encode the network name so we don't deal with escaping issues.
binary.WriteTo([]byte(Fmt(`{"network":"%X"`, config.App().GetString("network"))), w, n, err) binary.WriteTo([]byte(Fmt(`{"network":"%X"`, config.GetString("network"))), w, n, err)
binary.WriteTo([]byte(`,"proposal":{"block_parts":`), w, n, err) binary.WriteTo([]byte(`,"proposal":{"block_parts":`), w, n, err)
p.BlockParts.WriteSignBytes(w, n, err) p.BlockParts.WriteSignBytes(w, n, err)
binary.WriteTo([]byte(Fmt(`,"height":%v,"pol_parts":`, p.Height)), w, n, err) binary.WriteTo([]byte(Fmt(`,"height":%v,"pol_parts":`, p.Height)), w, n, err)

View File

@ -5,7 +5,7 @@ import (
"github.com/tendermint/tendermint/account" "github.com/tendermint/tendermint/account"
. "github.com/tendermint/tendermint/common" . "github.com/tendermint/tendermint/common"
"github.com/tendermint/tendermint/config" _ "github.com/tendermint/tendermint/test"
"github.com/tendermint/tendermint/types" "github.com/tendermint/tendermint/types"
) )
@ -20,7 +20,7 @@ func TestProposalSignable(t *testing.T) {
signBytes := account.SignBytes(proposal) signBytes := account.SignBytes(proposal)
signStr := string(signBytes) signStr := string(signBytes)
expected := Fmt(`{"network":"%X","proposal":{"block_parts":{"hash":"626C6F636B7061727473","total":111},"height":12345,"pol_parts":{"hash":"706F6C7061727473","total":222},"round":23456}}`, expected := Fmt(`{"network":"%X","proposal":{"block_parts":{"hash":"626C6F636B7061727473","total":111},"height":12345,"pol_parts":{"hash":"706F6C7061727473","total":222},"round":23456}}`,
config.App().GetString("network")) config.GetString("network"))
if signStr != expected { if signStr != expected {
t.Errorf("Got unexpected sign string for SendTx. Expected:\n%v\nGot:\n%v", expected, signStr) t.Errorf("Got unexpected sign string for SendTx. Expected:\n%v\nGot:\n%v", expected, signStr)
} }

View File

@ -6,6 +6,7 @@ import (
. "github.com/tendermint/tendermint/common" . "github.com/tendermint/tendermint/common"
. "github.com/tendermint/tendermint/common/test" . "github.com/tendermint/tendermint/common/test"
sm "github.com/tendermint/tendermint/state" sm "github.com/tendermint/tendermint/state"
_ "github.com/tendermint/tendermint/test"
"github.com/tendermint/tendermint/types" "github.com/tendermint/tendermint/types"
"testing" "testing"

13
db/config.go Normal file
View File

@ -0,0 +1,13 @@
package db
import (
cfg "github.com/tendermint/tendermint/config"
)
var config cfg.Config = nil
func init() {
cfg.OnConfig(func(newConfig cfg.Config) {
config = newConfig
})
}

View File

@ -4,7 +4,6 @@ import (
"path" "path"
. "github.com/tendermint/tendermint/common" . "github.com/tendermint/tendermint/common"
"github.com/tendermint/tendermint/config"
) )
type DB interface { type DB interface {
@ -32,19 +31,19 @@ func GetDB(name string) DB {
if db != nil { if db != nil {
return db.(DB) return db.(DB)
} }
switch config.App().GetString("db_backend") { switch config.GetString("db_backend") {
case DBBackendMemDB: case DBBackendMemDB:
db := NewMemDB() db := NewMemDB()
dbs.Set(name, db) dbs.Set(name, db)
return db return db
case DBBackendLevelDB: case DBBackendLevelDB:
db, err := NewLevelDB(path.Join(config.App().GetString("db_dir"), name+".db")) db, err := NewLevelDB(path.Join(config.GetString("db_dir"), name+".db"))
if err != nil { if err != nil {
panic(err) panic(err)
} }
dbs.Set(name, db) dbs.Set(name, db)
return db return db
default: default:
panic(Fmt("Unknown DB backend: %v", config.App().GetString("db_backend"))) panic(Fmt("Unknown DB backend: %v", config.GetString("db_backend")))
} }
} }

14
logger/config.go Normal file
View File

@ -0,0 +1,14 @@
package logger
import (
cfg "github.com/tendermint/tendermint/config"
)
var config cfg.Config = nil
func init() {
cfg.OnConfig(func(newConfig cfg.Config) {
config = newConfig
Reset() // reset log root upon config change.
})
}

View File

@ -5,7 +5,6 @@ import (
"github.com/tendermint/log15" "github.com/tendermint/log15"
. "github.com/tendermint/tendermint/common" . "github.com/tendermint/tendermint/common"
"github.com/tendermint/tendermint/config"
) )
var rootHandler log15.Handler var rootHandler log15.Handler
@ -16,31 +15,19 @@ func init() {
// You might want to call this after resetting tendermint/config. // You might want to call this after resetting tendermint/config.
func Reset() { func Reset() {
handlers := []log15.Handler{}
var logLevel string = "debug"
if config != nil {
logLevel = config.GetString("log_level")
}
// stdout handler // stdout handler
//handlers := []log15.Handler{}
stdoutHandler := log15.LvlFilterHandler( stdoutHandler := log15.LvlFilterHandler(
getLevel(config.App().GetString("log_level")), getLevel(logLevel),
log15.StreamHandler(os.Stdout, log15.TerminalFormat()), log15.StreamHandler(os.Stdout, log15.TerminalFormat()),
) )
handlers = append(handlers, stdoutHandler) //handlers = append(handlers, stdoutHandler)
/*
// Maybe also write to a file.
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 {
fmt.Printf("Could not create directory: %v", err)
os.Exit(1)
}
// File handler
handlers = append(handlers, log15.LvlFilterHandler(
getLevel(config.App().GetString("log_file_level")),
log15.Must.FileHandler(_logFileDir+"/tendermint.log", log15.LogfmtFormat()),
))
}
*/
// Set rootHandler. // Set rootHandler.
//rootHandler = log15.MultiHandler(handlers...) //rootHandler = log15.MultiHandler(handlers...)

13
node/config.go Normal file
View File

@ -0,0 +1,13 @@
package node
import (
cfg "github.com/tendermint/tendermint/config"
)
var config cfg.Config = nil
func init() {
cfg.OnConfig(func(newConfig cfg.Config) {
config = newConfig
})
}

View File

@ -12,7 +12,6 @@ import (
bc "github.com/tendermint/tendermint/blockchain" bc "github.com/tendermint/tendermint/blockchain"
. "github.com/tendermint/tendermint/common" . "github.com/tendermint/tendermint/common"
"github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/consensus" "github.com/tendermint/tendermint/consensus"
dbm "github.com/tendermint/tendermint/db" dbm "github.com/tendermint/tendermint/db"
"github.com/tendermint/tendermint/events" "github.com/tendermint/tendermint/events"
@ -54,13 +53,13 @@ func NewNode() *Node {
stateDB := dbm.GetDB("state") stateDB := dbm.GetDB("state")
state := sm.LoadState(stateDB) state := sm.LoadState(stateDB)
if state == nil { if state == nil {
state = sm.MakeGenesisStateFromFile(stateDB, config.App().GetString("genesis_file")) state = sm.MakeGenesisStateFromFile(stateDB, config.GetString("genesis_file"))
state.Save() state.Save()
} }
// Get PrivValidator // Get PrivValidator
var privValidator *sm.PrivValidator var privValidator *sm.PrivValidator
privValidatorFile := config.App().GetString("priv_validator_file") privValidatorFile := config.GetString("priv_validator_file")
if _, err := os.Stat(privValidatorFile); err == nil { if _, err := os.Stat(privValidatorFile); err == nil {
privValidator = sm.LoadPrivValidator(privValidatorFile) privValidator = sm.LoadPrivValidator(privValidatorFile)
log.Info("Loaded PrivValidator", log.Info("Loaded PrivValidator",
@ -76,11 +75,11 @@ func NewNode() *Node {
eventSwitch.Start() eventSwitch.Start()
// Get PEXReactor // Get PEXReactor
book := p2p.NewAddrBook(config.App().GetString("addrbook_file")) book := p2p.NewAddrBook(config.GetString("addrbook_file"))
pexReactor := p2p.NewPEXReactor(book) pexReactor := p2p.NewPEXReactor(book)
// Get BlockchainReactor // Get BlockchainReactor
bcReactor := bc.NewBlockchainReactor(state, blockStore, config.App().GetBool("fast_sync")) bcReactor := bc.NewBlockchainReactor(state, blockStore, config.GetBool("fast_sync"))
// Get MempoolReactor // Get MempoolReactor
mempool := mempl.NewMempool(state.Copy()) mempool := mempl.NewMempool(state.Copy())
@ -94,7 +93,7 @@ func NewNode() *Node {
} }
// so the consensus reactor won't do anything until we're synced // so the consensus reactor won't do anything until we're synced
if config.App().GetBool("fast_sync") { if config.GetBool("fast_sync") {
consensusReactor.SetSyncing(true) consensusReactor.SetSyncing(true)
} }
@ -157,7 +156,7 @@ func (n *Node) AddListener(l p2p.Listener) {
// NOTE: Blocking // NOTE: Blocking
func (n *Node) DialSeed() { func (n *Node) DialSeed() {
// permute the list, dial them in random order. // permute the list, dial them in random order.
seeds := strings.Split(config.App().GetString("seeds"), ",") seeds := strings.Split(config.GetString("seeds"), ",")
perm := rand.Perm(len(seeds)) perm := rand.Perm(len(seeds))
for i := 0; i < len(perm); i++ { for i := 0; i < len(perm); i++ {
go func(i int) { go func(i int) {
@ -189,7 +188,7 @@ func (n *Node) StartRPC() {
core.SetSwitch(n.sw) core.SetSwitch(n.sw)
core.SetPrivValidator(n.privValidator) core.SetPrivValidator(n.privValidator)
listenAddr := config.App().GetString("rpc_laddr") listenAddr := config.GetString("rpc_laddr")
mux := http.NewServeMux() mux := http.NewServeMux()
rpc.RegisterEventsHandler(mux, n.evsw) rpc.RegisterEventsHandler(mux, n.evsw)
rpc.RegisterRPCFuncs(mux, core.Routes) rpc.RegisterRPCFuncs(mux, core.Routes)
@ -218,9 +217,9 @@ func (n *Node) EventSwitch() *events.EventSwitch {
func makeNodeInfo(sw *p2p.Switch) *types.NodeInfo { func makeNodeInfo(sw *p2p.Switch) *types.NodeInfo {
nodeInfo := &types.NodeInfo{ nodeInfo := &types.NodeInfo{
Network: config.App().GetString("network"), Network: config.GetString("network"),
Moniker: config.App().GetString("moniker"), Moniker: config.GetString("moniker"),
Version: config.App().GetString("version"), Version: config.GetString("version"),
} }
if !sw.IsListening() { if !sw.IsListening() {
return nodeInfo return nodeInfo
@ -228,7 +227,7 @@ func makeNodeInfo(sw *p2p.Switch) *types.NodeInfo {
p2pListener := sw.Listeners()[0] p2pListener := sw.Listeners()[0]
p2pHost := p2pListener.ExternalAddress().IP.String() p2pHost := p2pListener.ExternalAddress().IP.String()
p2pPort := p2pListener.ExternalAddress().Port p2pPort := p2pListener.ExternalAddress().Port
rpcListenAddr := config.App().GetString("rpc_laddr") rpcListenAddr := config.GetString("rpc_laddr")
_, rpcPortStr, _ := net.SplitHostPort(rpcListenAddr) _, rpcPortStr, _ := net.SplitHostPort(rpcListenAddr)
rpcPort, err := strconv.Atoi(rpcPortStr) rpcPort, err := strconv.Atoi(rpcPortStr)
if err != nil { if err != nil {
@ -248,17 +247,17 @@ func makeNodeInfo(sw *p2p.Switch) *types.NodeInfo {
func RunNode() { func RunNode() {
// Create & start node // Create & start node
n := NewNode() n := NewNode()
l := p2p.NewDefaultListener("tcp", config.App().GetString("node_laddr"), false) l := p2p.NewDefaultListener("tcp", config.GetString("node_laddr"), false)
n.AddListener(l) n.AddListener(l)
n.Start() n.Start()
// If seedNode is provided by config, dial out. // If seedNode is provided by config, dial out.
if len(config.App().GetStringSlice("seeds")) != 0 { if len(config.GetStringSlice("seeds")) != 0 {
n.DialSeed() n.DialSeed()
} }
// Run the RPC server. // Run the RPC server.
if config.App().GetString("rpc_laddr") != "" { if config.GetString("rpc_laddr") != "" {
n.StartRPC() n.StartRPC()
} }

View File

@ -324,7 +324,7 @@ func (a *AddrBook) saveToFile(filePath string) {
log.Error("Failed to save AddrBook to file", "err", err) log.Error("Failed to save AddrBook to file", "err", err)
return return
} }
err = AtomicWriteFile(filePath, jsonBytes) err = WriteFileAtomic(filePath, jsonBytes)
if err != nil { if err != nil {
log.Error("Failed to save AddrBook to file", "file", filePath, "error", err) log.Error("Failed to save AddrBook to file", "file", filePath, "error", err)
} }

13
rpc/core/config.go Normal file
View File

@ -0,0 +1,13 @@
package core
import (
cfg "github.com/tendermint/tendermint/config"
)
var config cfg.Config = nil
func init() {
cfg.OnConfig(func(newConfig cfg.Config) {
config = newConfig
})
}

View File

@ -1,7 +1,6 @@
package core package core
import ( import (
"github.com/tendermint/tendermint/config"
dbm "github.com/tendermint/tendermint/db" dbm "github.com/tendermint/tendermint/db"
ctypes "github.com/tendermint/tendermint/rpc/core/types" ctypes "github.com/tendermint/tendermint/rpc/core/types"
sm "github.com/tendermint/tendermint/state" sm "github.com/tendermint/tendermint/state"
@ -12,7 +11,7 @@ import (
func Status() (*ctypes.ResponseStatus, error) { func Status() (*ctypes.ResponseStatus, error) {
db := dbm.NewMemDB() db := dbm.NewMemDB()
genesisState := sm.MakeGenesisStateFromFile(db, config.App().GetString("genesis_file")) genesisState := sm.MakeGenesisStateFromFile(db, config.GetString("genesis_file"))
genesisHash := genesisState.Hash() genesisHash := genesisState.Hash()
latestHeight := blockStore.Height() latestHeight := blockStore.Height()
var ( var (
@ -27,9 +26,9 @@ func Status() (*ctypes.ResponseStatus, error) {
} }
return &ctypes.ResponseStatus{ return &ctypes.ResponseStatus{
Moniker: config.App().GetString("moniker"), Moniker: config.GetString("moniker"),
Network: config.App().GetString("network"), Network: config.GetString("network"),
Version: config.App().GetString("version"), Version: config.GetString("version"),
GenesisHash: genesisHash, GenesisHash: genesisHash,
PubKey: privValidator.PubKey, PubKey: privValidator.PubKey,
LatestBlockHash: latestBlockHash, LatestBlockHash: latestBlockHash,

View File

@ -5,9 +5,9 @@ import (
"encoding/hex" "encoding/hex"
"github.com/tendermint/tendermint/account" "github.com/tendermint/tendermint/account"
. "github.com/tendermint/tendermint/common" . "github.com/tendermint/tendermint/common"
"github.com/tendermint/tendermint/config" cfg "github.com/tendermint/tendermint/config"
tmcfg "github.com/tendermint/tendermint/config/tendermint_test"
"github.com/tendermint/tendermint/consensus" "github.com/tendermint/tendermint/consensus"
"github.com/tendermint/tendermint/logger"
nm "github.com/tendermint/tendermint/node" nm "github.com/tendermint/tendermint/node"
"github.com/tendermint/tendermint/p2p" "github.com/tendermint/tendermint/p2p"
ctypes "github.com/tendermint/tendermint/rpc/core/types" ctypes "github.com/tendermint/tendermint/rpc/core/types"
@ -20,9 +20,10 @@ import (
// global variables for use across all tests // global variables for use across all tests
var ( var (
rpcAddr = "127.0.0.1:8089" config cfg.Config = nil
requestAddr = "http://" + rpcAddr + "/" rpcAddr = "127.0.0.1:36657" // Not 46657
websocketAddr = "ws://" + rpcAddr + "/events" requestAddr = "http://" + rpcAddr + "/"
websocketAddr = "ws://" + rpcAddr + "/events"
node *nm.Node node *nm.Node
@ -61,7 +62,7 @@ func decodeHex(hexStr string) []byte {
func newNode(ready chan struct{}) { func newNode(ready chan struct{}) {
// Create & start node // Create & start node
node = nm.NewNode() node = nm.NewNode()
l := p2p.NewDefaultListener("tcp", config.App().GetString("node_laddr"), false) l := p2p.NewDefaultListener("tcp", config.GetString("node_laddr"), false)
node.AddListener(l) node.AddListener(l)
node.Start() node.Start()
@ -76,17 +77,8 @@ func newNode(ready chan struct{}) {
// initialize config and create new node // initialize config and create new node
func init() { func init() {
rootDir := ".tendermint" config = tmcfg.GetConfig("")
config.Init(rootDir) cfg.ApplyConfig(config)
app := config.App()
app.Set("genesis_file", rootDir+"/genesis.json")
app.Set("seeds", "")
app.Set("priv_validator_file", rootDir+"/priv_validator.json")
app.Set("db_backend", "memdb")
app.Set("rpc_laddr", rpcAddr)
app.Set("log_level", "debug")
config.SetApp(app)
logger.Reset()
// Save new priv_validator file. // Save new priv_validator file.
priv := &state.PrivValidator{ priv := &state.PrivValidator{
@ -94,7 +86,7 @@ func init() {
PubKey: account.PubKeyEd25519(decodeHex(userPub)), PubKey: account.PubKeyEd25519(decodeHex(userPub)),
PrivKey: account.PrivKeyEd25519(decodeHex(userPriv)), PrivKey: account.PrivKeyEd25519(decodeHex(userPriv)),
} }
priv.SetFile(rootDir + "/priv_validator.json") priv.SetFile(config.GetString("priv_validator_file"))
priv.Save() priv.Save()
consensus.RoundDuration0 = 3 * time.Second consensus.RoundDuration0 = 3 * time.Second

View File

@ -4,7 +4,6 @@ import (
"bytes" "bytes"
"fmt" "fmt"
. "github.com/tendermint/tendermint/common" . "github.com/tendermint/tendermint/common"
"github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/types" "github.com/tendermint/tendermint/types"
"testing" "testing"
) )
@ -15,9 +14,9 @@ func testStatus(t *testing.T, typ string) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if resp.Network != config.App().GetString("network") { if resp.Network != config.GetString("network") {
t.Fatal(fmt.Errorf("Network mismatch: got %s expected %s", t.Fatal(fmt.Errorf("Network mismatch: got %s expected %s",
resp.Network, config.App().Get("network"))) resp.Network, config.Get("network")))
} }
} }

View File

@ -12,7 +12,6 @@ import (
"github.com/tendermint/tendermint/account" "github.com/tendermint/tendermint/account"
"github.com/tendermint/tendermint/binary" "github.com/tendermint/tendermint/binary"
. "github.com/tendermint/tendermint/common" . "github.com/tendermint/tendermint/common"
"github.com/tendermint/tendermint/config"
. "github.com/tendermint/tendermint/consensus/types" . "github.com/tendermint/tendermint/consensus/types"
"github.com/tendermint/tendermint/types" "github.com/tendermint/tendermint/types"
@ -50,7 +49,7 @@ type PrivValidator struct {
// For persistence. // For persistence.
// Overloaded for testing. // Overloaded for testing.
filename string filePath string
mtx sync.Mutex mtx sync.Mutex
} }
@ -68,27 +67,27 @@ func GenPrivValidator() *PrivValidator {
LastHeight: 0, LastHeight: 0,
LastRound: 0, LastRound: 0,
LastStep: stepNone, LastStep: stepNone,
filename: config.App().GetString("priv_validator_file"), filePath: "",
} }
} }
func LoadPrivValidator(filename string) *PrivValidator { func LoadPrivValidator(filePath string) *PrivValidator {
privValJSONBytes, err := ioutil.ReadFile(filename) privValJSONBytes, err := ioutil.ReadFile(filePath)
if err != nil { if err != nil {
panic(err) panic(err)
} }
privVal := binary.ReadJSON(&PrivValidator{}, privValJSONBytes, &err).(*PrivValidator) privVal := binary.ReadJSON(&PrivValidator{}, privValJSONBytes, &err).(*PrivValidator)
if err != nil { if err != nil {
Exit(Fmt("Error reading PrivValidator from %v: %v\n", filename, err)) Exit(Fmt("Error reading PrivValidator from %v: %v\n", filePath, err))
} }
privVal.filename = filename privVal.filePath = filePath
return privVal return privVal
} }
func (privVal *PrivValidator) SetFile(filename string) { func (privVal *PrivValidator) SetFile(filePath string) {
privVal.mtx.Lock() privVal.mtx.Lock()
defer privVal.mtx.Unlock() defer privVal.mtx.Unlock()
privVal.filename = filename privVal.filePath = filePath
} }
func (privVal *PrivValidator) Save() { func (privVal *PrivValidator) Save() {
@ -98,8 +97,11 @@ func (privVal *PrivValidator) Save() {
} }
func (privVal *PrivValidator) save() { func (privVal *PrivValidator) save() {
if privVal.filePath == "" {
panic("Cannot save PrivValidator: filePath not set")
}
jsonBytes := binary.JSONBytes(privVal) jsonBytes := binary.JSONBytes(privVal)
err := AtomicWriteFile(privVal.filename, jsonBytes) err := WriteFileAtomic(privVal.filePath, jsonBytes)
if err != nil { if err != nil {
// `@; BOOM!!! // `@; BOOM!!!
panic(err) panic(err)

View File

@ -2,7 +2,7 @@ package state
import ( import (
"github.com/tendermint/tendermint/account" "github.com/tendermint/tendermint/account"
"github.com/tendermint/tendermint/config" _ "github.com/tendermint/tendermint/test"
"github.com/tendermint/tendermint/types" "github.com/tendermint/tendermint/types"
"bytes" "bytes"
@ -65,7 +65,7 @@ func TestCopyState(t *testing.T) {
func makeBlock(t *testing.T, state *State, commits []types.Commit, txs []types.Tx) *types.Block { func makeBlock(t *testing.T, state *State, commits []types.Commit, txs []types.Tx) *types.Block {
block := &types.Block{ block := &types.Block{
Header: &types.Header{ Header: &types.Header{
Network: config.App().GetString("network"), Network: "tendermint_test",
Height: state.LastBlockHeight + 1, Height: state.LastBlockHeight + 1,
Time: state.LastBlockTime.Add(time.Minute), Time: state.LastBlockTime.Add(time.Minute),
Fees: 0, Fees: 0,

View File

@ -38,7 +38,8 @@ func RandAccount(randBalance bool, minBalance uint64) (*account.Account, *accoun
func RandValidator(randBonded bool, minBonded uint64) (*ValidatorInfo, *Validator, *PrivValidator) { func RandValidator(randBonded bool, minBonded uint64) (*ValidatorInfo, *Validator, *PrivValidator) {
privVal := GenPrivValidator() privVal := GenPrivValidator()
_, privVal.filename = Tempfile("priv_validator_") _, tempFilePath := Tempfile("priv_validator_")
privVal.SetFile(tempFilePath)
bonded := minBonded bonded := minBonded
if randBonded { if randBonded {
bonded += uint64(RandUint32()) bonded += uint64(RandUint32())

15
test/init.go Normal file
View File

@ -0,0 +1,15 @@
// Import this in all *_test.go files to initialize ~/.tendermint_test.
// TODO: Reset each time?
package test
import (
cfg "github.com/tendermint/tendermint/config"
tmcfg "github.com/tendermint/tendermint/config/tendermint_test"
)
func init() {
// Creates ~/.tendermint_test/*
config := tmcfg.GetConfig("")
cfg.ApplyConfig(config)
}

View File

@ -11,7 +11,6 @@ import (
"github.com/tendermint/tendermint/account" "github.com/tendermint/tendermint/account"
"github.com/tendermint/tendermint/binary" "github.com/tendermint/tendermint/binary"
. "github.com/tendermint/tendermint/common" . "github.com/tendermint/tendermint/common"
"github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/merkle" "github.com/tendermint/tendermint/merkle"
) )
@ -24,7 +23,7 @@ type Block struct {
// Basic validation that doesn't involve state data. // Basic validation that doesn't involve state data.
func (b *Block) ValidateBasic(lastBlockHeight uint, lastBlockHash []byte, func (b *Block) ValidateBasic(lastBlockHeight uint, lastBlockHash []byte,
lastBlockParts PartSetHeader, lastBlockTime time.Time) error { lastBlockParts PartSetHeader, lastBlockTime time.Time) error {
if b.Network != config.App().GetString("network") { if b.Network != config.GetString("network") {
return errors.New("Wrong Block.Header.Network") return errors.New("Wrong Block.Header.Network")
} }
if b.Height != lastBlockHeight+1 { if b.Height != lastBlockHeight+1 {

13
types/config.go Normal file
View File

@ -0,0 +1,13 @@
package types
import (
cfg "github.com/tendermint/tendermint/config"
)
var config cfg.Config = nil
func init() {
cfg.OnConfig(func(newConfig cfg.Config) {
config = newConfig
})
}

View File

@ -7,7 +7,6 @@ import (
"github.com/tendermint/tendermint/account" "github.com/tendermint/tendermint/account"
"github.com/tendermint/tendermint/binary" "github.com/tendermint/tendermint/binary"
. "github.com/tendermint/tendermint/common" . "github.com/tendermint/tendermint/common"
"github.com/tendermint/tendermint/config"
) )
var ( var (
@ -132,7 +131,7 @@ type SendTx struct {
func (tx *SendTx) WriteSignBytes(w io.Writer, n *int64, err *error) { func (tx *SendTx) WriteSignBytes(w io.Writer, n *int64, err *error) {
// We hex encode the network name so we don't deal with escaping issues. // We hex encode the network name so we don't deal with escaping issues.
binary.WriteTo([]byte(Fmt(`{"network":"%X"`, config.App().GetString("network"))), w, n, err) binary.WriteTo([]byte(Fmt(`{"network":"%X"`, config.GetString("network"))), w, n, err)
binary.WriteTo([]byte(Fmt(`,"tx":[%v,{"inputs":[`, TxTypeSend)), w, n, err) binary.WriteTo([]byte(Fmt(`,"tx":[%v,{"inputs":[`, TxTypeSend)), w, n, err)
for i, in := range tx.Inputs { for i, in := range tx.Inputs {
in.WriteSignBytes(w, n, err) in.WriteSignBytes(w, n, err)
@ -166,7 +165,7 @@ type CallTx struct {
func (tx *CallTx) WriteSignBytes(w io.Writer, n *int64, err *error) { func (tx *CallTx) WriteSignBytes(w io.Writer, n *int64, err *error) {
// We hex encode the network name so we don't deal with escaping issues. // We hex encode the network name so we don't deal with escaping issues.
binary.WriteTo([]byte(Fmt(`{"network":"%X"`, config.App().GetString("network"))), w, n, err) binary.WriteTo([]byte(Fmt(`{"network":"%X"`, config.GetString("network"))), w, n, err)
binary.WriteTo([]byte(Fmt(`,"tx":[%v,{"address":"%X","data":"%X"`, TxTypeCall, tx.Address, tx.Data)), w, n, err) binary.WriteTo([]byte(Fmt(`,"tx":[%v,{"address":"%X","data":"%X"`, TxTypeCall, tx.Address, tx.Data)), w, n, err)
binary.WriteTo([]byte(Fmt(`,"fee":%v,"gas_limit":%v,"input":`, tx.Fee, tx.GasLimit)), w, n, err) binary.WriteTo([]byte(Fmt(`,"fee":%v,"gas_limit":%v,"input":`, tx.Fee, tx.GasLimit)), w, n, err)
tx.Input.WriteSignBytes(w, n, err) tx.Input.WriteSignBytes(w, n, err)
@ -187,7 +186,7 @@ type BondTx struct {
func (tx *BondTx) WriteSignBytes(w io.Writer, n *int64, err *error) { func (tx *BondTx) WriteSignBytes(w io.Writer, n *int64, err *error) {
// We hex encode the network name so we don't deal with escaping issues. // We hex encode the network name so we don't deal with escaping issues.
binary.WriteTo([]byte(Fmt(`{"network":"%X"`, config.App().GetString("network"))), w, n, err) binary.WriteTo([]byte(Fmt(`{"network":"%X"`, config.GetString("network"))), w, n, err)
binary.WriteTo([]byte(Fmt(`,"tx":[%v,{"inputs":[`, TxTypeBond)), w, n, err) binary.WriteTo([]byte(Fmt(`,"tx":[%v,{"inputs":[`, TxTypeBond)), w, n, err)
for i, in := range tx.Inputs { for i, in := range tx.Inputs {
in.WriteSignBytes(w, n, err) in.WriteSignBytes(w, n, err)
@ -221,7 +220,7 @@ type UnbondTx struct {
func (tx *UnbondTx) WriteSignBytes(w io.Writer, n *int64, err *error) { func (tx *UnbondTx) WriteSignBytes(w io.Writer, n *int64, err *error) {
// We hex encode the network name so we don't deal with escaping issues. // We hex encode the network name so we don't deal with escaping issues.
binary.WriteTo([]byte(Fmt(`{"network":"%X"`, config.App().GetString("network"))), w, n, err) binary.WriteTo([]byte(Fmt(`{"network":"%X"`, config.GetString("network"))), w, n, err)
binary.WriteTo([]byte(Fmt(`,"tx":[%v,{"address":"%X","height":%v}]}`, TxTypeUnbond, tx.Address, tx.Height)), w, n, err) binary.WriteTo([]byte(Fmt(`,"tx":[%v,{"address":"%X","height":%v}]}`, TxTypeUnbond, tx.Address, tx.Height)), w, n, err)
} }
@ -239,7 +238,7 @@ type RebondTx struct {
func (tx *RebondTx) WriteSignBytes(w io.Writer, n *int64, err *error) { func (tx *RebondTx) WriteSignBytes(w io.Writer, n *int64, err *error) {
// We hex encode the network name so we don't deal with escaping issues. // We hex encode the network name so we don't deal with escaping issues.
binary.WriteTo([]byte(Fmt(`{"network":"%X"`, config.App().GetString("network"))), w, n, err) binary.WriteTo([]byte(Fmt(`{"network":"%X"`, config.GetString("network"))), w, n, err)
binary.WriteTo([]byte(Fmt(`,"tx":[%v,{"address":"%X","height":%v}]}`, TxTypeRebond, tx.Address, tx.Height)), w, n, err) binary.WriteTo([]byte(Fmt(`,"tx":[%v,{"address":"%X","height":%v}]}`, TxTypeRebond, tx.Address, tx.Height)), w, n, err)
} }

View File

@ -5,7 +5,7 @@ import (
"github.com/tendermint/tendermint/account" "github.com/tendermint/tendermint/account"
. "github.com/tendermint/tendermint/common" . "github.com/tendermint/tendermint/common"
"github.com/tendermint/tendermint/config" _ "github.com/tendermint/tendermint/test"
) )
func TestSendTxSignable(t *testing.T) { func TestSendTxSignable(t *testing.T) {
@ -36,7 +36,7 @@ func TestSendTxSignable(t *testing.T) {
signBytes := account.SignBytes(sendTx) signBytes := account.SignBytes(sendTx)
signStr := string(signBytes) signStr := string(signBytes)
expected := Fmt(`{"network":"%X","tx":[1,{"inputs":[{"address":"696E70757431","amount":12345,"sequence":67890},{"address":"696E70757432","amount":111,"sequence":222}],"outputs":[{"address":"6F757470757431","amount":333},{"address":"6F757470757432","amount":444}]}]}`, expected := Fmt(`{"network":"%X","tx":[1,{"inputs":[{"address":"696E70757431","amount":12345,"sequence":67890},{"address":"696E70757432","amount":111,"sequence":222}],"outputs":[{"address":"6F757470757431","amount":333},{"address":"6F757470757432","amount":444}]}]}`,
config.App().GetString("network")) config.GetString("network"))
if signStr != expected { if signStr != expected {
t.Errorf("Got unexpected sign string for SendTx. Expected:\n%v\nGot:\n%v", expected, signStr) t.Errorf("Got unexpected sign string for SendTx. Expected:\n%v\nGot:\n%v", expected, signStr)
} }
@ -57,7 +57,7 @@ func TestCallTxSignable(t *testing.T) {
signBytes := account.SignBytes(callTx) signBytes := account.SignBytes(callTx)
signStr := string(signBytes) signStr := string(signBytes)
expected := Fmt(`{"network":"%X","tx":[2,{"address":"636F6E747261637431","data":"6461746131","fee":222,"gas_limit":111,"input":{"address":"696E70757431","amount":12345,"sequence":67890}}]}`, expected := Fmt(`{"network":"%X","tx":[2,{"address":"636F6E747261637431","data":"6461746131","fee":222,"gas_limit":111,"input":{"address":"696E70757431","amount":12345,"sequence":67890}}]}`,
config.App().GetString("network")) config.GetString("network"))
if signStr != expected { if signStr != expected {
t.Errorf("Got unexpected sign string for CallTx. Expected:\n%v\nGot:\n%v", expected, signStr) t.Errorf("Got unexpected sign string for CallTx. Expected:\n%v\nGot:\n%v", expected, signStr)
} }
@ -93,7 +93,7 @@ func TestBondTxSignable(t *testing.T) {
signBytes := account.SignBytes(bondTx) signBytes := account.SignBytes(bondTx)
signStr := string(signBytes) signStr := string(signBytes)
expected := Fmt(`{"network":"%X","tx":[17,{"inputs":[{"address":"696E70757431","amount":12345,"sequence":67890},{"address":"696E70757432","amount":111,"sequence":222}],"pub_key":[1,"3B6A27BCCEB6A42D62A3A8D02A6F0D73653215771DE243A63AC048A18B59DA29"],"unbond_to":[{"address":"6F757470757431","amount":333},{"address":"6F757470757432","amount":444}]}]}`, expected := Fmt(`{"network":"%X","tx":[17,{"inputs":[{"address":"696E70757431","amount":12345,"sequence":67890},{"address":"696E70757432","amount":111,"sequence":222}],"pub_key":[1,"3B6A27BCCEB6A42D62A3A8D02A6F0D73653215771DE243A63AC048A18B59DA29"],"unbond_to":[{"address":"6F757470757431","amount":333},{"address":"6F757470757432","amount":444}]}]}`,
config.App().GetString("network")) config.GetString("network"))
if signStr != expected { if signStr != expected {
t.Errorf("Got unexpected sign string for BondTx") t.Errorf("Got unexpected sign string for BondTx")
} }
@ -107,7 +107,7 @@ func TestUnbondTxSignable(t *testing.T) {
signBytes := account.SignBytes(unbondTx) signBytes := account.SignBytes(unbondTx)
signStr := string(signBytes) signStr := string(signBytes)
expected := Fmt(`{"network":"%X","tx":[18,{"address":"6164647265737331","height":111}]}`, expected := Fmt(`{"network":"%X","tx":[18,{"address":"6164647265737331","height":111}]}`,
config.App().GetString("network")) config.GetString("network"))
if signStr != expected { if signStr != expected {
t.Errorf("Got unexpected sign string for UnbondTx") t.Errorf("Got unexpected sign string for UnbondTx")
} }
@ -121,7 +121,7 @@ func TestRebondTxSignable(t *testing.T) {
signBytes := account.SignBytes(rebondTx) signBytes := account.SignBytes(rebondTx)
signStr := string(signBytes) signStr := string(signBytes)
expected := Fmt(`{"network":"%X","tx":[19,{"address":"6164647265737331","height":111}]}`, expected := Fmt(`{"network":"%X","tx":[19,{"address":"6164647265737331","height":111}]}`,
config.App().GetString("network")) config.GetString("network"))
if signStr != expected { if signStr != expected {
t.Errorf("Got unexpected sign string for RebondTx") t.Errorf("Got unexpected sign string for RebondTx")
} }

View File

@ -8,7 +8,6 @@ import (
"github.com/tendermint/tendermint/account" "github.com/tendermint/tendermint/account"
"github.com/tendermint/tendermint/binary" "github.com/tendermint/tendermint/binary"
. "github.com/tendermint/tendermint/common" . "github.com/tendermint/tendermint/common"
"github.com/tendermint/tendermint/config"
) )
var ( var (
@ -48,7 +47,7 @@ const (
func (vote *Vote) WriteSignBytes(w io.Writer, n *int64, err *error) { func (vote *Vote) WriteSignBytes(w io.Writer, n *int64, err *error) {
// We hex encode the network name so we don't deal with escaping issues. // We hex encode the network name so we don't deal with escaping issues.
binary.WriteTo([]byte(Fmt(`{"network":"%X"`, config.App().GetString("network"))), w, n, err) binary.WriteTo([]byte(Fmt(`{"network":"%X"`, config.GetString("network"))), w, n, err)
binary.WriteTo([]byte(Fmt(`,"vote":{"block_hash":"%X","block_parts":%v`, vote.BlockHash, vote.BlockParts)), w, n, err) binary.WriteTo([]byte(Fmt(`,"vote":{"block_hash":"%X","block_parts":%v`, vote.BlockHash, vote.BlockParts)), w, n, err)
binary.WriteTo([]byte(Fmt(`,"height":%v,"round":%v,"type":%v}}`, vote.Height, vote.Round, vote.Type)), w, n, err) binary.WriteTo([]byte(Fmt(`,"height":%v,"round":%v,"type":%v}}`, vote.Height, vote.Round, vote.Type)), w, n, err)
} }