Skip to content

Commit

Permalink
Merge pull request #97 from renaynay/recency
Browse files Browse the repository at this point in the history
fix(sync): Allow some more slack for recency estimation
  • Loading branch information
renaynay authored Aug 25, 2023
2 parents d9a7037 + ef65ee7 commit 52e9af7
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 7 deletions.
11 changes: 11 additions & 0 deletions sync/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ type Parameters struct {
// Keeping it private to disable serialization for it.
// default value is set to 0 so syncer will constantly request networking head.
blockTime time.Duration
// recencyThreshold describes the time period for which a header is
// considered "recent". The default is blockTime + 5 seconds.
recencyThreshold time.Duration
}

// DefaultParameters returns the default params to configure the syncer.
Expand All @@ -50,6 +53,14 @@ func WithBlockTime(duration time.Duration) Options {
}
}

// WithRecencyThreshold is a functional option that configures the
// `recencyThreshold` parameter.
func WithRecencyThreshold(threshold time.Duration) Options {
return func(p *Parameters) {
p.recencyThreshold = threshold
}
}

// WithTrustingPeriod is a functional option that configures the
// `TrustingPeriod` parameter.
func WithTrustingPeriod(duration time.Duration) Options {
Expand Down
13 changes: 8 additions & 5 deletions sync/sync_head.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func (s *Syncer[H]) Head(ctx context.Context, _ ...header.HeadOption[H]) (H, err
return sbjHead, err
}
// if subjective header is recent enough (relative to the network's block time) - just use it
if isRecent(sbjHead, s.Params.blockTime) {
if isRecent(sbjHead, s.Params.blockTime, s.Params.recencyThreshold) {
return sbjHead, nil
}
// otherwise, request head from the network
Expand Down Expand Up @@ -98,7 +98,7 @@ func (s *Syncer[H]) subjectiveHead(ctx context.Context) (H, error) {
return trustHead, nil
case isExpired(trustHead, s.Params.TrustingPeriod):
log.Warnw("subjective initialization with an expired header", "height", trustHead.Height())
case !isRecent(trustHead, s.Params.blockTime):
case !isRecent(trustHead, s.Params.blockTime, s.Params.recencyThreshold):
log.Warnw("subjective initialization with an old header", "height", trustHead.Height())
}
log.Warn("trusted peer is out of sync")
Expand Down Expand Up @@ -189,7 +189,10 @@ func isExpired[H header.Header[H]](header H, period time.Duration) bool {
return !expirationTime.After(time.Now())
}

// isRecent checks if header is recent against the given blockTime.
func isRecent[H header.Header[H]](header H, blockTime time.Duration) bool {
return time.Since(header.Time()) <= blockTime+blockTime/2 // add half block time drift
// isRecent checks if header is recent against the given recency threshold.
func isRecent[H header.Header[H]](header H, blockTime, recencyThreshold time.Duration) bool {
if recencyThreshold == 0 {
recencyThreshold = blockTime + blockTime/2 // allow some drift by adding additional buffer of 1/2 of block time
}
return time.Since(header.Time()) <= recencyThreshold
}
2 changes: 1 addition & 1 deletion sync/sync_head_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ func TestSyncer_HeadWithTrustedHead(t *testing.T) {
wrappedGetter,
localStore,
headertest.NewDummySubscriber(),
// forces a request for a new sync target
WithBlockTime(time.Nanosecond),
WithRecencyThreshold(time.Nanosecond), // forces a request for a new sync target
// ensures that syncer's store contains a subjective head that is within
// the unbonding period so that the syncer can use a header from the network
// as a sync target
Expand Down
6 changes: 5 additions & 1 deletion sync/sync_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ func TestSyncSimpleRequestingHead(t *testing.T) {
localStore,
headertest.NewDummySubscriber(),
WithBlockTime(time.Second*30),
WithRecencyThreshold(time.Second*35), // add 5 second buffer
WithTrustingPeriod(time.Microsecond),
)
require.NoError(t, err)
Expand Down Expand Up @@ -72,6 +73,8 @@ func TestDoSyncFullRangeFromExternalPeer(t *testing.T) {
local.NewExchange(remoteStore),
localStore,
headertest.NewDummySubscriber(),
WithBlockTime(time.Nanosecond),
WithRecencyThreshold(time.Nanosecond),
)
require.NoError(t, err)
require.NoError(t, syncer.Start(ctx))
Expand Down Expand Up @@ -306,7 +309,8 @@ func TestSync_InvalidSyncTarget(t *testing.T) {
local.NewExchange[*headertest.DummyHeader](remoteStore),
localStore,
headertest.NewDummySubscriber(),
WithBlockTime(time.Nanosecond), // force syncer to request more recent sync target
WithBlockTime(time.Nanosecond),
WithRecencyThreshold(time.Nanosecond), // force syncer to request more recent sync target
)
require.NoError(t, err)

Expand Down

0 comments on commit 52e9af7

Please sign in to comment.