lightning-terminal/lnd_ready.go

55 lines
1.4 KiB
Go
Raw Permalink Normal View History

package terminal
import (
"context"
"fmt"
"time"
"github.com/lightningnetwork/lnd/lnrpc"
)
// waitForLndRPCReady polls lnd's StateService until lnd's RPC interceptor has
// left the WAITING_TO_START state, or timeout elapses. Unlike every other
// lnd RPC, the StateService is exempt from both lnd's macaroon check and its
// RPC-readiness check (see lnd's rpcperms.InterceptorChain), so it can be
// queried on a fresh connection before the wallet is unlocked and before any
// macaroon exists. This lets us distinguish lnd's gRPC listener merely being
// bound (which is all readyChan/unlockChan guarantee) from lnd actually being
// able to service non-State RPCs.
func waitForLndRPCReady(ctx context.Context, stateClient lnrpc.StateClient,
timeout time.Duration) error {
timer := time.NewTimer(timeout)
defer timer.Stop()
var lastErr error
for {
resp, err := stateClient.GetState(ctx, &lnrpc.GetStateRequest{})
switch {
case err != nil:
lastErr = err
case resp.State != lnrpc.WalletState_WAITING_TO_START:
return nil
}
select {
case <-time.After(stateServicePollInterval):
case <-timer.C:
if lastErr != nil {
return fmt.Errorf("lnd's RPC interceptor "+
"did not leave WAITING_TO_START "+
"within %v: %w", timeout, lastErr)
}
return fmt.Errorf("lnd's RPC interceptor did not "+
"leave WAITING_TO_START within %v", timeout)
case <-ctx.Done():
return ctx.Err()
}
}
}