diff --git a/CHANGELOG.md b/CHANGELOG.md index 850721728..1dbf7a70a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 0.10.2 (TBD) + +FEATURES: +- Add consensus reactor sleep durations to the config + ## 0.10.1 (June 28, 2017) FEATURES: diff --git a/config/config.go b/config/config.go index 42ca60992..567084421 100644 --- a/config/config.go +++ b/config/config.go @@ -5,9 +5,10 @@ import ( "path/filepath" "time" - "github.com/tendermint/tendermint/types" + "github.com/tendermint/tendermint/types" // TODO: remove ) +// Config defines the top level configuration for a Tendermint node type Config struct { // Top level options use an anonymous struct BaseConfig `mapstructure:",squash"` @@ -19,6 +20,7 @@ type Config struct { Consensus *ConsensusConfig `mapstructure:"consensus"` } +// DefaultConfig returns a default configuration for a Tendermint node func DefaultConfig() *Config { return &Config{ BaseConfig: DefaultBaseConfig(), @@ -29,6 +31,7 @@ func DefaultConfig() *Config { } } +// TestConfig returns a configuration that can be used for testing func TestConfig() *Config { return &Config{ BaseConfig: TestBaseConfig(), @@ -39,7 +42,7 @@ func TestConfig() *Config { } } -// Set the RootDir for all Config structs +// SetRoot sets the RootDir for all Config structs func (cfg *Config) SetRoot(root string) *Config { cfg.BaseConfig.RootDir = root cfg.RPC.RootDir = root @@ -52,7 +55,7 @@ func (cfg *Config) SetRoot(root string) *Config { //----------------------------------------------------------------------------- // BaseConfig -// BaseConfig struct for a Tendermint node +// BaseConfig defines the base configuration for a Tendermint node type BaseConfig struct { // The root directory for all data. // This should be set in viper so it can unmarshal into this struct @@ -102,6 +105,7 @@ type BaseConfig struct { DBPath string `mapstructure:"db_dir"` } +// DefaultBaseConfig returns a default base configuration for a Tendermint node func DefaultBaseConfig() BaseConfig { return BaseConfig{ Genesis: "genesis.json", @@ -119,6 +123,7 @@ func DefaultBaseConfig() BaseConfig { } } +// TestBaseConfig returns a base configuration for testing a Tendermint node func TestBaseConfig() BaseConfig { conf := DefaultBaseConfig() conf.ChainID = "tendermint_test" @@ -128,22 +133,27 @@ func TestBaseConfig() BaseConfig { return conf } +// GenesisFile returns the full path to the genesis.json file func (b BaseConfig) GenesisFile() string { return rootify(b.Genesis, b.RootDir) } +// PrivValidatorFile returns the full path to the priv_validator.json file func (b BaseConfig) PrivValidatorFile() string { return rootify(b.PrivValidator, b.RootDir) } +// DBDir returns the full path to the database directory func (b BaseConfig) DBDir() string { return rootify(b.DBPath, b.RootDir) } +// DefaultLogLevel returns a default log level of "error" func DefaultLogLevel() string { return "error" } +// DefaultPackageLogLevels returns a default log level setting so all packages log at "error", while the `state` package logs at "info" func DefaultPackageLogLevels() string { return fmt.Sprintf("state:info,*:%s", DefaultLogLevel()) } @@ -151,6 +161,7 @@ func DefaultPackageLogLevels() string { //----------------------------------------------------------------------------- // RPCConfig +// RPCConfig defines the configuration options for the Tendermint RPC server type RPCConfig struct { RootDir string `mapstructure:"home"` @@ -165,6 +176,7 @@ type RPCConfig struct { Unsafe bool `mapstructure:"unsafe"` } +// DefaultRPCConfig returns a default configuration for the RPC server func DefaultRPCConfig() *RPCConfig { return &RPCConfig{ ListenAddress: "tcp://0.0.0.0:46657", @@ -173,6 +185,7 @@ func DefaultRPCConfig() *RPCConfig { } } +// TestRPCConfig returns a configuration for testing the RPC server func TestRPCConfig() *RPCConfig { conf := DefaultRPCConfig() conf.ListenAddress = "tcp://0.0.0.0:36657" @@ -184,6 +197,7 @@ func TestRPCConfig() *RPCConfig { //----------------------------------------------------------------------------- // P2PConfig +// P2PConfig defines the configuration options for the Tendermint peer-to-peer networking layer type P2PConfig struct { RootDir string `mapstructure:"home"` ListenAddress string `mapstructure:"laddr"` @@ -195,6 +209,7 @@ type P2PConfig struct { MaxNumPeers int `mapstructure:"max_num_peers"` } +// DefaultP2PConfig returns a default configuration for the peer-to-peer layer func DefaultP2PConfig() *P2PConfig { return &P2PConfig{ ListenAddress: "tcp://0.0.0.0:46656", @@ -204,6 +219,7 @@ func DefaultP2PConfig() *P2PConfig { } } +// TestP2PConfig returns a configuration for testing the peer-to-peer layer func TestP2PConfig() *P2PConfig { conf := DefaultP2PConfig() conf.ListenAddress = "tcp://0.0.0.0:36656" @@ -211,6 +227,7 @@ func TestP2PConfig() *P2PConfig { return conf } +// AddrBookFile returns the full path to the address bool func (p *P2PConfig) AddrBookFile() string { return rootify(p.AddrBook, p.RootDir) } @@ -218,6 +235,7 @@ func (p *P2PConfig) AddrBookFile() string { //----------------------------------------------------------------------------- // MempoolConfig +// MempoolConfig defines the configuration options for the Tendermint mempool type MempoolConfig struct { RootDir string `mapstructure:"home"` Recheck bool `mapstructure:"recheck"` @@ -226,6 +244,7 @@ type MempoolConfig struct { WalPath string `mapstructure:"wal_dir"` } +// DefaultMempoolConfig returns a default configuration for the Tendermint mempool func DefaultMempoolConfig() *MempoolConfig { return &MempoolConfig{ Recheck: true, @@ -235,6 +254,7 @@ func DefaultMempoolConfig() *MempoolConfig { } } +// WalDir returns the full path to the mempool's write-ahead log func (m *MempoolConfig) WalDir() string { return rootify(m.WalPath, m.RootDir) } @@ -242,8 +262,8 @@ func (m *MempoolConfig) WalDir() string { //----------------------------------------------------------------------------- // ConsensusConfig -// ConsensusConfig holds timeouts and details about the WAL, the block structure, -// and timeouts in the consensus protocol. +// ConsensusConfig defines the confuguration for the Tendermint consensus service, +// including timeouts and details about the WAL and the block structure. type ConsensusConfig struct { RootDir string `mapstructure:"home"` WalPath string `mapstructure:"wal_file"` @@ -269,46 +289,64 @@ type ConsensusConfig struct { // TODO: This probably shouldn't be exposed but it makes it // easy to write tests for the wal/replay BlockPartSize int `mapstructure:"block_part_size"` + + // Reactor sleep duration parameters are in ms + PeerGossipSleepDuration int `mapstructure:"peer_gossip_sleep_duration"` + PeerQueryMaj23SleepDuration int `mapstructure:"peer_query_maj23_sleep_duration"` } -// Wait this long for a proposal +// Propose returns the amount of time to wait for a proposal func (cfg *ConsensusConfig) Propose(round int) time.Duration { return time.Duration(cfg.TimeoutPropose+cfg.TimeoutProposeDelta*round) * time.Millisecond } -// After receiving any +2/3 prevote, wait this long for stragglers +// Prevote returns the amount of time to wait for straggler votes after receiving any +2/3 prevotes func (cfg *ConsensusConfig) Prevote(round int) time.Duration { return time.Duration(cfg.TimeoutPrevote+cfg.TimeoutPrevoteDelta*round) * time.Millisecond } -// After receiving any +2/3 precommits, wait this long for stragglers +// Precommit returns the amount of time to wait for straggler votes after receiving any +2/3 precommits func (cfg *ConsensusConfig) Precommit(round int) time.Duration { return time.Duration(cfg.TimeoutPrecommit+cfg.TimeoutPrecommitDelta*round) * time.Millisecond } -// After receiving +2/3 precommits for a single block (a commit), wait this long for stragglers in the next height's RoundStepNewHeight +// Commit returns the amount of time to wait for straggler votes after receiving +2/3 precommits for a single block (ie. a commit). func (cfg *ConsensusConfig) Commit(t time.Time) time.Time { return t.Add(time.Duration(cfg.TimeoutCommit) * time.Millisecond) } +// PeerGossipSleep returns the amount of time to sleep if there is nothing to send from the ConsensusReactor +func (cfg *ConsensusConfig) PeerGossipSleep() time.Duration { + return time.Duration(cfg.PeerGossipSleepDuration) * time.Millisecond +} + +// PeerQueryMaj23Sleep returns the amount of time to sleep after each VoteSetMaj23Message is sent in the ConsensusReactor +func (cfg *ConsensusConfig) PeerQueryMaj23Sleep() time.Duration { + return time.Duration(cfg.PeerQueryMaj23SleepDuration) * time.Millisecond +} + +// DefaultConsensusConfig returns a default configuration for the consensus service func DefaultConsensusConfig() *ConsensusConfig { return &ConsensusConfig{ - WalPath: "data/cs.wal/wal", - WalLight: false, - TimeoutPropose: 3000, - TimeoutProposeDelta: 500, - TimeoutPrevote: 1000, - TimeoutPrevoteDelta: 500, - TimeoutPrecommit: 1000, - TimeoutPrecommitDelta: 500, - TimeoutCommit: 1000, - SkipTimeoutCommit: false, - MaxBlockSizeTxs: 10000, - MaxBlockSizeBytes: 1, // TODO - BlockPartSize: types.DefaultBlockPartSize, // TODO: we shouldnt be importing types + WalPath: "data/cs.wal/wal", + WalLight: false, + TimeoutPropose: 3000, + TimeoutProposeDelta: 500, + TimeoutPrevote: 1000, + TimeoutPrevoteDelta: 500, + TimeoutPrecommit: 1000, + TimeoutPrecommitDelta: 500, + TimeoutCommit: 1000, + SkipTimeoutCommit: false, + MaxBlockSizeTxs: 10000, + MaxBlockSizeBytes: 1, // TODO + BlockPartSize: types.DefaultBlockPartSize, // TODO: we shouldnt be importing types + PeerGossipSleepDuration: 100, + PeerQueryMaj23SleepDuration: 2000, } } +// TestConsensusConfig returns a configuration for testing the consensus service func TestConsensusConfig() *ConsensusConfig { config := DefaultConsensusConfig() config.TimeoutPropose = 2000 @@ -322,6 +360,7 @@ func TestConsensusConfig() *ConsensusConfig { return config } +// WalFile returns the full path to the write-ahead log file func (c *ConsensusConfig) WalFile() string { if c.walFile != "" { return c.walFile @@ -329,6 +368,7 @@ func (c *ConsensusConfig) WalFile() string { return rootify(c.WalPath, c.RootDir) } +// SetWalFile sets the path to the write-ahead log file func (c *ConsensusConfig) SetWalFile(walFile string) { c.walFile = walFile } diff --git a/consensus/reactor.go b/consensus/reactor.go index 50207ed52..902ed76f7 100644 --- a/consensus/reactor.go +++ b/consensus/reactor.go @@ -21,9 +21,7 @@ const ( VoteChannel = byte(0x22) VoteSetBitsChannel = byte(0x23) - peerGossipSleepDuration = 100 * time.Millisecond // Time to sleep if there's nothing to send. - peerQueryMaj23SleepDuration = 2 * time.Second // Time to sleep after each VoteSetMaj23Message sent - maxConsensusMessageSize = 1048576 // 1MB; NOTE: keep in sync with types.PartSet sizes. + maxConsensusMessageSize = 1048576 // 1MB; NOTE/TODO: keep in sync with types.PartSet sizes. ) //----------------------------------------------------------------------------- @@ -413,12 +411,12 @@ OUTER_LOOP: blockMeta := conR.conS.blockStore.LoadBlockMeta(prs.Height) if blockMeta == nil { logger.Error("Failed to load block meta", "peer height", prs.Height, "ourHeight", rs.Height, "blockstoreHeight", conR.conS.blockStore.Height(), "pv", conR.conS.privValidator) - time.Sleep(peerGossipSleepDuration) + time.Sleep(conR.conS.config.PeerGossipSleep()) continue OUTER_LOOP } else if !blockMeta.BlockID.PartsHeader.Equals(prs.ProposalBlockPartsHeader) { logger.Info("Peer ProposalBlockPartsHeader mismatch, sleeping", "peerHeight", prs.Height, "blockPartsHeader", blockMeta.BlockID.PartsHeader, "peerBlockPartsHeader", prs.ProposalBlockPartsHeader) - time.Sleep(peerGossipSleepDuration) + time.Sleep(conR.conS.config.PeerGossipSleep()) continue OUTER_LOOP } // Load the part @@ -426,7 +424,7 @@ OUTER_LOOP: if part == nil { logger.Error("Could not load part", "index", index, "peerHeight", prs.Height, "blockPartsHeader", blockMeta.BlockID.PartsHeader, "peerBlockPartsHeader", prs.ProposalBlockPartsHeader) - time.Sleep(peerGossipSleepDuration) + time.Sleep(conR.conS.config.PeerGossipSleep()) continue OUTER_LOOP } // Send the part @@ -441,7 +439,7 @@ OUTER_LOOP: continue OUTER_LOOP } else { //logger.Info("No parts to send in catch-up, sleeping") - time.Sleep(peerGossipSleepDuration) + time.Sleep(conR.conS.config.PeerGossipSleep()) continue OUTER_LOOP } } @@ -449,7 +447,7 @@ OUTER_LOOP: // If height and round don't match, sleep. if (rs.Height != prs.Height) || (rs.Round != prs.Round) { //logger.Info("Peer Height|Round mismatch, sleeping", "peerHeight", prs.Height, "peerRound", prs.Round, "peer", peer) - time.Sleep(peerGossipSleepDuration) + time.Sleep(conR.conS.config.PeerGossipSleep()) continue OUTER_LOOP } @@ -483,7 +481,7 @@ OUTER_LOOP: } // Nothing to do. Sleep. - time.Sleep(peerGossipSleepDuration) + time.Sleep(conR.conS.config.PeerGossipSleep()) continue OUTER_LOOP } } @@ -581,7 +579,7 @@ OUTER_LOOP: sleeping = 1 } - time.Sleep(peerGossipSleepDuration) + time.Sleep(conR.conS.config.PeerGossipSleep()) continue OUTER_LOOP } } @@ -611,7 +609,7 @@ OUTER_LOOP: Type: types.VoteTypePrevote, BlockID: maj23, }}) - time.Sleep(peerQueryMaj23SleepDuration) + time.Sleep(conR.conS.config.PeerQueryMaj23Sleep()) } } } @@ -628,7 +626,7 @@ OUTER_LOOP: Type: types.VoteTypePrecommit, BlockID: maj23, }}) - time.Sleep(peerQueryMaj23SleepDuration) + time.Sleep(conR.conS.config.PeerQueryMaj23Sleep()) } } } @@ -645,7 +643,7 @@ OUTER_LOOP: Type: types.VoteTypePrevote, BlockID: maj23, }}) - time.Sleep(peerQueryMaj23SleepDuration) + time.Sleep(conR.conS.config.PeerQueryMaj23Sleep()) } } } @@ -664,11 +662,11 @@ OUTER_LOOP: Type: types.VoteTypePrecommit, BlockID: commit.BlockID, }}) - time.Sleep(peerQueryMaj23SleepDuration) + time.Sleep(conR.conS.config.PeerQueryMaj23Sleep()) } } - time.Sleep(peerQueryMaj23SleepDuration) + time.Sleep(conR.conS.config.PeerQueryMaj23Sleep()) continue OUTER_LOOP }