Remove privval.GetAddress(), memoize pubkey (#2948)

privval: remove GetAddress(), memoize pubkey
This commit is contained in:
Ismail Khoffi
2018-12-22 06:36:45 +01:00
committed by Ethan Buchman
parent 2348f38927
commit 6a80412a01
20 changed files with 194 additions and 143 deletions

View File

@@ -67,7 +67,10 @@ func (sc *IPCVal) OnStart() error {
return err
}
sc.RemoteSignerClient = NewRemoteSignerClient(sc.conn)
sc.RemoteSignerClient, err = NewRemoteSignerClient(sc.conn)
if err != nil {
return err
}
// Start a routine to keep the connection alive
sc.cancelPing = make(chan struct{}, 1)

View File

@@ -6,6 +6,8 @@ import (
"net"
"sync"
"github.com/pkg/errors"
"github.com/tendermint/go-amino"
"github.com/tendermint/tendermint/crypto"
cmn "github.com/tendermint/tendermint/libs/common"
@@ -15,8 +17,9 @@ import (
// RemoteSignerClient implements PrivValidator, it uses a socket to request signatures
// from an external process.
type RemoteSignerClient struct {
conn net.Conn
lock sync.Mutex
conn net.Conn
consensusPubKey crypto.PubKey
mtx sync.Mutex
}
// Check that RemoteSignerClient implements PrivValidator.
@@ -25,38 +28,29 @@ var _ types.PrivValidator = (*RemoteSignerClient)(nil)
// NewRemoteSignerClient returns an instance of RemoteSignerClient.
func NewRemoteSignerClient(
conn net.Conn,
) *RemoteSignerClient {
) (*RemoteSignerClient, error) {
sc := &RemoteSignerClient{
conn: conn,
}
return sc
}
// GetAddress implements PrivValidator.
func (sc *RemoteSignerClient) GetAddress() types.Address {
pubKey, err := sc.getPubKey()
if err != nil {
panic(err)
return nil, cmn.ErrorWrap(err, "error while retrieving public key for remote signer")
}
return pubKey.Address()
// retrieve and memoize the consensus public key once:
sc.consensusPubKey = pubKey
return sc, nil
}
// GetPubKey implements PrivValidator.
func (sc *RemoteSignerClient) GetPubKey() crypto.PubKey {
pubKey, err := sc.getPubKey()
if err != nil {
panic(err)
}
return pubKey
return sc.consensusPubKey
}
func (sc *RemoteSignerClient) getPubKey() (crypto.PubKey, error) {
sc.lock.Lock()
defer sc.lock.Unlock()
sc.mtx.Lock()
defer sc.mtx.Unlock()
err := writeMsg(sc.conn, &PubKeyMsg{})
err := writeMsg(sc.conn, &PubKeyRequest{})
if err != nil {
return nil, err
}
@@ -65,14 +59,22 @@ func (sc *RemoteSignerClient) getPubKey() (crypto.PubKey, error) {
if err != nil {
return nil, err
}
pubKeyResp, ok := res.(*PubKeyResponse)
if !ok {
return nil, errors.Wrap(ErrUnexpectedResponse, "response is not PubKeyResponse")
}
return res.(*PubKeyMsg).PubKey, nil
if pubKeyResp.Error != nil {
return nil, errors.Wrap(pubKeyResp.Error, "failed to get private validator's public key")
}
return pubKeyResp.PubKey, nil
}
// SignVote implements PrivValidator.
func (sc *RemoteSignerClient) SignVote(chainID string, vote *types.Vote) error {
sc.lock.Lock()
defer sc.lock.Unlock()
sc.mtx.Lock()
defer sc.mtx.Unlock()
err := writeMsg(sc.conn, &SignVoteRequest{Vote: vote})
if err != nil {
@@ -101,8 +103,8 @@ func (sc *RemoteSignerClient) SignProposal(
chainID string,
proposal *types.Proposal,
) error {
sc.lock.Lock()
defer sc.lock.Unlock()
sc.mtx.Lock()
defer sc.mtx.Unlock()
err := writeMsg(sc.conn, &SignProposalRequest{Proposal: proposal})
if err != nil {
@@ -127,8 +129,8 @@ func (sc *RemoteSignerClient) SignProposal(
// Ping is used to check connection health.
func (sc *RemoteSignerClient) Ping() error {
sc.lock.Lock()
defer sc.lock.Unlock()
sc.mtx.Lock()
defer sc.mtx.Unlock()
err := writeMsg(sc.conn, &PingRequest{})
if err != nil {
@@ -152,7 +154,8 @@ type RemoteSignerMsg interface{}
func RegisterRemoteSignerMsg(cdc *amino.Codec) {
cdc.RegisterInterface((*RemoteSignerMsg)(nil), nil)
cdc.RegisterConcrete(&PubKeyMsg{}, "tendermint/remotesigner/PubKeyMsg", nil)
cdc.RegisterConcrete(&PubKeyRequest{}, "tendermint/remotesigner/PubKeyRequest", nil)
cdc.RegisterConcrete(&PubKeyResponse{}, "tendermint/remotesigner/PubKeyResponse", nil)
cdc.RegisterConcrete(&SignVoteRequest{}, "tendermint/remotesigner/SignVoteRequest", nil)
cdc.RegisterConcrete(&SignedVoteResponse{}, "tendermint/remotesigner/SignedVoteResponse", nil)
cdc.RegisterConcrete(&SignProposalRequest{}, "tendermint/remotesigner/SignProposalRequest", nil)
@@ -161,9 +164,13 @@ func RegisterRemoteSignerMsg(cdc *amino.Codec) {
cdc.RegisterConcrete(&PingResponse{}, "tendermint/remotesigner/PingResponse", nil)
}
// PubKeyMsg is a PrivValidatorSocket message containing the public key.
type PubKeyMsg struct {
// PubKeyRequest requests the consensus public key from the remote signer.
type PubKeyRequest struct{}
// PubKeyResponse is a PrivValidatorSocket message containing the public key.
type PubKeyResponse struct {
PubKey crypto.PubKey
Error *RemoteSignerError
}
// SignVoteRequest is a PrivValidatorSocket message containing a vote.
@@ -227,10 +234,10 @@ func handleRequest(req RemoteSignerMsg, chainID string, privVal types.PrivValida
var err error
switch r := req.(type) {
case *PubKeyMsg:
case *PubKeyRequest:
var p crypto.PubKey
p = privVal.GetPubKey()
res = &PubKeyMsg{p}
res = &PubKeyResponse{p, nil}
case *SignVoteRequest:
err = privVal.SignVote(chainID, r.Vote)
if err != nil {

View File

@@ -107,8 +107,10 @@ func (sc *TCPVal) OnStart() error {
}
sc.conn = conn
sc.RemoteSignerClient = NewRemoteSignerClient(sc.conn)
sc.RemoteSignerClient, err = NewRemoteSignerClient(sc.conn)
if err != nil {
return err
}
// Start a routine to keep the connection alive
sc.cancelPing = make(chan struct{}, 1)

View File

@@ -25,15 +25,10 @@ func TestSocketPVAddress(t *testing.T) {
defer sc.Stop()
defer rs.Stop()
serverAddr := rs.privVal.GetAddress()
clientAddr := sc.GetAddress()
serverAddr := rs.privVal.GetPubKey().Address()
clientAddr := sc.GetPubKey().Address()
assert.Equal(t, serverAddr, clientAddr)
// TODO(xla): Remove when PrivValidator2 replaced PrivValidator.
assert.Equal(t, serverAddr, sc.GetAddress())
}
func TestSocketPVPubKey(t *testing.T) {
@@ -47,12 +42,9 @@ func TestSocketPVPubKey(t *testing.T) {
clientKey, err := sc.getPubKey()
require.NoError(t, err)
privKey := rs.privVal.GetPubKey()
privvalPubKey := rs.privVal.GetPubKey()
assert.Equal(t, privKey, clientKey)
// TODO(xla): Remove when PrivValidator2 replaced PrivValidator.
assert.Equal(t, privKey, sc.GetPubKey())
assert.Equal(t, privvalPubKey, clientKey)
}
func TestSocketPVProposal(t *testing.T) {
@@ -153,9 +145,9 @@ func TestSocketPVDeadline(t *testing.T) {
go func(sc *TCPVal) {
defer close(listenc)
require.NoError(t, sc.Start())
assert.Equal(t, sc.Start().(cmn.Error).Data(), ErrConnTimeout)
assert.True(t, sc.IsRunning())
assert.False(t, sc.IsRunning())
}(sc)
for {
@@ -174,9 +166,6 @@ func TestSocketPVDeadline(t *testing.T) {
}
<-listenc
_, err := sc.getPubKey()
assert.Equal(t, err.(cmn.Error).Data(), ErrConnTimeout)
}
func TestRemoteSignerRetry(t *testing.T) {
@@ -310,14 +299,15 @@ func TestErrUnexpectedResponse(t *testing.T) {
testStartSocketPV(t, readyc, sc)
defer sc.Stop()
RemoteSignerConnDeadline(time.Millisecond)(rs)
RemoteSignerConnRetries(1e6)(rs)
RemoteSignerConnRetries(100)(rs)
// we do not want to Start() the remote signer here and instead use the connection to
// reply with intentionally wrong replies below:
rsConn, err := rs.connect()
defer rsConn.Close()
require.NoError(t, err)
require.NotNil(t, rsConn)
// send over public key to get the remote signer running:
go testReadWriteResponse(t, &PubKeyResponse{}, rsConn)
<-readyc
// Proposal: