From c4f7256766fd4cd46ac89c5259e77fe5b0a0bf45 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Wed, 26 Feb 2020 10:20:51 +0100 Subject: [PATCH] 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 --- .../adr-046-light-client-implementation.md | 4 +- lite2/client.go | 175 ++++++++---------- lite2/client_test.go | 31 +--- lite2/store/db/db.go | 17 +- lite2/store/db/db_test.go | 18 +- lite2/store/errors.go | 1 + lite2/store/store.go | 12 +- lite2/verifier.go | 14 +- 8 files changed, 119 insertions(+), 153 deletions(-) diff --git a/docs/architecture/adr-046-light-client-implementation.md b/docs/architecture/adr-046-light-client-implementation.md index 11dc79fb9..071149512 100644 --- a/docs/architecture/adr-046-light-client-implementation.md +++ b/docs/architecture/adr-046-light-client-implementation.md @@ -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) diff --git a/lite2/client.go b/lite2/client.go index 65040c133..36b366b93 100644 --- a/lite2/client.go +++ b/lite2/client.go @@ -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 diff --git a/lite2/client_test.go b/lite2/client_test.go index a6b615227..3500c918d 100644 --- a/lite2/client_test.go +++ b/lite2/client_test.go @@ -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( diff --git a/lite2/store/db/db.go b/lite2/store/db/db.go index 89897ed7f..baae0d040 100644 --- a/lite2/store/db/db.go +++ b/lite2/store/db/db.go @@ -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 diff --git a/lite2/store/db/db_test.go b/lite2/store/db/db_test.go index a1dc3000e..8e317d29b 100644 --- a/lite2/store/db/db_test.go +++ b/lite2/store/db/db_test.go @@ -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) diff --git a/lite2/store/errors.go b/lite2/store/errors.go index 8a587047b..2f77bc893 100644 --- a/lite2/store/errors.go +++ b/lite2/store/errors.go @@ -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") diff --git a/lite2/store/store.go b/lite2/store/store.go index 33b94821d..65cd82731 100644 --- a/lite2/store/store.go +++ b/lite2/store/store.go @@ -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. diff --git a/lite2/verifier.go b/lite2/verifier.go index 5491c8d91..c0732a69c 100644 --- a/lite2/verifier.go +++ b/lite2/verifier.go @@ -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) }