diff --git a/Makefile b/Makefile index 6a3b2381f..8835722b8 100644 --- a/Makefile +++ b/Makefile @@ -12,19 +12,19 @@ NOVENDOR = go list github.com/tendermint/tendermint/... | grep -v /vendor/ install: get_deps go install github.com/tendermint/tendermint/cmd/tendermint -build: +build: go build -o build/tendermint github.com/tendermint/tendermint/cmd/tendermint -build_race: +build_race: go build -race -o build/tendermint github.com/tendermint/tendermint/cmd/tendermint test: build go test `${NOVENDOR}` - + test_race: build go test -race `${NOVENDOR}` -test_integrations: +test_integrations: bash ./test/test.sh test100: build @@ -48,6 +48,7 @@ get_deps: get_vendor_deps: go get github.com/Masterminds/glide + rm -rf vendor/ glide install update_deps: diff --git a/config/tendermint/config.go b/config/tendermint/config.go index a48f801e9..2e8d90254 100644 --- a/config/tendermint/config.go +++ b/config/tendermint/config.go @@ -84,6 +84,8 @@ func GetConfig(rootDir string) cfg.Config { mapConfig.SetDefault("timeout_precommit", 1000) mapConfig.SetDefault("timeout_precommit_delta", 500) mapConfig.SetDefault("timeout_commit", 1000) + // make progress asap (no `timeout_commit`) on full precommit votes + mapConfig.SetDefault("skip_timeout_commit", false) mapConfig.SetDefault("mempool_recheck", true) mapConfig.SetDefault("mempool_recheck_empty", true) mapConfig.SetDefault("mempool_broadcast", true) diff --git a/config/tendermint_test/config.go b/config/tendermint_test/config.go index 28b1da805..421c0017b 100644 --- a/config/tendermint_test/config.go +++ b/config/tendermint_test/config.go @@ -98,6 +98,7 @@ func ResetConfig(localPath string) cfg.Config { mapConfig.SetDefault("timeout_precommit", 10) mapConfig.SetDefault("timeout_precommit_delta", 1) mapConfig.SetDefault("timeout_commit", 10) + mapConfig.SetDefault("skip_timeout_commit", true) mapConfig.SetDefault("mempool_recheck", true) mapConfig.SetDefault("mempool_recheck_empty", true) mapConfig.SetDefault("mempool_broadcast", true) diff --git a/consensus/reactor_test.go b/consensus/reactor_test.go index 995f4a387..f2024fe81 100644 --- a/consensus/reactor_test.go +++ b/consensus/reactor_test.go @@ -149,6 +149,7 @@ func TestValidatorSetChanges(t *testing.T) { nPeers := 8 nVals := 4 css := randConsensusNetWithPeers(nVals, nPeers, "consensus_val_set_changes_test", newMockTickerFunc(true), newPersistentDummy) + reactors := make([]*ConsensusReactor, nPeers) eventChans := make([]chan interface{}, nPeers) for i := 0; i < nPeers; i++ { @@ -261,6 +262,49 @@ func TestValidatorSetChanges(t *testing.T) { waitForAndValidateBlock(t, nPeers, activeVals, eventChans, css) } +// Check we can make blocks with skip_timeout_commit=false +func TestReactorWithTimeoutCommit(t *testing.T) { + N := 4 + css := randConsensusNet(N, "consensus_reactor_with_timeout_commit_test", newMockTickerFunc(false)) + + // override default SkipTimeoutCommit == true for tests + for i := 0; i < N; i++ { + css[i].timeoutParams.SkipTimeoutCommit = false + } + + reactors := make([]*ConsensusReactor, N-1) + eventChans := make([]chan interface{}, N-1) + for i := 0; i < N-1; i++ { + reactors[i] = NewConsensusReactor(css[i], true) // so we dont start the consensus states + + eventSwitch := events.NewEventSwitch() + _, err := eventSwitch.Start() + if err != nil { + t.Fatalf("Failed to start switch: %v", err) + } + + reactors[i].SetEventSwitch(eventSwitch) + eventChans[i] = subscribeToEvent(eventSwitch, "tester", types.EventStringNewBlock(), 1) + } + // make connected switches and start all reactors + p2p.MakeConnectedSwitches(N-1, func(i int, s *p2p.Switch) *p2p.Switch { + s.AddReactor("CONSENSUS", reactors[i]) + return s + }, p2p.Connect2Switches) + + // start the state machines + for i := 0; i < N-1; i++ { + s := reactors[i].conS.GetState() + reactors[i].SwitchToConsensus(s) + } + + // wait till everyone makes the first new block + timeoutWaitGroup(t, N-1, func(wg *sync.WaitGroup, j int) { + <-eventChans[j] + wg.Done() + }) +} + func waitForAndValidateBlock(t *testing.T, n int, activeVals map[string]struct{}, eventChans []chan interface{}, css []*ConsensusState, txs ...[]byte) { timeoutWaitGroup(t, n, func(wg *sync.WaitGroup, j int) { newBlockI := <-eventChans[j] diff --git a/consensus/state.go b/consensus/state.go index 3020a214a..13125a5d3 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -24,15 +24,17 @@ import ( //----------------------------------------------------------------------------- // Timeout Parameters -// All in milliseconds +// TimeoutParams holds timeouts and deltas for each round step. +// All timeouts and deltas in milliseconds. type TimeoutParams struct { - Propose0 int - ProposeDelta int - Prevote0 int - PrevoteDelta int - Precommit0 int - PrecommitDelta int - Commit0 int + Propose0 int + ProposeDelta int + Prevote0 int + PrevoteDelta int + Precommit0 int + PrecommitDelta int + Commit0 int + SkipTimeoutCommit bool } // Wait this long for a proposal @@ -55,16 +57,17 @@ func (tp *TimeoutParams) Commit(t time.Time) time.Time { return t.Add(time.Duration(tp.Commit0) * time.Millisecond) } -// Initialize parameters from config +// InitTimeoutParamsFromConfig initializes parameters from config func InitTimeoutParamsFromConfig(config cfg.Config) *TimeoutParams { return &TimeoutParams{ - Propose0: config.GetInt("timeout_propose"), - ProposeDelta: config.GetInt("timeout_propose_delta"), - Prevote0: config.GetInt("timeout_prevote"), - PrevoteDelta: config.GetInt("timeout_prevote_delta"), - Precommit0: config.GetInt("timeout_precommit"), - PrecommitDelta: config.GetInt("timeout_precommit_delta"), - Commit0: config.GetInt("timeout_commit"), + Propose0: config.GetInt("timeout_propose"), + ProposeDelta: config.GetInt("timeout_propose_delta"), + Prevote0: config.GetInt("timeout_prevote"), + PrevoteDelta: config.GetInt("timeout_prevote_delta"), + Precommit0: config.GetInt("timeout_precommit"), + PrecommitDelta: config.GetInt("timeout_precommit_delta"), + Commit0: config.GetInt("timeout_commit"), + SkipTimeoutCommit: config.GetBool("skip_timeout_commit"), } } @@ -1388,8 +1391,8 @@ func (cs *ConsensusState) addVote(vote *types.Vote, peerKey string) (added bool, log.Info(Fmt("Added to lastPrecommits: %v", cs.LastCommit.StringShort())) types.FireEventVote(cs.evsw, types.EventDataVote{vote}) - if cs.LastCommit.HasAll() { - // if we have all the votes now, + // if we can skip timeoutCommit and have all the votes now, + if cs.timeoutParams.SkipTimeoutCommit && cs.LastCommit.HasAll() { // go straight to new round (skip timeout commit) // cs.scheduleTimeout(time.Duration(0), cs.Height, 0, RoundStepNewHeight) cs.enterNewRound(cs.Height, 0) @@ -1452,7 +1455,7 @@ func (cs *ConsensusState) addVote(vote *types.Vote, peerKey string) (added bool, cs.enterPrecommit(height, vote.Round) cs.enterCommit(height, vote.Round) - if precommits.HasAll() { + if cs.timeoutParams.SkipTimeoutCommit && cs.LastCommit.HasAll() { // if we have all the votes now, // go straight to new round (skip timeout commit) // cs.scheduleTimeout(time.Duration(0), cs.Height, 0, RoundStepNewHeight)