From 4ea494e8c5fc262289b66d016c0d33a70337622c Mon Sep 17 00:00:00 2001 From: "Johan T. Halseth" Date: Fri, 29 Jan 2021 15:49:48 +0100 Subject: [PATCH] lnrpc: wrap subservers in GrpcHandler In order to be able to register the subservers with the root grpc server before we have all dependencies available, we wrap them in an GrpcHandler struct. This struct will initially hold an empty reference to the subservers, which allows us to register with the GRPC server, and later populate and create the subserver instance. --- lnrpc/autopilotrpc/autopilot_server.go | 36 ++++++++++++++++++++---- lnrpc/autopilotrpc/driver.go | 7 ++--- lnrpc/chainrpc/chainnotifier_server.go | 36 ++++++++++++++++++++---- lnrpc/chainrpc/driver.go | 8 ++---- lnrpc/invoicesrpc/driver.go | 7 ++--- lnrpc/invoicesrpc/invoices_server.go | 36 ++++++++++++++++++++---- lnrpc/routerrpc/driver.go | 6 ++-- lnrpc/routerrpc/router_server.go | 36 ++++++++++++++++++++---- lnrpc/signrpc/driver.go | 8 ++---- lnrpc/signrpc/signer_server.go | 36 ++++++++++++++++++++---- lnrpc/sub_server.go | 31 +++++++++++++------- lnrpc/verrpc/driver.go | 6 ++-- lnrpc/verrpc/server.go | 33 ++++++++++++++++++---- lnrpc/walletrpc/driver.go | 8 ++++-- lnrpc/walletrpc/walletkit_server.go | 36 ++++++++++++++++++++---- lnrpc/watchtowerrpc/driver.go | 7 ++--- lnrpc/watchtowerrpc/handler.go | 38 +++++++++++++++++++++---- lnrpc/wtclientrpc/driver.go | 7 ++--- lnrpc/wtclientrpc/wtclient.go | 39 ++++++++++++++++++++------ rpcserver.go | 26 +++++++++-------- 20 files changed, 341 insertions(+), 106 deletions(-) diff --git a/lnrpc/autopilotrpc/autopilot_server.go b/lnrpc/autopilotrpc/autopilot_server.go index fd9649ad..b3ece6cb 100644 --- a/lnrpc/autopilotrpc/autopilot_server.go +++ b/lnrpc/autopilotrpc/autopilot_server.go @@ -51,6 +51,13 @@ var ( } ) +// 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 { + AutopilotServer +} + // Server is a sub-server of the main RPC server: the autopilot RPC. This sub // RPC server allows external callers to access the status of the autopilot // currently active within lnd, as well as configuring it at runtime. @@ -118,11 +125,11 @@ func (s *Server) Name() string { // is called, each sub-server won't be able to have // requests routed towards it. // -// NOTE: This is part of the lnrpc.SubServer interface. -func (s *Server) RegisterWithRootServer(grpcServer *grpc.Server) error { +// 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. - RegisterAutopilotServer(grpcServer, s) + RegisterAutopilotServer(grpcServer, r) log.Debugf("Autopilot RPC server successfully register with root " + "gRPC server") @@ -134,8 +141,8 @@ func (s *Server) RegisterWithRootServer(grpcServer *grpc.Server) error { // 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.SubServer interface. -func (s *Server) RegisterWithRestServer(ctx context.Context, +// 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 { // We make sure that we register it with the main REST server to ensure @@ -152,6 +159,25 @@ func (s *Server) RegisterWithRestServer(ctx context.Context, 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.AutopilotServer = subServer + return subServer, macPermissions, nil +} + // Status returns the current status of the autopilot agent. // // NOTE: Part of the AutopilotServer interface. diff --git a/lnrpc/autopilotrpc/driver.go b/lnrpc/autopilotrpc/driver.go index 7615e242..8f849c3e 100644 --- a/lnrpc/autopilotrpc/driver.go +++ b/lnrpc/autopilotrpc/driver.go @@ -13,7 +13,7 @@ import ( // that is meant for us in the config dispatcher, then we'll exit with an // error. func createNewSubServer(configRegistry lnrpc.SubServerConfigDispatcher) ( - lnrpc.SubServer, lnrpc.MacaroonPerms, error) { + *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 @@ -48,9 +48,8 @@ func createNewSubServer(configRegistry lnrpc.SubServerConfigDispatcher) ( func init() { subServer := &lnrpc.SubServerDriver{ SubServerName: subServerName, - New: func(c lnrpc.SubServerConfigDispatcher) (lnrpc.SubServer, - lnrpc.MacaroonPerms, error) { - return createNewSubServer(c) + NewGrpcHandler: func() lnrpc.GrpcHandler { + return &ServerShell{} }, } diff --git a/lnrpc/chainrpc/chainnotifier_server.go b/lnrpc/chainrpc/chainnotifier_server.go index 3e35ab60..80f3c0ea 100644 --- a/lnrpc/chainrpc/chainnotifier_server.go +++ b/lnrpc/chainrpc/chainnotifier_server.go @@ -72,6 +72,13 @@ var ( "still in the process of starting") ) +// 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 { + ChainNotifierServer +} + // Server is a sub-server of the main RPC server: the chain notifier RPC. This // RPC sub-server allows external callers to access the full chain notifier // capabilities of lnd. This allows callers to create custom protocols, external @@ -172,11 +179,11 @@ func (s *Server) Name() string { // sub-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.SubServer interface. -func (s *Server) RegisterWithRootServer(grpcServer *grpc.Server) error { +// 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. - RegisterChainNotifierServer(grpcServer, s) + RegisterChainNotifierServer(grpcServer, r) log.Debug("ChainNotifier RPC server successfully register with root " + "gRPC server") @@ -188,8 +195,8 @@ func (s *Server) RegisterWithRootServer(grpcServer *grpc.Server) error { // 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.SubServer interface. -func (s *Server) RegisterWithRestServer(ctx context.Context, +// 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 { // We make sure that we register it with the main REST server to ensure @@ -206,6 +213,25 @@ func (s *Server) RegisterWithRestServer(ctx context.Context, 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.ChainNotifierServer = subServer + return subServer, macPermissions, nil +} + // RegisterConfirmationsNtfn is a synchronous response-streaming RPC that // registers an intent for a client to be notified once a confirmation request // has reached its required number of confirmations on-chain. diff --git a/lnrpc/chainrpc/driver.go b/lnrpc/chainrpc/driver.go index 0a932fb6..be307f82 100644 --- a/lnrpc/chainrpc/driver.go +++ b/lnrpc/chainrpc/driver.go @@ -13,7 +13,7 @@ import ( // the config that is meant for us in the config dispatcher, then we'll exit // with an error. func createNewSubServer(configRegistry lnrpc.SubServerConfigDispatcher) ( - lnrpc.SubServer, lnrpc.MacaroonPerms, error) { + *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 @@ -55,10 +55,8 @@ func createNewSubServer(configRegistry lnrpc.SubServerConfigDispatcher) ( func init() { subServer := &lnrpc.SubServerDriver{ SubServerName: subServerName, - New: func(c lnrpc.SubServerConfigDispatcher) ( - lnrpc.SubServer, lnrpc.MacaroonPerms, error) { - - return createNewSubServer(c) + NewGrpcHandler: func() lnrpc.GrpcHandler { + return &ServerShell{} }, } diff --git a/lnrpc/invoicesrpc/driver.go b/lnrpc/invoicesrpc/driver.go index 54ad1fc1..5183c878 100644 --- a/lnrpc/invoicesrpc/driver.go +++ b/lnrpc/invoicesrpc/driver.go @@ -13,7 +13,7 @@ import ( // that is meant for us in the config dispatcher, then we'll exit with an // error. func createNewSubServer(configRegistry lnrpc.SubServerConfigDispatcher) ( - lnrpc.SubServer, lnrpc.MacaroonPerms, error) { + *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 @@ -40,9 +40,8 @@ func createNewSubServer(configRegistry lnrpc.SubServerConfigDispatcher) ( func init() { subServer := &lnrpc.SubServerDriver{ SubServerName: subServerName, - New: func(c lnrpc.SubServerConfigDispatcher) (lnrpc.SubServer, - lnrpc.MacaroonPerms, error) { - return createNewSubServer(c) + NewGrpcHandler: func() lnrpc.GrpcHandler { + return &ServerShell{} }, } diff --git a/lnrpc/invoicesrpc/invoices_server.go b/lnrpc/invoicesrpc/invoices_server.go index 3f053956..9c092e57 100644 --- a/lnrpc/invoicesrpc/invoices_server.go +++ b/lnrpc/invoicesrpc/invoices_server.go @@ -66,6 +66,13 @@ var ( DefaultInvoicesMacFilename = "invoices.macaroon" ) +// 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 { + InvoicesServer +} + // Server is a sub-server of the main RPC server: the invoices RPC. This sub // RPC server allows external callers to access the status of the invoices // currently active within lnd, as well as configuring it at runtime. @@ -157,11 +164,11 @@ func (s *Server) Name() string { // 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.SubServer interface. -func (s *Server) RegisterWithRootServer(grpcServer *grpc.Server) error { +// 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. - RegisterInvoicesServer(grpcServer, s) + RegisterInvoicesServer(grpcServer, r) log.Debugf("Invoices RPC server successfully registered with root " + "gRPC server") @@ -173,8 +180,8 @@ func (s *Server) RegisterWithRootServer(grpcServer *grpc.Server) error { // 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.SubServer interface. -func (s *Server) RegisterWithRestServer(ctx context.Context, +// 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 { // We make sure that we register it with the main REST server to ensure @@ -191,6 +198,25 @@ func (s *Server) RegisterWithRestServer(ctx context.Context, 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.InvoicesServer = subServer + return subServer, macPermissions, nil +} + // SubscribeSingleInvoice returns a uni-directional stream (server -> client) // for notifying the client of state changes for a specified invoice. func (s *Server) SubscribeSingleInvoice(req *SubscribeSingleInvoiceRequest, diff --git a/lnrpc/routerrpc/driver.go b/lnrpc/routerrpc/driver.go index e174e222..0899464c 100644 --- a/lnrpc/routerrpc/driver.go +++ b/lnrpc/routerrpc/driver.go @@ -11,7 +11,7 @@ import ( // config that is meant for us in the config dispatcher, then we'll exit with // an error. func createNewSubServer(configRegistry lnrpc.SubServerConfigDispatcher) ( - lnrpc.SubServer, lnrpc.MacaroonPerms, error) { + *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 @@ -46,8 +46,8 @@ func createNewSubServer(configRegistry lnrpc.SubServerConfigDispatcher) ( func init() { subServer := &lnrpc.SubServerDriver{ SubServerName: subServerName, - New: func(c lnrpc.SubServerConfigDispatcher) (lnrpc.SubServer, lnrpc.MacaroonPerms, error) { - return createNewSubServer(c) + NewGrpcHandler: func() lnrpc.GrpcHandler { + return &ServerShell{} }, } diff --git a/lnrpc/routerrpc/router_server.go b/lnrpc/routerrpc/router_server.go index bc9d7514..02192ddc 100644 --- a/lnrpc/routerrpc/router_server.go +++ b/lnrpc/routerrpc/router_server.go @@ -129,6 +129,13 @@ var ( DefaultRouterMacFilename = "router.macaroon" ) +// ServerShell a is 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 { + RouterServer +} + // Server is a stand alone sub RPC server which exposes functionality that // allows clients to route arbitrary payment through the Lightning Network. type Server struct { @@ -233,11 +240,11 @@ func (s *Server) Name() string { // 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.SubServer interface. -func (s *Server) RegisterWithRootServer(grpcServer *grpc.Server) error { +// 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. - RegisterRouterServer(grpcServer, s) + RegisterRouterServer(grpcServer, r) log.Debugf("Router RPC server successfully register with root gRPC " + "server") @@ -249,8 +256,8 @@ func (s *Server) RegisterWithRootServer(grpcServer *grpc.Server) error { // 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.SubServer interface. -func (s *Server) RegisterWithRestServer(ctx context.Context, +// 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 { // We make sure that we register it with the main REST server to ensure @@ -267,6 +274,25 @@ func (s *Server) RegisterWithRestServer(ctx context.Context, 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.RouterServer = subServer + return subServer, macPermissions, nil +} + // SendPaymentV2 attempts to route a payment described by the passed // PaymentRequest to the final destination. If we are unable to route the // payment, or cannot find a route that satisfies the constraints in the diff --git a/lnrpc/signrpc/driver.go b/lnrpc/signrpc/driver.go index b598c33c..cd130d5e 100644 --- a/lnrpc/signrpc/driver.go +++ b/lnrpc/signrpc/driver.go @@ -13,7 +13,7 @@ import ( // config that is meant for us in the config dispatcher, then we'll exit with // an error. func createNewSubServer(configRegistry lnrpc.SubServerConfigDispatcher) ( - lnrpc.SubServer, lnrpc.MacaroonPerms, error) { + *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 @@ -55,10 +55,8 @@ func createNewSubServer(configRegistry lnrpc.SubServerConfigDispatcher) ( func init() { subServer := &lnrpc.SubServerDriver{ SubServerName: subServerName, - New: func(c lnrpc.SubServerConfigDispatcher) ( - lnrpc.SubServer, lnrpc.MacaroonPerms, error) { - - return createNewSubServer(c) + NewGrpcHandler: func() lnrpc.GrpcHandler { + return &ServerShell{} }, } diff --git a/lnrpc/signrpc/signer_server.go b/lnrpc/signrpc/signer_server.go index fdeb3f58..c48c36e1 100644 --- a/lnrpc/signrpc/signer_server.go +++ b/lnrpc/signrpc/signer_server.go @@ -76,6 +76,13 @@ var ( DefaultSignerMacFilename = "signer.macaroon" ) +// 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 { + SignerServer +} + // Server is a sub-server of the main RPC server: the signer RPC. This sub RPC // server allows external callers to access the full signing capabilities of // lnd. This allows callers to create custom protocols, external to lnd, even @@ -167,11 +174,11 @@ func (s *Server) Name() string { // is called, each sub-server won't be able to have // requests routed towards it. // -// NOTE: This is part of the lnrpc.SubServer interface. -func (s *Server) RegisterWithRootServer(grpcServer *grpc.Server) error { +// 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. - RegisterSignerServer(grpcServer, s) + RegisterSignerServer(grpcServer, r) log.Debugf("Signer RPC server successfully register with root gRPC " + "server") @@ -183,8 +190,8 @@ func (s *Server) RegisterWithRootServer(grpcServer *grpc.Server) error { // 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.SubServer interface. -func (s *Server) RegisterWithRestServer(ctx context.Context, +// 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 { // We make sure that we register it with the main REST server to ensure @@ -201,6 +208,25 @@ func (s *Server) RegisterWithRestServer(ctx context.Context, 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.SignerServer = subServer + return subServer, macPermissions, nil +} + // SignOutputRaw generates a signature for the passed transaction according to // the data within the passed SignReq. If we're unable to find the keys that // correspond to the KeyLocators in the SignReq then we'll return an error. diff --git a/lnrpc/sub_server.go b/lnrpc/sub_server.go index 7970273a..23033abb 100644 --- a/lnrpc/sub_server.go +++ b/lnrpc/sub_server.go @@ -32,7 +32,14 @@ type SubServer interface { // Name returns a unique string representation of the sub-server. This // can be used to identify the sub-server and also de-duplicate them. Name() string +} +// GrpcHandler is the interface that should be registered with the root gRPC +// server, and is the interface that implements the subserver's defined RPC. +// Before the actual sub server has been created, this will be an empty shell +// allowing us to start the gRPC server before we have all the dependencies +// needed to create the subserver itself. +type GrpcHandler interface { // 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 @@ -45,6 +52,14 @@ type SubServer interface { // routed towards it. RegisterWithRestServer(context.Context, *runtime.ServeMux, string, []grpc.DialOption) error + + // 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. + CreateSubServer(subCfgs SubServerConfigDispatcher) (SubServer, + MacaroonPerms, error) } // SubServerConfigDispatcher is an interface that all sub-servers will use to @@ -60,22 +75,18 @@ type SubServerConfigDispatcher interface { } // SubServerDriver is a template struct that allows the root server to create a -// sub-server with minimal knowledge. The root server only need a fully -// populated SubServerConfigDispatcher and with the aide of the -// RegisterSubServers method, it's able to create and initialize all -// sub-servers. +// sub-server gRPC handler with minimal knowledge. type SubServerDriver struct { // SubServerName is the full name of a sub-sever. // // NOTE: This MUST be unique. SubServerName string - // New creates, and fully initializes a new sub-server instance with - // the aide of the SubServerConfigDispatcher. This closure should - // return the SubServer, ready for action, along with the set of - // macaroon permissions that the sub-server wishes to pass on to the - // root server for all methods routed towards it. - New func(subCfgs SubServerConfigDispatcher) (SubServer, MacaroonPerms, error) + // NewGrpcHandler creates a a new sub-server gRPC interface that can be + // registered with the root gRPC server. It is not expected that the + // SubServer is ready for operation before its CreateSubServer and + // Start methods have been called. + NewGrpcHandler func() GrpcHandler } var ( diff --git a/lnrpc/verrpc/driver.go b/lnrpc/verrpc/driver.go index db250f7d..49977f69 100644 --- a/lnrpc/verrpc/driver.go +++ b/lnrpc/verrpc/driver.go @@ -9,10 +9,8 @@ import ( func init() { subServer := &lnrpc.SubServerDriver{ SubServerName: subServerName, - New: func(c lnrpc.SubServerConfigDispatcher) (lnrpc.SubServer, - lnrpc.MacaroonPerms, error) { - - return &Server{}, macPermissions, nil + NewGrpcHandler: func() lnrpc.GrpcHandler { + return &ServerShell{} }, } diff --git a/lnrpc/verrpc/server.go b/lnrpc/verrpc/server.go index ecbd29c1..31c34899 100644 --- a/lnrpc/verrpc/server.go +++ b/lnrpc/verrpc/server.go @@ -5,6 +5,7 @@ import ( "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/lightningnetwork/lnd/build" + "github.com/lightningnetwork/lnd/lnrpc" "google.golang.org/grpc" "gopkg.in/macaroon-bakery.v2/bakery" ) @@ -18,6 +19,13 @@ var 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 { + VersionerServer +} + // Server is an rpc server that supports querying for information about the // running binary. type Server struct{} @@ -48,9 +56,9 @@ func (s *Server) Name() string { // 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.SubServer interface. -func (s *Server) RegisterWithRootServer(grpcServer *grpc.Server) error { - RegisterVersionerServer(grpcServer, s) +// NOTE: This is part of the lnrpc.GrpcHandler interface. +func (r *ServerShell) RegisterWithRootServer(grpcServer *grpc.Server) error { + RegisterVersionerServer(grpcServer, r) log.Debugf("Versioner RPC server successfully registered with root " + "gRPC server") @@ -62,8 +70,8 @@ func (s *Server) RegisterWithRootServer(grpcServer *grpc.Server) error { // 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.SubServer interface. -func (s *Server) RegisterWithRestServer(ctx context.Context, +// 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 { // We make sure that we register it with the main REST server to ensure @@ -80,6 +88,21 @@ func (s *Server) RegisterWithRestServer(ctx context.Context, 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(_ lnrpc.SubServerConfigDispatcher) ( + lnrpc.SubServer, lnrpc.MacaroonPerms, error) { + + subServer := &Server{} + r.VersionerServer = subServer + return subServer, macPermissions, nil +} + // GetVersion returns information about the compiled binary. func (s *Server) GetVersion(_ context.Context, _ *VersionRequest) (*Version, error) { diff --git a/lnrpc/walletrpc/driver.go b/lnrpc/walletrpc/driver.go index deb02a6e..649445a2 100644 --- a/lnrpc/walletrpc/driver.go +++ b/lnrpc/walletrpc/driver.go @@ -12,7 +12,9 @@ import ( // 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) (lnrpc.SubServer, lnrpc.MacaroonPerms, error) { +func createNewSubServer(configRegistry lnrpc.SubServerConfigDispatcher) ( + *WalletKit, 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 @@ -67,8 +69,8 @@ func createNewSubServer(configRegistry lnrpc.SubServerConfigDispatcher) (lnrpc.S func init() { subServer := &lnrpc.SubServerDriver{ SubServerName: subServerName, - New: func(c lnrpc.SubServerConfigDispatcher) (lnrpc.SubServer, lnrpc.MacaroonPerms, error) { - return createNewSubServer(c) + NewGrpcHandler: func() lnrpc.GrpcHandler { + return &ServerShell{} }, } diff --git a/lnrpc/walletrpc/walletkit_server.go b/lnrpc/walletrpc/walletkit_server.go index 04fafc25..392c6f30 100644 --- a/lnrpc/walletrpc/walletkit_server.go +++ b/lnrpc/walletrpc/walletkit_server.go @@ -148,6 +148,13 @@ var ( // an empty label. var ErrZeroLabel = errors.New("cannot label transaction with empty label") +// 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 { + WalletKitServer +} + // WalletKit is a sub-RPC server that exposes a tool kit which allows clients // to execute common wallet operations. This includes requesting new addresses, // keys (for contracts!), and publishing transactions. @@ -233,11 +240,11 @@ func (w *WalletKit) Name() string { // 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.SubServer interface. -func (w *WalletKit) RegisterWithRootServer(grpcServer *grpc.Server) error { +// 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. - RegisterWalletKitServer(grpcServer, w) + RegisterWalletKitServer(grpcServer, r) log.Debugf("WalletKit RPC server successfully registered with " + "root gRPC server") @@ -249,8 +256,8 @@ func (w *WalletKit) RegisterWithRootServer(grpcServer *grpc.Server) error { // 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.SubServer interface. -func (w *WalletKit) RegisterWithRestServer(ctx context.Context, +// 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 { // We make sure that we register it with the main REST server to ensure @@ -267,6 +274,25 @@ func (w *WalletKit) RegisterWithRestServer(ctx context.Context, 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.WalletKitServer = subServer + return subServer, macPermissions, nil +} + // ListUnspent returns useful information about each unspent output owned by the // wallet, as reported by the underlying `ListUnspentWitness`; the information // returned is: outpoint, amount in satoshis, address, address type, diff --git a/lnrpc/watchtowerrpc/driver.go b/lnrpc/watchtowerrpc/driver.go index dc9cecce..3fa5f1d2 100644 --- a/lnrpc/watchtowerrpc/driver.go +++ b/lnrpc/watchtowerrpc/driver.go @@ -13,7 +13,7 @@ import ( // that is meant for us in the config dispatcher, then we'll exit with an // error. func createNewSubServer(configRegistry lnrpc.SubServerConfigDispatcher) ( - lnrpc.SubServer, lnrpc.MacaroonPerms, error) { + *Handler, 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 @@ -40,9 +40,8 @@ func createNewSubServer(configRegistry lnrpc.SubServerConfigDispatcher) ( func init() { subServer := &lnrpc.SubServerDriver{ SubServerName: subServerName, - New: func(c lnrpc.SubServerConfigDispatcher) (lnrpc.SubServer, - lnrpc.MacaroonPerms, error) { - return createNewSubServer(c) + NewGrpcHandler: func() lnrpc.GrpcHandler { + return &ServerShell{} }, } diff --git a/lnrpc/watchtowerrpc/handler.go b/lnrpc/watchtowerrpc/handler.go index d4124708..88add9d0 100644 --- a/lnrpc/watchtowerrpc/handler.go +++ b/lnrpc/watchtowerrpc/handler.go @@ -5,7 +5,7 @@ package watchtowerrpc import ( "context" "errors" - fmt "fmt" + "fmt" "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/lightningnetwork/lnd/lnrpc" @@ -35,6 +35,13 @@ var ( ErrTowerNotActive = errors.New("watchtower not active") ) +// 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 { + WatchtowerServer +} + // Handler is the RPC server we'll use to interact with the backing active // watchtower. type Handler struct { @@ -80,11 +87,11 @@ func (c *Handler) Name() string { // 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.SubServer interface. -func (c *Handler) RegisterWithRootServer(grpcServer *grpc.Server) error { +// 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. - RegisterWatchtowerServer(grpcServer, c) + RegisterWatchtowerServer(grpcServer, r) log.Debugf("Watchtower RPC server successfully register with root " + "gRPC server") @@ -96,8 +103,8 @@ func (c *Handler) RegisterWithRootServer(grpcServer *grpc.Server) error { // 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.SubServer interface. -func (c *Handler) RegisterWithRestServer(ctx context.Context, +// 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 { // We make sure that we register it with the main REST server to ensure @@ -114,6 +121,25 @@ func (c *Handler) RegisterWithRestServer(ctx context.Context, 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.WatchtowerServer = subServer + return subServer, macPermissions, nil +} + // AddTower adds a new watchtower reachable at the given address and considers // it for new sessions. If the watchtower already exists, then any new addresses // included will be considered when dialing it for session negotiations and diff --git a/lnrpc/wtclientrpc/driver.go b/lnrpc/wtclientrpc/driver.go index 78e39976..cecbbf43 100644 --- a/lnrpc/wtclientrpc/driver.go +++ b/lnrpc/wtclientrpc/driver.go @@ -12,7 +12,7 @@ import ( // that is meant for us in the config dispatcher, then we'll exit with an // error. func createNewSubServer(configRegistry lnrpc.SubServerConfigDispatcher) ( - lnrpc.SubServer, lnrpc.MacaroonPerms, error) { + *WatchtowerClient, 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 @@ -46,9 +46,8 @@ func createNewSubServer(configRegistry lnrpc.SubServerConfigDispatcher) ( func init() { subServer := &lnrpc.SubServerDriver{ SubServerName: subServerName, - New: func(c lnrpc.SubServerConfigDispatcher) (lnrpc.SubServer, - lnrpc.MacaroonPerms, error) { - return createNewSubServer(c) + NewGrpcHandler: func() lnrpc.GrpcHandler { + return &ServerShell{} }, } diff --git a/lnrpc/wtclientrpc/wtclient.go b/lnrpc/wtclientrpc/wtclient.go index 4d55e468..fa3c640d 100644 --- a/lnrpc/wtclientrpc/wtclient.go +++ b/lnrpc/wtclientrpc/wtclient.go @@ -64,6 +64,13 @@ var ( ErrWtclientNotActive = errors.New("watchtower client not active") ) +// 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 { + WatchtowerClientServer +} + // WatchtowerClient is the RPC server we'll use to interact with the backing // active watchtower client. // @@ -112,14 +119,11 @@ func (c *WatchtowerClient) Name() string { // 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.SubServer interface. -func (c *WatchtowerClient) RegisterWithRootServer(grpcServer *grpc.Server) error { +// 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. - RegisterWatchtowerClientServer(grpcServer, c) - - c.cfg.Log.Debugf("WatchtowerClient RPC server successfully registered " + - "with root gRPC server") + RegisterWatchtowerClientServer(grpcServer, r) return nil } @@ -128,8 +132,8 @@ func (c *WatchtowerClient) RegisterWithRootServer(grpcServer *grpc.Server) error // 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.SubServer interface. -func (c *WatchtowerClient) RegisterWithRestServer(ctx context.Context, +// 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 { // We make sure that we register it with the main REST server to ensure @@ -142,6 +146,25 @@ func (c *WatchtowerClient) RegisterWithRestServer(ctx context.Context, 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.WatchtowerClientServer = subServer + return subServer, macPermissions, nil +} + // isActive returns nil if the watchtower client is initialized so that we can // process RPC requests. func (c *WatchtowerClient) isActive() error { diff --git a/rpcserver.go b/rpcserver.go index 294b42f3..a7b200bd 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -492,7 +492,8 @@ type rpcServer struct { // own independent service. This allows us to expose a set of // micro-service like abstractions to the outside world for users to // consume. - subServers []lnrpc.SubServer + subServers []lnrpc.SubServer + subGrpcHandlers []lnrpc.GrpcHandler // grpcServer is the main gRPC server that this RPC server, and all the // sub-servers will use to register themselves and accept client @@ -616,8 +617,9 @@ func newRPCServer(cfg *Config, s *server, macService *macaroons.Service, } var ( - subServers []lnrpc.SubServer - subServerPerms []lnrpc.MacaroonPerms + subServers []lnrpc.SubServer + subGrpcHandlers []lnrpc.GrpcHandler + subServerPerms []lnrpc.MacaroonPerms ) // Before we create any of the sub-servers, we need to ensure that all @@ -639,8 +641,9 @@ func newRPCServer(cfg *Config, s *server, macService *macaroons.Service, // Now that the sub-servers have all their dependencies in place, we // can create each sub-server! registeredSubServers := lnrpc.RegisteredSubServers() - for _, subServer := range registeredSubServers { - subServerInstance, macPerms, err := subServer.New(subServerCgs) + for _, driver := range registeredSubServers { + handler := driver.NewGrpcHandler() + subServer, macPerms, err := handler.CreateSubServer(subServerCgs) if err != nil { return nil, err } @@ -648,7 +651,8 @@ func newRPCServer(cfg *Config, s *server, macService *macaroons.Service, // We'll collect the sub-server, and also the set of // permissions it needs for macaroons so we can apply the // interceptors below. - subServers = append(subServers, subServerInstance) + subServers = append(subServers, subServer) + subGrpcHandlers = append(subGrpcHandlers, handler) subServerPerms = append(subServerPerms, macPerms) } @@ -767,6 +771,7 @@ func newRPCServer(cfg *Config, s *server, macService *macaroons.Service, listenerCleanUp: []func(){cleanup}, restProxyDest: restProxyDest, subServers: subServers, + subGrpcHandlers: subGrpcHandlers, restListen: restListen, grpcServer: grpcServer, server: s, @@ -782,12 +787,11 @@ func newRPCServer(cfg *Config, s *server, macService *macaroons.Service, // Now the main RPC server has been registered, we'll iterate through // all the sub-RPC servers and register them to ensure that requests // are properly routed towards them. - for _, subServer := range subServers { + for _, subServer := range subGrpcHandlers { err := subServer.RegisterWithRootServer(grpcServer) if err != nil { return nil, fmt.Errorf("unable to register "+ - "sub-server %v with root: %v", - subServer.Name(), err) + "sub-server with root: %v", err) } } @@ -885,13 +889,13 @@ func (r *rpcServer) Start() error { if err != nil { return err } - for _, subServer := range r.subServers { + for _, subServer := range r.subGrpcHandlers { err := subServer.RegisterWithRestServer( restCtx, restMux, r.restProxyDest, r.restDialOpts, ) if err != nil { return fmt.Errorf("unable to register REST sub-server "+ - "%v with root: %v", subServer.Name(), err) + "with root: %v", err) } }