Browse Source

lite2: add Start, TrustedValidatorSet funcs (#4337)

* lite2: add Start method

There are few reasons to do that:

1) separation of state and dynamics (some users will want to delay
   starting the light client; does not matter we should not allow them
   to create a light client object)
2) less important, but some users might not need autoUpdateRoutine and
   removeNoLongerTrustedHeadersRoutine routines

* lite2: wait till routines are finished in Stop

because they are started in Start, it feels more natural to wait for
them to finish in Stop.

* lite2: add TrustedValidatorSet func
pull/4344/head
Anton Kaliaev 5 years ago
committed by GitHub
parent
commit
59a922d38a
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 96 additions and 17 deletions
  1. +49
    -17
      lite2/client.go
  2. +39
    -0
      lite2/client_test.go
  3. +8
    -0
      lite2/example_test.go

+ 49
- 17
lite2/client.go View File

@ -209,16 +209,6 @@ func NewClient(
}
}
if c.removeNoLongerTrustedHeadersPeriod > 0 {
c.routinesWaitGroup.Add(1)
go c.removeNoLongerTrustedHeadersRoutine()
}
if c.updatePeriod > 0 {
c.routinesWaitGroup.Add(1)
go c.autoUpdateRoutine()
}
return c, nil
}
@ -367,10 +357,30 @@ func (c *Client) initializeWithTrustOptions(options TrustOptions) error {
return c.updateTrustedHeaderAndVals(h, nextVals)
}
// Stop stops all the goroutines. If you wish to remove all the data, call
// Cleanup.
// Start starts two processes: 1) auto updating 2) removing outdated headers.
func (c *Client) Start() error {
c.logger.Info("Starting light client")
if c.removeNoLongerTrustedHeadersPeriod > 0 {
c.routinesWaitGroup.Add(1)
go c.removeNoLongerTrustedHeadersRoutine()
}
if c.updatePeriod > 0 {
c.routinesWaitGroup.Add(1)
go c.autoUpdateRoutine()
}
return nil
}
// Stop stops two processes: 1) auto updating 2) removing outdated headers.
// Stop only returns after both of them are finished running. If you wish to
// remove all the data, call Cleanup.
func (c *Client) Stop() {
c.logger.Info("Stopping light client")
close(c.quit)
c.routinesWaitGroup.Wait()
}
// TrustedHeader returns a trusted header at the given height (0 - the latest)
@ -415,6 +425,30 @@ func (c *Client) TrustedHeader(height int64, now time.Time) (*types.SignedHeader
return h, nil
}
// TrustedValidatorSet returns a trusted validator set at the given height (0 -
// the latest) or nil if no such validator set exist. The second return
// parameter is height validator set corresponds to (useful when you pass 0).
//
// height must be >= 0.
//
// It returns an error if:
// - header signed by that validator set expired (ErrOldHeaderExpired)
// - there are some issues with the trusted store, although that should not
// happen normally;
// - negative height is passed;
// - validator set is not found.
//
// 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 is not expired.
_, err := c.TrustedHeader(height, now)
if err != nil {
return nil, err
}
return c.trustedStore.ValidatorSet(height)
}
// LastTrustedHeight returns a last trusted height. -1 and nil are returned if
// there are no trusted headers.
//
@ -511,12 +545,10 @@ func (c *Client) VerifyHeader(newHeader *types.SignedHeader, newVals *types.Vali
return c.updateTrustedHeaderAndVals(newHeader, nextVals)
}
// Cleanup removes all the data (headers and validator sets) stored. It blocks
// until internal routines are finished. Note: the client must be stopped at
// this point.
// Cleanup removes all the data (headers and validator sets) stored. Note: the
// client must be stopped at this point.
func (c *Client) Cleanup() error {
c.routinesWaitGroup.Wait()
c.logger.Info("Cleanup everything")
c.logger.Info("Removing all the data")
return c.cleanup(0)
}


+ 39
- 0
lite2/client_test.go View File

@ -137,6 +137,8 @@ func TestClient_SequentialVerification(t *testing.T) {
} else {
require.NoError(t, err)
}
err = c.Start()
require.NoError(t, err)
defer c.Stop()
_, err = c.VerifyHeaderAtHeight(3, bTime.Add(3*time.Hour))
@ -235,6 +237,8 @@ func TestClient_SkippingVerification(t *testing.T) {
} else {
require.NoError(t, err)
}
err = c.Start()
require.NoError(t, err)
defer c.Stop()
_, err = c.VerifyHeaderAtHeight(3, bTime.Add(3*time.Hour))
@ -290,6 +294,8 @@ func TestClientRemovesNoLongerTrustedHeaders(t *testing.T) {
Logger(log.TestingLogger()),
)
require.NoError(t, err)
err = c.Start()
require.NoError(t, err)
defer c.Stop()
// Verify new headers.
@ -349,6 +355,8 @@ func TestClient_Cleanup(t *testing.T) {
Logger(log.TestingLogger()),
)
require.NoError(t, err)
err = c.Start()
require.NoError(t, err)
c.Stop()
c.Cleanup()
@ -402,6 +410,9 @@ func TestClientRestoreTrustedHeaderAfterStartup1(t *testing.T) {
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)
@ -441,6 +452,9 @@ func TestClientRestoreTrustedHeaderAfterStartup1(t *testing.T) {
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)
@ -496,6 +510,9 @@ func TestClientRestoreTrustedHeaderAfterStartup2(t *testing.T) {
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))
@ -541,6 +558,9 @@ func TestClientRestoreTrustedHeaderAfterStartup2(t *testing.T) {
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))
@ -598,6 +618,9 @@ func TestClientRestoreTrustedHeaderAfterStartup3(t *testing.T) {
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))
@ -648,6 +671,9 @@ func TestClientRestoreTrustedHeaderAfterStartup3(t *testing.T) {
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))
@ -706,6 +732,8 @@ func TestClient_Update(t *testing.T) {
Logger(log.TestingLogger()),
)
require.NoError(t, err)
err = c.Start()
require.NoError(t, err)
defer c.Stop()
// should result in downloading & verifying header #3
@ -763,6 +791,13 @@ func TestClient_Concurrency(t *testing.T) {
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)
@ -783,6 +818,10 @@ func TestClient_Concurrency(t *testing.T) {
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)
}()
}


+ 8
- 0
lite2/example_test.go View File

@ -63,6 +63,10 @@ func TestExample_Client_AutoUpdate(t *testing.T) {
if err != nil {
stdlog.Fatal(err)
}
err = c.Start()
if err != nil {
stdlog.Fatal(err)
}
defer func() {
c.Stop()
c.Cleanup()
@ -125,6 +129,10 @@ func TestExample_Client_ManualUpdate(t *testing.T) {
if err != nil {
stdlog.Fatal(err)
}
err = c.Start()
if err != nil {
stdlog.Fatal(err)
}
defer func() {
c.Stop()
c.Cleanup()


Loading…
Cancel
Save