diff --git a/consensus/mempool_test.go b/consensus/mempool_test.go index 9f332e15c..18daf67a6 100644 --- a/consensus/mempool_test.go +++ b/consensus/mempool_test.go @@ -15,7 +15,7 @@ func init() { config = ResetConfig("consensus_mempool_test") } -func TestTxsAvailable(t *testing.T) { +func TestNoProgressUntilTxsAvailable(t *testing.T) { config := ResetConfig("consensus_mempool_txs_available_test") config.Consensus.NoEmptyBlocks = true state, privVals := randGenesisState(1, false, 10) @@ -25,10 +25,12 @@ func TestTxsAvailable(t *testing.T) { newBlockCh := subscribeToEvent(cs.evsw, "tester", types.EventStringNewBlock(), 1) startTestRound(cs, height, round) - // we shouldnt make progress until theres a tx + ensureNewStep(newBlockCh) // first block gets committed + ensureNoNewStep(newBlockCh) + deliverTxsRange(cs, 0, 2) + ensureNewStep(newBlockCh) // commit txs + ensureNewStep(newBlockCh) // commit updated app hash ensureNoNewStep(newBlockCh) - deliverTxsRange(cs, 0, 100) - ensureNewStep(newBlockCh) } func deliverTxsRange(cs *ConsensusState, start, end int) { diff --git a/consensus/state.go b/consensus/state.go index 878b235a3..b18b40db3 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -779,14 +779,29 @@ func (cs *ConsensusState) enterNewRound(height int, round int) { types.FireEventNewRound(cs.evsw, cs.RoundStateEvent()) // Wait for txs to be available in the mempool - // before we enterPropose - if cs.config.NoEmptyBlocks { + // before we enterPropose. If the last block changed the app hash, + // we may need an empty "proof" block, and enterPropose immediately. + if cs.config.NoEmptyBlocks && !cs.needProofBlock(height) { go cs.waitForTxs(height, round) } else { cs.enterPropose(height, round) } } +// needProofBlock returns true on the first height (so the genesis app hash is signed right away) +// and where the last block (height-1) caused the app hash to change +func (cs *ConsensusState) needProofBlock(height int) bool { + if height == 1 { + return true + } + + lastBlockMeta := cs.blockStore.LoadBlockMeta(height - 1) + if !bytes.Equal(cs.state.AppHash, lastBlockMeta.Header.AppHash) { + return true + } + return false +} + func (cs *ConsensusState) waitForTxs(height, round int) { // if we're the proposer, start a heartbeat routine // to tell other peers we're just waiting for txs (for debugging)