github.com/DFWallet/tendermint-cosmos@v0.0.2/config/toml.go (about) 1 package config 2 3 import ( 4 "bytes" 5 "fmt" 6 "io/ioutil" 7 "path/filepath" 8 "strings" 9 "text/template" 10 11 tmos "github.com/DFWallet/tendermint-cosmos/libs/os" 12 ) 13 14 // DefaultDirPerm is the default permissions used when creating directories. 15 const DefaultDirPerm = 0700 16 17 var configTemplate *template.Template 18 19 func init() { 20 var err error 21 tmpl := template.New("configFileTemplate").Funcs(template.FuncMap{ 22 "StringsJoin": strings.Join, 23 }) 24 if configTemplate, err = tmpl.Parse(defaultConfigTemplate); err != nil { 25 panic(err) 26 } 27 } 28 29 /****** these are for production settings ***********/ 30 31 // EnsureRoot creates the root, config, and data directories if they don't exist, 32 // and panics if it fails. 33 func EnsureRoot(rootDir string) { 34 if err := tmos.EnsureDir(rootDir, DefaultDirPerm); err != nil { 35 panic(err.Error()) 36 } 37 if err := tmos.EnsureDir(filepath.Join(rootDir, defaultConfigDir), DefaultDirPerm); err != nil { 38 panic(err.Error()) 39 } 40 if err := tmos.EnsureDir(filepath.Join(rootDir, defaultDataDir), DefaultDirPerm); err != nil { 41 panic(err.Error()) 42 } 43 44 configFilePath := filepath.Join(rootDir, defaultConfigFilePath) 45 46 // Write default config file if missing. 47 if !tmos.FileExists(configFilePath) { 48 writeDefaultConfigFile(configFilePath) 49 } 50 } 51 52 // XXX: this func should probably be called by cmd/tendermint/commands/init.go 53 // alongside the writing of the genesis.json and priv_validator.json 54 func writeDefaultConfigFile(configFilePath string) { 55 WriteConfigFile(configFilePath, DefaultConfig()) 56 } 57 58 // WriteConfigFile renders config using the template and writes it to configFilePath. 59 func WriteConfigFile(configFilePath string, config *Config) { 60 var buffer bytes.Buffer 61 62 if err := configTemplate.Execute(&buffer, config); err != nil { 63 panic(err) 64 } 65 66 tmos.MustWriteFile(configFilePath, buffer.Bytes(), 0644) 67 } 68 69 // Note: any changes to the comments/variables/mapstructure 70 // must be reflected in the appropriate struct in config/config.go 71 const defaultConfigTemplate = `# This is a TOML config file. 72 # For more information, see https://github.com/toml-lang/toml 73 74 # NOTE: Any path below can be absolute (e.g. "/var/myawesomeapp/data") or 75 # relative to the home directory (e.g. "data"). The home directory is 76 # "$HOME/.tendermint" by default, but could be changed via $TMHOME env variable 77 # or --home cmd flag. 78 79 ####################################################################### 80 ### Main Base Config Options ### 81 ####################################################################### 82 83 # TCP or UNIX socket address of the ABCI application, 84 # or the name of an ABCI application compiled in with the Tendermint binary 85 proxy_app = "{{ .BaseConfig.ProxyApp }}" 86 87 # A custom human readable name for this node 88 moniker = "{{ .BaseConfig.Moniker }}" 89 90 # If this node is many blocks behind the tip of the chain, FastSync 91 # allows them to catchup quickly by downloading blocks in parallel 92 # and verifying their commits 93 fast_sync = {{ .BaseConfig.FastSyncMode }} 94 95 # Database backend: goleveldb | cleveldb | boltdb | rocksdb | badgerdb 96 # * goleveldb (github.com/syndtr/goleveldb - most popular implementation) 97 # - pure go 98 # - stable 99 # * cleveldb (uses levigo wrapper) 100 # - fast 101 # - requires gcc 102 # - use cleveldb build tag (go build -tags cleveldb) 103 # * boltdb (uses etcd's fork of bolt - github.com/etcd-io/bbolt) 104 # - EXPERIMENTAL 105 # - may be faster is some use-cases (random reads - indexer) 106 # - use boltdb build tag (go build -tags boltdb) 107 # * rocksdb (uses github.com/tecbot/gorocksdb) 108 # - EXPERIMENTAL 109 # - requires gcc 110 # - use rocksdb build tag (go build -tags rocksdb) 111 # * badgerdb (uses github.com/dgraph-io/badger) 112 # - EXPERIMENTAL 113 # - use badgerdb build tag (go build -tags badgerdb) 114 db_backend = "{{ .BaseConfig.DBBackend }}" 115 116 # Database directory 117 db_dir = "{{ js .BaseConfig.DBPath }}" 118 119 # Output level for logging, including package level options 120 log_level = "{{ .BaseConfig.LogLevel }}" 121 122 # Output format: 'plain' (colored text) or 'json' 123 log_format = "{{ .BaseConfig.LogFormat }}" 124 125 ##### additional base config options ##### 126 127 # Path to the JSON file containing the initial validator set and other meta data 128 genesis_file = "{{ js .BaseConfig.Genesis }}" 129 130 # Path to the JSON file containing the private key to use as a validator in the consensus protocol 131 priv_validator_key_file = "{{ js .BaseConfig.PrivValidatorKey }}" 132 133 # Path to the JSON file containing the last sign state of a validator 134 priv_validator_state_file = "{{ js .BaseConfig.PrivValidatorState }}" 135 136 # TCP or UNIX socket address for Tendermint to listen on for 137 # connections from an external PrivValidator process 138 priv_validator_laddr = "{{ .BaseConfig.PrivValidatorListenAddr }}" 139 140 # Path to the JSON file containing the private key to use for node authentication in the p2p protocol 141 node_key_file = "{{ js .BaseConfig.NodeKey }}" 142 143 # Mechanism to connect to the ABCI application: socket | grpc 144 abci = "{{ .BaseConfig.ABCI }}" 145 146 # If true, query the ABCI app on connecting to a new peer 147 # so the app can decide if we should keep the connection or not 148 filter_peers = {{ .BaseConfig.FilterPeers }} 149 150 151 ####################################################################### 152 ### Advanced Configuration Options ### 153 ####################################################################### 154 155 ####################################################### 156 ### RPC Server Configuration Options ### 157 ####################################################### 158 [rpc] 159 160 # TCP or UNIX socket address for the RPC server to listen on 161 laddr = "{{ .RPC.ListenAddress }}" 162 163 # A list of origins a cross-domain request can be executed from 164 # Default value '[]' disables cors support 165 # Use '["*"]' to allow any origin 166 cors_allowed_origins = [{{ range .RPC.CORSAllowedOrigins }}{{ printf "%q, " . }}{{end}}] 167 168 # A list of methods the client is allowed to use with cross-domain requests 169 cors_allowed_methods = [{{ range .RPC.CORSAllowedMethods }}{{ printf "%q, " . }}{{end}}] 170 171 # A list of non simple headers the client is allowed to use with cross-domain requests 172 cors_allowed_headers = [{{ range .RPC.CORSAllowedHeaders }}{{ printf "%q, " . }}{{end}}] 173 174 # TCP or UNIX socket address for the gRPC server to listen on 175 # NOTE: This server only supports /broadcast_tx_commit 176 grpc_laddr = "{{ .RPC.GRPCListenAddress }}" 177 178 # Maximum number of simultaneous connections. 179 # Does not include RPC (HTTP&WebSocket) connections. See max_open_connections 180 # If you want to accept a larger number than the default, make sure 181 # you increase your OS limits. 182 # 0 - unlimited. 183 # Should be < {ulimit -Sn} - {MaxNumInboundPeers} - {MaxNumOutboundPeers} - {N of wal, db and other open files} 184 # 1024 - 40 - 10 - 50 = 924 = ~900 185 grpc_max_open_connections = {{ .RPC.GRPCMaxOpenConnections }} 186 187 # Activate unsafe RPC commands like /dial_seeds and /unsafe_flush_mempool 188 unsafe = {{ .RPC.Unsafe }} 189 190 # Maximum number of simultaneous connections (including WebSocket). 191 # Does not include gRPC connections. See grpc_max_open_connections 192 # If you want to accept a larger number than the default, make sure 193 # you increase your OS limits. 194 # 0 - unlimited. 195 # Should be < {ulimit -Sn} - {MaxNumInboundPeers} - {MaxNumOutboundPeers} - {N of wal, db and other open files} 196 # 1024 - 40 - 10 - 50 = 924 = ~900 197 max_open_connections = {{ .RPC.MaxOpenConnections }} 198 199 # Maximum number of unique clientIDs that can /subscribe 200 # If you're using /broadcast_tx_commit, set to the estimated maximum number 201 # of broadcast_tx_commit calls per block. 202 max_subscription_clients = {{ .RPC.MaxSubscriptionClients }} 203 204 # Maximum number of unique queries a given client can /subscribe to 205 # If you're using GRPC (or Local RPC client) and /broadcast_tx_commit, set to 206 # the estimated # maximum number of broadcast_tx_commit calls per block. 207 max_subscriptions_per_client = {{ .RPC.MaxSubscriptionsPerClient }} 208 209 # How long to wait for a tx to be committed during /broadcast_tx_commit. 210 # WARNING: Using a value larger than 10s will result in increasing the 211 # global HTTP write timeout, which applies to all connections and endpoints. 212 # See https://github.com/DFWallet/tendermint-cosmos/issues/3435 213 timeout_broadcast_tx_commit = "{{ .RPC.TimeoutBroadcastTxCommit }}" 214 215 # Maximum size of request body, in bytes 216 max_body_bytes = {{ .RPC.MaxBodyBytes }} 217 218 # Maximum size of request header, in bytes 219 max_header_bytes = {{ .RPC.MaxHeaderBytes }} 220 221 # The path to a file containing certificate that is used to create the HTTPS server. 222 # Might be either absolute path or path related to Tendermint's config directory. 223 # If the certificate is signed by a certificate authority, 224 # the certFile should be the concatenation of the server's certificate, any intermediates, 225 # and the CA's certificate. 226 # NOTE: both tls_cert_file and tls_key_file must be present for Tendermint to create HTTPS server. 227 # Otherwise, HTTP server is run. 228 tls_cert_file = "{{ .RPC.TLSCertFile }}" 229 230 # The path to a file containing matching private key that is used to create the HTTPS server. 231 # Might be either absolute path or path related to Tendermint's config directory. 232 # NOTE: both tls-cert-file and tls-key-file must be present for Tendermint to create HTTPS server. 233 # Otherwise, HTTP server is run. 234 tls_key_file = "{{ .RPC.TLSKeyFile }}" 235 236 # pprof listen address (https://golang.org/pkg/net/http/pprof) 237 pprof_laddr = "{{ .RPC.PprofListenAddress }}" 238 239 ####################################################### 240 ### P2P Configuration Options ### 241 ####################################################### 242 [p2p] 243 244 # Address to listen for incoming connections 245 laddr = "{{ .P2P.ListenAddress }}" 246 247 # Address to advertise to peers for them to dial 248 # If empty, will use the same port as the laddr, 249 # and will introspect on the listener or use UPnP 250 # to figure out the address. ip and port are required 251 # example: 159.89.10.97:26656 252 external_address = "{{ .P2P.ExternalAddress }}" 253 254 # Comma separated list of seed nodes to connect to 255 seeds = "{{ .P2P.Seeds }}" 256 257 # Comma separated list of nodes to keep persistent connections to 258 persistent_peers = "{{ .P2P.PersistentPeers }}" 259 260 # UPNP port forwarding 261 upnp = {{ .P2P.UPNP }} 262 263 # Path to address book 264 addr_book_file = "{{ js .P2P.AddrBook }}" 265 266 # Set true for strict address routability rules 267 # Set false for private or local networks 268 addr_book_strict = {{ .P2P.AddrBookStrict }} 269 270 # Maximum number of inbound peers 271 max_num_inbound_peers = {{ .P2P.MaxNumInboundPeers }} 272 273 # Maximum number of outbound peers to connect to, excluding persistent peers 274 max_num_outbound_peers = {{ .P2P.MaxNumOutboundPeers }} 275 276 # List of node IDs, to which a connection will be (re)established ignoring any existing limits 277 unconditional_peer_ids = "{{ .P2P.UnconditionalPeerIDs }}" 278 279 # Maximum pause when redialing a persistent peer (if zero, exponential backoff is used) 280 persistent_peers_max_dial_period = "{{ .P2P.PersistentPeersMaxDialPeriod }}" 281 282 # Time to wait before flushing messages out on the connection 283 flush_throttle_timeout = "{{ .P2P.FlushThrottleTimeout }}" 284 285 # Maximum size of a message packet payload, in bytes 286 max_packet_msg_payload_size = {{ .P2P.MaxPacketMsgPayloadSize }} 287 288 # Rate at which packets can be sent, in bytes/second 289 send_rate = {{ .P2P.SendRate }} 290 291 # Rate at which packets can be received, in bytes/second 292 recv_rate = {{ .P2P.RecvRate }} 293 294 # Set true to enable the peer-exchange reactor 295 pex = {{ .P2P.PexReactor }} 296 297 # Seed mode, in which node constantly crawls the network and looks for 298 # peers. If another node asks it for addresses, it responds and disconnects. 299 # 300 # Does not work if the peer-exchange reactor is disabled. 301 seed_mode = {{ .P2P.SeedMode }} 302 303 # Comma separated list of peer IDs to keep private (will not be gossiped to other peers) 304 private_peer_ids = "{{ .P2P.PrivatePeerIDs }}" 305 306 # Toggle to disable guard against peers connecting from the same ip. 307 allow_duplicate_ip = {{ .P2P.AllowDuplicateIP }} 308 309 # Peer connection configuration. 310 handshake_timeout = "{{ .P2P.HandshakeTimeout }}" 311 dial_timeout = "{{ .P2P.DialTimeout }}" 312 313 ####################################################### 314 ### Mempool Configuration Option ### 315 ####################################################### 316 [mempool] 317 318 recheck = {{ .Mempool.Recheck }} 319 broadcast = {{ .Mempool.Broadcast }} 320 wal_dir = "{{ js .Mempool.WalPath }}" 321 322 # Maximum number of transactions in the mempool 323 size = {{ .Mempool.Size }} 324 325 # Limit the total size of all txs in the mempool. 326 # This only accounts for raw transactions (e.g. given 1MB transactions and 327 # max_txs_bytes=5MB, mempool will only accept 5 transactions). 328 max_txs_bytes = {{ .Mempool.MaxTxsBytes }} 329 330 # Size of the cache (used to filter transactions we saw earlier) in transactions 331 cache_size = {{ .Mempool.CacheSize }} 332 333 # Do not remove invalid transactions from the cache (default: false) 334 # Set to true if it's not possible for any invalid transaction to become valid 335 # again in the future. 336 keep-invalid-txs-in-cache = {{ .Mempool.KeepInvalidTxsInCache }} 337 338 # Maximum size of a single transaction. 339 # NOTE: the max size of a tx transmitted over the network is {max_tx_bytes}. 340 max_tx_bytes = {{ .Mempool.MaxTxBytes }} 341 342 # Maximum size of a batch of transactions to send to a peer 343 # Including space needed by encoding (one varint per transaction). 344 # XXX: Unused due to https://github.com/DFWallet/tendermint-cosmos/issues/5796 345 max_batch_bytes = {{ .Mempool.MaxBatchBytes }} 346 347 ####################################################### 348 ### State Sync Configuration Options ### 349 ####################################################### 350 [statesync] 351 # State sync rapidly bootstraps a new node by discovering, fetching, and restoring a state machine 352 # snapshot from peers instead of fetching and replaying historical blocks. Requires some peers in 353 # the network to take and serve state machine snapshots. State sync is not attempted if the node 354 # has any local state (LastBlockHeight > 0). The node will have a truncated block history, 355 # starting from the height of the snapshot. 356 enable = {{ .StateSync.Enable }} 357 358 # RPC servers (comma-separated) for light client verification of the synced state machine and 359 # retrieval of state data for node bootstrapping. Also needs a trusted height and corresponding 360 # header hash obtained from a trusted source, and a period during which validators can be trusted. 361 # 362 # For Cosmos SDK-based chains, trust_period should usually be about 2/3 of the unbonding time (~2 363 # weeks) during which they can be financially punished (slashed) for misbehavior. 364 rpc_servers = "{{ StringsJoin .StateSync.RPCServers "," }}" 365 trust_height = {{ .StateSync.TrustHeight }} 366 trust_hash = "{{ .StateSync.TrustHash }}" 367 trust_period = "{{ .StateSync.TrustPeriod }}" 368 369 # Time to spend discovering snapshots before initiating a restore. 370 discovery_time = "{{ .StateSync.DiscoveryTime }}" 371 372 # Temporary directory for state sync snapshot chunks, defaults to the OS tempdir (typically /tmp). 373 # Will create a new, randomly named directory within, and remove it when done. 374 temp_dir = "{{ .StateSync.TempDir }}" 375 376 # The timeout duration before re-requesting a chunk, possibly from a different 377 # peer (default: 1 minute). 378 chunk_request_timeout = "{{ .StateSync.ChunkRequestTimeout }}" 379 380 # The number of concurrent chunk fetchers to run (default: 1). 381 chunk_fetchers = "{{ .StateSync.ChunkFetchers }}" 382 383 ####################################################### 384 ### Fast Sync Configuration Connections ### 385 ####################################################### 386 [fastsync] 387 388 # Fast Sync version to use: 389 # 1) "v0" (default) - the legacy fast sync implementation 390 # 2) "v1" - refactor of v0 version for better testability 391 # 2) "v2" - complete redesign of v0, optimized for testability & readability 392 version = "{{ .FastSync.Version }}" 393 394 ####################################################### 395 ### Consensus Configuration Options ### 396 ####################################################### 397 [consensus] 398 399 wal_file = "{{ js .Consensus.WalPath }}" 400 401 # How long we wait for a proposal block before prevoting nil 402 timeout_propose = "{{ .Consensus.TimeoutPropose }}" 403 # How much timeout_propose increases with each round 404 timeout_propose_delta = "{{ .Consensus.TimeoutProposeDelta }}" 405 # How long we wait after receiving +2/3 prevotes for “anything” (ie. not a single block or nil) 406 timeout_prevote = "{{ .Consensus.TimeoutPrevote }}" 407 # How much the timeout_prevote increases with each round 408 timeout_prevote_delta = "{{ .Consensus.TimeoutPrevoteDelta }}" 409 # How long we wait after receiving +2/3 precommits for “anything” (ie. not a single block or nil) 410 timeout_precommit = "{{ .Consensus.TimeoutPrecommit }}" 411 # How much the timeout_precommit increases with each round 412 timeout_precommit_delta = "{{ .Consensus.TimeoutPrecommitDelta }}" 413 # How long we wait after committing a block, before starting on the new 414 # height (this gives us a chance to receive some more precommits, even 415 # though we already have +2/3). 416 timeout_commit = "{{ .Consensus.TimeoutCommit }}" 417 418 # How many blocks to look back to check existence of the node's consensus votes before joining consensus 419 # When non-zero, the node will panic upon restart 420 # if the same consensus key was used to sign {double_sign_check_height} last blocks. 421 # So, validators should stop the state machine, wait for some blocks, and then restart the state machine to avoid panic. 422 double_sign_check_height = {{ .Consensus.DoubleSignCheckHeight }} 423 424 # Make progress as soon as we have all the precommits (as if TimeoutCommit = 0) 425 skip_timeout_commit = {{ .Consensus.SkipTimeoutCommit }} 426 427 # EmptyBlocks mode and possible interval between empty blocks 428 create_empty_blocks = {{ .Consensus.CreateEmptyBlocks }} 429 create_empty_blocks_interval = "{{ .Consensus.CreateEmptyBlocksInterval }}" 430 431 # Reactor sleep duration parameters 432 peer_gossip_sleep_duration = "{{ .Consensus.PeerGossipSleepDuration }}" 433 peer_query_maj23_sleep_duration = "{{ .Consensus.PeerQueryMaj23SleepDuration }}" 434 435 ####################################################### 436 ### Transaction Indexer Configuration Options ### 437 ####################################################### 438 [tx_index] 439 440 # What indexer to use for transactions 441 # 442 # The application will set which txs to index. In some cases a node operator will be able 443 # to decide which txs to index based on configuration set in the application. 444 # 445 # Options: 446 # 1) "null" 447 # 2) "kv" (default) - the simplest possible indexer, backed by key-value storage (defaults to levelDB; see DBBackend). 448 # - When "kv" is chosen "tx.height" and "tx.hash" will always be indexed. 449 indexer = "{{ .TxIndex.Indexer }}" 450 451 ####################################################### 452 ### Instrumentation Configuration Options ### 453 ####################################################### 454 [instrumentation] 455 456 # When true, Prometheus metrics are served under /metrics on 457 # PrometheusListenAddr. 458 # Check out the documentation for the list of available metrics. 459 prometheus = {{ .Instrumentation.Prometheus }} 460 461 # Address to listen for Prometheus collector(s) connections 462 prometheus_listen_addr = "{{ .Instrumentation.PrometheusListenAddr }}" 463 464 # Maximum number of simultaneous connections. 465 # If you want to accept a larger number than the default, make sure 466 # you increase your OS limits. 467 # 0 - unlimited. 468 max_open_connections = {{ .Instrumentation.MaxOpenConnections }} 469 470 # Instrumentation namespace 471 namespace = "{{ .Instrumentation.Namespace }}" 472 ` 473 474 /****** these are for test settings ***********/ 475 476 func ResetTestRoot(testName string) *Config { 477 return ResetTestRootWithChainID(testName, "") 478 } 479 480 func ResetTestRootWithChainID(testName string, chainID string) *Config { 481 // create a unique, concurrency-safe test directory under os.TempDir() 482 rootDir, err := ioutil.TempDir("", fmt.Sprintf("%s-%s_", chainID, testName)) 483 if err != nil { 484 panic(err) 485 } 486 // ensure config and data subdirs are created 487 if err := tmos.EnsureDir(filepath.Join(rootDir, defaultConfigDir), DefaultDirPerm); err != nil { 488 panic(err) 489 } 490 if err := tmos.EnsureDir(filepath.Join(rootDir, defaultDataDir), DefaultDirPerm); err != nil { 491 panic(err) 492 } 493 494 baseConfig := DefaultBaseConfig() 495 configFilePath := filepath.Join(rootDir, defaultConfigFilePath) 496 genesisFilePath := filepath.Join(rootDir, baseConfig.Genesis) 497 privKeyFilePath := filepath.Join(rootDir, baseConfig.PrivValidatorKey) 498 privStateFilePath := filepath.Join(rootDir, baseConfig.PrivValidatorState) 499 500 // Write default config file if missing. 501 if !tmos.FileExists(configFilePath) { 502 writeDefaultConfigFile(configFilePath) 503 } 504 if !tmos.FileExists(genesisFilePath) { 505 if chainID == "" { 506 chainID = "tendermint_test" 507 } 508 testGenesis := fmt.Sprintf(testGenesisFmt, chainID) 509 tmos.MustWriteFile(genesisFilePath, []byte(testGenesis), 0644) 510 } 511 // we always overwrite the priv val 512 tmos.MustWriteFile(privKeyFilePath, []byte(testPrivValidatorKey), 0644) 513 tmos.MustWriteFile(privStateFilePath, []byte(testPrivValidatorState), 0644) 514 515 config := TestConfig().SetRoot(rootDir) 516 return config 517 } 518 519 var testGenesisFmt = `{ 520 "genesis_time": "2018-10-10T08:20:13.695936996Z", 521 "chain_id": "%s", 522 "initial_height": "1", 523 "consensus_params": { 524 "block": { 525 "max_bytes": "22020096", 526 "max_gas": "-1", 527 "time_iota_ms": "10" 528 }, 529 "evidence": { 530 "max_age_num_blocks": "100000", 531 "max_age_duration": "172800000000000", 532 "max_bytes": "1048576" 533 }, 534 "validator": { 535 "pub_key_types": [ 536 "ed25519" 537 ] 538 }, 539 "version": {} 540 }, 541 "validators": [ 542 { 543 "pub_key": { 544 "type": "tendermint/PubKeyEd25519", 545 "value":"AT/+aaL1eB0477Mud9JMm8Sh8BIvOYlPGC9KkIUmFaE=" 546 }, 547 "power": "10", 548 "name": "" 549 } 550 ], 551 "app_hash": "" 552 }` 553 554 var testPrivValidatorKey = `{ 555 "address": "A3258DCBF45DCA0DF052981870F2D1441A36D145", 556 "pub_key": { 557 "type": "tendermint/PubKeyEd25519", 558 "value": "AT/+aaL1eB0477Mud9JMm8Sh8BIvOYlPGC9KkIUmFaE=" 559 }, 560 "priv_key": { 561 "type": "tendermint/PrivKeyEd25519", 562 "value": "EVkqJO/jIXp3rkASXfh9YnyToYXRXhBr6g9cQVxPFnQBP/5povV4HTjvsy530kybxKHwEi85iU8YL0qQhSYVoQ==" 563 } 564 }` 565 566 var testPrivValidatorState = `{ 567 "height": "0", 568 "round": 0, 569 "step": 0 570 }`