Skip to content

Commit 09ad764

Browse files
committed
Make bootstrapping handle its own timeouts
Currently, an engine registers timeouts into the handler, which schedules the timeouts on behalf of the the engine. The handler then notifies the engine when the timeout expired. However, the only engine that uses this mechanism is the bootstrapping engine, and not the other engine types such as the snowman and state sync engines. It therefore makes sense that the bootstrapper handle its own timeouts instead of delegating them to the handler. By moving the timeout handling into the bootstrapper, we can make the API of the common.Engine be slimmer by removing the Timeout() method from it. Signed-off-by: Yacov Manevich <yacov.manevich@avalabs.org>
1 parent 3cacae5 commit 09ad764

File tree

17 files changed

+172
-126
lines changed

17 files changed

+172
-126
lines changed

chains/manager.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -962,7 +962,6 @@ func (m *manager) createAvalancheChain(
962962
StartupTracker: startupTracker,
963963
Sender: snowmanMessageSender,
964964
BootstrapTracker: sb,
965-
Timer: h,
966965
PeerTracker: peerTracker,
967966
AncestorsMaxContainersReceived: m.BootstrapAncestorsMaxContainersReceived,
968967
DB: blockBootstrappingDB,
@@ -1358,7 +1357,6 @@ func (m *manager) createSnowmanChain(
13581357
StartupTracker: startupTracker,
13591358
Sender: messageSender,
13601359
BootstrapTracker: sb,
1361-
Timer: h,
13621360
PeerTracker: peerTracker,
13631361
AncestorsMaxContainersReceived: m.BootstrapAncestorsMaxContainersReceived,
13641362
DB: bootstrappingDB,

message/internal_msg_builder.go

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import (
1616
var (
1717
disconnected = &Disconnected{}
1818
gossipRequest = &GossipRequest{}
19-
timeout = &Timeout{}
2019

2120
_ fmt.Stringer = (*GetStateSummaryFrontierFailed)(nil)
2221
_ chainIDGetter = (*GetStateSummaryFrontierFailed)(nil)
@@ -50,8 +49,6 @@ var (
5049
_ fmt.Stringer = (*Disconnected)(nil)
5150

5251
_ fmt.Stringer = (*GossipRequest)(nil)
53-
54-
_ fmt.Stringer = (*Timeout)(nil)
5552
)
5653

5754
type GetStateSummaryFrontierFailed struct {
@@ -391,18 +388,3 @@ func InternalGossipRequest(
391388
expiration: mockable.MaxTime,
392389
}
393390
}
394-
395-
type Timeout struct{}
396-
397-
func (Timeout) String() string {
398-
return ""
399-
}
400-
401-
func InternalTimeout(nodeID ids.NodeID) InboundMessage {
402-
return &inboundMessage{
403-
nodeID: nodeID,
404-
op: TimeoutOp,
405-
message: timeout,
406-
expiration: mockable.MaxTime,
407-
}
408-
}

snow/engine/common/bootstrap_tracker.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,4 @@ type BootstrapTracker interface {
1313

1414
// Bootstrapped marks the named chain as being bootstrapped
1515
Bootstrapped(chainID ids.ID)
16-
17-
OnBootstrapCompleted() chan struct{}
1816
}

snow/engine/common/engine.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -415,9 +415,6 @@ type InternalHandler interface {
415415
// Notify this engine of peer changes.
416416
validators.Connector
417417

418-
// Notify this engine that a registered timeout has fired.
419-
Timeout(context.Context) error
420-
421418
// Gossip to the network a container on the accepted frontier
422419
Gossip(context.Context) error
423420

snow/engine/common/timer.go

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,3 @@
22
// See the file LICENSE for licensing terms.
33

44
package common
5-
6-
import "time"
7-
8-
// Timer describes the standard interface for specifying a timeout
9-
type Timer interface {
10-
// RegisterTimeout specifies how much time to delay the next timeout message
11-
// by. If the subnet has been bootstrapped, the timeout will fire
12-
// immediately.
13-
RegisterTimeout(time.Duration)
14-
}

snow/engine/common/traced_engine.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -329,13 +329,6 @@ func (e *tracedEngine) Disconnected(ctx context.Context, nodeID ids.NodeID) erro
329329
return e.engine.Disconnected(ctx, nodeID)
330330
}
331331

332-
func (e *tracedEngine) Timeout(ctx context.Context) error {
333-
ctx, span := e.tracer.Start(ctx, "tracedEngine.Timeout")
334-
defer span.End()
335-
336-
return e.engine.Timeout(ctx)
337-
}
338-
339332
func (e *tracedEngine) Gossip(ctx context.Context) error {
340333
ctx, span := e.tracer.Start(ctx, "tracedEngine.Gossip")
341334
defer span.End()

snow/engine/enginetest/engine.go

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import (
1919
)
2020

2121
var (
22-
errTimeout = errors.New("unexpectedly called Timeout")
2322
errGossip = errors.New("unexpectedly called Gossip")
2423
errNotify = errors.New("unexpectedly called Notify")
2524
errGetStateSummaryFrontier = errors.New("unexpectedly called GetStateSummaryFrontier")
@@ -189,19 +188,6 @@ func (e *Engine) Start(ctx context.Context, startReqID uint32) error {
189188
return errStart
190189
}
191190

192-
func (e *Engine) Timeout(ctx context.Context) error {
193-
if e.TimeoutF != nil {
194-
return e.TimeoutF(ctx)
195-
}
196-
if !e.CantTimeout {
197-
return nil
198-
}
199-
if e.T != nil {
200-
require.FailNow(e.T, errTimeout.Error())
201-
}
202-
return errTimeout
203-
}
204-
205191
func (e *Engine) Gossip(ctx context.Context) error {
206192
if e.GossipF != nil {
207193
return e.GossipF(ctx)

snow/engine/enginetest/timer.go

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,8 @@ import (
88
"time"
99

1010
"github.com/stretchr/testify/require"
11-
12-
"github.com/ava-labs/avalanchego/snow/engine/common"
1311
)
1412

15-
var _ common.Timer = (*Timer)(nil)
16-
1713
// Timer is a test timer
1814
type Timer struct {
1915
T *testing.T
@@ -23,15 +19,14 @@ type Timer struct {
2319
RegisterTimeoutF func(time.Duration)
2420
}
2521

26-
// Default set the default callable value to [cant]
27-
func (t *Timer) Default(cant bool) {
28-
t.CantRegisterTimout = cant
29-
}
30-
3122
func (t *Timer) RegisterTimeout(delay time.Duration) {
3223
if t.RegisterTimeoutF != nil {
3324
t.RegisterTimeoutF(delay)
3425
} else if t.CantRegisterTimout && t.T != nil {
3526
require.FailNow(t.T, "Unexpectedly called RegisterTimeout")
3627
}
3728
}
29+
30+
func (t *Timer) Preempt() {
31+
t.RegisterTimeout(time.Duration(0))
32+
}

snow/engine/snowman/bootstrap/bootstrapper.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ type Bootstrapper struct {
7070
Config
7171
shouldHalt func() bool
7272
*metrics
73-
73+
TimeoutRegistry TimeoutRegistry
7474
// list of NoOpsHandler for messages dropped by bootstrapper
7575
common.StateSummaryFrontierHandler
7676
common.AcceptedStateSummaryHandler
@@ -119,7 +119,7 @@ type Bootstrapper struct {
119119

120120
func New(config Config, onFinished func(ctx context.Context, lastReqID uint32) error) (*Bootstrapper, error) {
121121
metrics, err := newMetrics(config.Ctx.Registerer)
122-
return &Bootstrapper{
122+
bs := &Bootstrapper{
123123
shouldHalt: config.ShouldHalt,
124124
nonVerifyingParser: config.NonVerifyingParse,
125125
Config: config,
@@ -139,7 +139,15 @@ func New(config Config, onFinished func(ctx context.Context, lastReqID uint32) e
139139

140140
executedStateTransitions: math.MaxInt,
141141
onFinished: onFinished,
142-
}, err
142+
}
143+
144+
bs.TimeoutRegistry = newTimeoutHandler(func() {
145+
if err := bs.Timeout(context.TODO()); err != nil {
146+
bs.Config.Ctx.Log.Warn("Encountered error during bootstrapping: %w", zap.Error(err))
147+
}
148+
})
149+
150+
return bs, err
143151
}
144152

145153
func (b *Bootstrapper) Context() *snow.ConsensusContext {
@@ -696,14 +704,15 @@ func (b *Bootstrapper) tryStartExecuting(ctx context.Context) error {
696704

697705
// Notify the subnet that this chain is synced
698706
b.Config.BootstrapTracker.Bootstrapped(b.Ctx.ChainID)
707+
b.TimeoutRegistry.Preempt()
699708

700709
// If the subnet hasn't finished bootstrapping, this chain should remain
701710
// syncing.
702711
if !b.Config.BootstrapTracker.IsBootstrapped() {
703712
log("waiting for the remaining chains in this subnet to finish syncing")
704713
// Restart bootstrapping after [bootstrappingDelay] to keep up to date
705714
// on the latest tip.
706-
b.Config.Timer.RegisterTimeout(bootstrappingDelay)
715+
b.TimeoutRegistry.RegisterTimeout(bootstrappingDelay)
707716
b.awaitingTimeout = true
708717
return nil
709718
}

snow/engine/snowman/bootstrap/bootstrapper_test.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@ func newConfig(t *testing.T) (Config, ids.NodeID, *enginetest.Sender, *blocktest
103103
PeerTracker: peerTracker,
104104
Sender: sender,
105105
BootstrapTracker: bootstrapTracker,
106-
Timer: &enginetest.Timer{},
107106
AncestorsMaxContainersReceived: 2000,
108107
DB: memdb.New(),
109108
VM: vm,
@@ -155,7 +154,6 @@ func TestBootstrapperStartsOnlyIfEnoughStakeIsConnected(t *testing.T) {
155154
PeerTracker: peerTracker,
156155
Sender: sender,
157156
BootstrapTracker: &enginetest.BootstrapTracker{},
158-
Timer: &enginetest.Timer{},
159157
AncestorsMaxContainersReceived: 2000,
160158
DB: memdb.New(),
161159
VM: vm,
@@ -180,6 +178,7 @@ func TestBootstrapperStartsOnlyIfEnoughStakeIsConnected(t *testing.T) {
180178
}
181179
bs, err := New(cfg, dummyCallback)
182180
require.NoError(err)
181+
bs.TimeoutRegistry = &enginetest.Timer{}
183182

184183
vm.CantSetState = false
185184
vm.CantConnected = true
@@ -236,6 +235,7 @@ func TestBootstrapperSingleFrontier(t *testing.T) {
236235
},
237236
)
238237
require.NoError(err)
238+
bs.TimeoutRegistry = &enginetest.Timer{}
239239

240240
require.NoError(bs.Start(context.Background(), 0))
241241

@@ -264,6 +264,7 @@ func TestBootstrapperUnknownByzantineResponse(t *testing.T) {
264264
},
265265
)
266266
require.NoError(err)
267+
bs.TimeoutRegistry = &enginetest.Timer{}
267268

268269
require.NoError(bs.Start(context.Background(), 0))
269270

@@ -309,6 +310,7 @@ func TestBootstrapperPartialFetch(t *testing.T) {
309310
},
310311
)
311312
require.NoError(err)
313+
bs.TimeoutRegistry = &enginetest.Timer{}
312314

313315
require.NoError(bs.Start(context.Background(), 0))
314316

@@ -359,6 +361,7 @@ func TestBootstrapperEmptyResponse(t *testing.T) {
359361
},
360362
)
361363
require.NoError(err)
364+
bs.TimeoutRegistry = &enginetest.Timer{}
362365

363366
require.NoError(bs.Start(context.Background(), 0))
364367

@@ -407,6 +410,7 @@ func TestBootstrapperAncestors(t *testing.T) {
407410
},
408411
)
409412
require.NoError(err)
413+
bs.TimeoutRegistry = &enginetest.Timer{}
410414

411415
require.NoError(bs.Start(context.Background(), 0))
412416

@@ -452,6 +456,7 @@ func TestBootstrapperFinalized(t *testing.T) {
452456
},
453457
)
454458
require.NoError(err)
459+
bs.TimeoutRegistry = &enginetest.Timer{}
455460

456461
require.NoError(bs.Start(context.Background(), 0))
457462

@@ -494,6 +499,7 @@ func TestRestartBootstrapping(t *testing.T) {
494499
},
495500
)
496501
require.NoError(err)
502+
bs.TimeoutRegistry = &enginetest.Timer{}
497503

498504
require.NoError(bs.Start(context.Background(), 0))
499505

@@ -558,6 +564,7 @@ func TestBootstrapOldBlockAfterStateSync(t *testing.T) {
558564
},
559565
)
560566
require.NoError(err)
567+
bs.TimeoutRegistry = &enginetest.Timer{}
561568

562569
require.NoError(bs.Start(context.Background(), 0))
563570

@@ -598,6 +605,7 @@ func TestBootstrapContinueAfterHalt(t *testing.T) {
598605
},
599606
)
600607
require.NoError(err)
608+
bs.TimeoutRegistry = &enginetest.Timer{}
601609

602610
getBlockF := vm.GetBlockF
603611
vm.GetBlockF = func(ctx context.Context, blkID ids.ID) (snowman.Block, error) {
@@ -690,7 +698,6 @@ func TestBootstrapNoParseOnNew(t *testing.T) {
690698
PeerTracker: peerTracker,
691699
Sender: sender,
692700
BootstrapTracker: bootstrapTracker,
693-
Timer: &enginetest.Timer{},
694701
AncestorsMaxContainersReceived: 2000,
695702
DB: intervalDB,
696703
VM: vm,
@@ -728,6 +735,7 @@ func TestBootstrapperReceiveStaleAncestorsMessage(t *testing.T) {
728735
},
729736
)
730737
require.NoError(err)
738+
bs.TimeoutRegistry = &enginetest.Timer{}
731739

732740
require.NoError(bs.Start(context.Background(), 0))
733741

@@ -772,6 +780,7 @@ func TestBootstrapperRollbackOnSetState(t *testing.T) {
772780
return nil
773781
},
774782
)
783+
bs.TimeoutRegistry = &enginetest.Timer{}
775784
require.NoError(err)
776785

777786
vm.SetStateF = func(context.Context, snow.State) error {

0 commit comments

Comments
 (0)