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) } }