Skip to content

Commit

Permalink
blockstore: fix problem with seen commit (tendermint#6782)
Browse files Browse the repository at this point in the history
  • Loading branch information
cmwaters authored Jul 30, 2021
1 parent 3aec71c commit 02f8e4c
Show file tree
Hide file tree
Showing 26 changed files with 258 additions and 73 deletions.
2 changes: 1 addition & 1 deletion abci/client/mocks/client.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion internal/consensus/mocks/cons_sync_reactor.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions internal/consensus/replay_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1203,8 +1203,8 @@ func (bs *mockBlockStore) SaveBlock(block *types.Block, blockParts *types.PartSe
func (bs *mockBlockStore) LoadBlockCommit(height int64) *types.Commit {
return bs.commits[height-1]
}
func (bs *mockBlockStore) LoadSeenCommit(height int64) *types.Commit {
return bs.commits[height-1]
func (bs *mockBlockStore) LoadSeenCommit() *types.Commit {
return bs.commits[len(bs.commits)-1]
}

func (bs *mockBlockStore) PruneBlocks(height int64) (uint64, error) {
Expand Down
23 changes: 17 additions & 6 deletions internal/consensus/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,14 @@ func (cs *State) LoadCommit(height int64) *types.Commit {
defer cs.mtx.RUnlock()

if height == cs.blockStore.Height() {
return cs.blockStore.LoadSeenCommit(height)
commit := cs.blockStore.LoadSeenCommit()
// NOTE: Retrieving the height of the most recent block and retrieving
// the most recent commit does not currently occur as an atomic
// operation. We check the height and commit here in case a more recent
// commit has arrived since retrieving the latest height.
if commit != nil && commit.Height == height {
return commit
}
}

return cs.blockStore.LoadBlockCommit(height)
Expand Down Expand Up @@ -594,15 +601,19 @@ func (cs *State) sendInternalMessage(mi msgInfo) {
// Reconstruct LastCommit from SeenCommit, which we saved along with the block,
// (which happens even before saving the state)
func (cs *State) reconstructLastCommit(state sm.State) {
seenCommit := cs.blockStore.LoadSeenCommit(state.LastBlockHeight)
if seenCommit == nil {
commit := cs.blockStore.LoadSeenCommit()
if commit == nil || commit.Height != state.LastBlockHeight {
commit = cs.blockStore.LoadBlockCommit(state.LastBlockHeight)
}

if commit == nil {
panic(fmt.Sprintf(
"failed to reconstruct last commit; seen commit for height %v not found",
"failed to reconstruct last commit; commit for height %v not found",
state.LastBlockHeight,
))
}

lastPrecommits := types.CommitToVoteSet(state.ChainID, seenCommit, state.LastValidators)
lastPrecommits := types.CommitToVoteSet(state.ChainID, commit, state.LastValidators)
if !lastPrecommits.HasTwoThirdsMajority() {
panic("failed to reconstruct last commit; does not have +2/3 maj")
}
Expand Down Expand Up @@ -2318,7 +2329,7 @@ func (cs *State) checkDoubleSigningRisk(height int64) error {
}

for i := int64(1); i < doubleSignCheckHeight; i++ {
lastCommit := cs.blockStore.LoadSeenCommit(height - i)
lastCommit := cs.LoadCommit(height - i)
if lastCommit != nil {
for sigIdx, s := range lastCommit.Signatures {
if s.BlockIDFlag == types.BlockIDFlagCommit && bytes.Equal(s.ValidatorAddress, valAddr) {
Expand Down
2 changes: 1 addition & 1 deletion internal/evidence/mocks/block_store.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion internal/p2p/mocks/connection.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion internal/p2p/mocks/peer.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion internal/p2p/mocks/transport.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion internal/statesync/mocks/state_provider.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion light/provider/mocks/provider.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion light/rpc/mocks/light_client.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion proxy/mocks/app_conn_consensus.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion proxy/mocks/app_conn_mempool.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion proxy/mocks/app_conn_query.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion proxy/mocks/app_conn_snapshot.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 21 additions & 6 deletions rpc/client/evidence_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,6 @@ func TestBroadcastEvidence_DuplicateVoteEvidence(t *testing.T) {
defer cancel()

n, config := NodeSuite(t)

// previous versions of this test used a shared fixture with
// other tests, and in this version we give it a little time
// for the node to make progress before running the test
time.Sleep(100 * time.Millisecond)

chainID := config.ChainID()

pv, err := privval.LoadOrGenFilePV(config.PrivValidator.KeyFile(), config.PrivValidator.StateFile())
Expand All @@ -131,6 +125,9 @@ func TestBroadcastEvidence_DuplicateVoteEvidence(t *testing.T) {
correct, fakes := makeEvidences(t, pv, chainID)
t.Logf("client %d", i)

// make sure that the node has produced enough blocks
waitForBlock(ctx, t, c, 2)

result, err := c.BroadcastEvidence(ctx, correct)
require.NoError(t, err, "BroadcastEvidence(%s) failed", correct)
assert.Equal(t, correct.Hash(), result.Hash, "expected result hash to match evidence hash")
Expand Down Expand Up @@ -171,3 +168,21 @@ func TestBroadcastEmptyEvidence(t *testing.T) {
assert.Error(t, err)
}
}

func waitForBlock(ctx context.Context, t *testing.T, c client.Client, height int64) {
timer := time.NewTimer(0 * time.Millisecond)
defer timer.Stop()
for {
select {
case <-ctx.Done():
return
case <-timer.C:
status, err := c.Status(ctx)
require.NoError(t, err)
if status.SyncInfo.LatestBlockHeight >= height {
return
}
timer.Reset(200 * time.Millisecond)
}
}
}
2 changes: 1 addition & 1 deletion rpc/client/mocks/client.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 9 additions & 2 deletions rpc/core/blocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,12 +135,19 @@ func (env *Environment) Commit(ctx *rpctypes.Context, heightPtr *int64) (*ctypes
// If the next block has not been committed yet,
// use a non-canonical commit
if height == env.BlockStore.Height() {
commit := env.BlockStore.LoadSeenCommit(height)
return ctypes.NewResultCommit(&header, commit, false), nil
commit := env.BlockStore.LoadSeenCommit()
// NOTE: we can't yet ensure atomicity of operations in asserting
// whether this is the latest height and retrieving the seen commit
if commit != nil && commit.Height == height {
return ctypes.NewResultCommit(&header, commit, false), nil
}
}

// Return the canonical commit (comes from the block at height+1)
commit := env.BlockStore.LoadBlockCommit(height)
if commit == nil {
return nil, nil
}
return ctypes.NewResultCommit(&header, commit, true), nil
}

Expand Down
2 changes: 1 addition & 1 deletion rpc/core/blocks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ func (mockBlockStore) LoadBlock(height int64) *types.Block { retur
func (mockBlockStore) LoadBlockByHash(hash []byte) *types.Block { return nil }
func (mockBlockStore) LoadBlockPart(height int64, index int) *types.Part { return nil }
func (mockBlockStore) LoadBlockCommit(height int64) *types.Commit { return nil }
func (mockBlockStore) LoadSeenCommit(height int64) *types.Commit { return nil }
func (mockBlockStore) LoadSeenCommit() *types.Commit { return nil }
func (mockBlockStore) PruneBlocks(height int64) (uint64, error) { return 0, nil }
func (mockBlockStore) SaveBlock(block *types.Block, blockParts *types.PartSet, seenCommit *types.Commit) {
}
167 changes: 167 additions & 0 deletions state/indexer/mocks/event_sink.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 02f8e4c

Please sign in to comment.