mirror of
https://github.com/tendermint/tendermint.git
synced 2026-09-20 15:04:22 +00:00
privval: add grpc (#5725)
Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com>
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
grpc "google.golang.org/grpc"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
cryptoenc "github.com/tendermint/tendermint/crypto/encoding"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
privvalproto "github.com/tendermint/tendermint/proto/tendermint/privval"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
// SignerClient implements PrivValidator.
|
||||
// Handles remote validator connections that provide signing services
|
||||
type SignerClient struct {
|
||||
logger log.Logger
|
||||
|
||||
client privvalproto.PrivValidatorAPIClient
|
||||
conn *grpc.ClientConn
|
||||
chainID string
|
||||
}
|
||||
|
||||
var _ types.PrivValidator = (*SignerClient)(nil)
|
||||
|
||||
// NewSignerClient returns an instance of SignerClient.
|
||||
// it will start the endpoint (if not already started)
|
||||
func NewSignerClient(conn *grpc.ClientConn,
|
||||
chainID string, log log.Logger) (*SignerClient, error) {
|
||||
|
||||
sc := &SignerClient{
|
||||
logger: log,
|
||||
chainID: chainID,
|
||||
client: privvalproto.NewPrivValidatorAPIClient(conn), // Create the Private Validator Client
|
||||
}
|
||||
|
||||
return sc, nil
|
||||
}
|
||||
|
||||
// Close closes the underlying connection
|
||||
func (sc *SignerClient) Close() error {
|
||||
sc.logger.Info("Stopping service")
|
||||
if sc.conn != nil {
|
||||
return sc.conn.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Implement PrivValidator
|
||||
|
||||
// GetPubKey retrieves a public key from a remote signer
|
||||
// returns an error if client is not able to provide the key
|
||||
func (sc *SignerClient) GetPubKey() (crypto.PubKey, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) // Todo: should this be configurable?
|
||||
defer cancel()
|
||||
resp, err := sc.client.GetPubKey(ctx, &privvalproto.PubKeyRequest{ChainId: sc.chainID})
|
||||
if err != nil {
|
||||
errStatus, _ := status.FromError(err)
|
||||
sc.logger.Error("SignerClient::GetPubKey", "err", errStatus.Message())
|
||||
return nil, errStatus.Err()
|
||||
}
|
||||
|
||||
pk, err := cryptoenc.PubKeyFromProto(resp.PubKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return pk, nil
|
||||
}
|
||||
|
||||
// SignVote requests a remote signer to sign a vote
|
||||
func (sc *SignerClient) SignVote(chainID string, vote *tmproto.Vote) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
defer cancel()
|
||||
resp, err := sc.client.SignVote(ctx, &privvalproto.SignVoteRequest{ChainId: sc.chainID, Vote: vote})
|
||||
if err != nil {
|
||||
errStatus, _ := status.FromError(err)
|
||||
sc.logger.Error("Client SignVote", "err", errStatus.Message())
|
||||
return errStatus.Err()
|
||||
}
|
||||
|
||||
*vote = resp.Vote
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SignProposal requests a remote signer to sign a proposal
|
||||
func (sc *SignerClient) SignProposal(chainID string, proposal *tmproto.Proposal) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
defer cancel()
|
||||
resp, err := sc.client.SignProposal(
|
||||
ctx, &privvalproto.SignProposalRequest{ChainId: chainID, Proposal: proposal})
|
||||
|
||||
if err != nil {
|
||||
errStatus, _ := status.FromError(err)
|
||||
sc.logger.Error("SignerClient::SignProposal", "err", errStatus.Message())
|
||||
return errStatus.Err()
|
||||
}
|
||||
|
||||
*proposal = resp.Proposal
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
package grpc_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
grpc "google.golang.org/grpc"
|
||||
"google.golang.org/grpc/test/bufconn"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/crypto/tmhash"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmrand "github.com/tendermint/tendermint/libs/rand"
|
||||
tmgrpc "github.com/tendermint/tendermint/privval/grpc"
|
||||
privvalproto "github.com/tendermint/tendermint/proto/tendermint/privval"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
const chainID = "chain-id"
|
||||
|
||||
func dialer(pv types.PrivValidator, logger log.Logger) (*grpc.Server, func(context.Context, string) (net.Conn, error)) {
|
||||
listener := bufconn.Listen(1024 * 1024)
|
||||
|
||||
server := grpc.NewServer()
|
||||
|
||||
s := tmgrpc.NewSignerServer(chainID, pv, logger)
|
||||
|
||||
privvalproto.RegisterPrivValidatorAPIServer(server, s)
|
||||
|
||||
go func() {
|
||||
if err := server.Serve(listener); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
return server, func(context.Context, string) (net.Conn, error) {
|
||||
return listener.Dial()
|
||||
}
|
||||
}
|
||||
|
||||
func TestSignerClient_GetPubKey(t *testing.T) {
|
||||
|
||||
ctx := context.Background()
|
||||
mockPV := types.NewMockPV()
|
||||
logger := log.TestingLogger()
|
||||
srv, dialer := dialer(mockPV, logger)
|
||||
defer srv.Stop()
|
||||
|
||||
conn, err := grpc.DialContext(ctx, "", grpc.WithInsecure(), grpc.WithContextDialer(dialer))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
client, err := tmgrpc.NewSignerClient(conn, chainID, logger)
|
||||
require.NoError(t, err)
|
||||
|
||||
pk, err := client.GetPubKey()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, mockPV.PrivKey.PubKey(), pk)
|
||||
}
|
||||
|
||||
func TestSignerClient_SignVote(t *testing.T) {
|
||||
|
||||
ctx := context.Background()
|
||||
mockPV := types.NewMockPV()
|
||||
logger := log.TestingLogger()
|
||||
srv, dialer := dialer(mockPV, logger)
|
||||
defer srv.Stop()
|
||||
|
||||
conn, err := grpc.DialContext(ctx, "", grpc.WithInsecure(), grpc.WithContextDialer(dialer))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
client, err := tmgrpc.NewSignerClient(conn, chainID, logger)
|
||||
require.NoError(t, err)
|
||||
|
||||
ts := time.Now()
|
||||
hash := tmrand.Bytes(tmhash.Size)
|
||||
valAddr := tmrand.Bytes(crypto.AddressSize)
|
||||
|
||||
want := &types.Vote{
|
||||
Type: tmproto.PrecommitType,
|
||||
Height: 1,
|
||||
Round: 2,
|
||||
BlockID: types.BlockID{Hash: hash, PartSetHeader: types.PartSetHeader{Hash: hash, Total: 2}},
|
||||
Timestamp: ts,
|
||||
ValidatorAddress: valAddr,
|
||||
ValidatorIndex: 1,
|
||||
}
|
||||
|
||||
have := &types.Vote{
|
||||
Type: tmproto.PrecommitType,
|
||||
Height: 1,
|
||||
Round: 2,
|
||||
BlockID: types.BlockID{Hash: hash, PartSetHeader: types.PartSetHeader{Hash: hash, Total: 2}},
|
||||
Timestamp: ts,
|
||||
ValidatorAddress: valAddr,
|
||||
ValidatorIndex: 1,
|
||||
}
|
||||
|
||||
pbHave := have.ToProto()
|
||||
|
||||
err = client.SignVote(chainID, pbHave)
|
||||
require.NoError(t, err)
|
||||
|
||||
pbWant := want.ToProto()
|
||||
|
||||
require.NoError(t, mockPV.SignVote(chainID, pbWant))
|
||||
|
||||
assert.Equal(t, pbWant.Signature, pbHave.Signature)
|
||||
}
|
||||
|
||||
func TestSignerClient_SignProposal(t *testing.T) {
|
||||
|
||||
ctx := context.Background()
|
||||
mockPV := types.NewMockPV()
|
||||
logger := log.TestingLogger()
|
||||
srv, dialer := dialer(mockPV, logger)
|
||||
defer srv.Stop()
|
||||
|
||||
conn, err := grpc.DialContext(ctx, "", grpc.WithInsecure(), grpc.WithContextDialer(dialer))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
client, err := tmgrpc.NewSignerClient(conn, chainID, logger)
|
||||
require.NoError(t, err)
|
||||
|
||||
ts := time.Now()
|
||||
hash := tmrand.Bytes(tmhash.Size)
|
||||
|
||||
have := &types.Proposal{
|
||||
Type: tmproto.ProposalType,
|
||||
Height: 1,
|
||||
Round: 2,
|
||||
POLRound: 2,
|
||||
BlockID: types.BlockID{Hash: hash, PartSetHeader: types.PartSetHeader{Hash: hash, Total: 2}},
|
||||
Timestamp: ts,
|
||||
}
|
||||
want := &types.Proposal{
|
||||
Type: tmproto.ProposalType,
|
||||
Height: 1,
|
||||
Round: 2,
|
||||
POLRound: 2,
|
||||
BlockID: types.BlockID{Hash: hash, PartSetHeader: types.PartSetHeader{Hash: hash, Total: 2}},
|
||||
Timestamp: ts,
|
||||
}
|
||||
|
||||
pbHave := have.ToProto()
|
||||
|
||||
err = client.SignProposal(chainID, pbHave)
|
||||
require.NoError(t, err)
|
||||
|
||||
pbWant := want.ToProto()
|
||||
|
||||
require.NoError(t, mockPV.SignProposal(chainID, pbWant))
|
||||
|
||||
assert.Equal(t, pbWant.Signature, pbHave.Signature)
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
cryptoenc "github.com/tendermint/tendermint/crypto/encoding"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
privvalproto "github.com/tendermint/tendermint/proto/tendermint/privval"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
// SignerServer implements PrivValidatorAPIServer 9generated via protobuf services)
|
||||
// Handles remote validator connections that provide signing services
|
||||
type SignerServer struct {
|
||||
logger log.Logger
|
||||
chainID string
|
||||
privVal types.PrivValidator
|
||||
}
|
||||
|
||||
func NewSignerServer(chainID string,
|
||||
privVal types.PrivValidator, log log.Logger) *SignerServer {
|
||||
|
||||
return &SignerServer{
|
||||
logger: log,
|
||||
chainID: chainID,
|
||||
privVal: privVal,
|
||||
}
|
||||
}
|
||||
|
||||
var _ privvalproto.PrivValidatorAPIServer = (*SignerServer)(nil)
|
||||
|
||||
// PubKey receives a request for the pubkey
|
||||
// returns the pubkey on success and error on failure
|
||||
func (ss *SignerServer) GetPubKey(ctx context.Context, req *privvalproto.PubKeyRequest) (
|
||||
*privvalproto.PubKeyResponse, error) {
|
||||
var pubKey crypto.PubKey
|
||||
|
||||
pubKey, err := ss.privVal.GetPubKey()
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.NotFound, "error getting pubkey: %v", err)
|
||||
}
|
||||
|
||||
pk, err := cryptoenc.PubKeyToProto(pubKey)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "error transitioning pubkey to proto: %v", err)
|
||||
}
|
||||
|
||||
ss.logger.Info("SignerServer: GetPubKey Success")
|
||||
|
||||
return &privvalproto.PubKeyResponse{PubKey: pk}, nil
|
||||
}
|
||||
|
||||
// SignVote receives a vote sign requests, attempts to sign it
|
||||
// returns SignedVoteResponse on success and error on failure
|
||||
func (ss *SignerServer) SignVote(ctx context.Context, req *privvalproto.SignVoteRequest) (
|
||||
*privvalproto.SignedVoteResponse, error) {
|
||||
vote := req.Vote
|
||||
|
||||
err := ss.privVal.SignVote(req.ChainId, vote)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "error signing vote: %v", err)
|
||||
}
|
||||
|
||||
ss.logger.Info("SignerServer: SignVote Success")
|
||||
|
||||
return &privvalproto.SignedVoteResponse{Vote: *vote}, nil
|
||||
}
|
||||
|
||||
// SignProposal receives a proposal sign requests, attempts to sign it
|
||||
// returns SignedProposalResponse on success and error on failure
|
||||
func (ss *SignerServer) SignProposal(ctx context.Context, req *privvalproto.SignProposalRequest) (
|
||||
*privvalproto.SignedProposalResponse, error) {
|
||||
proposal := req.Proposal
|
||||
|
||||
err := ss.privVal.SignProposal(req.ChainId, proposal)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "error signing proposal: %v", err)
|
||||
}
|
||||
|
||||
ss.logger.Info("SignerServer: SignProposal Success")
|
||||
|
||||
return &privvalproto.SignedProposalResponse{Proposal: *proposal}, nil
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
package grpc_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/crypto/tmhash"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmrand "github.com/tendermint/tendermint/libs/rand"
|
||||
tmgrpc "github.com/tendermint/tendermint/privval/grpc"
|
||||
privvalproto "github.com/tendermint/tendermint/proto/tendermint/privval"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
const ChainID = "123"
|
||||
|
||||
func TestGetPubKey(t *testing.T) {
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
pv types.PrivValidator
|
||||
err bool
|
||||
}{
|
||||
{name: "valid", pv: types.NewMockPV(), err: false},
|
||||
{name: "error on pubkey", pv: types.NewErroringMockPV(), err: true},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
s := tmgrpc.NewSignerServer(ChainID, tc.pv, log.TestingLogger())
|
||||
|
||||
req := &privvalproto.PubKeyRequest{ChainId: ChainID}
|
||||
resp, err := s.GetPubKey(context.Background(), req)
|
||||
if tc.err {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
pk, err := tc.pv.GetPubKey()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, resp.PubKey.GetEd25519(), pk.Bytes())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestSignVote(t *testing.T) {
|
||||
|
||||
ts := time.Now()
|
||||
hash := tmrand.Bytes(tmhash.Size)
|
||||
valAddr := tmrand.Bytes(crypto.AddressSize)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
pv types.PrivValidator
|
||||
have, want *types.Vote
|
||||
err bool
|
||||
}{
|
||||
{name: "valid", pv: types.NewMockPV(), have: &types.Vote{
|
||||
Type: tmproto.PrecommitType,
|
||||
Height: 1,
|
||||
Round: 2,
|
||||
BlockID: types.BlockID{Hash: hash, PartSetHeader: types.PartSetHeader{Hash: hash, Total: 2}},
|
||||
Timestamp: ts,
|
||||
ValidatorAddress: valAddr,
|
||||
ValidatorIndex: 1,
|
||||
}, want: &types.Vote{
|
||||
Type: tmproto.PrecommitType,
|
||||
Height: 1,
|
||||
Round: 2,
|
||||
BlockID: types.BlockID{Hash: hash, PartSetHeader: types.PartSetHeader{Hash: hash, Total: 2}},
|
||||
Timestamp: ts,
|
||||
ValidatorAddress: valAddr,
|
||||
ValidatorIndex: 1,
|
||||
},
|
||||
err: false},
|
||||
{name: "invalid vote", pv: types.NewErroringMockPV(), have: &types.Vote{
|
||||
Type: tmproto.PrecommitType,
|
||||
Height: 1,
|
||||
Round: 2,
|
||||
BlockID: types.BlockID{Hash: hash, PartSetHeader: types.PartSetHeader{Hash: hash, Total: 2}},
|
||||
Timestamp: ts,
|
||||
ValidatorAddress: valAddr,
|
||||
ValidatorIndex: 1,
|
||||
Signature: []byte("signed"),
|
||||
}, want: &types.Vote{
|
||||
Type: tmproto.PrecommitType,
|
||||
Height: 1,
|
||||
Round: 2,
|
||||
BlockID: types.BlockID{Hash: hash, PartSetHeader: types.PartSetHeader{Hash: hash, Total: 2}},
|
||||
Timestamp: ts,
|
||||
ValidatorAddress: valAddr,
|
||||
ValidatorIndex: 1,
|
||||
Signature: []byte("signed"),
|
||||
},
|
||||
err: true},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
s := tmgrpc.NewSignerServer(ChainID, tc.pv, log.TestingLogger())
|
||||
|
||||
req := &privvalproto.SignVoteRequest{ChainId: ChainID, Vote: tc.have.ToProto()}
|
||||
resp, err := s.SignVote(context.Background(), req)
|
||||
if tc.err {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
pbVote := tc.want.ToProto()
|
||||
|
||||
require.NoError(t, tc.pv.SignVote(ChainID, pbVote))
|
||||
assert.Equal(t, pbVote.Signature, resp.Vote.Signature)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSignProposal(t *testing.T) {
|
||||
|
||||
ts := time.Now()
|
||||
hash := tmrand.Bytes(tmhash.Size)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
pv types.PrivValidator
|
||||
have, want *types.Proposal
|
||||
err bool
|
||||
}{
|
||||
{name: "valid", pv: types.NewMockPV(), have: &types.Proposal{
|
||||
Type: tmproto.ProposalType,
|
||||
Height: 1,
|
||||
Round: 2,
|
||||
POLRound: 2,
|
||||
BlockID: types.BlockID{Hash: hash, PartSetHeader: types.PartSetHeader{Hash: hash, Total: 2}},
|
||||
Timestamp: ts,
|
||||
}, want: &types.Proposal{
|
||||
Type: tmproto.ProposalType,
|
||||
Height: 1,
|
||||
Round: 2,
|
||||
POLRound: 2,
|
||||
BlockID: types.BlockID{Hash: hash, PartSetHeader: types.PartSetHeader{Hash: hash, Total: 2}},
|
||||
Timestamp: ts,
|
||||
},
|
||||
err: false},
|
||||
{name: "invalid proposal", pv: types.NewErroringMockPV(), have: &types.Proposal{
|
||||
Type: tmproto.ProposalType,
|
||||
Height: 1,
|
||||
Round: 2,
|
||||
POLRound: 2,
|
||||
BlockID: types.BlockID{Hash: hash, PartSetHeader: types.PartSetHeader{Hash: hash, Total: 2}},
|
||||
Timestamp: ts,
|
||||
Signature: []byte("signed"),
|
||||
}, want: &types.Proposal{
|
||||
Type: tmproto.ProposalType,
|
||||
Height: 1,
|
||||
Round: 2,
|
||||
POLRound: 2,
|
||||
BlockID: types.BlockID{Hash: hash, PartSetHeader: types.PartSetHeader{Hash: hash, Total: 2}},
|
||||
Timestamp: ts,
|
||||
Signature: []byte("signed"),
|
||||
},
|
||||
err: true},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
s := tmgrpc.NewSignerServer(ChainID, tc.pv, log.TestingLogger())
|
||||
|
||||
req := &privvalproto.SignProposalRequest{ChainId: ChainID, Proposal: tc.have.ToProto()}
|
||||
resp, err := s.SignProposal(context.Background(), req)
|
||||
if tc.err {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
pbProposal := tc.want.ToProto()
|
||||
require.NoError(t, tc.pv.SignProposal(ChainID, pbProposal))
|
||||
assert.Equal(t, pbProposal.Signature, resp.Proposal.Signature)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/retry"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
grpc "google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/keepalive"
|
||||
)
|
||||
|
||||
// DefaultDialOptions constructs a list of grpc dial options
|
||||
func DefaultDialOptions(
|
||||
extraOpts ...grpc.DialOption,
|
||||
) []grpc.DialOption {
|
||||
const (
|
||||
retries = 50 // 50 * 100ms = 5s total
|
||||
timeout = 1 * time.Second
|
||||
maxCallRecvMsgSize = 1 << 20 // Default 5Mb
|
||||
)
|
||||
|
||||
var kacp = keepalive.ClientParameters{
|
||||
Time: 10 * time.Second, // send pings every 10 seconds if there is no activity
|
||||
Timeout: 2 * time.Second, // wait 2 seconds for ping ack before considering the connection dead
|
||||
}
|
||||
|
||||
opts := []grpc_retry.CallOption{
|
||||
grpc_retry.WithBackoff(grpc_retry.BackoffExponential(timeout)),
|
||||
}
|
||||
|
||||
dialOpts := []grpc.DialOption{
|
||||
grpc.WithKeepaliveParams(kacp),
|
||||
grpc.WithDefaultCallOptions(
|
||||
grpc.MaxCallRecvMsgSize(maxCallRecvMsgSize),
|
||||
grpc_retry.WithMax(retries),
|
||||
),
|
||||
grpc.WithUnaryInterceptor(
|
||||
grpc_retry.UnaryClientInterceptor(opts...),
|
||||
),
|
||||
}
|
||||
|
||||
dialOpts = append(dialOpts, extraOpts...)
|
||||
|
||||
return dialOpts
|
||||
}
|
||||
|
||||
func GenerateTLS(certPath, keyPath, ca string, log log.Logger) grpc.DialOption {
|
||||
certificate, err := tls.LoadX509KeyPair(
|
||||
certPath,
|
||||
keyPath,
|
||||
)
|
||||
if err != nil {
|
||||
log.Error("error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
certPool := x509.NewCertPool()
|
||||
bs, err := ioutil.ReadFile(ca)
|
||||
if err != nil {
|
||||
log.Error("failed to read ca cert:", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
ok := certPool.AppendCertsFromPEM(bs)
|
||||
if !ok {
|
||||
log.Error("failed to append certs")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
transportCreds := credentials.NewTLS(&tls.Config{
|
||||
Certificates: []tls.Certificate{certificate},
|
||||
RootCAs: certPool,
|
||||
MinVersion: tls.VersionTLS13,
|
||||
})
|
||||
|
||||
return grpc.WithTransportCredentials(transportCreds)
|
||||
}
|
||||
Reference in New Issue
Block a user