From 0b7364f54bd204fc9a007df90dce62a7b85176e8 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Sun, 16 Jun 2024 19:15:05 -0400 Subject: [PATCH] graph+server: add template for new graph Builder sub-system This is preparation for an upcoming commit that will move over various responsibilities from the ChannelRouter to the graph Builder. So that that commit can be a pure code-move commit, the template for the new sub-system is added up front here. --- graph/builder.go | 57 ++++++++++++++++++++++++++++++++++++++++++++++++ graph/log.go | 47 +++++++++++++++++++++++++++++++++++++++ log.go | 2 ++ server.go | 14 ++++++++++++ 4 files changed, 120 insertions(+) create mode 100644 graph/builder.go create mode 100644 graph/log.go diff --git a/graph/builder.go b/graph/builder.go new file mode 100644 index 000000000..633e33bd1 --- /dev/null +++ b/graph/builder.go @@ -0,0 +1,57 @@ +package graph + +import ( + "sync" + "sync/atomic" +) + +// Config holds the configuration required by the Builder. +type Config struct{} + +// Builder builds and maintains a view of the Lightning Network graph. +type Builder struct { + started atomic.Bool + stopped atomic.Bool + + cfg *Config + + quit chan struct{} + wg sync.WaitGroup +} + +// NewBuilder constructs a new Builder. +func NewBuilder(cfg *Config) (*Builder, error) { + return &Builder{ + cfg: cfg, + quit: make(chan struct{}), + }, nil +} + +// Start launches all the goroutines the Builder requires to carry out its +// duties. If the builder has already been started, then this method is a noop. +func (b *Builder) Start() error { + if !b.started.CompareAndSwap(false, true) { + return nil + } + + log.Info("Builder starting") + + return nil +} + +// Stop signals to the Builder that it should halt all routines. This method +// will *block* until all goroutines have excited. If the builder has already +// stopped then this method will return immediately. +func (b *Builder) Stop() error { + if !b.stopped.CompareAndSwap(false, true) { + return nil + } + + log.Info("Builder shutting down...") + defer log.Debug("Builder shutdown complete") + + close(b.quit) + b.wg.Wait() + + return nil +} diff --git a/graph/log.go b/graph/log.go new file mode 100644 index 000000000..2bd55297a --- /dev/null +++ b/graph/log.go @@ -0,0 +1,47 @@ +package graph + +import ( + "github.com/btcsuite/btclog" + "github.com/lightningnetwork/lnd/build" +) + +// log is a logger that is initialized with no output filters. This means the +// package will not perform any logging by default until the caller requests +// it. +var log btclog.Logger + +const Subsystem = "GRPH" + +// The default amount of logging is none. +func init() { + UseLogger(build.NewSubLogger(Subsystem, nil)) +} + +// DisableLog disables all library log output. Logging output is disabled by +// by default until UseLogger is called. +func DisableLog() { + UseLogger(btclog.Disabled) +} + +// UseLogger uses a specified Logger to output package logging info. This +// should be used in preference to SetLogWriter if the caller is also using +// btclog. +func UseLogger(logger btclog.Logger) { + log = logger +} + +// logClosure is used to provide a closure over expensive logging operations so +// don't have to be performed when the logging level doesn't warrant it. +type logClosure func() string + +// String invokes the underlying function and returns the result. +func (c logClosure) String() string { + return c() +} + +// newLogClosure returns a new closure over a function that returns a string +// which itself provides a Stringer interface so that it can be used with the +// logging system. +func newLogClosure(c func() string) logClosure { + return logClosure(c) +} diff --git a/log.go b/log.go index f6da0235a..1b170f5ea 100644 --- a/log.go +++ b/log.go @@ -18,6 +18,7 @@ import ( "github.com/lightningnetwork/lnd/contractcourt" "github.com/lightningnetwork/lnd/discovery" "github.com/lightningnetwork/lnd/funding" + "github.com/lightningnetwork/lnd/graph" "github.com/lightningnetwork/lnd/healthcheck" "github.com/lightningnetwork/lnd/htlcswitch" "github.com/lightningnetwork/lnd/invoices" @@ -179,6 +180,7 @@ func SetupLoggers(root *build.RotatingLogWriter, interceptor signal.Interceptor) AddSubLogger(root, btcwallet.Subsystem, interceptor, btcwallet.UseLogger) AddSubLogger(root, rpcwallet.Subsystem, interceptor, rpcwallet.UseLogger) AddSubLogger(root, peersrpc.Subsystem, interceptor, peersrpc.UseLogger) + AddSubLogger(root, graph.Subsystem, interceptor, graph.UseLogger) } // AddSubLogger is a helper method to conveniently create and register the diff --git a/server.go b/server.go index f32fb611e..17108ee46 100644 --- a/server.go +++ b/server.go @@ -41,6 +41,7 @@ import ( "github.com/lightningnetwork/lnd/feature" "github.com/lightningnetwork/lnd/fn" "github.com/lightningnetwork/lnd/funding" + "github.com/lightningnetwork/lnd/graph" "github.com/lightningnetwork/lnd/healthcheck" "github.com/lightningnetwork/lnd/htlcswitch" "github.com/lightningnetwork/lnd/htlcswitch/hop" @@ -271,6 +272,8 @@ type server struct { missionControl *routing.MissionControl + graphBuilder *graph.Builder + chanRouter *routing.ChannelRouter controlTower routing.ControlTower @@ -973,6 +976,11 @@ func newServer(cfg *Config, listenAddrs []net.Addr, strictPruning := cfg.Bitcoin.Node == "neutrino" || cfg.Routing.StrictZombiePruning + s.graphBuilder, err = graph.NewBuilder(&graph.Config{}) + if err != nil { + return nil, fmt.Errorf("can't create graph builder: %w", err) + } + s.chanRouter, err = routing.New(routing.Config{ SelfNode: selfNode.PubKeyBytes, RoutingGraph: graphsession.NewRoutingGraph(chanGraph), @@ -2019,6 +2027,12 @@ func (s *server) Start() error { } cleanup = cleanup.add(s.authGossiper.Stop) + if err := s.graphBuilder.Start(); err != nil { + startErr = err + return + } + cleanup = cleanup.add(s.graphBuilder.Stop) + if err := s.chanRouter.Start(); err != nil { startErr = err return