From 9db17d7a228128a70c280c66210c5721a29a5dac Mon Sep 17 00:00:00 2001 From: positiveblue Date: Fri, 26 Nov 2021 16:03:00 -0800 Subject: [PATCH] lnrpc: add peersrpc subsever --- lnrpc/peersrpc/config_active.go | 6 ++ lnrpc/peersrpc/config_default.go | 7 ++ lnrpc/peersrpc/driver.go | 55 ++++++++++++ lnrpc/peersrpc/log.go | 48 +++++++++++ lnrpc/peersrpc/peers_server.go | 142 +++++++++++++++++++++++++++++++ 5 files changed, 258 insertions(+) create mode 100644 lnrpc/peersrpc/config_active.go create mode 100644 lnrpc/peersrpc/config_default.go create mode 100644 lnrpc/peersrpc/driver.go create mode 100644 lnrpc/peersrpc/log.go create mode 100644 lnrpc/peersrpc/peers_server.go diff --git a/lnrpc/peersrpc/config_active.go b/lnrpc/peersrpc/config_active.go new file mode 100644 index 000000000..f661875fc --- /dev/null +++ b/lnrpc/peersrpc/config_active.go @@ -0,0 +1,6 @@ +//go:build peersrpc +// +build peersrpc + +package peersrpc + +type Config struct{} diff --git a/lnrpc/peersrpc/config_default.go b/lnrpc/peersrpc/config_default.go new file mode 100644 index 000000000..8b359a85c --- /dev/null +++ b/lnrpc/peersrpc/config_default.go @@ -0,0 +1,7 @@ +//go:build !peersrpc +// +build !peersrpc + +package peersrpc + +// Config is empty for non-peersrpc builds. +type Config struct{} diff --git a/lnrpc/peersrpc/driver.go b/lnrpc/peersrpc/driver.go new file mode 100644 index 000000000..8abf3ed92 --- /dev/null +++ b/lnrpc/peersrpc/driver.go @@ -0,0 +1,55 @@ +//go:build peersrpc +// +build peersrpc + +package peersrpc + +import ( + "fmt" + + "github.com/lightningnetwork/lnd/lnrpc" +) + +// createNewSubServer is a helper method that will create the new sub server +// given the main config dispatcher method. If we're unable to find the config +// that is meant for us in the config dispatcher, then we'll exit with an +// error. +func createNewSubServer(configRegistry lnrpc.SubServerConfigDispatcher) ( + *Server, lnrpc.MacaroonPerms, error) { + + // We'll attempt to look up the config that we expect, according to our + // subServerName name. If we can't find this, then we'll exit with an + // error, as we're unable to properly initialize ourselves without this + // config. + subServerConf, ok := configRegistry.FetchConfig(subServerName) + if !ok { + return nil, nil, fmt.Errorf("unable to find config for "+ + "subserver type %s", subServerName) + } + + // Now that we've found an object mapping to our service name, we'll + // ensure that it's the type we need. + config, ok := subServerConf.(*Config) + if !ok { + return nil, nil, fmt.Errorf("wrong type of config for "+ + "subserver %s, expected %T got %T", subServerName, + &Config{}, subServerConf) + } + + return New(config) +} + +func init() { + subServer := &lnrpc.SubServerDriver{ + SubServerName: subServerName, + NewGrpcHandler: func() lnrpc.GrpcHandler { + return &ServerShell{} + }, + } + + // If the build tag is active, then we'll register ourselves as a + // sub-RPC server within the global lnrpc package namespace. + if err := lnrpc.RegisterSubServer(subServer); err != nil { + panic(fmt.Sprintf("failed to register sub server driver "+ + "'%s': %v", subServerName, err)) + } +} diff --git a/lnrpc/peersrpc/log.go b/lnrpc/peersrpc/log.go new file mode 100644 index 000000000..13bc6c354 --- /dev/null +++ b/lnrpc/peersrpc/log.go @@ -0,0 +1,48 @@ +package peersrpc + +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 + +// Subsystem defines the logging code for this subsystem. +const Subsystem = "PRPC" + +// 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 // nolint:unused + +// 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 { // nolint:unused + return logClosure(c) +} diff --git a/lnrpc/peersrpc/peers_server.go b/lnrpc/peersrpc/peers_server.go new file mode 100644 index 000000000..c8af26617 --- /dev/null +++ b/lnrpc/peersrpc/peers_server.go @@ -0,0 +1,142 @@ +//go:build peersrpc +// +build peersrpc + +package peersrpc + +import ( + "context" + "sync/atomic" + + "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" + "github.com/lightningnetwork/lnd/lnrpc" + "google.golang.org/grpc" + "gopkg.in/macaroon-bakery.v2/bakery" +) + +const ( + // subServerName is the name of the sub rpc server. We'll use this name + // to register ourselves, and we also require that the main + // SubServerConfigDispatcher instance recognize tt as the name of our + // RPC service. + subServerName = "PeersRPC" +) + +var ( + // macPermissions maps RPC calls to the permissions they require. + macPermissions = map[string][]bakery.Op{} +) + +// ServerShell is a shell struct holding a reference to the actual sub-server. +// It is used to register the gRPC sub-server with the root server before we +// have the necessary dependencies to populate the actual sub-server. +type ServerShell struct { + PeersServer +} + +// Server is a sub-server of the main RPC server: the peers RPC. This sub +// RPC server allows to intereact with our Peers in the Lightning Network. +type Server struct { + started int32 // To be used atomically. + shutdown int32 // To be used atomically. + + // Required by the grpc-gateway/v2 library for forward compatibility. + // Must be after the atomically used variables to not break struct + // alignment. + UnimplementedPeersServer + + cfg *Config +} + +// A compile time check to ensure that Server fully implements the PeersServer +// gRPC service. +var _ PeersServer = (*Server)(nil) + +// New returns a new instance of the peersrpc Peers sub-server. We also +// return the set of permissions for the macaroons that we may create within +// this method. If the macaroons we need aren't found in the filepath, then +// we'll create them on start up. If we're unable to locate, or create the +// macaroons we need, then we'll return with an error. +func New(cfg *Config) (*Server, lnrpc.MacaroonPerms, error) { + server := &Server{ + cfg: cfg, + } + + return server, macPermissions, nil +} + +// Start launches any helper goroutines required for the Server to function. +// +// NOTE: This is part of the lnrpc.SubServer interface. +func (s *Server) Start() error { + if atomic.AddInt32(&s.started, 1) != 1 { + return nil + } + + return nil +} + +// Stop signals any active goroutines for a graceful closure. +// +// NOTE: This is part of the lnrpc.SubServer interface. +func (s *Server) Stop() error { + if atomic.AddInt32(&s.shutdown, 1) != 1 { + return nil + } + + return nil +} + +// Name returns a unique string representation of the sub-server. This can be +// used to identify the sub-server and also de-duplicate them. +// +// NOTE: This is part of the lnrpc.SubServer interface. +func (s *Server) Name() string { + return subServerName +} + +// RegisterWithRootServer will be called by the root gRPC server to direct a +// sub RPC server to register itself with the main gRPC root server. Until this +// is called, each sub-server won't be able to have +// requests routed towards it. +// +// NOTE: This is part of the lnrpc.GrpcHandler interface. +func (r *ServerShell) RegisterWithRootServer(grpcServer *grpc.Server) error { + // We make sure that we register it with the main gRPC server to ensure + // all our methods are routed properly. + RegisterPeersServer(grpcServer, r) + + log.Debugf("Peers RPC server successfully register with root " + + "gRPC server") + + return nil +} + +// RegisterWithRestServer will be called by the root REST mux to direct a sub +// RPC server to register itself with the main REST mux server. Until this is +// called, each sub-server won't be able to have requests routed towards it. +// +// NOTE: This is part of the lnrpc.GrpcHandler interface. +func (r *ServerShell) RegisterWithRestServer(ctx context.Context, + mux *runtime.ServeMux, dest string, opts []grpc.DialOption) error { + + return nil +} + +// CreateSubServer populates the subserver's dependencies using the passed +// SubServerConfigDispatcher. This method should fully initialize the +// sub-server instance, making it ready for action. It returns the macaroon +// permissions that the sub-server wishes to pass on to the root server for all +// methods routed towards it. +// +// NOTE: This is part of the lnrpc.GrpcHandler interface. +func (r *ServerShell) CreateSubServer(configRegistry lnrpc.SubServerConfigDispatcher) ( + lnrpc.SubServer, lnrpc.MacaroonPerms, error) { + + subServer, macPermissions, err := createNewSubServer(configRegistry) + if err != nil { + return nil, nil, err + } + + r.PeersServer = subServer + return subServer, macPermissions, nil +}