diff --git a/rpc_proxy.go b/rpc_proxy.go index ab6d749a..53cea101 100644 --- a/rpc_proxy.go +++ b/rpc_proxy.go @@ -10,6 +10,7 @@ import ( "net" "net/http" "strings" + "sync/atomic" "time" "github.com/improbable-eng/grpc-web/go/grpcweb" @@ -37,6 +38,10 @@ const ( HeaderMacaroon = "Macaroon" ) +// ErrWaitingToStart is returned if Lit's rpcProxy is not yet ready to handle +// calls. +var ErrWaitingToStart = fmt.Errorf("waiting for the RPC server to start") + // proxyErr is an error type that adds more context to an error occurring in the // proxy. type proxyErr struct { @@ -147,6 +152,10 @@ func newRpcProxy(cfg *Config, validator macaroons.MacaroonValidator, type rpcProxy struct { litrpc.UnimplementedProxyServer + // started is set to 1 once the rpcProxy has successfully started. It + // must only ever be used atomically. + started int32 + cfg *Config basicAuth string permsMgr *perms.Manager @@ -218,9 +227,17 @@ func (p *rpcProxy) Start() error { } } + atomic.CompareAndSwapInt32(&p.started, 0, 1) + return nil } +// hasStarted returns true if the rpcProxy has started and is ready to handle +// requests. +func (p *rpcProxy) hasStarted() bool { + return atomic.LoadInt32(&p.started) == 1 +} + // Stop shuts down the lnd connection. func (p *rpcProxy) Stop() error { p.grpcServer.Stop() @@ -399,6 +416,10 @@ func (p *rpcProxy) UnaryServerInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + if !p.hasStarted() { + return nil, ErrWaitingToStart + } + uriPermissions, ok := p.permsMgr.URIPermissions(info.FullMethod) if !ok { return nil, fmt.Errorf("%s: unknown permissions "+ @@ -440,6 +461,10 @@ func (p *rpcProxy) StreamServerInterceptor(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { + if !p.hasStarted() { + return ErrWaitingToStart + } + uriPermissions, ok := p.permsMgr.URIPermissions(info.FullMethod) if !ok { return fmt.Errorf("%s: unknown permissions required "+