controller.go 2.92 KB
Newer Older
1 2 3 4 5
package syncnode

import (
	"context"
	"fmt"
6
	"sync/atomic"
7

8
	"github.com/ethereum-optimism/optimism/op-service/eth"
9 10
	"github.com/ethereum/go-ethereum/log"

11
	"github.com/ethereum-optimism/optimism/op-node/rollup/event"
12 13
	"github.com/ethereum-optimism/optimism/op-service/locks"
	"github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/depset"
14
	"github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/superevents"
15 16 17
	"github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types"
)

18 19 20
// SyncNodesController manages a collection of active sync nodes.
// Sync nodes are used to sync the supervisor,
// and subject to the canonical chain view as followed by the supervisor.
21
type SyncNodesController struct {
22
	logger log.Logger
23

24
	id          atomic.Uint64
25
	controllers locks.RWMap[eth.ChainID, *locks.RWMap[*ManagedNode, struct{}]]
26

27 28 29 30
	eventSys event.System

	emitter event.Emitter

31
	backend backend
32 33 34 35

	depSet depset.DependencySet
}

36 37
var _ event.AttachEmitter = (*SyncNodesController)(nil)

38
// NewSyncNodesController creates a new SyncNodeController
39
func NewSyncNodesController(l log.Logger, depset depset.DependencySet, eventSys event.System, backend backend) *SyncNodesController {
40
	return &SyncNodesController{
41 42 43 44
		logger:   l,
		depSet:   depset,
		eventSys: eventSys,
		backend:  backend,
45 46 47
	}
}

48 49 50 51 52 53 54 55
func (snc *SyncNodesController) AttachEmitter(em event.Emitter) {
	snc.emitter = em
}

func (snc *SyncNodesController) OnEvent(ev event.Event) bool {
	return false
}

56
func (snc *SyncNodesController) Close() error {
57
	snc.controllers.Range(func(chainID eth.ChainID, controllers *locks.RWMap[*ManagedNode, struct{}]) bool {
58 59 60 61 62 63
		controllers.Range(func(node *ManagedNode, _ struct{}) bool {
			node.Close()
			return true
		})
		return true
	})
64 65 66
	return nil
}

67 68
// AttachNodeController attaches a node to be managed by the supervisor.
// If noSubscribe, the node is not actively polled/subscribed to, and requires manual ManagedNode.PullEvents calls.
69
func (snc *SyncNodesController) AttachNodeController(chainID eth.ChainID, ctrl SyncControl, noSubscribe bool) (Node, error) {
70 71
	if !snc.depSet.HasChain(chainID) {
		return nil, fmt.Errorf("chain %v not in dependency set: %w", chainID, types.ErrUnknownChain)
72
	}
73
	// lazy init the controllers map for this chain
74 75 76 77 78 79 80 81 82 83
	snc.controllers.Default(chainID, func() *locks.RWMap[*ManagedNode, struct{}] {
		return &locks.RWMap[*ManagedNode, struct{}]{}
	})
	controllersForChain, _ := snc.controllers.Get(chainID)
	node := NewManagedNode(snc.logger, chainID, ctrl, snc.backend, noSubscribe)

	nodeID := snc.id.Add(1)
	name := fmt.Sprintf("syncnode-%s-%d", chainID, nodeID)
	snc.eventSys.Register(name, node, event.DefaultRegisterOpts())

84 85 86 87
	controllersForChain.Set(node, struct{}{})
	anchor, err := ctrl.AnchorPoint(context.Background())
	if err != nil {
		return nil, fmt.Errorf("failed to get anchor point: %w", err)
88
	}
89 90 91 92
	snc.emitter.Emit(superevents.AnchorEvent{
		ChainID: chainID,
		Anchor:  anchor,
	})
93 94
	node.Start()
	return node, nil
95
}