diff --git a/privval/signer_client_test.go b/privval/signer_client_test.go index 4aeed2b54..389428fd9 100644 --- a/privval/signer_client_test.go +++ b/privval/signer_client_test.go @@ -214,6 +214,7 @@ type BrokenSignerDialerEndpoint struct { *SignerDialerEndpoint } +// nolint func (ss *BrokenSignerDialerEndpoint) writeMessage(msg RemoteSignerMsg) (err error) { _, err = cdc.MarshalBinaryLengthPrefixedWriter(ss.conn, PubKeyResponse{}) return diff --git a/privval/signer_dialer_endpoint.go b/privval/signer_dialer_endpoint.go index 15d4c2eed..c5900e009 100644 --- a/privval/signer_dialer_endpoint.go +++ b/privval/signer_dialer_endpoint.go @@ -7,7 +7,6 @@ import ( "sync" "time" - "github.com/tendermint/tendermint/crypto" cmn "github.com/tendermint/tendermint/libs/common" "github.com/tendermint/tendermint/libs/log" "github.com/tendermint/tendermint/types" @@ -32,11 +31,8 @@ func SignerServiceEndpointConnRetries(retries int) SignerServiceEndpointOption { } // TODO(jleni): Create a common type for a signerEndpoint (common for both listener/dialer) -// getConnection -// AcceptNewConnection // read // write -// close // SignerDialerEndpoint dials using its dialer and responds to any // signature requests using its privVal. @@ -95,17 +91,34 @@ func (ss *SignerDialerEndpoint) OnStart() error { // OnStop implements cmn.Service. func (ss *SignerDialerEndpoint) OnStop() { - // Trigger a stop and wait + ss.Logger.Debug("SignerDialerEndpoint: OnStop calling Close") + _ = ss.Close() +} + +// IsConnected indicates if there is an active connection +func (ss *SignerDialerEndpoint) IsConnected() bool { + ss.mtx.Lock() + defer ss.mtx.Unlock() + return ss.isConnected() +} + +// Close closes the underlying net.Conn. +func (ss *SignerDialerEndpoint) Close() error { + ss.mtx.Lock() + defer ss.mtx.Unlock() + close(ss.stopCh) <-ss.stoppedCh + ss.Logger.Debug("SignerDialerEndpoint: Close") if ss.conn != nil { if err := ss.conn.Close(); err != nil { ss.Logger.Error("OnStop", "err", cmn.ErrorWrap(err, "closing listener failed")) - ss.Logger.Debug("Reset conn") ss.conn = nil } } + + return nil } func (ss *SignerDialerEndpoint) serviceLoop() { @@ -209,7 +222,7 @@ func (ss *SignerDialerEndpoint) handleRequest() { return } - res, err := handleMessage(req, ss.chainID, ss.privVal) + res, err := HandleValidatorRequest(req, ss.chainID, ss.privVal) if err != nil { // only log the error; we'll reply with an error in res @@ -223,35 +236,7 @@ func (ss *SignerDialerEndpoint) handleRequest() { } } -func handleMessage(req RemoteSignerMsg, chainID string, privVal types.PrivValidator) (RemoteSignerMsg, error) { - var res RemoteSignerMsg - var err error - - switch r := req.(type) { - case *PubKeyRequest: - var p crypto.PubKey - p = privVal.GetPubKey() - res = &PubKeyResponse{p, nil} - - case *SignVoteRequest: - err = privVal.SignVote(chainID, r.Vote) - if err != nil { - res = &SignedVoteResponse{nil, &RemoteSignerError{0, err.Error()}} - } else { - res = &SignedVoteResponse{r.Vote, nil} - } - - case *SignProposalRequest: - err = privVal.SignProposal(chainID, r.Proposal) - if err != nil { - res = &SignedProposalResponse{nil, &RemoteSignerError{0, err.Error()}} - } else { - res = &SignedProposalResponse{r.Proposal, nil} - } - - default: - err = fmt.Errorf("unknown msg: %v", r) - } - - return res, err +// IsConnected indicates if there is an active connection +func (ve *SignerDialerEndpoint) isConnected() bool { + return ve.IsRunning() && ve.conn != nil } diff --git a/privval/signer_listener_endpoint.go b/privval/signer_listener_endpoint.go index b2cf4bb89..09f552bb4 100644 --- a/privval/signer_listener_endpoint.go +++ b/privval/signer_listener_endpoint.go @@ -42,7 +42,7 @@ func NewSignerListenerEndpoint(logger log.Logger, listener net.Listener) *Signer func (ve *SignerListenerEndpoint) OnStart() error { ve.Logger.Debug("SignerListenerEndpoint: OnStart") - err := ve.AcceptNewConnection() + err := ve.acceptNewConnection() if err != nil { ve.Logger.Error("OnStart", "err", err) return err @@ -67,8 +67,11 @@ func (ve *SignerListenerEndpoint) IsConnected() bool { // WaitForConnection waits maxWait for a connection or returns a timeout error func (ve *SignerListenerEndpoint) WaitForConnection(maxWait time.Duration) error { - // TODO(jleni): complete this - return nil + ve.mtx.Lock() + defer ve.mtx.Unlock() + + // TODO(jleni): Pass maxwait through + return ve.ensureConnection() } // Close closes the underlying net.Conn. @@ -96,18 +99,14 @@ func (ve *SignerListenerEndpoint) SendRequest(request RemoteSignerMsg) (RemoteSi defer ve.mtx.Unlock() ve.Logger.Debug("SignerListenerEndpoint: Send request", "connected", ve.isConnected()) - - if !ve.isConnected() { - ve.Logger.Info("SignerListenerEndpoint: Reconnecting") - err := ve.AcceptNewConnection() - if err != nil { - return nil, cmn.ErrorWrap(ErrListenerNoConnection, "could not reconnect") - } + err := ve.ensureConnection() + if err != nil { + return nil, err } ve.Logger.Debug("Send request. Write") - err := ve.writeMessage(request) + err = ve.writeMessage(request) if err != nil { return nil, err } @@ -125,8 +124,17 @@ func (ve *SignerListenerEndpoint) SendRequest(request RemoteSignerMsg) (RemoteSi // IsConnected indicates if there is an active connection func (ve *SignerListenerEndpoint) isConnected() bool { - // return ve.IsRunning() && ve.conn != nil - return ve.conn != nil + return ve.IsRunning() && ve.conn != nil +} + +func (ve *SignerListenerEndpoint) ensureConnection() error { + if !ve.isConnected() { + err := ve.acceptNewConnection() + if err != nil { + return cmn.ErrorWrap(ErrListenerNoConnection, "could not reconnect") + } + } + return nil } // dropConnection closes the current connection but does not touch the listening socket @@ -193,11 +201,7 @@ func (ve *SignerListenerEndpoint) writeMessage(msg RemoteSignerMsg) (err error) return } -// AcceptNewConnection waits to accept a new connection. -func (ve *SignerListenerEndpoint) AcceptNewConnection() error { - ve.mtx.Lock() - defer ve.mtx.Unlock() - +func (ve *SignerListenerEndpoint) acceptNewConnection() error { ve.Logger.Debug("SignerListenerEndpoint: AcceptNewConnection") if !ve.IsRunning() || ve.listener == nil { diff --git a/privval/signer_service.go b/privval/signer_service.go new file mode 100644 index 000000000..016a7dde0 --- /dev/null +++ b/privval/signer_service.go @@ -0,0 +1,41 @@ +package privval + +import ( + "fmt" + + "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/types" +) + +func HandleValidatorRequest(req RemoteSignerMsg, chainID string, privVal types.PrivValidator) (RemoteSignerMsg, error) { + var res RemoteSignerMsg + var err error + + switch r := req.(type) { + case *PubKeyRequest: + var p crypto.PubKey + p = privVal.GetPubKey() + res = &PubKeyResponse{p, nil} + + case *SignVoteRequest: + err = privVal.SignVote(chainID, r.Vote) + if err != nil { + res = &SignedVoteResponse{nil, &RemoteSignerError{0, err.Error()}} + } else { + res = &SignedVoteResponse{r.Vote, nil} + } + + case *SignProposalRequest: + err = privVal.SignProposal(chainID, r.Proposal) + if err != nil { + res = &SignedProposalResponse{nil, &RemoteSignerError{0, err.Error()}} + } else { + res = &SignedProposalResponse{r.Proposal, nil} + } + + default: + err = fmt.Errorf("unknown msg: %v", r) + } + + return res, err +}