Skip to content

Commit a99d7ac

Browse files
committed
estimation test
1 parent 88e6f69 commit a99d7ac

File tree

4 files changed

+64
-11
lines changed

4 files changed

+64
-11
lines changed

headertest/dummy_suite.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"time"
66
)
77

8+
const HeaderTime = time.Nanosecond
9+
810
// DummySuite provides everything you need to test chain of DummyHeaders.
911
// If not, please don't hesitate to extend it for your case.
1012
type DummySuite struct {
@@ -42,7 +44,7 @@ func (s *DummySuite) NextHeader() *DummyHeader {
4244
}
4345

4446
dh := RandDummyHeader(s.t)
45-
dh.Timestamp = s.head.Time().Add(time.Nanosecond)
47+
dh.Timestamp = s.head.Time().Add(HeaderTime)
4648
dh.HeightI = s.head.Height() + 1
4749
dh.PreviousHash = s.head.Hash()
4850
dh.Chainid = s.head.ChainID()

sync/sync_head.go

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,7 @@ func (s *Syncer[H]) Head(ctx context.Context, _ ...header.HeadOption[H]) (H, err
5050
// NOTE: We could trust the netHead like we do during 'automatic subjective initialization'
5151
// but in this case our subjective head is not expired, so we should verify netHead
5252
// and only if it is valid, set it as new head
53-
err = s.incomingNetworkHead(ctx, netHead)
54-
if err != nil {
55-
log.Errorw("incoming network head failed",
56-
"height", netHead.Height(),
57-
"hash", netHead.Hash().String(),
58-
"err", err)
59-
}
53+
_ = s.incomingNetworkHead(ctx, netHead)
6054
// netHead was either accepted or rejected as the new subjective
6155
// anyway return most current known subjective head
6256
return s.subjectiveHead(ctx)
@@ -155,6 +149,11 @@ func (s *Syncer[H]) incomingNetworkHead(ctx context.Context, head H) error {
155149
// To be reworked by bsync.
156150
_, err := s.subjectiveTail(ctx, head)
157151
if err != nil {
152+
log.Errorw("subjective tail failed",
153+
"new_head", head.Height(),
154+
"hash", head.Hash().String(),
155+
"err", err,
156+
)
158157
return err
159158
}
160159

sync/sync_tail.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212

1313
// TODO:
1414
// * Refactor tests
15-
// * Write tests for estimation
1615
// * Ensure sync always happen on start
1716

1817
// subjectiveTail returns the current Tail header.
@@ -26,19 +25,23 @@ func (s *Syncer[H]) subjectiveTail(ctx context.Context, head H) (H, error) {
2625

2726
var fetched bool
2827
if tailHash, outdated := s.isTailHashOutdated(tail); outdated {
28+
log.Debugw("tail hash updated", "hash", tailHash)
2929
tail, err = s.store.Get(ctx, tailHash)
3030
if err != nil {
31+
log.Debugw("tail hash not available locally, fetching...", "hash", tailHash)
3132
tail, err = s.getter.Get(ctx, tailHash)
3233
if err != nil {
3334
return tail, fmt.Errorf("getting SyncFromHash tail(%x): %w", tailHash, err)
3435
}
3536
fetched = true
3637
}
3738
} else if tailHeight, outdated := s.isTailHeightOutdated(tail); outdated {
39+
log.Debugw("tail height updated", "height", tailHeight)
3840
if tailHeight <= s.store.Height() {
3941
tail, err = s.store.GetByHeight(ctx, tailHeight)
4042
}
4143
if err != nil || tailHeight != tail.Height() {
44+
log.Debugw("tail height not available locally, fetching...", "height", tailHeight)
4245
tail, err = s.getter.GetByHeight(ctx, tailHeight)
4346
if err != nil {
4447
return tail, fmt.Errorf("getting SyncFromHeight tail(%d): %w", tailHeight, err)
@@ -62,22 +65,26 @@ func (s *Syncer[H]) subjectiveTail(ctx context.Context, head H) (H, error) {
6265
// current tail is relevant as is
6366
return tail, nil
6467
}
68+
log.Debugw("current tail is beyond pruning window", "current_height", tail.Height(), "diff", diff.String())
6569

6670
toDeleteEstimate := uint64(diff / s.Params.blockTime) //nolint:gosec
6771
estimatedNewTail := tail.Height() + toDeleteEstimate
6872

6973
for {
7074
tail, err = s.store.GetByHeight(ctx, estimatedNewTail)
7175
if err != nil {
72-
log.Errorw("getting estimated tail from store ", "error", err)
76+
log.Errorw("getting estimated tail from store", "height", estimatedNewTail, "error", err)
7377
return tail, err
7478
}
75-
if tail.Time().UTC().Before(cutoffTime) {
79+
if tail.Time().UTC().Compare(cutoffTime) <= 0 {
80+
// tail before or equal to cutoffTime
7681
break
7782
}
7883

7984
estimatedNewTail++
8085
}
86+
87+
log.Debugw("estimated new tail", "new_height", tail.Height())
8188
}
8289
}
8390

sync/sync_tail_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,51 @@ import (
1414
"github.com/celestiaorg/go-header/store"
1515
)
1616

17+
func TestSyncer_TailEstimation(t *testing.T) {
18+
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
19+
t.Cleanup(cancel)
20+
21+
remoteStore := headertest.NewStore[*headertest.DummyHeader](t, headertest.NewTestSuite(t), 100)
22+
23+
ds := dssync.MutexWrap(datastore.NewMapDatastore())
24+
localStore, err := store.NewStore[*headertest.DummyHeader](
25+
ds,
26+
store.WithWriteBatchSize(1),
27+
)
28+
require.NoError(t, err)
29+
err = localStore.Start(ctx)
30+
require.NoError(t, err)
31+
32+
syncer, err := NewSyncer[*headertest.DummyHeader](
33+
remoteStore,
34+
localStore,
35+
headertest.NewDummySubscriber(),
36+
WithBlockTime(headertest.HeaderTime),
37+
WithPruningWindow(time.Nanosecond*50),
38+
)
39+
require.NoError(t, err)
40+
41+
err = syncer.Start(ctx)
42+
require.NoError(t, err)
43+
time.Sleep(time.Millisecond * 10)
44+
err = syncer.SyncWait(ctx)
45+
require.NoError(t, err)
46+
require.EqualValues(t, 100, syncer.State().Height)
47+
48+
tail, err := localStore.Tail(ctx)
49+
require.NoError(t, err)
50+
require.EqualValues(t, tail.Height(), 1)
51+
52+
// simulate new header arrival by triggering recency check
53+
head, err := syncer.Head(ctx)
54+
require.NoError(t, err)
55+
require.Equal(t, head.Height(), remoteStore.Height())
56+
57+
tail, err = localStore.Tail(ctx)
58+
require.NoError(t, err)
59+
require.EqualValues(t, 50, tail.Height())
60+
}
61+
1762
func TestSyncer_TailReconfiguration(t *testing.T) {
1863
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
1964
t.Cleanup(cancel)

0 commit comments

Comments
 (0)