- package lite
-
- import (
- "sync"
- "testing"
- "time"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-
- dbm "github.com/tendermint/tm-db"
-
- "github.com/tendermint/tendermint/libs/log"
- "github.com/tendermint/tendermint/lite2/provider"
- mockp "github.com/tendermint/tendermint/lite2/provider/mock"
- dbs "github.com/tendermint/tendermint/lite2/store/db"
- "github.com/tendermint/tendermint/types"
- )
-
- func TestClient_SequentialVerification(t *testing.T) {
- const (
- chainID = "sequential-verification"
- )
-
- var (
- keys = genPrivKeys(4)
- // 20, 30, 40, 50 - the first 3 don't have 2/3, the last 3 do!
- vals = keys.ToValidators(20, 10)
- bTime, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
- header = keys.GenSignedHeader(chainID, 1, bTime, nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
- )
-
- testCases := []struct {
- otherHeaders map[int64]*types.SignedHeader // all except ^
- vals map[int64]*types.ValidatorSet
- initErr bool
- verifyErr bool
- }{
- // good
- {
- map[int64]*types.SignedHeader{
- // trusted header
- 1: header,
- // interim header (3/3 signed)
- 2: keys.GenSignedHeader(chainID, 2, bTime.Add(1*time.Hour), nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
- // last header (3/3 signed)
- 3: keys.GenSignedHeader(chainID, 3, bTime.Add(2*time.Hour), nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
- },
- map[int64]*types.ValidatorSet{
- 1: vals,
- 2: vals,
- 3: vals,
- 4: vals,
- },
- false,
- false,
- },
- // bad: different first header
- {
- map[int64]*types.SignedHeader{
- // different header
- 1: keys.GenSignedHeader(chainID, 1, bTime.Add(1*time.Hour), nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
- },
- map[int64]*types.ValidatorSet{
- 1: vals,
- },
- true,
- false,
- },
- // bad: 1/3 signed interim header
- {
- map[int64]*types.SignedHeader{
- // trusted header
- 1: header,
- // interim header (1/3 signed)
- 2: keys.GenSignedHeader(chainID, 2, bTime.Add(1*time.Hour), nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), len(keys)-1, len(keys)),
- // last header (3/3 signed)
- 3: keys.GenSignedHeader(chainID, 3, bTime.Add(2*time.Hour), nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
- },
- map[int64]*types.ValidatorSet{
- 1: vals,
- 2: vals,
- 3: vals,
- 4: vals,
- },
- false,
- true,
- },
- // bad: 1/3 signed last header
- {
- map[int64]*types.SignedHeader{
- // trusted header
- 1: header,
- // interim header (3/3 signed)
- 2: keys.GenSignedHeader(chainID, 2, bTime.Add(1*time.Hour), nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
- // last header (1/3 signed)
- 3: keys.GenSignedHeader(chainID, 3, bTime.Add(2*time.Hour), nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), len(keys)-1, len(keys)),
- },
- map[int64]*types.ValidatorSet{
- 1: vals,
- 2: vals,
- 3: vals,
- 4: vals,
- },
- false,
- true,
- },
- }
-
- for _, tc := range testCases {
- c, err := NewClient(
- chainID,
- TrustOptions{
- Period: 4 * time.Hour,
- Height: 1,
- Hash: header.Hash(),
- },
- mockp.New(
- chainID,
- tc.otherHeaders,
- tc.vals,
- ),
- []provider.Provider{mockp.New(
- chainID,
- tc.otherHeaders,
- tc.vals,
- )},
- dbs.New(dbm.NewMemDB(), chainID),
- SequentialVerification(),
- )
-
- if tc.initErr {
- require.Error(t, err)
- continue
- } else {
- require.NoError(t, err)
- }
- err = c.Start()
- require.NoError(t, err)
- defer c.Stop()
-
- _, err = c.VerifyHeaderAtHeight(3, bTime.Add(3*time.Hour))
- if tc.verifyErr {
- assert.Error(t, err)
- } else {
- assert.NoError(t, err)
- }
- }
- }
-
- func TestClient_SkippingVerification(t *testing.T) {
- const (
- chainID = "skipping-verification"
- )
-
- var (
- keys = genPrivKeys(4)
- // 20, 30, 40, 50 - the first 3 don't have 2/3, the last 3 do!
- vals = keys.ToValidators(20, 10)
- bTime, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
- header = keys.GenSignedHeader(chainID, 1, bTime, nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
- )
-
- // required for 2nd test case
- newKeys := genPrivKeys(4)
- newVals := newKeys.ToValidators(10, 1)
-
- testCases := []struct {
- otherHeaders map[int64]*types.SignedHeader // all except ^
- vals map[int64]*types.ValidatorSet
- initErr bool
- verifyErr bool
- }{
- // good
- {
- map[int64]*types.SignedHeader{
- // trusted header
- 1: header,
- // last header (3/3 signed)
- 3: keys.GenSignedHeader(chainID, 3, bTime.Add(2*time.Hour), nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
- },
- map[int64]*types.ValidatorSet{
- 1: vals,
- 2: vals,
- 3: vals,
- 4: vals,
- },
- false,
- false,
- },
- // good, val set changes 100% at height 2
- {
- map[int64]*types.SignedHeader{
- // trusted header
- 1: header,
- // interim header (3/3 signed)
- 2: keys.GenSignedHeader(chainID, 2, bTime.Add(1*time.Hour), nil, vals, newVals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
- // last header (0/4 of the original val set signed)
- 3: newKeys.GenSignedHeader(chainID, 3, bTime.Add(2*time.Hour), nil, newVals, newVals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(newKeys)),
- },
- map[int64]*types.ValidatorSet{
- 1: vals,
- 2: vals,
- 3: newVals,
- 4: newVals,
- },
- false,
- false,
- },
- }
-
- for _, tc := range testCases {
- c, err := NewClient(
- chainID,
- TrustOptions{
- Period: 4 * time.Hour,
- Height: 1,
- Hash: header.Hash(),
- },
- mockp.New(
- chainID,
- tc.otherHeaders,
- tc.vals,
- ),
- []provider.Provider{mockp.New(
- chainID,
- tc.otherHeaders,
- tc.vals,
- )},
- dbs.New(dbm.NewMemDB(), chainID),
- SkippingVerification(DefaultTrustLevel),
- )
- if tc.initErr {
- require.Error(t, err)
- continue
- } else {
- require.NoError(t, err)
- }
- err = c.Start()
- require.NoError(t, err)
- defer c.Stop()
-
- _, err = c.VerifyHeaderAtHeight(3, bTime.Add(3*time.Hour))
- if tc.verifyErr {
- assert.Error(t, err)
- } else {
- assert.NoError(t, err)
- }
- }
- }
-
- func TestClientRemovesNoLongerTrustedHeaders(t *testing.T) {
- const (
- chainID = "TestClientRemovesNoLongerTrustedHeaders"
- )
-
- var (
- keys = genPrivKeys(4)
- // 20, 30, 40, 50 - the first 3 don't have 2/3, the last 3 do!
- vals = keys.ToValidators(20, 10)
- bTime, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
- header = keys.GenSignedHeader(chainID, 1, bTime, nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
- )
-
- primary := mockp.New(
- chainID,
- map[int64]*types.SignedHeader{
- // trusted header
- 1: header,
- // interim header (3/3 signed)
- 2: keys.GenSignedHeader(chainID, 2, bTime.Add(2*time.Hour), nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
- // last header (3/3 signed)
- 3: keys.GenSignedHeader(chainID, 3, bTime.Add(4*time.Hour), nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
- },
- map[int64]*types.ValidatorSet{
- 1: vals,
- 2: vals,
- 3: vals,
- 4: vals,
- },
- )
-
- c, err := NewClient(
- chainID,
- TrustOptions{
- Period: 4 * time.Hour,
- Height: 1,
- Hash: header.Hash(),
- },
- primary,
- []provider.Provider{primary},
- dbs.New(dbm.NewMemDB(), chainID),
- Logger(log.TestingLogger()),
- )
- require.NoError(t, err)
- err = c.Start()
- require.NoError(t, err)
- defer c.Stop()
-
- // Verify new headers.
- _, err = c.VerifyHeaderAtHeight(2, bTime.Add(2*time.Hour).Add(1*time.Second))
- require.NoError(t, err)
- now := bTime.Add(4 * time.Hour).Add(1 * time.Second)
- _, err = c.VerifyHeaderAtHeight(3, now)
- require.NoError(t, err)
-
- // Remove expired headers.
- c.RemoveNoLongerTrustedHeaders(now)
-
- // Check expired headers are no longer available.
- h, err := c.TrustedHeader(1, now)
- assert.Error(t, err)
- assert.Nil(t, h)
-
- // Check not expired headers are available.
- h, err = c.TrustedHeader(2, now)
- assert.NoError(t, err)
- assert.NotNil(t, h)
- }
-
- func TestClient_Cleanup(t *testing.T) {
- const (
- chainID = "TestClient_Cleanup"
- )
-
- var (
- keys = genPrivKeys(4)
- // 20, 30, 40, 50 - the first 3 don't have 2/3, the last 3 do!
- vals = keys.ToValidators(20, 10)
- bTime, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
- header = keys.GenSignedHeader(chainID, 1, bTime, nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
- )
-
- primary := mockp.New(
- chainID,
- map[int64]*types.SignedHeader{
- // trusted header
- 1: header,
- },
- map[int64]*types.ValidatorSet{
- 1: vals,
- 2: vals,
- },
- )
-
- c, err := NewClient(
- chainID,
- TrustOptions{
- Period: 4 * time.Hour,
- Height: 1,
- Hash: header.Hash(),
- },
- primary,
- []provider.Provider{primary},
- dbs.New(dbm.NewMemDB(), chainID),
- Logger(log.TestingLogger()),
- )
- require.NoError(t, err)
- err = c.Start()
- require.NoError(t, err)
-
- c.Stop()
- c.Cleanup()
-
- // Check no headers exist after Cleanup.
- h, err := c.TrustedHeader(1, bTime.Add(1*time.Second))
- assert.Error(t, err)
- assert.Nil(t, h)
- }
-
- // trustedHeader.Height == options.Height
- func TestClientRestoreTrustedHeaderAfterStartup1(t *testing.T) {
- const (
- chainID = "TestClientRestoreTrustedHeaderAfterStartup1"
- )
-
- var (
- keys = genPrivKeys(4)
- // 20, 30, 40, 50 - the first 3 don't have 2/3, the last 3 do!
- vals = keys.ToValidators(20, 10)
- bTime, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
- header = keys.GenSignedHeader(chainID, 1, bTime, nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
- )
-
- // 1. options.Hash == trustedHeader.Hash
- {
- trustedStore := dbs.New(dbm.NewMemDB(), chainID)
- err := trustedStore.SaveSignedHeaderAndNextValidatorSet(header, vals)
- require.NoError(t, err)
-
- primary := mockp.New(
- chainID,
- map[int64]*types.SignedHeader{
- // trusted header
- 1: header,
- },
- map[int64]*types.ValidatorSet{
- 1: vals,
- 2: vals,
- },
- )
-
- c, err := NewClient(
- chainID,
- TrustOptions{
- Period: 4 * time.Hour,
- Height: 1,
- Hash: header.Hash(),
- },
- primary,
- []provider.Provider{primary},
- trustedStore,
- Logger(log.TestingLogger()),
- )
- require.NoError(t, err)
- err = c.Start()
- require.NoError(t, err)
- defer c.Stop()
-
- h, err := c.TrustedHeader(1, bTime.Add(1*time.Second))
- assert.NoError(t, err)
- assert.NotNil(t, h)
- assert.Equal(t, h.Hash(), header.Hash())
- }
-
- // 2. options.Hash != trustedHeader.Hash
- {
- trustedStore := dbs.New(dbm.NewMemDB(), chainID)
- err := trustedStore.SaveSignedHeaderAndNextValidatorSet(header, vals)
- require.NoError(t, err)
-
- // header1 != header
- header1 := keys.GenSignedHeader(chainID, 1, bTime.Add(1*time.Hour), nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
-
- primary := mockp.New(
- chainID,
- map[int64]*types.SignedHeader{
- // trusted header
- 1: header1,
- },
- map[int64]*types.ValidatorSet{
- 1: vals,
- 2: vals,
- },
- )
-
- c, err := NewClient(
- chainID,
- TrustOptions{
- Period: 4 * time.Hour,
- Height: 1,
- Hash: header1.Hash(),
- },
- primary,
- []provider.Provider{primary},
- trustedStore,
- Logger(log.TestingLogger()),
- )
- require.NoError(t, err)
- err = c.Start()
- require.NoError(t, err)
- defer c.Stop()
-
- h, err := c.TrustedHeader(1, bTime.Add(1*time.Second))
- assert.NoError(t, err)
- assert.NotNil(t, h)
- assert.Equal(t, h.Hash(), header1.Hash())
- }
- }
-
- // trustedHeader.Height < options.Height
- func TestClientRestoreTrustedHeaderAfterStartup2(t *testing.T) {
- const (
- chainID = "TestClientRestoreTrustedHeaderAfterStartup2"
- )
-
- var (
- keys = genPrivKeys(4)
- // 20, 30, 40, 50 - the first 3 don't have 2/3, the last 3 do!
- vals = keys.ToValidators(20, 10)
- bTime, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
- header = keys.GenSignedHeader(chainID, 1, bTime, nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
- )
-
- // 1. options.Hash == trustedHeader.Hash
- {
- trustedStore := dbs.New(dbm.NewMemDB(), chainID)
- err := trustedStore.SaveSignedHeaderAndNextValidatorSet(header, vals)
- require.NoError(t, err)
-
- header2 := keys.GenSignedHeader(chainID, 2, bTime.Add(2*time.Hour), nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
-
- primary := mockp.New(
- chainID,
- map[int64]*types.SignedHeader{
- 1: header,
- 2: header2,
- },
- map[int64]*types.ValidatorSet{
- 1: vals,
- 2: vals,
- 3: vals,
- },
- )
- c, err := NewClient(
- chainID,
- TrustOptions{
- Period: 4 * time.Hour,
- Height: 2,
- Hash: header2.Hash(),
- },
- primary,
- []provider.Provider{primary},
- trustedStore,
- Logger(log.TestingLogger()),
- )
- require.NoError(t, err)
- err = c.Start()
- require.NoError(t, err)
- defer c.Stop()
-
- // Check we still have the 1st header (+header+).
- h, err := c.TrustedHeader(1, bTime.Add(2*time.Hour).Add(1*time.Second))
- assert.NoError(t, err)
- assert.NotNil(t, h)
- assert.Equal(t, h.Hash(), header.Hash())
- }
-
- // 2. options.Hash != trustedHeader.Hash
- // This could happen if previous provider was lying to us.
- {
- trustedStore := dbs.New(dbm.NewMemDB(), chainID)
- err := trustedStore.SaveSignedHeaderAndNextValidatorSet(header, vals)
- require.NoError(t, err)
-
- // header1 != header
- header1 := keys.GenSignedHeader(chainID, 1, bTime.Add(1*time.Hour), nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
-
- header2 := keys.GenSignedHeader(chainID, 2, bTime.Add(2*time.Hour), nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
-
- primary := mockp.New(
- chainID,
- map[int64]*types.SignedHeader{
- 1: header1,
- 2: header2,
- },
- map[int64]*types.ValidatorSet{
- 1: vals,
- 2: vals,
- 3: vals,
- },
- )
-
- c, err := NewClient(
- chainID,
- TrustOptions{
- Period: 4 * time.Hour,
- Height: 2,
- Hash: header2.Hash(),
- },
- primary,
- []provider.Provider{primary},
- trustedStore,
- Logger(log.TestingLogger()),
- )
- require.NoError(t, err)
- err = c.Start()
- require.NoError(t, err)
- defer c.Stop()
-
- // Check we no longer have the invalid 1st header (+header+).
- h, err := c.TrustedHeader(1, bTime.Add(2*time.Hour).Add(1*time.Second))
- assert.Error(t, err)
- assert.Nil(t, h)
- }
- }
-
- // trustedHeader.Height > options.Height
- func TestClientRestoreTrustedHeaderAfterStartup3(t *testing.T) {
- const (
- chainID = "TestClientRestoreTrustedHeaderAfterStartup3"
- )
-
- var (
- keys = genPrivKeys(4)
- // 20, 30, 40, 50 - the first 3 don't have 2/3, the last 3 do!
- vals = keys.ToValidators(20, 10)
- bTime, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
- header = keys.GenSignedHeader(chainID, 1, bTime, nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
- )
-
- // 1. options.Hash == trustedHeader.Hash
- {
- trustedStore := dbs.New(dbm.NewMemDB(), chainID)
- err := trustedStore.SaveSignedHeaderAndNextValidatorSet(header, vals)
- require.NoError(t, err)
-
- header2 := keys.GenSignedHeader(chainID, 2, bTime.Add(2*time.Hour), nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
- err = trustedStore.SaveSignedHeaderAndNextValidatorSet(header2, vals)
- require.NoError(t, err)
-
- primary := mockp.New(
- chainID,
- map[int64]*types.SignedHeader{
- 1: header,
- 2: header2,
- },
- map[int64]*types.ValidatorSet{
- 1: vals,
- 2: vals,
- 3: vals,
- },
- )
-
- c, err := NewClient(
- chainID,
- TrustOptions{
- Period: 4 * time.Hour,
- Height: 1,
- Hash: header.Hash(),
- },
- primary,
- []provider.Provider{primary},
- trustedStore,
- Logger(log.TestingLogger()),
- )
- require.NoError(t, err)
- err = c.Start()
- require.NoError(t, err)
- defer c.Stop()
-
- // Check we still have the 1st header (+header+).
- h, err := c.TrustedHeader(1, bTime.Add(2*time.Hour).Add(1*time.Second))
- assert.NoError(t, err)
- assert.NotNil(t, h)
- assert.Equal(t, h.Hash(), header.Hash())
-
- // Check we no longer have 2nd header (+header2+).
- h, err = c.TrustedHeader(2, bTime.Add(2*time.Hour).Add(1*time.Second))
- assert.Error(t, err)
- assert.Nil(t, h)
- }
-
- // 2. options.Hash != trustedHeader.Hash
- // This could happen if previous provider was lying to us.
- {
- trustedStore := dbs.New(dbm.NewMemDB(), chainID)
- err := trustedStore.SaveSignedHeaderAndNextValidatorSet(header, vals)
- require.NoError(t, err)
-
- // header1 != header
- header1 := keys.GenSignedHeader(chainID, 1, bTime.Add(1*time.Hour), nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
-
- header2 := keys.GenSignedHeader(chainID, 2, bTime.Add(2*time.Hour), nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
- err = trustedStore.SaveSignedHeaderAndNextValidatorSet(header2, vals)
- require.NoError(t, err)
-
- primary := mockp.New(
- chainID,
- map[int64]*types.SignedHeader{
- 1: header1,
- },
- map[int64]*types.ValidatorSet{
- 1: vals,
- 2: vals,
- },
- )
-
- c, err := NewClient(
- chainID,
- TrustOptions{
- Period: 4 * time.Hour,
- Height: 1,
- Hash: header1.Hash(),
- },
- primary,
- []provider.Provider{primary},
- trustedStore,
- Logger(log.TestingLogger()),
- )
- require.NoError(t, err)
- err = c.Start()
- require.NoError(t, err)
- defer c.Stop()
-
- // Check we have swapped invalid 1st header (+header+) with correct one (+header1+).
- h, err := c.TrustedHeader(1, bTime.Add(2*time.Hour).Add(1*time.Second))
- assert.NoError(t, err)
- assert.NotNil(t, h)
- assert.Equal(t, h.Hash(), header1.Hash())
-
- // Check we no longer have invalid 2nd header (+header2+).
- h, err = c.TrustedHeader(2, bTime.Add(2*time.Hour).Add(1*time.Second))
- assert.Error(t, err)
- assert.Nil(t, h)
- }
- }
-
- func TestClient_Update(t *testing.T) {
- const (
- chainID = "TestClient_Update"
- )
-
- var (
- keys = genPrivKeys(4)
- // 20, 30, 40, 50 - the first 3 don't have 2/3, the last 3 do!
- vals = keys.ToValidators(20, 10)
- bTime, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
- header = keys.GenSignedHeader(chainID, 1, bTime, nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
- )
-
- primary := mockp.New(
- chainID,
- map[int64]*types.SignedHeader{
- // trusted header
- 1: header,
- // interim header (3/3 signed)
- 2: keys.GenSignedHeader(chainID, 2, bTime.Add(30*time.Minute), nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
- // last header (3/3 signed)
- 3: keys.GenSignedHeader(chainID, 3, bTime.Add(1*time.Hour), nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
- },
- map[int64]*types.ValidatorSet{
- 1: vals,
- 2: vals,
- 3: vals,
- 4: vals,
- },
- )
-
- c, err := NewClient(
- chainID,
- TrustOptions{
- Period: 4 * time.Hour,
- Height: 1,
- Hash: header.Hash(),
- },
- primary,
- []provider.Provider{primary},
- dbs.New(dbm.NewMemDB(), chainID),
- Logger(log.TestingLogger()),
- )
- require.NoError(t, err)
- err = c.Start()
- require.NoError(t, err)
- defer c.Stop()
-
- // should result in downloading & verifying header #3
- err = c.Update(bTime.Add(2 * time.Hour))
- require.NoError(t, err)
-
- h, err := c.TrustedHeader(3, bTime.Add(2*time.Hour))
- assert.NoError(t, err)
- require.NotNil(t, h)
- assert.EqualValues(t, 3, h.Height)
- }
-
- func TestClient_Concurrency(t *testing.T) {
- const (
- chainID = "TestClient_Concurrency"
- )
-
- var (
- keys = genPrivKeys(4)
- // 20, 30, 40, 50 - the first 3 don't have 2/3, the last 3 do!
- vals = keys.ToValidators(20, 10)
- bTime, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
- header = keys.GenSignedHeader(chainID, 1, bTime, nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
- )
-
- primary := mockp.New(
- chainID,
- map[int64]*types.SignedHeader{
- // trusted header
- 1: header,
- // interim header (3/3 signed)
- 2: keys.GenSignedHeader(chainID, 2, bTime.Add(30*time.Minute), nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
- // last header (3/3 signed)
- 3: keys.GenSignedHeader(chainID, 3, bTime.Add(1*time.Hour), nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
- },
- map[int64]*types.ValidatorSet{
- 1: vals,
- 2: vals,
- 3: vals,
- 4: vals,
- },
- )
-
- c, err := NewClient(
- chainID,
- TrustOptions{
- Period: 4 * time.Hour,
- Height: 1,
- Hash: header.Hash(),
- },
- primary,
- []provider.Provider{primary},
- dbs.New(dbm.NewMemDB(), chainID),
- UpdatePeriod(0),
- Logger(log.TestingLogger()),
- )
- require.NoError(t, err)
- err = c.Start()
- require.NoError(t, err)
- defer c.Stop()
-
- _, err = c.VerifyHeaderAtHeight(2, bTime.Add(2*time.Hour))
- require.NoError(t, err)
-
- var wg sync.WaitGroup
- for i := 0; i < 100; i++ {
- wg.Add(1)
- go func() {
- defer wg.Done()
-
- // NOTE: Cleanup, Stop, VerifyHeaderAtHeight and Verify are not supposed
- // to be concurrenly safe.
-
- assert.Equal(t, chainID, c.ChainID())
-
- _, err := c.LastTrustedHeight()
- assert.NoError(t, err)
-
- _, err = c.FirstTrustedHeight()
- assert.NoError(t, err)
-
- h, err := c.TrustedHeader(1, bTime.Add(2*time.Hour))
- assert.NoError(t, err)
- assert.NotNil(t, h)
-
- vals, err := c.TrustedValidatorSet(2, bTime.Add(2*time.Hour))
- assert.NoError(t, err)
- assert.NotNil(t, vals)
- }()
- }
-
- wg.Wait()
- }
-
- func TestProvider_Replacement(t *testing.T) {
- const (
- chainID = "TestProvider_Replacement"
- )
-
- var (
- keys = genPrivKeys(4)
- // 20, 30, 40, 50 - the first 3 don't have 2/3, the last 3 do!
- vals = keys.ToValidators(20, 10)
- bTime, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
- header = keys.GenSignedHeader(chainID, 1, bTime, nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
- primary = mockp.NewDeadMock(chainID)
- witness = mockp.New(
- chainID,
- map[int64]*types.SignedHeader{
- // trusted header
- 1: header,
- // interim header (3/3 signed)
- 2: keys.GenSignedHeader(chainID, 2, bTime.Add(30*time.Minute), nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
- // last header (3/3 signed)
- 3: keys.GenSignedHeader(chainID, 3, bTime.Add(1*time.Hour), nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
- },
- map[int64]*types.ValidatorSet{
- 1: vals,
- 2: vals,
- 3: vals,
- 4: vals,
- },
- )
- )
-
- c, err := NewClient(
- chainID,
- TrustOptions{
- Period: 4 * time.Hour,
- Height: 1,
- Hash: header.Hash(),
- },
- primary,
- []provider.Provider{witness},
- dbs.New(dbm.NewMemDB(), chainID),
- UpdatePeriod(0),
- Logger(log.TestingLogger()),
- )
- require.NoError(t, err)
- err = c.Start()
- require.NoError(t, err)
- defer c.Stop()
-
- assert.NotEqual(t, c.Primary(), primary)
- assert.Equal(t, 0, len(c.Witnesses()))
- }
-
- func TestProvider_TrustedHeaderFetchesMissingHeader(t *testing.T) {
- const (
- chainID = "TestProvider_TrustedHeaderFetchesMissingHeader"
- )
-
- var (
- keys = genPrivKeys(4)
- // 20, 30, 40, 50 - the first 3 don't have 2/3, the last 3 do!
- vals = keys.ToValidators(20, 10)
- bTime, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
- h1 = keys.GenSignedHeader(chainID, 1, bTime, nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
- h2 = keys.GenSignedHeaderLastBlockID(chainID, 2, bTime.Add(30*time.Minute), nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys), types.BlockID{Hash: h1.Hash()})
- h3 = keys.GenSignedHeaderLastBlockID(chainID, 3, bTime.Add(1*time.Hour), nil, vals, vals,
- []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys), types.BlockID{Hash: h2.Hash()})
- primary = mockp.New(
- chainID,
- map[int64]*types.SignedHeader{
- 1: h1,
- 2: h2,
- 3: h3,
- },
- map[int64]*types.ValidatorSet{
- 1: vals,
- 2: vals,
- 3: vals,
- 4: vals,
- },
- )
- )
-
- c, err := NewClient(
- chainID,
- TrustOptions{
- Period: 1 * time.Hour,
- Height: 3,
- Hash: h3.Hash(),
- },
- primary,
- []provider.Provider{primary},
- dbs.New(dbm.NewMemDB(), chainID),
- UpdatePeriod(0),
- Logger(log.TestingLogger()),
- )
- require.NoError(t, err)
- err = c.Start()
- require.NoError(t, err)
- defer c.Stop()
-
- // 1) header is missing => expect no error
- h, err := c.TrustedHeader(2, bTime.Add(1*time.Hour).Add(1*time.Second))
- require.NoError(t, err)
- if assert.NotNil(t, h) {
- assert.EqualValues(t, 2, h.Height)
- }
-
- // 2) header is missing, but it's expired => expect error
- h, err = c.TrustedHeader(1, bTime.Add(1*time.Hour).Add(1*time.Second))
- assert.Error(t, err)
- assert.Nil(t, h)
- }
|