diff --git a/.github/ISSUE_TEMPLATE b/.github/ISSUE_TEMPLATE index c9c1f6a0..e0edb29f 100644 --- a/.github/ISSUE_TEMPLATE +++ b/.github/ISSUE_TEMPLATE @@ -35,6 +35,8 @@ in a case of bug. **Logs (you can paste a part showing an error or attach the whole file)**: +**Config (you can paste only the changes you've made)**: + **`/dump_consensus_state` output for consensus bugs** **Anything else do we need to know**: diff --git a/CHANGELOG.md b/CHANGELOG.md index 5afc0221..71891e99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,17 @@ # Changelog -## 0.20.1 +## 0.21.0 -BUG FIXES: +*June 20th, 2018* +BREAKING CHANGES + +- [config] Change default ports from 4665X to 2665X + +BUG FIXES + +- [consensus] Fix #1754 where we don't make blocks when `create_empty_blocks=false` +- [mempool] Fix #1761 where we don't process txs if `cache_size=0` - [rpc] fix memory leak in Websocket (when using `/subscribe` method) ## 0.20.0 diff --git a/consensus/state.go b/consensus/state.go index d46ec583..3834b151 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -460,9 +460,12 @@ func (cs *ConsensusState) updateToState(state sm.State) { // If state isn't further out than cs.state, just ignore. // This happens when SwitchToConsensus() is called in the reactor. - // We don't want to reset e.g. the Votes. + // We don't want to reset e.g. the Votes, but we still want to + // signal the new round step, because other services (eg. mempool) + // depend on having an up-to-date peer state! if !cs.state.IsEmpty() && (state.LastBlockHeight <= cs.state.LastBlockHeight) { cs.Logger.Info("Ignoring updateToState()", "newHeight", state.LastBlockHeight+1, "oldHeight", cs.state.LastBlockHeight+1) + cs.newStep() return } @@ -492,6 +495,7 @@ func (cs *ConsensusState) updateToState(state sm.State) { } else { cs.StartTime = cs.config.Commit(cs.CommitTime) } + cs.Validators = validators cs.Proposal = nil cs.ProposalBlock = nil @@ -517,7 +521,7 @@ func (cs *ConsensusState) newStep() { rs := cs.RoundStateEvent() cs.wal.Write(rs) cs.nSteps++ - // newStep is called by updateToStep in NewConsensusState before the eventBus is set! + // newStep is called by updateToState in NewConsensusState before the eventBus is set! if cs.eventBus != nil { cs.eventBus.PublishEventNewRoundStep(rs) cs.evsw.FireEvent(types.EventNewRoundStep, &cs.RoundState) diff --git a/mempool/mempool.go b/mempool/mempool.go index 5af16b3c..935dfaac 100644 --- a/mempool/mempool.go +++ b/mempool/mempool.go @@ -77,7 +77,7 @@ type Mempool struct { // Keep a cache of already-seen txs. // This reduces the pressure on the proxyApp. - cache *txCache + cache txCache // A log of mempool txs wal *auto.AutoFile @@ -97,7 +97,11 @@ func NewMempool(config *cfg.MempoolConfig, proxyAppConn proxy.AppConnMempool, he recheckCursor: nil, recheckEnd: nil, logger: log.NewNopLogger(), - cache: newTxCache(config.CacheSize), + } + if config.CacheSize > 0 { + mempool.cache = newMapTxCache(config.CacheSize) + } else { + mempool.cache = nopTxCache{} } proxyAppConn.SetResponseCallback(mempool.resCb) return mempool @@ -328,11 +332,11 @@ func (mem *Mempool) notifyTxsAvailable() { panic("notified txs available but mempool is empty!") } if mem.txsAvailable != nil && !mem.notifiedTxsAvailable { + // channel cap is 1, so this will send once select { case mem.txsAvailable <- mem.height + 1: default: } - mem.notifiedTxsAvailable = true } } @@ -448,33 +452,42 @@ func (memTx *mempoolTx) Height() int64 { //-------------------------------------------------------------------------------- -// txCache maintains a cache of transactions. -type txCache struct { +type txCache interface { + Reset() + Push(tx types.Tx) bool + Remove(tx types.Tx) +} + +// mapTxCache maintains a cache of transactions. +type mapTxCache struct { mtx sync.Mutex size int map_ map[string]struct{} list *list.List // to remove oldest tx when cache gets too big } -// newTxCache returns a new txCache. -func newTxCache(cacheSize int) *txCache { - return &txCache{ +var _ txCache = (*mapTxCache)(nil) + +// newMapTxCache returns a new mapTxCache. +func newMapTxCache(cacheSize int) *mapTxCache { + return &mapTxCache{ size: cacheSize, map_: make(map[string]struct{}, cacheSize), list: list.New(), } } -// Reset resets the txCache to empty. -func (cache *txCache) Reset() { +// Reset resets the cache to an empty state. +func (cache *mapTxCache) Reset() { cache.mtx.Lock() cache.map_ = make(map[string]struct{}, cache.size) cache.list.Init() cache.mtx.Unlock() } -// Push adds the given tx to the txCache. It returns false if tx is already in the cache. -func (cache *txCache) Push(tx types.Tx) bool { +// Push adds the given tx to the cache and returns true. It returns false if tx +// is already in the cache. +func (cache *mapTxCache) Push(tx types.Tx) bool { cache.mtx.Lock() defer cache.mtx.Unlock() @@ -496,8 +509,16 @@ func (cache *txCache) Push(tx types.Tx) bool { } // Remove removes the given tx from the cache. -func (cache *txCache) Remove(tx types.Tx) { +func (cache *mapTxCache) Remove(tx types.Tx) { cache.mtx.Lock() delete(cache.map_, string(tx)) cache.mtx.Unlock() } + +type nopTxCache struct{} + +var _ txCache = (*nopTxCache)(nil) + +func (nopTxCache) Reset() {} +func (nopTxCache) Push(types.Tx) bool { return true } +func (nopTxCache) Remove(types.Tx) {} diff --git a/mempool/reactor.go b/mempool/reactor.go index 54a3c32f..5d1f4e79 100644 --- a/mempool/reactor.go +++ b/mempool/reactor.go @@ -6,7 +6,7 @@ import ( "time" abci "github.com/tendermint/abci/types" - "github.com/tendermint/go-amino" + amino "github.com/tendermint/go-amino" "github.com/tendermint/tmlibs/clist" "github.com/tendermint/tmlibs/log" @@ -45,6 +45,14 @@ func (memR *MempoolReactor) SetLogger(l log.Logger) { memR.Mempool.SetLogger(l) } +// OnStart implements p2p.BaseReactor. +func (memR *MempoolReactor) OnStart() error { + if !memR.config.Broadcast { + memR.Logger.Info("Tx broadcasting is disabled") + } + return nil +} + // GetChannels implements Reactor. // It returns the list of channels for this reactor. func (memR *MempoolReactor) GetChannels() []*p2p.ChannelDescriptor { @@ -129,7 +137,8 @@ func (memR *MempoolReactor) broadcastTxRoutine(peer p2p.Peer) { height := memTx.Height() if peerState_i := peer.Get(types.PeerStateKey); peerState_i != nil { peerState := peerState_i.(PeerState) - if peerState.GetHeight() < height-1 { // Allow for a lag of 1 block + peerHeight := peerState.GetHeight() + if peerHeight < height-1 { // Allow for a lag of 1 block time.Sleep(peerCatchupSleepIntervalMS * time.Millisecond) continue } diff --git a/types/keys.go b/types/keys.go index 99255119..941e82b6 100644 --- a/types/keys.go +++ b/types/keys.go @@ -2,6 +2,5 @@ package types // UNSTABLE var ( - PeerStateKey = "ConsensusReactor.peerState" - PeerMempoolChKey = "MempoolReactor.peerMempoolCh" + PeerStateKey = "ConsensusReactor.peerState" ) diff --git a/version/version.go b/version/version.go index 791da51c..e6345606 100644 --- a/version/version.go +++ b/version/version.go @@ -3,14 +3,14 @@ package version // Version components const ( Maj = "0" - Min = "20" - Fix = "1" + Min = "21" + Fix = "0" ) var ( // Version is the current version of Tendermint // Must be a string because scripts like dist.sh read this file. - Version = "0.20.1-dev" + Version = "0.21.0-dev" // GitCommit is the current HEAD set using ldflags. GitCommit string