From 9601a9ab848cb03b5e4a3cf1e582dba834d6372c Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Wed, 5 Jan 2022 11:04:28 +0100 Subject: [PATCH] multi: make remote signer RPC timeout configurable --- config.go | 5 ++++- config_builder.go | 1 - lncfg/remotesigner.go | 35 +++++++++++++++++++++++++++++---- lnwallet/rpcwallet/rpcwallet.go | 22 +++++++++------------ sample-lnd.conf | 3 +++ 5 files changed, 47 insertions(+), 19 deletions(-) diff --git a/config.go b/config.go index 6666942ce..65b3b75c0 100644 --- a/config.go +++ b/config.go @@ -579,7 +579,9 @@ func DefaultConfig() Config { ChannelCommitInterval: defaultChannelCommitInterval, ChannelCommitBatchSize: defaultChannelCommitBatchSize, CoinSelectionStrategy: defaultCoinSelectionStrategy, - RemoteSigner: &lncfg.RemoteSigner{}, + RemoteSigner: &lncfg.RemoteSigner{ + Timeout: lncfg.DefaultRemoteSignerRPCTimeout, + }, } } @@ -1554,6 +1556,7 @@ func ValidateConfig(cfg Config, interceptor signal.Interceptor, fileParser, cfg.Cluster, cfg.HealthChecks, cfg.RPCMiddleware, + cfg.RemoteSigner, ) if err != nil { return nil, err diff --git a/config_builder.go b/config_builder.go index b32077aaa..1fd9fb116 100644 --- a/config_builder.go +++ b/config_builder.go @@ -688,7 +688,6 @@ func (d *RPCSignerWalletImpl) BuildChainControl( rpcKeyRing, err := rpcwallet.NewRPCKeyRing( baseKeyRing, walletController, d.DefaultWalletImpl.cfg.RemoteSigner, walletConfig.CoinType, - rpcwallet.DefaultRPCTimeout, ) if err != nil { err := fmt.Errorf("unable to create RPC remote signing wallet "+ diff --git a/lncfg/remotesigner.go b/lncfg/remotesigner.go index 90d1988cf..c4a0821d6 100644 --- a/lncfg/remotesigner.go +++ b/lncfg/remotesigner.go @@ -1,9 +1,36 @@ package lncfg +import ( + "fmt" + "time" +) + +const ( + // DefaultRemoteSignerRPCTimeout is the default timeout that is used + // when forwarding a request to the remote signer through RPC. + DefaultRemoteSignerRPCTimeout = 5 * time.Second +) + // RemoteSigner holds the configuration options for a remote RPC signer. type RemoteSigner struct { - Enable bool `long:"enable" description:"Use a remote signer for signing any on-chain related transactions or messages. Only recommended if local wallet is initialized as watch-only. Remote signer must use the same seed/root key as the local watch-only wallet but must have private keys."` - RPCHost string `long:"rpchost" description:"The remote signer's RPC host:port"` - MacaroonPath string `long:"macaroonpath" description:"The macaroon to use for authenticating with the remote signer"` - TLSCertPath string `long:"tlscertpath" description:"The TLS certificate to use for establishing the remote signer's identity"` + Enable bool `long:"enable" description:"Use a remote signer for signing any on-chain related transactions or messages. Only recommended if local wallet is initialized as watch-only. Remote signer must use the same seed/root key as the local watch-only wallet but must have private keys."` + RPCHost string `long:"rpchost" description:"The remote signer's RPC host:port"` + MacaroonPath string `long:"macaroonpath" description:"The macaroon to use for authenticating with the remote signer"` + TLSCertPath string `long:"tlscertpath" description:"The TLS certificate to use for establishing the remote signer's identity"` + Timeout time.Duration `long:"timeout" description:"The timeout for connecting to and signing requests with the remote signer. Valid time units are {s, m, h}."` +} + +// Validate checks the values configured for our remote RPC signer. +func (r *RemoteSigner) Validate() error { + if !r.Enable { + return nil + } + + if r.Timeout < time.Millisecond { + return fmt.Errorf("remote signer: timeout of %v is invalid, "+ + "cannot be smaller than %v", r.Timeout, + time.Millisecond) + } + + return nil } diff --git a/lnwallet/rpcwallet/rpcwallet.go b/lnwallet/rpcwallet/rpcwallet.go index dc1894fd5..01f9f5449 100644 --- a/lnwallet/rpcwallet/rpcwallet.go +++ b/lnwallet/rpcwallet/rpcwallet.go @@ -31,12 +31,6 @@ import ( "gopkg.in/macaroon.v2" ) -const ( - // DefaultRPCTimeout is the default timeout that is used when forwarding - // a request to the remote signer through RPC. - DefaultRPCTimeout = 5 * time.Second -) - var ( // ErrRemoteSigningPrivateKeyNotAvailable is the error that is returned // if an operation is requested from the RPC wallet that is not @@ -74,12 +68,11 @@ var _ lnwallet.WalletController = (*RPCKeyRing)(nil) // delegates any signing or ECDH operations to the remove signer through RPC. func NewRPCKeyRing(watchOnlyKeyRing keychain.SecretKeyRing, watchOnlyWalletController lnwallet.WalletController, - remoteSigner *lncfg.RemoteSigner, coinType uint32, - rpcTimeout time.Duration) (*RPCKeyRing, error) { + remoteSigner *lncfg.RemoteSigner, coinType uint32) (*RPCKeyRing, error) { rpcConn, err := connectRPC( remoteSigner.RPCHost, remoteSigner.TLSCertPath, - remoteSigner.MacaroonPath, + remoteSigner.MacaroonPath, remoteSigner.Timeout, ) if err != nil { return nil, fmt.Errorf("error connecting to the remote "+ @@ -90,7 +83,7 @@ func NewRPCKeyRing(watchOnlyKeyRing keychain.SecretKeyRing, WalletController: watchOnlyWalletController, watchOnlyKeyRing: watchOnlyKeyRing, coinType: coinType, - rpcTimeout: rpcTimeout, + rpcTimeout: remoteSigner.Timeout, signerClient: signrpc.NewSignerClient(rpcConn), walletClient: walletrpc.NewWalletKitClient(rpcConn), }, nil @@ -708,8 +701,8 @@ func (r *RPCKeyRing) remoteSign(tx *wire.MsgTx, signDesc *input.SignDescriptor, // connectRPC tries to establish an RPC connection to the given host:port with // the supplied certificate and macaroon. -func connectRPC(hostPort, tlsCertPath, macaroonPath string) (*grpc.ClientConn, - error) { +func connectRPC(hostPort, tlsCertPath, macaroonPath string, + timeout time.Duration) (*grpc.ClientConn, error) { certBytes, err := ioutil.ReadFile(tlsCertPath) if err != nil { @@ -743,8 +736,11 @@ func connectRPC(hostPort, tlsCertPath, macaroonPath string) (*grpc.ClientConn, cp, "", )), grpc.WithPerRPCCredentials(macCred), + grpc.WithBlock(), } - conn, err := grpc.Dial(hostPort, opts...) + ctxt, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + conn, err := grpc.DialContext(ctxt, hostPort, opts...) if err != nil { return nil, fmt.Errorf("unable to connect to RPC server: %v", err) diff --git a/sample-lnd.conf b/sample-lnd.conf index 36b1e4bb0..bccc2f3a1 100644 --- a/sample-lnd.conf +++ b/sample-lnd.conf @@ -1253,6 +1253,9 @@ litecoin.node=ltcd ; The TLS certificate to use for establishing the remote signer's identity. ; remotesigner.tlscertpath=/path/to/remote/signer/tls.cert +; The timeout for connecting to and signing requests with the remote signer. +; Valid time units are {s, m, h}. +; remotesigner.timeout=5s [gossip]