tendermint/lite/verifying/provider_test.go
2019-07-06 09:46:01 +02:00

281 lines
8.6 KiB
Go

package verifying
import (
"fmt"
"sync"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
dbm "github.com/tendermint/tendermint/libs/db"
log "github.com/tendermint/tendermint/libs/log"
"github.com/tendermint/tendermint/lite"
"github.com/tendermint/tendermint/types"
)
func TestProviderValidPath(t *testing.T) {
require := require.New(t)
trust := lite.NewDBProvider("trust", dbm.NewMemDB())
source := lite.NewDBProvider("source", dbm.NewMemDB())
// Set up the validators to generate test blocks.
var vote int64 = 10
keys := lite.GenPrivKeys(5)
nkeys := keys.Extend(1)
// Construct a bunch of commits, each with one more height than the last.
chainID := "inquiry-test"
consHash := []byte("params")
resHash := []byte("results")
count := 50
fcz := make([]lite.FullCommit, count)
for i := 0; i < count; i++ {
vals := keys.ToValidators(vote, 0)
nextVals := nkeys.ToValidators(vote, 0)
h := int64(1 + i)
appHash := []byte(fmt.Sprintf("h=%d", h))
fcz[i] = keys.GenFullCommit(
chainID, h, nil,
vals, nextVals,
appHash, consHash, resHash, 0, len(keys))
// Extend the keys by 1 each time.
keys = nkeys
nkeys = nkeys.Extend(1)
}
// Initialize a Verifier with the initial state.
err := trust.SaveFullCommit(fcz[0])
require.NoError(err)
vp, _ := NewProvider(chainID, trust, source)
vp.SetLogger(log.TestingLogger())
// The latest commit is the first one.
fc, err := vp.LatestFullCommit(chainID, 0, fcz[count-1].SignedHeader.Height)
require.NoError(err)
require.NoError(fc.ValidateFull(chainID))
require.Equal(fcz[0].SignedHeader, fc.SignedHeader)
// Adding a few commits in the middle should be insufficient.
// The latest commit is still the first one.
for i := 10; i < 13; i++ {
err := source.SaveFullCommit(fcz[i])
require.NoError(err)
}
fc, err = vp.LatestFullCommit(chainID, 0, fcz[count-1].SignedHeader.Height)
require.NoError(err)
require.NoError(fc.ValidateFull(chainID))
require.Equal(fcz[0].SignedHeader, fc.SignedHeader)
// With more info, we succeed.
for i := 0; i < count; i++ {
err := source.SaveFullCommit(fcz[i])
require.NoError(err)
}
fc, err = vp.LatestFullCommit(chainID, 0, fcz[count-1].SignedHeader.Height)
require.NoError(err)
require.NoError(fc.ValidateFull(chainID))
require.Equal(fcz[count-1].SignedHeader, fc.SignedHeader)
}
func TestProviderDynamicVerification(t *testing.T) {
trust := lite.NewDBProvider("trust", dbm.NewMemDB())
source := lite.NewDBProvider("source", dbm.NewMemDB())
// 10 commits with one valset, 1 to change,
// 10 commits with the next one
n1, n2 := 10, 10
nCommits := n1 + n2 + 1
maxHeight := int64(nCommits)
fcz := make([]lite.FullCommit, nCommits)
// gen the 2 val sets
chainID := "dynamic-verifier"
power := int64(10)
keys1 := lite.GenPrivKeys(5)
vals1 := keys1.ToValidators(power, 0)
keys2 := lite.GenPrivKeys(5)
vals2 := keys2.ToValidators(power, 0)
// make some commits with the first
for i := 0; i < n1; i++ {
fcz[i] = makeFullCommit(int64(i), keys1, vals1, vals1, chainID)
}
// update the val set
fcz[n1] = makeFullCommit(int64(n1), keys1, vals1, vals2, chainID)
// make some commits with the new one
for i := n1 + 1; i < nCommits; i++ {
fcz[i] = makeFullCommit(int64(i), keys2, vals2, vals2, chainID)
}
// Save everything in the source
for _, fc := range fcz {
source.SaveFullCommit(fc)
}
// Initialize a Verifier with the initial state.
err := trust.SaveFullCommit(fcz[0])
require.NoError(t, err)
vp, _ := NewProvider(chainID, trust, source)
vp.SetLogger(log.TestingLogger())
// fetch the latest from the source
latestFC, err := source.LatestFullCommit(chainID, 1, maxHeight)
require.NoError(t, err)
require.NoError(latestFC.ValidateFull(chainID))
require.Equal(fcz[nCommits-1].SignedHeader, latestFC.SignedHeader)
}
func makeFullCommit(height int64, keys lite.PrivKeys, vals, nextVals *types.ValidatorSet, chainID string) lite.FullCommit {
height += 1
consHash := []byte("special-params")
appHash := []byte(fmt.Sprintf("h=%d", height))
resHash := []byte(fmt.Sprintf("res=%d", height))
return keys.GenFullCommit(
chainID, height, nil,
vals, nextVals,
appHash, consHash, resHash, 0, len(keys))
}
func TestVerifingProviderHistorical(t *testing.T) {
assert, require := assert.New(t), require.New(t)
trust := lite.NewDBProvider("trust", dbm.NewMemDB())
source := lite.NewDBProvider("source", dbm.NewMemDB())
// Set up the validators to generate test blocks.
var vote int64 = 10
keys := lite.GenPrivKeys(5)
nkeys := keys.Extend(1)
// Construct a bunch of commits, each with one more height than the last.
chainID := "inquiry-test"
count := 10
consHash := []byte("special-params")
fcz := make([]lite.FullCommit, count)
for i := 0; i < count; i++ {
vals := keys.ToValidators(vote, 0)
nextVals := nkeys.ToValidators(vote, 0)
h := int64(1 + i)
appHash := []byte(fmt.Sprintf("h=%d", h))
resHash := []byte(fmt.Sprintf("res=%d", h))
fcz[i] = keys.GenFullCommit(
chainID, h, nil,
vals, nextVals,
appHash, consHash, resHash, 0, len(keys))
// Extend the keys by 1 each time.
keys = nkeys
nkeys = nkeys.Extend(1)
}
// Initialize a Verifier with the initial state.
err := trust.SaveFullCommit(fcz[0])
require.NoError(err)
vp, _ := NewProvider(chainID, trust, source)
vp.SetLogger(log.TestingLogger())
// Store a few full commits as trust.
for _, i := range []int{2, 5} {
trust.SaveFullCommit(fcz[i])
}
// See if we can jump forward using trusted full commits.
// Souce doesn't have fcz[9] so vp.LastTrustedHeight wont' change.
err = source.SaveFullCommit(fcz[7])
require.NoError(err, "%+v", err)
assert.Equal(fcz[7].Height(), vp.LastTrustedHeight())
fc_, err := trust.LatestFullCommit(chainID, fcz[8].Height(), fcz[8].Height())
require.Error(err, "%+v", err)
assert.Equal((lite.FullCommit{}), fc_)
// With fcz[9] Verify will update last trusted height.
err = source.SaveFullCommit(fcz[9])
require.NoError(err, "%+v", err)
assert.Equal(fcz[8].Height(), vp.LastTrustedHeight())
fc_, err = trust.LatestFullCommit(chainID, fcz[8].Height(), fcz[8].Height())
require.NoError(err, "%+v", err)
assert.Equal(fcz[8].Height(), fc_.Height())
// Add access to all full commits via untrusted source.
for i := 0; i < count; i++ {
err := source.SaveFullCommit(fcz[i])
require.NoError(err)
}
// Try to fetch an unknown commit from the past.
fc_, err = trust.LatestFullCommit(chainID, fcz[2].Height(), fcz[3].Height())
require.NoError(err, "%+v", err)
assert.Equal(fcz[2].Height(), fc_.Height())
assert.Equal(fcz[8].Height(), vp.LastTrustedHeight())
// TODO This should work for as long as the trust period hasn't passed for
// fcz[2]. Write a test that tries to retroactively fetchees fcz[3] from
// source. Initially it should fail since source doesn't have it, but it
// should succeed once source is provided it.
// Try to fetch the latest known commit.
fc_, err = trust.LatestFullCommit(chainID, 0, fcz[9].Height())
require.NoError(err, "%+v", err)
assert.Equal(fcz[9].Height(), fc_.Height())
assert.Equal(fcz[9].Height(), vp.LastTrustedHeight())
}
func TestConcurrentProvider(t *testing.T) {
_, require := assert.New(t), require.New(t)
trust := lite.NewDBProvider("trust", dbm.NewMemDB()).SetLimit(10)
source := lite.NewDBProvider("source", dbm.NewMemDB())
// Set up the validators to generate test blocks.
var vote int64 = 10
keys := lite.GenPrivKeys(5)
nkeys := keys.Extend(1)
// Construct a bunch of commits, each with one more height than the last.
chainID := "inquiry-test"
count := 10
consHash := []byte("special-params")
fcz := make([]lite.FullCommit, count)
for i := 0; i < count; i++ {
vals := keys.ToValidators(vote, 0)
nextVals := nkeys.ToValidators(vote, 0)
h := int64(1 + i)
appHash := []byte(fmt.Sprintf("h=%d", h))
resHash := []byte(fmt.Sprintf("res=%d", h))
fcz[i] = keys.GenFullCommit(
chainID, h, nil,
vals, nextVals,
appHash, consHash, resHash, 0, len(keys))
// Extend the keys by 1 each time.
keys = nkeys
nkeys = nkeys.Extend(1)
}
// Initialize a Verifier with the initial state.
err := trust.SaveFullCommit(fcz[0])
require.NoError(err)
vp, _ := NewProvider(chainID, trust, source)
vp.SetLogger(log.TestingLogger())
cp := lite.NewConcurrentUpdatingProvider(vp)
err = source.SaveFullCommit(fcz[7])
require.Nil(err, "%+v", err)
err = source.SaveFullCommit(fcz[8])
require.NoError(err, "%+v", err)
// sh := fcz[8].SignedHeader unused
var wg sync.WaitGroup
count = 100
errList := make([]error, count)
for i := 0; i < count; i++ {
wg.Add(1)
go func(index int) {
errList[index] = cp.UpdateToHeight(chainID, fcz[8].SignedHeader.Height)
defer wg.Done()
}(i)
}
wg.Wait()
for _, err := range errList {
require.NoError(err)
}
}