package lite import ( "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" dbm "github.com/tendermint/tm-db" log "github.com/tendermint/tendermint/libs/log" lerr "github.com/tendermint/tendermint/lite/errors" "github.com/tendermint/tendermint/types" ) // 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() PersistentProvider { return missingProvider{} } func (missingProvider) SaveFullCommit(FullCommit) error { return nil } func (missingProvider) LatestFullCommit(chainID string, minHeight, maxHeight int64) (FullCommit, error) { return FullCommit{}, lerr.ErrCommitNotFound() } func (missingProvider) ValidatorSet(chainID string, height int64) (*types.ValidatorSet, error) { return nil, errors.New("missing validator set") } func (missingProvider) SetLogger(_ log.Logger) {} func TestMemProvider(t *testing.T) { p := NewDBProvider("mem", dbm.NewMemDB()) checkProvider(t, p, "test-mem", "empty") } func TestMultiProvider(t *testing.T) { p := NewMultiProvider( NewMissingProvider(), NewDBProvider("mem", dbm.NewMemDB()), NewMissingProvider(), ) checkProvider(t, p, "test-cache", "kjfhekfhkewhgit") } func checkProvider(t *testing.T, p PersistentProvider, chainID, app string) { assert, require := assert.New(t), require.New(t) appHash := []byte(app) keys := genPrivKeys(5) count := 10 // Make a bunch of full commits. fcz := make([]FullCommit, count) for i := 0; i < count; i++ { vals := keys.ToValidators(10, int64(count/2)) h := int64(20 + 10*i) fcz[i] = keys.GenFullCommit(chainID, h, nil, vals, vals, appHash, []byte("params"), []byte("results"), 0, 5) } // Check that provider is initially empty. fc, err := p.LatestFullCommit(chainID, 1, 1<<63-1) require.NotNil(err) assert.True(lerr.IsErrCommitNotFound(err)) // Save all full commits to the provider. for _, fc := range fcz { err = p.SaveFullCommit(fc) require.Nil(err) // Make sure we can get it back. fc2, err := p.LatestFullCommit(chainID, fc.Height(), fc.Height()) assert.Nil(err) 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.LatestFullCommit(chainID, 1, 5000) if assert.Nil(err) { assert.Equal(fcz[count-1].Height(), fc.Height()) assert.Equal(fcz[count-1], fc) } // ... 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()) } } // 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.SaveFullCommit(fc) require.Nil(t, err) } } 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 := NewDBProvider("mem1", dbm.NewMemDB()) p2 := NewDBProvider("mem2", dbm.NewMemDB()) cp := NewMultiProvider(p, p2) chainID := "cache-best-height" appHash := []byte("01234567") keys := genPrivKeys(5) count := 10 // 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, vals, appHash, []byte("params"), []byte("results"), 0, 5) err := p2.SaveFullCommit(fc) require.NoError(err) } // 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) 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 checkLatestFullCommit(t, p2, chainID, 99, 90) checkLatestFullCommit(t, cp, chainID, 99, 90) }