Skip to content

Commit

Permalink
Simplify avalanche bootstrapping (#2286)
Browse files Browse the repository at this point in the history
  • Loading branch information
StephenButtolph authored Nov 15, 2023
1 parent 5dff153 commit d00b67f
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 540 deletions.
35 changes: 13 additions & 22 deletions chains/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -929,29 +929,20 @@ func (m *manager) createAvalancheChain(
}

// create bootstrap gear
_, specifiedLinearizationTime := version.CortinaTimes[ctx.NetworkID]
specifiedLinearizationTime = specifiedLinearizationTime && ctx.ChainID == m.XChainID
avalancheBootstrapperConfig := avbootstrap.Config{
Config: common.Config{
Ctx: ctx,
Beacons: vdrs,
SampleK: sampleK,
StartupTracker: startupTracker,
Alpha: bootstrapWeight/2 + 1, // must be > 50%
Sender: avalancheMessageSender,
BootstrapTracker: sb,
Timer: h,
RetryBootstrap: m.RetryBootstrap,
RetryBootstrapWarnFrequency: m.RetryBootstrapWarnFrequency,
AncestorsMaxContainersReceived: m.BootstrapAncestorsMaxContainersReceived,
SharedCfg: &common.SharedConfig{},
},
AllGetsServer: avaGetHandler,
VtxBlocked: vtxBlocker,
TxBlocked: txBlocker,
Manager: vtxManager,
VM: linearizableVM,
LinearizeOnStartup: !specifiedLinearizationTime,
AllGetsServer: avaGetHandler,
Ctx: ctx,
Beacons: vdrs,
StartupTracker: startupTracker,
Sender: avalancheMessageSender,
AncestorsMaxContainersReceived: m.BootstrapAncestorsMaxContainersReceived,
VtxBlocked: vtxBlocker,
TxBlocked: txBlocker,
Manager: vtxManager,
VM: linearizableVM,
}
if ctx.ChainID == m.XChainID {
avalancheBootstrapperConfig.StopVertexID = version.CortinaXChainStopVertexID[ctx.NetworkID]
}

avalancheBootstrapper, err := avbootstrap.New(
Expand Down
2 changes: 1 addition & 1 deletion node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -1022,7 +1022,7 @@ func (n *Node) initChainManager(avaxAssetID ids.ID) error {
BootstrapAncestorsMaxContainersSent: n.Config.BootstrapAncestorsMaxContainersSent,
BootstrapAncestorsMaxContainersReceived: n.Config.BootstrapAncestorsMaxContainersReceived,
ApricotPhase4Time: version.GetApricotPhase4Time(n.Config.NetworkID),
ApricotPhase4MinPChainHeight: version.GetApricotPhase4MinPChainHeight(n.Config.NetworkID),
ApricotPhase4MinPChainHeight: version.ApricotPhase4MinPChainHeight[n.Config.NetworkID],
ResourceTracker: n.resourceTracker,
StateSyncBeacons: n.Config.StateSyncIDs,
TracingEnabled: n.Config.TraceConfig.Enabled,
Expand Down
141 changes: 53 additions & 88 deletions snow/engine/avalanche/bootstrap/bootstrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ func New(

StateSummaryFrontierHandler: common.NewNoOpStateSummaryFrontierHandler(config.Ctx.Log),
AcceptedStateSummaryHandler: common.NewNoOpAcceptedStateSummaryHandler(config.Ctx.Log),
AcceptedFrontierHandler: common.NewNoOpAcceptedFrontierHandler(config.Ctx.Log),
AcceptedHandler: common.NewNoOpAcceptedHandler(config.Ctx.Log),
PutHandler: common.NewNoOpPutHandler(config.Ctx.Log),
QueryHandler: common.NewNoOpQueryHandler(config.Ctx.Log),
ChitsHandler: common.NewNoOpChitsHandler(config.Ctx.Log),
Expand All @@ -52,41 +54,41 @@ func New(
OnFinished: onFinished,
},
}

if err := b.metrics.Initialize("bs", config.Ctx.AvalancheRegisterer); err != nil {
return nil, err
}

config.Config.Bootstrapable = b
b.Bootstrapper = common.NewCommonBootstrapper(config.Config)
return b, nil
return b, b.metrics.Initialize("bs", config.Ctx.AvalancheRegisterer)
}

// Note: To align with the Snowman invariant, it should be guaranteed the VM is
// not used until after the bootstrapper has been Started.
type bootstrapper struct {
Config
common.Halter

// list of NoOpsHandler for messages dropped by bootstrapper
common.StateSummaryFrontierHandler
common.AcceptedStateSummaryHandler
common.AcceptedFrontierHandler
common.AcceptedHandler
common.PutHandler
common.QueryHandler
common.ChitsHandler
common.AppHandler

common.Bootstrapper
common.Fetcher
metrics

started bool

// IDs of vertices that we will send a GetAncestors request for once we are
// not at the max number of outstanding requests
needToFetch set.Set[ids.ID]

// Contains IDs of vertices that have recently been processed
processedCache *cache.LRU[ids.ID, struct{}]

// Tracks the last requestID that was used in a request
requestID uint32
}

func (b *bootstrapper) Context() *snow.ConsensusContext {
return b.Ctx
}

func (b *bootstrapper) Clear(context.Context) error {
Expand Down Expand Up @@ -256,16 +258,7 @@ func (b *bootstrapper) Connected(
return err
}

if err := b.StartupTracker.Connected(ctx, nodeID, nodeVersion); err != nil {
return err
}

if b.started || !b.StartupTracker.ShouldStart() {
return nil
}

b.started = true
return b.Startup(ctx)
return b.StartupTracker.Connected(ctx, nodeID, nodeVersion)
}

func (b *bootstrapper) Disconnected(ctx context.Context, nodeID ids.NodeID) error {
Expand Down Expand Up @@ -327,7 +320,7 @@ func (b *bootstrapper) Start(ctx context.Context, startReqID uint32) error {
return err
}

b.Config.SharedCfg.RequestID = startReqID
b.requestID = startReqID

// If the network was already linearized, don't attempt to linearize it
// again.
Expand All @@ -336,38 +329,38 @@ func (b *bootstrapper) Start(ctx context.Context, startReqID uint32) error {
return fmt.Errorf("failed to get linearization status: %w", err)
}
if linearized {
edge := b.Manager.Edge(ctx)
return b.ForceAccepted(ctx, edge)
return b.ForceAccepted(ctx, nil)
}

// If requested, assume the currently accepted state is what was linearized.
//
// Note: This is used to linearize networks that were created after the
// linearization occurred.
if b.Config.LinearizeOnStartup {
edge := b.Manager.Edge(ctx)
stopVertex, err := b.Manager.BuildStopVtx(ctx, edge)
if err != nil {
return fmt.Errorf("failed to create stop vertex: %w", err)
}
if err := stopVertex.Accept(ctx); err != nil {
return fmt.Errorf("failed to accept stop vertex: %w", err)
}

stopVertexID := stopVertex.ID()
b.Ctx.Log.Info("accepted stop vertex",
zap.Stringer("vtxID", stopVertexID),
// If a stop vertex is well known, accept that.
if b.Config.StopVertexID != ids.Empty {
b.Ctx.Log.Info("using well known stop vertex",
zap.Stringer("vtxID", b.Config.StopVertexID),
)

return b.ForceAccepted(ctx, []ids.ID{stopVertexID})
return b.ForceAccepted(ctx, []ids.ID{b.Config.StopVertexID})
}

if !b.StartupTracker.ShouldStart() {
return nil
// If a stop vertex isn't well known, treat the current state as the final
// DAG state.
//
// Note: This is used to linearize networks that were created after the
// linearization occurred.
edge := b.Manager.Edge(ctx)
stopVertex, err := b.Manager.BuildStopVtx(ctx, edge)
if err != nil {
return fmt.Errorf("failed to create stop vertex: %w", err)
}
if err := stopVertex.Accept(ctx); err != nil {
return fmt.Errorf("failed to accept stop vertex: %w", err)
}

b.started = true
return b.Startup(ctx)
stopVertexID := stopVertex.ID()
b.Ctx.Log.Info("generated stop vertex",
zap.Stringer("vtxID", stopVertexID),
)

return b.ForceAccepted(ctx, nil)
}

func (b *bootstrapper) HealthCheck(ctx context.Context) (interface{}, error) {
Expand Down Expand Up @@ -410,10 +403,10 @@ func (b *bootstrapper) fetch(ctx context.Context, vtxIDs ...ids.ID) error {
return fmt.Errorf("dropping request for %s as there are no validators", vtxID)
}
validatorID := validatorIDs[0]
b.Config.SharedCfg.RequestID++
b.requestID++

b.OutstandingRequests.Add(validatorID, b.Config.SharedCfg.RequestID, vtxID)
b.Config.Sender.SendGetAncestors(ctx, validatorID, b.Config.SharedCfg.RequestID, vtxID) // request vertex and ancestors
b.OutstandingRequests.Add(validatorID, b.requestID, vtxID)
b.Config.Sender.SendGetAncestors(ctx, validatorID, b.requestID, vtxID) // request vertex and ancestors
}
return b.checkFinish(ctx)
}
Expand Down Expand Up @@ -498,15 +491,9 @@ func (b *bootstrapper) process(ctx context.Context, vtxs ...avalanche.Vertex) er

verticesFetchedSoFar := b.VtxBlocked.Jobs.PendingJobs()
if verticesFetchedSoFar%common.StatusUpdateFrequency == 0 { // Periodically print progress
if !b.Config.SharedCfg.Restarted {
b.Ctx.Log.Info("fetched vertices",
zap.Uint64("numVerticesFetched", verticesFetchedSoFar),
)
} else {
b.Ctx.Log.Debug("fetched vertices",
zap.Uint64("numVerticesFetched", verticesFetchedSoFar),
)
}
b.Ctx.Log.Info("fetched vertices",
zap.Uint64("numVerticesFetched", verticesFetchedSoFar),
)
}

parents, err := vtx.Parents()
Expand Down Expand Up @@ -578,66 +565,44 @@ func (b *bootstrapper) ForceAccepted(ctx context.Context, acceptedContainerIDs [
// checkFinish repeatedly executes pending transactions and requests new frontier blocks until there aren't any new ones
// after which it finishes the bootstrap process
func (b *bootstrapper) checkFinish(ctx context.Context) error {
// If there are outstanding requests for vertices or we still need to fetch vertices, we can't finish
pendingJobs := b.VtxBlocked.MissingIDs()
if b.IsBootstrapped() || len(pendingJobs) > 0 {
// If we still need to fetch vertices, we can't finish
if len(b.VtxBlocked.MissingIDs()) > 0 {
return nil
}

if !b.Config.SharedCfg.Restarted {
b.Ctx.Log.Info("executing transactions")
} else {
b.Ctx.Log.Debug("executing transactions")
}

b.Ctx.Log.Info("executing transactions")
_, err := b.TxBlocked.ExecuteAll(
ctx,
b.Config.Ctx,
b,
b.Config.SharedCfg.Restarted,
false,
b.Ctx.TxAcceptor,
)
if err != nil || b.Halted() {
return err
}

if !b.Config.SharedCfg.Restarted {
b.Ctx.Log.Info("executing vertices")
} else {
b.Ctx.Log.Debug("executing vertices")
}

b.Ctx.Log.Info("executing vertices")
_, err = b.VtxBlocked.ExecuteAll(
ctx,
b.Config.Ctx,
b,
b.Config.SharedCfg.Restarted,
false,
b.Ctx.VertexAcceptor,
)
if err != nil || b.Halted() {
return err
}

// If the chain is linearized, we should immediately move on to start
// bootstrapping snowman.
linearized, err := b.Manager.StopVertexAccepted(ctx)
if err != nil {
return err
}
if !linearized {
b.Ctx.Log.Debug("checking for stop vertex before finishing bootstrapping")
return b.Restart(ctx, true)
}

// Invariant: edge will only be the stop vertex after its acceptance.
// Invariant: edge will only be the stop vertex
edge := b.Manager.Edge(ctx)
stopVertexID := edge[0]
if err := b.VM.Linearize(ctx, stopVertexID); err != nil {
return err
}

b.processedCache.Flush()
return b.OnFinished(ctx, b.Config.SharedCfg.RequestID)
return b.OnFinished(ctx, b.requestID)
}

// A vertex is less than another vertex if it is unknown. Ties are broken by
Expand Down
Loading

0 comments on commit d00b67f

Please sign in to comment.