Refactor "lite" to handle delayed validator set changes.

Also, fix consensus liveness issue.
This commit is contained in:
Jae Kwon
2018-06-09 04:25:48 -07:00
parent a5b7ea93c4
commit bf0ff212b9
55 changed files with 1542 additions and 2449 deletions

View File

@ -1,98 +1,88 @@
// nolint: vetshadow
package lite_test
package lite
import (
"errors"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/lite"
liteErr "github.com/tendermint/tendermint/lite/errors"
lerr "github.com/tendermint/tendermint/lite/errors"
"github.com/tendermint/tendermint/types"
dbm "github.com/tendermint/tmlibs/db"
)
// missingProvider doesn't store anything, always a miss
// Designed as a mock for testing
// missingProvider doesn't store anything, always a miss.
// Designed as a mock for testing.
type missingProvider struct{}
// NewMissingProvider returns a provider which does not store anything and always misses.
func NewMissingProvider() lite.Provider {
func NewMissingProvider() PersistentProvider {
return missingProvider{}
}
func (missingProvider) StoreCommit(lite.FullCommit) error { return nil }
func (missingProvider) GetByHeight(int64) (lite.FullCommit, error) {
return lite.FullCommit{}, liteErr.ErrCommitNotFound()
func (missingProvider) SaveFullCommit(FullCommit) error { return nil }
func (missingProvider) LatestFullCommit(chainID string, minHeight, maxHeight int64) (FullCommit, error) {
return FullCommit{}, lerr.ErrCommitNotFound()
}
func (missingProvider) GetByHash([]byte) (lite.FullCommit, error) {
return lite.FullCommit{}, liteErr.ErrCommitNotFound()
}
func (missingProvider) LatestCommit() (lite.FullCommit, error) {
return lite.FullCommit{}, liteErr.ErrCommitNotFound()
func (missingProvider) ValidatorSet(chainID string, height int64) (*types.ValidatorSet, error) {
return nil, errors.New("missing validator set")
}
func TestMemProvider(t *testing.T) {
p := lite.NewMemStoreProvider()
p := NewDBProvider(dbm.NewMemDB())
checkProvider(t, p, "test-mem", "empty")
}
func TestCacheProvider(t *testing.T) {
p := lite.NewCacheProvider(
func TestMultiProvider(t *testing.T) {
p := NewMultiProvider(
NewMissingProvider(),
lite.NewMemStoreProvider(),
NewDBProvider(dbm.NewMemDB()),
NewMissingProvider(),
)
checkProvider(t, p, "test-cache", "kjfhekfhkewhgit")
}
func checkProvider(t *testing.T, p lite.Provider, chainID, app string) {
func checkProvider(t *testing.T, p PersistentProvider, chainID, app string) {
assert, require := assert.New(t), require.New(t)
appHash := []byte(app)
keys := lite.GenValKeys(5)
keys := genPrivKeys(5)
count := 10
// make a bunch of commits...
commits := make([]lite.FullCommit, count)
// Make a bunch of full commits.
fcz := make([]FullCommit, count)
for i := 0; i < count; i++ {
// two commits for each validator, to check how we handle dups
// (10, 0), (10, 1), (10, 1), (10, 2), (10, 2), ...
vals := keys.ToValidators(10, int64(count/2))
h := int64(20 + 10*i)
commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, []byte("params"), []byte("results"), 0, 5)
fcz[i] = keys.GenFullCommit(chainID, h, nil, vals, vals, appHash, []byte("params"), []byte("results"), 0, 5)
}
// check provider is empty
fc, err := p.GetByHeight(20)
// Check that provider is initially empty.
fc, err := p.LatestFullCommit(chainID, 1, 1<<63-1)
require.NotNil(err)
assert.True(liteErr.IsCommitNotFoundErr(err))
assert.True(lerr.IsErrCommitNotFound(err))
fc, err = p.GetByHash(commits[3].ValidatorsHash())
require.NotNil(err)
assert.True(liteErr.IsCommitNotFoundErr(err))
// now add them all to the provider
for _, s := range commits {
err = p.StoreCommit(s)
// Save all full commits to the provider.
for _, fc := range fcz {
err = p.SaveFullCommit(fc)
require.Nil(err)
// and make sure we can get it back
s2, err := p.GetByHash(s.ValidatorsHash())
// Make sure we can get it back.
fc2, err := p.LatestFullCommit(chainID, fc.Height(), fc.Height())
assert.Nil(err)
assert.Equal(s, s2)
// by height as well
s2, err = p.GetByHeight(s.Height())
assert.Nil(err)
assert.Equal(s, s2)
assert.Equal(fc.SignedHeader, fc2.SignedHeader)
assert.Equal(fc.Validators, fc2.Validators)
assert.Equal(fc.NextValidators, fc2.NextValidators)
}
// make sure we get the last hash if we overstep
fc, err = p.GetByHeight(5000)
// Make sure we get the last hash if we overstep.
fc, err = p.LatestFullCommit(chainID, 1, 5000)
if assert.Nil(err) {
assert.Equal(commits[count-1].Height(), fc.Height())
assert.Equal(commits[count-1], fc)
assert.Equal(fcz[count-1].Height(), fc.Height())
assert.Equal(fcz[count-1], fc)
}
// and middle ones as well
fc, err = p.GetByHeight(47)
// ... and middle ones as well.
fc, err = p.LatestFullCommit(chainID, 1, 47)
if assert.Nil(err) {
// we only step by 10, so 40 must be the one below this
assert.EqualValues(40, fc.Height())
@ -100,50 +90,49 @@ func checkProvider(t *testing.T, p lite.Provider, chainID, app string) {
}
// this will make a get height, and if it is good, set the data as well
func checkGetHeight(t *testing.T, p lite.Provider, ask, expect int64) {
fc, err := p.GetByHeight(ask)
require.Nil(t, err, "GetByHeight")
// This will make a get height, and if it is good, set the data as well.
func checkLatestFullCommit(t *testing.T, p PersistentProvider, chainID string, ask, expect int64) {
fc, err := p.LatestFullCommit(chainID, 1, ask)
require.Nil(t, err)
if assert.Equal(t, expect, fc.Height()) {
err = p.StoreCommit(fc)
require.Nil(t, err, "StoreCommit")
err = p.SaveFullCommit(fc)
require.Nil(t, err)
}
}
func TestCacheGetsBestHeight(t *testing.T) {
// assert, require := assert.New(t), require.New(t)
func TestMultiLatestFullCommit(t *testing.T) {
require := require.New(t)
// we will write data to the second level of the cache (p2),
// and see what gets cached, stored in
p := lite.NewMemStoreProvider()
p2 := lite.NewMemStoreProvider()
cp := lite.NewCacheProvider(p, p2)
// We will write data to the second level of the cache (p2), and see what
// gets cached/stored in.
p := NewDBProvider(dbm.NewMemDB())
p2 := NewDBProvider(dbm.NewMemDB())
cp := NewMultiProvider(p, p2)
chainID := "cache-best-height"
appHash := []byte("01234567")
keys := lite.GenValKeys(5)
keys := genPrivKeys(5)
count := 10
// set a bunch of commits
// Set a bunch of full commits.
for i := 0; i < count; i++ {
vals := keys.ToValidators(10, int64(count/2))
h := int64(10 * (i + 1))
fc := keys.GenFullCommit(chainID, h, nil, vals, appHash, []byte("params"), []byte("results"), 0, 5)
err := p2.StoreCommit(fc)
fc := keys.GenFullCommit(chainID, h, nil, vals, vals, appHash, []byte("params"), []byte("results"), 0, 5)
err := p2.SaveFullCommit(fc)
require.NoError(err)
}
// let's get a few heights from the cache and set them proper
checkGetHeight(t, cp, 57, 50)
checkGetHeight(t, cp, 33, 30)
// Get a few heights from the cache and set them proper.
checkLatestFullCommit(t, cp, chainID, 57, 50)
checkLatestFullCommit(t, cp, chainID, 33, 30)
// make sure they are set in p as well (but nothing else)
checkGetHeight(t, p, 44, 30)
checkGetHeight(t, p, 50, 50)
checkGetHeight(t, p, 99, 50)
checkLatestFullCommit(t, p, chainID, 44, 30)
checkLatestFullCommit(t, p, chainID, 50, 50)
checkLatestFullCommit(t, p, chainID, 99, 50)
// now, query the cache for a higher value
checkGetHeight(t, p2, 99, 90)
checkGetHeight(t, cp, 99, 90)
checkLatestFullCommit(t, p2, chainID, 99, 90)
checkLatestFullCommit(t, cp, chainID, 99, 90)
}