Skip to content

Commit 4e0c93a

Browse files
update grpc benchmarks to support real crypto
Signed-off-by: Said Altury <Said.Altury@ibm.com>
1 parent 74f5347 commit 4e0c93a

File tree

3 files changed

+179
-57
lines changed

3 files changed

+179
-57
lines changed

integration/benchmark/grpc/grpc_bench_test.go

Lines changed: 176 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,16 @@ package test
88

99
import (
1010
"encoding/json"
11+
"os"
12+
"path/filepath"
1113
"testing"
1214
"time"
1315

1416
"github.com/hyperledger-labs/fabric-smart-client/integration/benchmark"
1517
benchviews "github.com/hyperledger-labs/fabric-smart-client/integration/benchmark/views"
1618
"github.com/hyperledger-labs/fabric-smart-client/platform/view/services/grpc"
1719
"github.com/hyperledger-labs/fabric-smart-client/platform/view/services/metrics/disabled"
20+
"github.com/hyperledger-labs/fabric-smart-client/platform/view/services/view/grpc/client"
1821
"github.com/hyperledger-labs/fabric-smart-client/platform/view/services/view/grpc/server"
1922
"github.com/hyperledger-labs/fabric-smart-client/platform/view/services/view/grpc/server/protos"
2023
"github.com/hyperledger-labs/fabric-smart-client/platform/view/view"
@@ -23,12 +26,115 @@ import (
2326
"go.opentelemetry.io/otel/trace/noop"
2427
)
2528

29+
// setupCrypto generates certificates and writes them to temporary files.
30+
// It returns the paths and a cleanup function to delete the files after the test.
31+
func setupCrypto(tb testing.TB) (certPath, keyPath string) {
32+
// 1. Call your helper to get PEM bytes
33+
keyPEM, certPEM, err := makeSelfSignedCert()
34+
require.NoError(tb, err)
35+
36+
// 2. Create Temp Directory
37+
tmpDir := tb.TempDir()
38+
39+
certPath = filepath.Join(tmpDir, "cert.pem")
40+
keyPath = filepath.Join(tmpDir, "key.pem")
41+
42+
// 3. Write the PEM bytes directly to files
43+
err = os.WriteFile(certPath, certPEM, 0644)
44+
require.NoError(tb, err)
45+
46+
err = os.WriteFile(keyPath, keyPEM, 0600)
47+
require.NoError(tb, err)
48+
49+
return certPath, keyPath
50+
}
51+
52+
// --- Option Types ---
53+
54+
type serverConfig struct {
55+
workload view.View
56+
signer client.SigningIdentity
57+
idProvider *benchmark.MockIdentityProvider
58+
}
59+
60+
type clientConfig struct {
61+
signer client.SigningIdentity
62+
}
63+
64+
type ServerOption func(tb testing.TB, c *serverConfig)
65+
type ClientOption func(tb testing.TB, c *clientConfig)
66+
67+
// --- Server Options ---
68+
69+
func WithCPUWorkload(n int) ServerOption {
70+
return func(tb testing.TB, c *serverConfig) {
71+
params := &benchviews.CPUParams{N: n}
72+
input, _ := json.Marshal(params)
73+
factory := &benchviews.CPUViewFactory{}
74+
v, err := factory.NewView(input)
75+
require.NoError(tb, err)
76+
c.workload = v
77+
}
78+
}
79+
80+
func WithECDSAWorkload() ServerOption {
81+
return func(tb testing.TB, c *serverConfig) {
82+
params := &benchviews.ECDSASignParams{}
83+
input, _ := json.Marshal(params)
84+
factory := &benchviews.ECDSASignViewFactory{}
85+
v, err := factory.NewView(input)
86+
require.NoError(tb, err)
87+
c.workload = v
88+
}
89+
}
90+
91+
func WithServerMockSigner(id string) ServerOption {
92+
return func(tb testing.TB, c *serverConfig) {
93+
mIdentity := view.Identity(id)
94+
c.signer = &benchmark.MockSigner{
95+
SerializeFunc: func() ([]byte, error) { return mIdentity.Bytes(), nil },
96+
SignFunc: func(b []byte) ([]byte, error) { return b, nil },
97+
}
98+
c.idProvider = &benchmark.MockIdentityProvider{DefaultSigner: mIdentity}
99+
}
100+
}
101+
102+
func WithServerECDSASigner(certPath, keyPath string) ServerOption {
103+
return func(tb testing.TB, c *serverConfig) {
104+
signer, err := client.NewX509SigningIdentity(certPath, keyPath)
105+
require.NoError(tb, err)
106+
c.signer = signer
107+
serialized, _ := signer.Serialize()
108+
c.idProvider = &benchmark.MockIdentityProvider{DefaultSigner: view.Identity(serialized)}
109+
}
110+
}
111+
112+
// --- Client Options ---
113+
114+
func WithClientMockSigner(id string) ClientOption {
115+
return func(tb testing.TB, c *clientConfig) {
116+
mIdentity := view.Identity(id)
117+
c.signer = &benchmark.MockSigner{
118+
SerializeFunc: func() ([]byte, error) { return mIdentity.Bytes(), nil },
119+
SignFunc: func(b []byte) ([]byte, error) { return b, nil },
120+
}
121+
}
122+
}
123+
124+
func WithClientECDSASigner(certPath, keyPath string) ClientOption {
125+
return func(tb testing.TB, c *clientConfig) {
126+
signer, err := client.NewX509SigningIdentity(certPath, keyPath)
127+
require.NoError(tb, err)
128+
c.signer = signer
129+
}
130+
}
131+
26132
func BenchmarkGRPCSingleConnectionCPU(b *testing.B) {
27-
srvEndpoint := setupServer(b, "cpu")
133+
srvEndpoint := setupServer(b, WithServerMockSigner("default-server-id"), WithCPUWorkload(200000))
28134
b.ResetTimer()
29135

30136
// we share a single connection among all client goroutines
31-
cli, closeF := setupClient(b, srvEndpoint)
137+
cli, closeF := setupClient(b, srvEndpoint, WithClientMockSigner("default-client-id"))
32138
defer closeF()
33139

34140
b.RunParallel(func(pb *testing.PB) {
@@ -42,12 +148,12 @@ func BenchmarkGRPCSingleConnectionCPU(b *testing.B) {
42148
}
43149

44150
func BenchmarkGRPCMultiConnectionCPU(b *testing.B) {
45-
srvEndpoint := setupServer(b, "cpu")
151+
srvEndpoint := setupServer(b, WithServerMockSigner("default-server-id"), WithCPUWorkload(200000))
46152
b.ResetTimer()
47153

48154
b.RunParallel(func(pb *testing.PB) {
49155
// each goroutine gets its own client + connection
50-
cli, closeF := setupClient(b, srvEndpoint)
156+
cli, closeF := setupClient(b, srvEndpoint, WithClientMockSigner("default-client-id"))
51157
defer closeF()
52158

53159
for pb.Next() {
@@ -61,12 +167,47 @@ func BenchmarkGRPCMultiConnectionCPU(b *testing.B) {
61167
}
62168

63169
// --- ECDSA Workload Benchmarks ---
170+
func BenchmarkGRPCSingleConnectionECDSAWithMockSigner(b *testing.B) {
171+
srvEndpoint := setupServer(b, WithECDSAWorkload(), WithServerMockSigner("default-server-id"))
172+
b.ResetTimer()
173+
174+
cli, closeF := setupClient(b, srvEndpoint, WithClientMockSigner("default-client-id"))
175+
defer closeF()
176+
b.RunParallel(func(pb *testing.PB) {
177+
for pb.Next() {
178+
resp, err := cli.CallViewWithContext(b.Context(), "fid", nil)
179+
require.NoError(b, err)
180+
require.NotNil(b, resp)
181+
}
182+
})
183+
benchmark.ReportTPS(b)
184+
}
64185

65-
func BenchmarkGRPCSingleConnectionECDSA(b *testing.B) {
66-
srvEndpoint := setupServer(b, "ecdsa")
186+
func BenchmarkGRPCMultiConnectionECDSAWithMockSigner(b *testing.B) {
187+
srvEndpoint := setupServer(b, WithECDSAWorkload(), WithServerMockSigner("default-server-id"))
67188
b.ResetTimer()
189+
b.RunParallel(func(pb *testing.PB) {
190+
cli, closeF := setupClient(b, srvEndpoint, WithClientMockSigner("default-client-id"))
191+
defer closeF()
68192

69-
cli, closeF := setupClient(b, srvEndpoint)
193+
for pb.Next() {
194+
resp, err := cli.CallViewWithContext(b.Context(), "fid", nil)
195+
require.NoError(b, err)
196+
require.NotNil(b, resp)
197+
}
198+
})
199+
benchmark.ReportTPS(b)
200+
}
201+
202+
// --- ECDSA Workload Benchmarks real gRPC crypto ---
203+
204+
func BenchmarkGRPCSingleConnectionECDSAWithECDSASigner(b *testing.B) {
205+
cPath, kPath := setupCrypto(b)
206+
207+
srvEndpoint := setupServer(b, WithECDSAWorkload(), WithServerECDSASigner(cPath, kPath))
208+
b.ResetTimer()
209+
210+
cli, closeF := setupClient(b, srvEndpoint, WithClientECDSASigner(cPath, kPath))
70211
defer closeF()
71212
b.RunParallel(func(pb *testing.PB) {
72213
for pb.Next() {
@@ -78,11 +219,13 @@ func BenchmarkGRPCSingleConnectionECDSA(b *testing.B) {
78219
benchmark.ReportTPS(b)
79220
}
80221

81-
func BenchmarkGRPCMultiConnectionECDSA(b *testing.B) {
82-
srvEndpoint := setupServer(b, "ecdsa")
222+
func BenchmarkGRPCMultiConnectionECDSAWithECDSASigner(b *testing.B) {
223+
cPath, kPath := setupCrypto(b)
224+
225+
srvEndpoint := setupServer(b, WithECDSAWorkload(), WithServerECDSASigner(cPath, kPath))
83226
b.ResetTimer()
84227
b.RunParallel(func(pb *testing.PB) {
85-
cli, closeF := setupClient(b, srvEndpoint)
228+
cli, closeF := setupClient(b, srvEndpoint, WithClientECDSASigner(cPath, kPath))
86229
defer closeF()
87230

88231
for pb.Next() {
@@ -94,23 +237,23 @@ func BenchmarkGRPCMultiConnectionECDSA(b *testing.B) {
94237
benchmark.ReportTPS(b)
95238
}
96239

97-
func setupServer(tb testing.TB, workloadType string) string {
240+
func setupServer(tb testing.TB, opts ...ServerOption) string {
98241
tb.Helper()
99242

100-
mDefaultIdentity := view.Identity("server identity")
101-
mSigner := &benchmark.MockSigner{
102-
SerializeFunc: func() ([]byte, error) {
103-
return mDefaultIdentity.Bytes(), nil
104-
},
105-
SignFunc: func(bytes []byte) ([]byte, error) {
106-
return bytes, nil
107-
},
243+
cfg := &serverConfig{}
244+
// Apply options
245+
for _, opt := range opts {
246+
opt(tb, cfg)
108247
}
109-
mIdentityProvider := &benchmark.MockIdentityProvider{DefaultSigner: mDefaultIdentity}
110-
mSigService := &benchmark.MockSignerProvider{DefaultSigner: mSigner}
111248

249+
// Validate that the options successfully populated the config
250+
require.NotNil(tb, cfg.workload, "server workload was not configured by options")
251+
require.NotNil(tb, cfg.signer, "server signer was not configured by options")
252+
require.NotNil(tb, cfg.idProvider, "server identity provider was not configured by options")
253+
254+
mSigService := &benchmark.MockSignerProvider{DefaultSigner: cfg.signer}
112255
// marshaller
113-
tm, err := server.NewResponseMarshaler(mIdentityProvider, mSigService)
256+
tm, err := server.NewResponseMarshaler(cfg.idProvider, mSigService)
114257
require.NoError(tb, err)
115258
require.NotNil(tb, tm)
116259

@@ -133,28 +276,8 @@ func setupServer(tb testing.TB, workloadType string) string {
133276
srv, err := server.NewViewServiceServer(tm, &server.YesPolicyChecker{}, server.NewMetrics(&disabled.Provider{}), noop.NewTracerProvider())
134277
require.NoError(tb, err)
135278
require.NotNil(tb, srv)
136-
137-
var v view.View
138-
switch workloadType {
139-
case "cpu":
140-
parms := &benchviews.CPUParams{N: 200000}
141-
input, _ := json.Marshal(parms)
142-
factory := &benchviews.CPUViewFactory{}
143-
v, _ = factory.NewView(input)
144-
case "ecdsa":
145-
parms := &benchviews.ECDSASignParams{}
146-
input, _ := json.Marshal(parms)
147-
factory := &benchviews.ECDSASignViewFactory{}
148-
v, _ = factory.NewView(input)
149-
default:
150-
tb.Fatalf("unknown workload type: %s", workloadType)
151-
}
152-
153279
// our view manager
154-
vm := &benchmark.MockViewManager{Constructor: func() view.View {
155-
return v
156-
}}
157-
280+
vm := &benchmark.MockViewManager{Constructor: func() view.View { return cfg.workload }}
158281
// register view manager wit grpc impl
159282
server.InstallViewHandler(vm, srv, noop.NewTracerProvider())
160283

@@ -170,19 +293,18 @@ func setupServer(tb testing.TB, workloadType string) string {
170293
return grpcSrv.Address()
171294
}
172295

173-
func setupClient(tb testing.TB, srvEndpoint string) (*benchmark.ViewClient, func()) {
296+
func setupClient(tb testing.TB, srvEndpoint string, opts ...ClientOption) (*benchmark.ViewClient, func()) {
174297
tb.Helper()
175298

176-
mDefaultIdentity := view.Identity("client identity")
177-
mSigner := &benchmark.MockSigner{
178-
SerializeFunc: func() ([]byte, error) {
179-
return mDefaultIdentity.Bytes(), nil
180-
},
181-
SignFunc: func(bytes []byte) ([]byte, error) {
182-
return bytes, nil
183-
}}
299+
cfg := &clientConfig{}
300+
// Apply options
301+
for _, opt := range opts {
302+
opt(tb, cfg)
303+
}
304+
// Validate that the signer is present before proceeding
305+
require.NotNil(tb, cfg.signer, "client signer was not configured by options")
184306

185-
signerIdentity, err := mSigner.Serialize()
307+
signerIdentity, err := cfg.signer.Serialize()
186308
require.NoError(tb, err)
187309

188310
grpcClient, err := grpc.NewGRPCClient(grpc.ClientConfig{
@@ -206,7 +328,7 @@ func setupClient(tb testing.TB, srvEndpoint string) (*benchmark.ViewClient, func
206328
require.NoError(tb, err)
207329

208330
cli := &benchmark.ViewClient{
209-
SignF: mSigner.Sign,
331+
SignF: cfg.signer.Sign,
210332
Creator: signerIdentity,
211333
TLSCertHash: tlsCertHash,
212334
Client: protos.NewViewServiceClient(conn),

integration/benchmark/grpc/reference_bench_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ func makeSelfSignedCert() ([]byte, []byte, error) {
8080
// 4. PEM-encode cert & private key
8181
certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
8282

83-
keyBytes, err := x509.MarshalECPrivateKey(key)
83+
keyBytes, err := x509.MarshalPKCS8PrivateKey(key)
8484
if err != nil {
8585
return nil, nil, err
8686
}

integration/benchmark/grpc/view_bench_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ import (
1414
)
1515

1616
func BenchmarkView(b *testing.B) {
17-
srvEndpoint := setupServer(b, "cpu")
17+
srvEndpoint := setupServer(b, WithServerMockSigner("default-server-id"), WithCPUWorkload(200000))
1818

1919
// we share a single connection among all client goroutines
20-
cli, closeF := setupClient(b, srvEndpoint)
20+
cli, closeF := setupClient(b, srvEndpoint, WithClientMockSigner("default-client-id"))
2121
defer closeF()
2222

2323
b.RunParallel(func(pb *testing.PB) {

0 commit comments

Comments
 (0)