package lite
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
log "github.com/tendermint/tendermint/libs/log"
|
|
"github.com/tendermint/tendermint/types"
|
|
dbm "github.com/tendermint/tm-db"
|
|
)
|
|
|
|
const testChainID = "inquiry-test"
|
|
|
|
func TestInquirerValidPath(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
trust := NewDBProvider("trust", dbm.NewMemDB())
|
|
source := NewDBProvider("source", dbm.NewMemDB())
|
|
|
|
// Set up the validators to generate test blocks.
|
|
var vote int64 = 10
|
|
keys := genPrivKeys(5)
|
|
nkeys := keys.Extend(1)
|
|
|
|
// Construct a bunch of commits, each with one more height than the last.
|
|
chainID := testChainID
|
|
consHash := []byte("params")
|
|
resHash := []byte("results")
|
|
count := 50
|
|
fcz := make([]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.Nil(err)
|
|
cert := NewDynamicVerifier(chainID, trust, source)
|
|
cert.SetLogger(log.TestingLogger())
|
|
|
|
// This should fail validation:
|
|
sh := fcz[count-1].SignedHeader
|
|
err = cert.Verify(sh)
|
|
require.NotNil(err)
|
|
|
|
// Adding a few commits in the middle should be insufficient.
|
|
for i := 10; i < 13; i++ {
|
|
err := source.SaveFullCommit(fcz[i])
|
|
require.Nil(err)
|
|
}
|
|
err = cert.Verify(sh)
|
|
assert.NotNil(err)
|
|
|
|
// With more info, we succeed.
|
|
for i := 0; i < count; i++ {
|
|
err := source.SaveFullCommit(fcz[i])
|
|
require.Nil(err)
|
|
}
|
|
err = cert.Verify(sh)
|
|
assert.Nil(err, "%+v", err)
|
|
}
|
|
|
|
func TestDynamicVerify(t *testing.T) {
|
|
trust := NewDBProvider("trust", dbm.NewMemDB())
|
|
source := 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([]FullCommit, nCommits)
|
|
|
|
// gen the 2 val sets
|
|
chainID := "dynamic-verifier"
|
|
power := int64(10)
|
|
keys1 := genPrivKeys(5)
|
|
vals1 := keys1.ToValidators(power, 0)
|
|
keys2 := 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.Nil(t, err)
|
|
ver := NewDynamicVerifier(chainID, trust, source)
|
|
ver.SetLogger(log.TestingLogger())
|
|
|
|
// fetch the latest from the source
|
|
latestFC, err := source.LatestFullCommit(chainID, 1, maxHeight)
|
|
require.NoError(t, err)
|
|
|
|
// try to update to the latest
|
|
err = ver.Verify(latestFC.SignedHeader)
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
func makeFullCommit(height int64, keys privKeys, vals, nextVals *types.ValidatorSet, chainID string) FullCommit {
|
|
height++
|
|
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 TestInquirerVerifyHistorical(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
trust := NewDBProvider("trust", dbm.NewMemDB())
|
|
source := NewDBProvider("source", dbm.NewMemDB())
|
|
|
|
// Set up the validators to generate test blocks.
|
|
var vote int64 = 10
|
|
keys := genPrivKeys(5)
|
|
nkeys := keys.Extend(1)
|
|
|
|
// Construct a bunch of commits, each with one more height than the last.
|
|
chainID := testChainID
|
|
count := 10
|
|
consHash := []byte("special-params")
|
|
fcz := make([]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.Nil(err)
|
|
cert := NewDynamicVerifier(chainID, trust, source)
|
|
cert.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 cert.LastTrustedHeight wont' change.
|
|
err = source.SaveFullCommit(fcz[7])
|
|
require.Nil(err, "%+v", err)
|
|
sh := fcz[8].SignedHeader
|
|
err = cert.Verify(sh)
|
|
require.Nil(err, "%+v", err)
|
|
assert.Equal(fcz[7].Height(), cert.LastTrustedHeight())
|
|
commit, err := trust.LatestFullCommit(chainID, fcz[8].Height(), fcz[8].Height())
|
|
require.NotNil(err, "%+v", err)
|
|
assert.Equal(commit, (FullCommit{}))
|
|
|
|
// With fcz[9] Verify will update last trusted height.
|
|
err = source.SaveFullCommit(fcz[9])
|
|
require.Nil(err, "%+v", err)
|
|
sh = fcz[8].SignedHeader
|
|
err = cert.Verify(sh)
|
|
require.Nil(err, "%+v", err)
|
|
assert.Equal(fcz[8].Height(), cert.LastTrustedHeight())
|
|
commit, err = trust.LatestFullCommit(chainID, fcz[8].Height(), fcz[8].Height())
|
|
require.Nil(err, "%+v", err)
|
|
assert.Equal(commit.Height(), fcz[8].Height())
|
|
|
|
// Add access to all full commits via untrusted source.
|
|
for i := 0; i < count; i++ {
|
|
err := source.SaveFullCommit(fcz[i])
|
|
require.Nil(err)
|
|
}
|
|
|
|
// Try to check an unknown seed in the past.
|
|
sh = fcz[3].SignedHeader
|
|
err = cert.Verify(sh)
|
|
require.Nil(err, "%+v", err)
|
|
assert.Equal(fcz[8].Height(), cert.LastTrustedHeight())
|
|
|
|
// Jump all the way forward again.
|
|
sh = fcz[count-1].SignedHeader
|
|
err = cert.Verify(sh)
|
|
require.Nil(err, "%+v", err)
|
|
assert.Equal(fcz[9].Height(), cert.LastTrustedHeight())
|
|
}
|
|
|
|
func TestConcurrencyInquirerVerify(t *testing.T) {
|
|
_, require := assert.New(t), require.New(t)
|
|
trust := NewDBProvider("trust", dbm.NewMemDB()).SetLimit(10)
|
|
source := NewDBProvider("source", dbm.NewMemDB())
|
|
|
|
// Set up the validators to generate test blocks.
|
|
var vote int64 = 10
|
|
keys := genPrivKeys(5)
|
|
nkeys := keys.Extend(1)
|
|
|
|
// Construct a bunch of commits, each with one more height than the last.
|
|
chainID := testChainID
|
|
count := 10
|
|
consHash := []byte("special-params")
|
|
fcz := make([]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.Nil(err)
|
|
cert := NewDynamicVerifier(chainID, trust, source)
|
|
cert.SetLogger(log.TestingLogger())
|
|
|
|
err = source.SaveFullCommit(fcz[7])
|
|
require.Nil(err, "%+v", err)
|
|
err = source.SaveFullCommit(fcz[8])
|
|
require.Nil(err, "%+v", err)
|
|
sh := fcz[8].SignedHeader
|
|
|
|
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] = cert.Verify(sh)
|
|
defer wg.Done()
|
|
}(i)
|
|
}
|
|
wg.Wait()
|
|
for _, err := range errList {
|
|
require.Nil(err)
|
|
}
|
|
}
|