Browse Source

lite2: store current validator set (#4472)

Before we were storing trustedHeader (height=1) and trustedNextVals
(height=2).

After this change, we will be storing trustedHeader (height=1) and
trustedVals (height=1). This a) simplifies the code b) fixes #4399
inconsistent pairing issue c) gives a relayer access to the current
validator set #4470.

The only downside is more jumps during bisection. If validator set
changes between trustedHeader and the next header (by 2/3 or more), the
light client will be forced to download the next header and check that
2/3+ signed the transition. But we don't expect validator set change too
much and too often, so it's an acceptable compromise.

Closes #4470 and #4399
anca/fix_TestReactorTerminationScenarios v0.33.1-dev1
Anton Kaliaev 4 years ago
committed by GitHub
parent
commit
c4f7256766
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 119 additions and 153 deletions
  1. +2
    -2
      docs/architecture/adr-046-light-client-implementation.md
  2. +76
    -99
      lite2/client.go
  3. +9
    -22
      lite2/client_test.go
  4. +9
    -8
      lite2/store/db/db.go
  5. +9
    -9
      lite2/store/db/db_test.go
  6. +1
    -0
      lite2/store/errors.go
  7. +6
    -6
      lite2/store/store.go
  8. +7
    -7
      lite2/verifier.go

+ 2
- 2
docs/architecture/adr-046-light-client-implementation.md View File

@ -91,8 +91,8 @@ The light client stores headers & validators in the trusted store:
```go
type Store interface {
SaveSignedHeaderAndNextValidatorSet(sh *types.SignedHeader, valSet *types.ValidatorSet) error
DeleteSignedHeaderAndNextValidatorSet(height int64) error
SaveSignedHeaderAndValidatorSet(sh *types.SignedHeader, valSet *types.ValidatorSet) error
DeleteSignedHeaderAndValidatorSet(height int64) error
SignedHeader(height int64) (*types.SignedHeader, error)
ValidatorSet(height int64) (*types.ValidatorSet, error)


+ 76
- 99
lite2/client.go View File

@ -122,8 +122,8 @@ type Client struct {
trustedStore store.Store
// Highest trusted header from the store (height=H).
latestTrustedHeader *types.SignedHeader
// Highest next validator set from the store (height=H+1).
latestTrustedNextVals *types.ValidatorSet
// Highest validator set from the store (height=H).
latestTrustedVals *types.ValidatorSet
// See UpdatePeriod option
updatePeriod time.Duration
@ -228,15 +228,16 @@ func NewClientFromTrustedStore(
return nil, err
}
if err := c.restoreTrustedHeaderAndNextVals(); err != nil {
if err := c.restoreTrustedHeaderAndVals(); err != nil {
return nil, err
}
return c, nil
}
// Load trustedHeader and trustedNextVals from trustedStore.
func (c *Client) restoreTrustedHeaderAndNextVals() error {
// restoreTrustedHeaderAndVals loads trustedHeader and trustedVals from
// trustedStore.
func (c *Client) restoreTrustedHeaderAndVals() error {
lastHeight, err := c.trustedStore.LastSignedHeaderHeight()
if err != nil {
return errors.Wrap(err, "can't get last trusted header height")
@ -248,15 +249,15 @@ func (c *Client) restoreTrustedHeaderAndNextVals() error {
return errors.Wrap(err, "can't get last trusted header")
}
trustedNextVals, err := c.trustedStore.ValidatorSet(lastHeight + 1)
trustedVals, err := c.trustedStore.ValidatorSet(lastHeight)
if err != nil {
return errors.Wrap(err, "can't get last trusted next validators")
return errors.Wrap(err, "can't get last trusted validators")
}
c.latestTrustedHeader = trustedHeader
c.latestTrustedNextVals = trustedNextVals
c.latestTrustedVals = trustedVals
c.logger.Debug("Restored trusted header and next vals", lastHeight)
c.logger.Debug("Restored trusted header and vals", "height", lastHeight)
}
return nil
@ -334,7 +335,9 @@ func (c *Client) checkTrustedHeaderUsingOptions(options TrustOptions) error {
return nil
}
// Fetch trustedHeader and trustedNextVals from primary provider.
// initializeWithTrustOptions fetches the weakly-trusted header and vals from
// primary provider. The header is cross-checked with witnesses for additional
// security.
func (c *Client) initializeWithTrustOptions(options TrustOptions) error {
// 1) Fetch and verify the header.
h, err := c.signedHeaderFromPrimary(options.Height)
@ -372,15 +375,8 @@ func (c *Client) initializeWithTrustOptions(options TrustOptions) error {
return errors.Wrap(err, "invalid commit")
}
// 3) Fetch and verify the next vals (verification happens in
// updateTrustedHeaderAndNextVals).
nextVals, err := c.validatorSetFromPrimary(options.Height + 1)
if err != nil {
return err
}
// 4) Persist both of them and continue.
return c.updateTrustedHeaderAndNextVals(h, nextVals)
// 3) Persist both of them and continue.
return c.updateTrustedHeaderAndVals(h, vals)
}
// Start starts two processes: 1) auto updating 2) removing outdated headers.
@ -463,9 +459,7 @@ func (c *Client) TrustedHeader(height int64, now time.Time) (*types.SignedHeader
// TrustedValidatorSet returns a trusted validator set at the given height. If
// a validator set is missing in trustedStore (e.g. the associated header was
// skipped during bisection), it will be downloaded from primary. The second
// return parameter is height validator set corresponds to (useful when you
// pass 0).
// skipped during bisection), it will be downloaded from primary.
//
// height must be >= 0.
//
@ -482,10 +476,10 @@ func (c *Client) TrustedHeader(height int64, now time.Time) (*types.SignedHeader
//
// Safe for concurrent use by multiple goroutines.
func (c *Client) TrustedValidatorSet(height int64, now time.Time) (*types.ValidatorSet, error) {
// Checks height is positive and header (note: height - 1) is not expired.
// Checks height is positive and header is not expired.
// Additionally, it fetches validator set from primary if it's missing in
// store.
_, err := c.TrustedHeader(height-1, now)
_, err := c.TrustedHeader(height, now)
if err != nil {
return nil, err
}
@ -528,10 +522,12 @@ func (c *Client) VerifyHeaderAtHeight(height int64, now time.Time) (*types.Signe
return nil, errors.New("negative or zero height")
}
// Check if header already verified.
h, err := c.TrustedHeader(height, now)
switch err.(type) {
case nil: // Return already trusted header
case nil:
c.logger.Info("Header has already been verified", "height", height, "hash", hash2str(h.Hash()))
// Return already trusted header
return h, nil
case ErrOldHeaderExpired:
return nil, err
@ -565,14 +561,11 @@ func (c *Client) VerifyHeaderAtHeight(height int64, now time.Time) (*types.Signe
// If, at any moment, SignedHeader or ValidatorSet are not found by the primary
// provider, provider.ErrSignedHeaderNotFound /
// provider.ErrValidatorSetNotFound error is returned.
//
// NOTE: although newVals is entered as input, trustedStore will only store the
// validator set at height newHeader.Height+1 (i.e.
// newHeader.NextValidatorsHash).
func (c *Client) VerifyHeader(newHeader *types.SignedHeader, newVals *types.ValidatorSet, now time.Time) error {
// Check if newHeader already verified.
h, err := c.TrustedHeader(newHeader.Height, now)
switch err.(type) {
case nil: // Return already trusted header
case nil:
// Make sure it's the same header.
if !bytes.Equal(h.Hash(), newHeader.Hash()) {
return errors.Errorf("existing trusted header %X does not match newHeader %X", h.Hash(), newHeader.Hash())
@ -597,9 +590,9 @@ func (c *Client) verifyHeader(newHeader *types.SignedHeader, newVals *types.Vali
if newHeader.Height >= c.latestTrustedHeader.Height {
switch c.verificationMode {
case sequential:
err = c.sequence(c.latestTrustedHeader, c.latestTrustedNextVals, newHeader, newVals, now)
err = c.sequence(c.latestTrustedHeader, newHeader, newVals, now)
case skipping:
err = c.bisection(c.latestTrustedHeader, c.latestTrustedNextVals, newHeader, newVals, now)
err = c.bisection(c.latestTrustedHeader, c.latestTrustedVals, newHeader, newVals, now)
default:
panic(fmt.Sprintf("Unknown verification mode: %b", c.verificationMode))
}
@ -624,13 +617,7 @@ func (c *Client) verifyHeader(newHeader *types.SignedHeader, newVals *types.Vali
return err
}
// Update trusted header and vals.
nextVals, err := c.validatorSetFromPrimary(newHeader.Height + 1)
if err != nil {
return err
}
return c.updateTrustedHeaderAndNextVals(newHeader, nextVals)
return c.updateTrustedHeaderAndVals(newHeader, newVals)
}
// Primary returns the primary provider.
@ -679,7 +666,7 @@ func (c *Client) cleanup(stopHeight int64) error {
stopHeight = oldestHeight
}
for height := stopHeight; height <= latestHeight; height++ {
err = c.trustedStore.DeleteSignedHeaderAndNextValidatorSet(height)
err = c.trustedStore.DeleteSignedHeaderAndValidatorSet(height)
if err != nil {
c.logger.Error("can't remove a trusted header & validator set", "err", err, "height", height)
continue
@ -687,8 +674,8 @@ func (c *Client) cleanup(stopHeight int64) error {
}
c.latestTrustedHeader = nil
c.latestTrustedNextVals = nil
err = c.restoreTrustedHeaderAndNextVals()
c.latestTrustedVals = nil
err = c.restoreTrustedHeaderAndVals()
if err != nil {
return err
}
@ -698,51 +685,46 @@ func (c *Client) cleanup(stopHeight int64) error {
// see VerifyHeader
func (c *Client) sequence(
trustedHeader *types.SignedHeader,
trustedNextVals *types.ValidatorSet,
initiallyTrustedHeader *types.SignedHeader,
newHeader *types.SignedHeader,
newVals *types.ValidatorSet,
now time.Time) error {
// 1) Verify any intermediate headers.
var (
interimHeader *types.SignedHeader
interimNextVals *types.ValidatorSet
err error
trustedHeader = initiallyTrustedHeader
interimHeader *types.SignedHeader
interimVals *types.ValidatorSet
err error
)
for height := trustedHeader.Height + 1; height <= newHeader.Height; height++ {
interimHeader, err = c.signedHeaderFromPrimary(height)
if err != nil {
return errors.Wrapf(err, "failed to obtain the header #%d", height)
for height := initiallyTrustedHeader.Height + 1; height <= newHeader.Height; height++ {
// 1) Fetch interim headers and vals if needed.
if height == newHeader.Height { // last header
interimHeader, interimVals = newHeader, newVals
} else { // intermediate headers
interimHeader, interimVals, err = c.fetchHeaderAndValsAtHeight(height)
if err != nil {
return errors.Wrapf(err, "failed to obtain the header #%d", height)
}
}
// 2) Verify them
c.logger.Debug("Verify newHeader against trustedHeader",
"trustedHeight", c.latestTrustedHeader.Height,
"trustedHash", hash2str(c.latestTrustedHeader.Hash()),
"trustedHeight", trustedHeader.Height,
"trustedHash", hash2str(trustedHeader.Hash()),
"newHeight", interimHeader.Height,
"newHash", hash2str(interimHeader.Hash()))
err = VerifyAdjacent(c.chainID, trustedHeader, interimHeader, trustedNextVals,
err = VerifyAdjacent(c.chainID, trustedHeader, interimHeader, interimVals,
c.trustingPeriod, now)
if err != nil {
return errors.Wrapf(err, "failed to verify the header #%d", height)
}
// Update trusted header and vals.
if height == newHeader.Height-1 {
interimNextVals = newVals
} else {
interimNextVals, err = c.validatorSetFromPrimary(height + 1)
if err != nil {
return errors.Wrapf(err, "failed to obtain the vals #%d", height+1)
}
if !bytes.Equal(interimHeader.NextValidatorsHash, interimNextVals.Hash()) {
return errors.Errorf("expected next validator's hash %X, but got %X (height #%d)",
interimHeader.NextValidatorsHash,
interimNextVals.Hash(),
interimHeader.Height)
}
}
trustedHeader, trustedNextVals = interimHeader, interimNextVals
// 3) Update trustedHeader
trustedHeader = interimHeader
}
return nil
@ -750,22 +732,28 @@ func (c *Client) sequence(
// see VerifyHeader
func (c *Client) bisection(
trustedHeader *types.SignedHeader, // height h
trustedNextVals *types.ValidatorSet, // height h + 1
newHeader *types.SignedHeader, // height g
newVals *types.ValidatorSet, // height g
initiallyTrustedHeader *types.SignedHeader,
initiallyTrustedVals *types.ValidatorSet,
newHeader *types.SignedHeader,
newVals *types.ValidatorSet,
now time.Time) error {
interimVals := newVals
interimHeader := newHeader
var (
trustedHeader = initiallyTrustedHeader
trustedVals = initiallyTrustedVals
interimHeader = newHeader
interimVals = newVals
)
for {
c.logger.Debug("Verify newHeader against trustedHeader",
"trustedHeight", trustedHeader.Height,
"trustedHash", hash2str(trustedHeader.Hash()),
"newHeight", newHeader.Height,
"newHash", hash2str(newHeader.Hash()))
err := Verify(c.chainID, trustedHeader, trustedNextVals, interimHeader, interimVals, c.trustingPeriod, now,
"newHeight", interimHeader.Height,
"newHash", hash2str(interimHeader.Hash()))
err := Verify(c.chainID, trustedHeader, trustedVals, interimHeader, interimVals, c.trustingPeriod, now,
c.trustLevel)
switch err.(type) {
case nil:
@ -774,17 +762,7 @@ func (c *Client) bisection(
}
// Update the lower bound to the previous upper bound
interimNextVals, err := c.validatorSetFromPrimary(interimHeader.Height + 1)
if err != nil {
return err
}
if !bytes.Equal(interimHeader.NextValidatorsHash, interimNextVals.Hash()) {
return errors.Errorf("expected next validator's hash %X, but got %X (height #%d)",
interimHeader.NextValidatorsHash,
interimNextVals.Hash(),
interimHeader.Height)
}
trustedHeader, trustedNextVals = interimHeader, interimNextVals
trustedHeader, trustedVals = interimHeader, interimVals
// Update the upper bound to the untrustedHeader
interimHeader, interimVals = newHeader, newVals
@ -801,18 +779,17 @@ func (c *Client) bisection(
}
}
// persist header and next validators to trustedStore.
func (c *Client) updateTrustedHeaderAndNextVals(h *types.SignedHeader, nextVals *types.ValidatorSet) error {
if !bytes.Equal(h.NextValidatorsHash, nextVals.Hash()) {
return errors.Errorf("expected next validator's hash %X, but got %X", h.NextValidatorsHash, nextVals.Hash())
func (c *Client) updateTrustedHeaderAndVals(h *types.SignedHeader, vals *types.ValidatorSet) error {
if !bytes.Equal(h.ValidatorsHash, vals.Hash()) {
return errors.Errorf("expected validator's hash %X, but got %X", h.ValidatorsHash, vals.Hash())
}
if err := c.trustedStore.SaveSignedHeaderAndNextValidatorSet(h, nextVals); err != nil {
if err := c.trustedStore.SaveSignedHeaderAndValidatorSet(h, vals); err != nil {
return errors.Wrap(err, "failed to save trusted header")
}
c.latestTrustedHeader = h
c.latestTrustedNextVals = nextVals
c.latestTrustedVals = vals
return nil
}
@ -898,7 +875,7 @@ func (c *Client) compareNewHeaderWithWitnesses(h *types.SignedHeader) error {
}
if !bytes.Equal(h.Hash(), altH.Hash()) {
if err = c.latestTrustedNextVals.VerifyCommitTrusting(c.chainID, altH.Commit.BlockID,
if err = c.latestTrustedVals.VerifyCommitTrusting(c.chainID, altH.Commit.BlockID,
altH.Height, altH.Commit, c.trustLevel); err != nil {
c.logger.Error("Witness sent us incorrect header", "err", err, "witness", witness)
witnessesToRemove = append(witnessesToRemove, i)
@ -1002,7 +979,7 @@ func (c *Client) RemoveNoLongerTrustedHeaders(now time.Time) {
break
}
err = c.trustedStore.DeleteSignedHeaderAndNextValidatorSet(height)
err = c.trustedStore.DeleteSignedHeaderAndValidatorSet(height)
if err != nil {
c.logger.Error("can't remove a trusted header & validator set", "err", err, "height", height)
continue


+ 9
- 22
lite2/client_test.go View File

@ -50,7 +50,6 @@ var (
1: vals,
2: vals,
3: vals,
4: vals,
},
)
deadNode = mockp.NewDeadMock(chainID)
@ -81,7 +80,6 @@ func TestClient_SequentialVerification(t *testing.T) {
1: vals,
2: vals,
3: vals,
4: vals,
},
false,
false,
@ -115,7 +113,6 @@ func TestClient_SequentialVerification(t *testing.T) {
1: vals,
2: vals,
3: vals,
4: vals,
},
false,
true,
@ -136,7 +133,6 @@ func TestClient_SequentialVerification(t *testing.T) {
1: vals,
2: vals,
3: vals,
4: vals,
},
false,
true,
@ -155,7 +151,6 @@ func TestClient_SequentialVerification(t *testing.T) {
1: vals,
2: vals,
3: newVals,
4: newVals,
},
false,
true,
@ -230,7 +225,6 @@ func TestClient_SkippingVerification(t *testing.T) {
1: vals,
2: vals,
3: vals,
4: vals,
},
false,
false,
@ -247,7 +241,6 @@ func TestClient_SkippingVerification(t *testing.T) {
1: vals,
2: vals,
3: transitVals,
4: transitVals,
},
false,
false,
@ -268,7 +261,6 @@ func TestClient_SkippingVerification(t *testing.T) {
1: vals,
2: vals,
3: newVals,
4: newVals,
},
false,
false,
@ -289,7 +281,6 @@ func TestClient_SkippingVerification(t *testing.T) {
1: vals,
2: vals,
3: newVals,
4: newVals,
},
false,
true,
@ -404,7 +395,7 @@ func TestClientRestoresTrustedHeaderAfterStartup1(t *testing.T) {
// 1. options.Hash == trustedHeader.Hash
{
trustedStore := dbs.New(dbm.NewMemDB(), chainID)
err := trustedStore.SaveSignedHeaderAndNextValidatorSet(h1, vals)
err := trustedStore.SaveSignedHeaderAndValidatorSet(h1, vals)
require.NoError(t, err)
c, err := NewClient(
@ -429,7 +420,7 @@ func TestClientRestoresTrustedHeaderAfterStartup1(t *testing.T) {
// 2. options.Hash != trustedHeader.Hash
{
trustedStore := dbs.New(dbm.NewMemDB(), chainID)
err := trustedStore.SaveSignedHeaderAndNextValidatorSet(h1, vals)
err := trustedStore.SaveSignedHeaderAndValidatorSet(h1, vals)
require.NoError(t, err)
// header1 != header
@ -444,7 +435,6 @@ func TestClientRestoresTrustedHeaderAfterStartup1(t *testing.T) {
},
map[int64]*types.ValidatorSet{
1: vals,
2: vals,
},
)
@ -477,7 +467,7 @@ func TestClientRestoresTrustedHeaderAfterStartup2(t *testing.T) {
// 1. options.Hash == trustedHeader.Hash
{
trustedStore := dbs.New(dbm.NewMemDB(), chainID)
err := trustedStore.SaveSignedHeaderAndNextValidatorSet(h1, vals)
err := trustedStore.SaveSignedHeaderAndValidatorSet(h1, vals)
require.NoError(t, err)
c, err := NewClient(
@ -508,7 +498,7 @@ func TestClientRestoresTrustedHeaderAfterStartup2(t *testing.T) {
// This could happen if previous provider was lying to us.
{
trustedStore := dbs.New(dbm.NewMemDB(), chainID)
err := trustedStore.SaveSignedHeaderAndNextValidatorSet(h1, vals)
err := trustedStore.SaveSignedHeaderAndValidatorSet(h1, vals)
require.NoError(t, err)
// header1 != header
@ -527,7 +517,6 @@ func TestClientRestoresTrustedHeaderAfterStartup2(t *testing.T) {
map[int64]*types.ValidatorSet{
1: vals,
2: vals,
3: vals,
},
)
@ -560,12 +549,12 @@ func TestClientRestoresTrustedHeaderAfterStartup3(t *testing.T) {
// 1. options.Hash == trustedHeader.Hash
{
trustedStore := dbs.New(dbm.NewMemDB(), chainID)
err := trustedStore.SaveSignedHeaderAndNextValidatorSet(h1, vals)
err := trustedStore.SaveSignedHeaderAndValidatorSet(h1, 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(h2, vals)
err = trustedStore.SaveSignedHeaderAndValidatorSet(h2, vals)
require.NoError(t, err)
primary := mockp.New(
@ -577,7 +566,6 @@ func TestClientRestoresTrustedHeaderAfterStartup3(t *testing.T) {
map[int64]*types.ValidatorSet{
1: vals,
2: vals,
3: vals,
},
)
@ -610,7 +598,7 @@ func TestClientRestoresTrustedHeaderAfterStartup3(t *testing.T) {
// This could happen if previous provider was lying to us.
{
trustedStore := dbs.New(dbm.NewMemDB(), chainID)
err := trustedStore.SaveSignedHeaderAndNextValidatorSet(h1, vals)
err := trustedStore.SaveSignedHeaderAndValidatorSet(h1, vals)
require.NoError(t, err)
// header1 != header
@ -619,7 +607,7 @@ func TestClientRestoresTrustedHeaderAfterStartup3(t *testing.T) {
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)
err = trustedStore.SaveSignedHeaderAndValidatorSet(header2, vals)
require.NoError(t, err)
primary := mockp.New(
@ -629,7 +617,6 @@ func TestClientRestoresTrustedHeaderAfterStartup3(t *testing.T) {
},
map[int64]*types.ValidatorSet{
1: vals,
2: vals,
},
)
@ -796,7 +783,7 @@ func TestClient_BackwardsVerification(t *testing.T) {
func TestClient_NewClientFromTrustedStore(t *testing.T) {
// 1) Initiate DB and fill with a "trusted" header
db := dbs.New(dbm.NewMemDB(), chainID)
err := db.SaveSignedHeaderAndNextValidatorSet(h1, vals)
err := db.SaveSignedHeaderAndValidatorSet(h1, vals)
require.NoError(t, err)
c, err := NewClientFromTrustedStore(


+ 9
- 8
lite2/store/db/db.go View File

@ -31,9 +31,9 @@ func New(db dbm.DB, prefix string) store.Store {
return &dbs{db: db, prefix: prefix, cdc: cdc}
}
// SaveSignedHeaderAndNextValidatorSet persists SignedHeader and ValidatorSet
// to the db.
func (s *dbs) SaveSignedHeaderAndNextValidatorSet(sh *types.SignedHeader, valSet *types.ValidatorSet) error {
// SaveSignedHeaderAndValidatorSet persists SignedHeader and ValidatorSet to
// the db.
func (s *dbs) SaveSignedHeaderAndValidatorSet(sh *types.SignedHeader, valSet *types.ValidatorSet) error {
if sh.Height <= 0 {
panic("negative or zero height")
}
@ -42,6 +42,7 @@ func (s *dbs) SaveSignedHeaderAndNextValidatorSet(sh *types.SignedHeader, valSet
if err != nil {
return errors.Wrap(err, "marshalling header")
}
valSetBz, err := s.cdc.MarshalBinaryLengthPrefixed(valSet)
if err != nil {
return errors.Wrap(err, "marshalling validator set")
@ -49,22 +50,22 @@ func (s *dbs) SaveSignedHeaderAndNextValidatorSet(sh *types.SignedHeader, valSet
b := s.db.NewBatch()
b.Set(s.shKey(sh.Height), shBz)
b.Set(s.vsKey(sh.Height+1), valSetBz)
b.Set(s.vsKey(sh.Height), valSetBz)
err = b.WriteSync()
b.Close()
return err
}
// DeleteSignedHeaderAndNextValidatorSet deletes SignedHeader and ValidatorSet
// from the db.
func (s *dbs) DeleteSignedHeaderAndNextValidatorSet(height int64) error {
// DeleteSignedHeaderAndValidatorSet deletes SignedHeader and ValidatorSet from
// the db.
func (s *dbs) DeleteSignedHeaderAndValidatorSet(height int64) error {
if height <= 0 {
panic("negative or zero height")
}
b := s.db.NewBatch()
b.Delete(s.shKey(height))
b.Delete(s.vsKey(height + 1))
b.Delete(s.vsKey(height))
err := b.WriteSync()
b.Close()
return err


+ 9
- 9
lite2/store/db/db_test.go View File

@ -24,7 +24,7 @@ func TestLast_FirstSignedHeaderHeight(t *testing.T) {
assert.EqualValues(t, -1, height)
// 1 key
err = dbStore.SaveSignedHeaderAndNextValidatorSet(
err = dbStore.SaveSignedHeaderAndValidatorSet(
&types.SignedHeader{Header: &types.Header{Height: 1}}, &types.ValidatorSet{})
require.NoError(t, err)
@ -37,20 +37,20 @@ func TestLast_FirstSignedHeaderHeight(t *testing.T) {
assert.EqualValues(t, 1, height)
}
func Test_SaveSignedHeaderAndNextValidatorSet(t *testing.T) {
dbStore := New(dbm.NewMemDB(), "Test_SaveSignedHeaderAndNextValidatorSet")
func Test_SaveSignedHeaderAndValidatorSet(t *testing.T) {
dbStore := New(dbm.NewMemDB(), "Test_SaveSignedHeaderAndValidatorSet")
// Empty store
h, err := dbStore.SignedHeader(1)
require.Error(t, err)
assert.Nil(t, h)
valSet, err := dbStore.ValidatorSet(2)
valSet, err := dbStore.ValidatorSet(1)
require.Error(t, err)
assert.Nil(t, valSet)
// 1 key
err = dbStore.SaveSignedHeaderAndNextValidatorSet(
err = dbStore.SaveSignedHeaderAndValidatorSet(
&types.SignedHeader{Header: &types.Header{Height: 1}}, &types.ValidatorSet{})
require.NoError(t, err)
@ -58,19 +58,19 @@ func Test_SaveSignedHeaderAndNextValidatorSet(t *testing.T) {
require.NoError(t, err)
assert.NotNil(t, h)
valSet, err = dbStore.ValidatorSet(2)
valSet, err = dbStore.ValidatorSet(1)
require.NoError(t, err)
assert.NotNil(t, valSet)
// Empty store
err = dbStore.DeleteSignedHeaderAndNextValidatorSet(1)
err = dbStore.DeleteSignedHeaderAndValidatorSet(1)
require.NoError(t, err)
h, err = dbStore.SignedHeader(1)
require.Error(t, err)
assert.Nil(t, h)
valSet, err = dbStore.ValidatorSet(2)
valSet, err = dbStore.ValidatorSet(1)
require.Error(t, err)
assert.Nil(t, valSet)
}
@ -83,7 +83,7 @@ func Test_SignedHeaderAfter(t *testing.T) {
dbStore.SignedHeaderAfter(100)
})
err := dbStore.SaveSignedHeaderAndNextValidatorSet(
err := dbStore.SaveSignedHeaderAndValidatorSet(
&types.SignedHeader{Header: &types.Header{Height: 2}}, &types.ValidatorSet{})
require.NoError(t, err)


+ 1
- 0
lite2/store/errors.go View File

@ -6,6 +6,7 @@ var (
// ErrSignedHeaderNotFound is returned when a store does not have the
// requested header.
ErrSignedHeaderNotFound = errors.New("signed header not found")
// ErrValidatorSetNotFound is returned when a store does not have the
// requested validator set.
ErrValidatorSetNotFound = errors.New("validator set not found")


+ 6
- 6
lite2/store/store.go View File

@ -4,17 +4,17 @@ import "github.com/tendermint/tendermint/types"
// Store is anything that can persistenly store headers.
type Store interface {
// SaveSignedHeaderAndNextValidatorSet saves a SignedHeader (h: sh.Height)
// and a ValidatorSet (h: sh.Height+1).
// SaveSignedHeaderAndValidatorSet saves a SignedHeader (h: sh.Height) and a
// ValidatorSet (h: sh.Height).
//
// height must be > 0.
SaveSignedHeaderAndNextValidatorSet(sh *types.SignedHeader, valSet *types.ValidatorSet) error
SaveSignedHeaderAndValidatorSet(sh *types.SignedHeader, valSet *types.ValidatorSet) error
// DeleteSignedHeaderAndNextValidatorSet deletes SignedHeader (h: height) and
// ValidatorSet (h: height+1).
// DeleteSignedHeaderAndValidatorSet deletes SignedHeader (h: height) and
// ValidatorSet (h: height).
//
// height must be > 0.
DeleteSignedHeaderAndNextValidatorSet(height int64) error
DeleteSignedHeaderAndValidatorSet(height int64) error
// SignedHeader returns the SignedHeader that corresponds to the given
// height.


+ 7
- 7
lite2/verifier.go View File

@ -21,15 +21,15 @@ var (
//
// a) trustedHeader can still be trusted (if not, ErrOldHeaderExpired is returned);
// b) untrustedHeader is valid;
// c) trustLevel ([1/3, 1]) of trustedHeaderNextVals signed correctly
// (if not, ErrNewValSetCantBeTrusted is returned);
// c) trustLevel ([1/3, 1]) of trustedHeaderVals (or trustedHeaderNextVals)
// signed correctly (if not, ErrNewValSetCantBeTrusted is returned);
// d) more than 2/3 of untrustedVals have signed h2 (if not,
// ErrNotEnoughVotingPowerSigned is returned);
// e) headers are non-adjacent.
func VerifyNonAdjacent(
chainID string,
trustedHeader *types.SignedHeader, // height=X
trustedNextVals *types.ValidatorSet, // height=X+1
trustedVals *types.ValidatorSet, // height=X or height=X+1
untrustedHeader *types.SignedHeader, // height=Y
untrustedVals *types.ValidatorSet, // height=Y
trustingPeriod time.Duration,
@ -49,7 +49,7 @@ func VerifyNonAdjacent(
}
// Ensure that +`trustLevel` (default 1/3) or more of last trusted validators signed correctly.
err := trustedNextVals.VerifyCommitTrusting(chainID, untrustedHeader.Commit.BlockID, untrustedHeader.Height,
err := trustedVals.VerifyCommitTrusting(chainID, untrustedHeader.Commit.BlockID, untrustedHeader.Height,
untrustedHeader.Commit, trustLevel)
if err != nil {
switch e := err.(type) {
@ -78,7 +78,7 @@ func VerifyNonAdjacent(
//
// a) trustedHeader can still be trusted (if not, ErrOldHeaderExpired is returned);
// b) untrustedHeader is valid;
// c) untrustedHeader.ValidatorsHash equals trustedHeaderNextVals.Hash()
// c) untrustedHeader.ValidatorsHash equals trustedHeader.NextValidatorsHash;
// d) more than 2/3 of new validators (untrustedVals) have signed h2 (if not,
// ErrNotEnoughVotingPowerSigned is returned);
// e) headers are adjacent.
@ -124,7 +124,7 @@ func VerifyAdjacent(
func Verify(
chainID string,
trustedHeader *types.SignedHeader, // height=X
trustedNextVals *types.ValidatorSet, // height=X+1
trustedVals *types.ValidatorSet, // height=X or height=X+1
untrustedHeader *types.SignedHeader, // height=Y
untrustedVals *types.ValidatorSet, // height=Y
trustingPeriod time.Duration,
@ -132,7 +132,7 @@ func Verify(
trustLevel tmmath.Fraction) error {
if untrustedHeader.Height != trustedHeader.Height+1 {
return VerifyNonAdjacent(chainID, trustedHeader, trustedNextVals, untrustedHeader, untrustedVals,
return VerifyNonAdjacent(chainID, trustedHeader, trustedVals, untrustedHeader, untrustedVals,
trustingPeriod, now, trustLevel)
}


Loading…
Cancel
Save