add a gRPC test client for performance measurement and stress testing

This commit is contained in:
Larry Ruane 2020-03-11 14:56:23 -06:00 committed by Larry Ruane
parent 2e71eb3d7e
commit 46edad2748
10 changed files with 423 additions and 65 deletions

View File

@ -217,6 +217,10 @@
<a href="#cash.z.wallet.sdk.rpc.ChainSpec"><span class="badge">M</span>ChainSpec</a>
</li>
<li>
<a href="#cash.z.wallet.sdk.rpc.Duration"><span class="badge">M</span>Duration</a>
</li>
<li>
<a href="#cash.z.wallet.sdk.rpc.Empty"><span class="badge">M</span>Empty</a>
</li>
@ -225,6 +229,10 @@
<a href="#cash.z.wallet.sdk.rpc.LightdInfo"><span class="badge">M</span>LightdInfo</a>
</li>
<li>
<a href="#cash.z.wallet.sdk.rpc.PingResponse"><span class="badge">M</span>PingResponse</a>
</li>
<li>
<a href="#cash.z.wallet.sdk.rpc.RawTransaction"><span class="badge">M</span>RawTransaction</a>
</li>
@ -530,6 +538,30 @@ in a pure-Sapling context, the fee will be calculable as:
<h3 id="cash.z.wallet.sdk.rpc.Duration">Duration</h3>
<p>Duration is currently used only for testing, so that the Ping rpc</p><p>can simulate a delay, to create many simultaneous connections. Units</p><p>are microseconds.</p>
<table class="field-table">
<thead>
<tr><td>Field</td><td>Type</td><td>Label</td><td>Description</td></tr>
</thead>
<tbody>
<tr>
<td>intervalUs</td>
<td><a href="#int64">int64</a></td>
<td></td>
<td><p> </p></td>
</tr>
</tbody>
</table>
<h3 id="cash.z.wallet.sdk.rpc.Empty">Empty</h3>
<p>Empty is for gRPCs that take no arguments, currently only GetLightdInfo.</p>
@ -538,7 +570,7 @@ in a pure-Sapling context, the fee will be calculable as:
<h3 id="cash.z.wallet.sdk.rpc.LightdInfo">LightdInfo</h3>
<p>The LightdInfo returns various information about this lightwalletd instance</p><p>and the state of the blockchain.</p>
<p>LightdInfo returns various information about this lightwalletd instance</p><p>and the state of the blockchain.</p>
<table class="field-table">
@ -603,6 +635,37 @@ in a pure-Sapling context, the fee will be calculable as:
<h3 id="cash.z.wallet.sdk.rpc.PingResponse">PingResponse</h3>
<p>PingResponse is used to indicate concurrency, how many Ping rpcs</p><p>are executing upon entry and upon exit (after the delay).</p>
<table class="field-table">
<thead>
<tr><td>Field</td><td>Type</td><td>Label</td><td>Description</td></tr>
</thead>
<tbody>
<tr>
<td>entry</td>
<td><a href="#int64">int64</a></td>
<td></td>
<td><p> </p></td>
</tr>
<tr>
<td>exit</td>
<td><a href="#int64">int64</a></td>
<td></td>
<td><p> </p></td>
</tr>
</tbody>
</table>
<h3 id="cash.z.wallet.sdk.rpc.RawTransaction">RawTransaction</h3>
<p>RawTransaction contains the complete transaction data. It also optionally includes </p><p>the block height in which the transaction was included</p>
@ -797,6 +860,13 @@ in a pure-Sapling context, the fee will be calculable as:
<td><p>Misc</p></td>
</tr>
<tr>
<td>Ping</td>
<td><a href="#cash.z.wallet.sdk.rpc.Duration">Duration</a></td>
<td><a href="#cash.z.wallet.sdk.rpc.PingResponse">PingResponse</a></td>
<td><p></p></td>
</tr>
</tbody>
</table>

View File

@ -13,6 +13,7 @@ import (
"regexp"
"strconv"
"strings"
"sync/atomic"
"time"
"github.com/zcash/lightwalletd/common"
@ -243,3 +244,14 @@ func (s *LwdStreamer) SendTransaction(ctx context.Context, rawtx *walletrpc.RawT
ErrorMessage: errMsg,
}, nil
}
// This rpc is used only for testing.
var concurrent int64
func (s *LwdStreamer) Ping(ctx context.Context, in *walletrpc.Duration) (*walletrpc.PingResponse, error) {
var response walletrpc.PingResponse
response.Entry = atomic.AddInt64(&concurrent, 1)
time.Sleep(time.Duration(in.IntervalUs) * time.Microsecond)
response.Exit = atomic.AddInt64(&concurrent, -1)
return &response, nil
}

2
go.mod
View File

@ -14,7 +14,7 @@ require (
github.com/spf13/viper v1.6.2
github.com/stretchr/testify v1.4.0 // indirect
golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c // indirect
golang.org/x/net v0.0.0-20200301022130-244492dfa37a // indirect
golang.org/x/net v0.0.0-20200319234117-63522dbf7eec // indirect
golang.org/x/sys v0.0.0-20200317113312-5766fd39f98d // indirect
golang.org/x/text v0.3.2 // indirect
google.golang.org/genproto v0.0.0-20200319113533-08878b785e9c // indirect

4
go.sum
View File

@ -187,8 +187,8 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200319234117-63522dbf7eec h1:w0SItUiQ4sBiXBAwWNkyu8Fu2Qpn/dtDIcoPkPDqjRw=
golang.org/x/net v0.0.0-20200319234117-63522dbf7eec/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=

View File

@ -15,13 +15,18 @@
* limitations under the License.
*
*/
// Package main implements a client for Greeter service.
// Package main implements a gRPC test client for lightwalletd.
// This file adapted from:
// https://github.com/grpc/grpc-go/blob/master/examples/helloworld/greeter_client/main.go
// For now at least, all it does is generate a load for performance and stress testing.
package main
import (
"context"
"flag"
"io"
"log"
"strconv"
"sync"
"time"
@ -33,29 +38,114 @@ const (
address = "localhost:9067"
)
type Options struct {
concurrency int `json:"concurrency"`
iterations int `json:"iterations"`
op string `json:"op"`
verbose *bool `json:"v"`
}
func main() {
opts := &Options{}
flag.IntVar(&opts.concurrency, "concurrency", 1, "number of threads")
flag.IntVar(&opts.iterations, "iterations", 1, "number of iterations")
flag.StringVar(&opts.op, "op", "ping", "operation(ping|getlightdinfo|getblock|getblockrange)")
opts.verbose = flag.Bool("v", false, "verbose (print operation results)")
flag.Parse()
// Remaining args are all integers (at least for now)
args := make([]int64, flag.NArg())
for i := 0; i < flag.NArg(); i++ {
var err error
if args[i], err = strconv.ParseInt(flag.Arg(i), 10, 64); err != nil {
log.Fatalf("argument %v is not an int64: %v", flag.Arg(i), err)
}
}
// Set up a connection to the server.
conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())
conn, err := grpc.Dial(address, grpc.WithInsecure(),
grpc.WithConnectParams(grpc.ConnectParams{MinConnectTimeout: 30 * time.Second}))
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewCompactTxStreamerClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 1000*time.Second)
ctx, cancel := context.WithTimeout(context.Background(), 100000*time.Second)
defer cancel()
var wg sync.WaitGroup
simultaneous := 2
wg.Add(simultaneous)
for i := 0; i < simultaneous; i++ {
go func() {
r, err := c.GetLightdInfo(ctx, &pb.Empty{})
if err != nil {
log.Fatalf("could not greet: %v", err)
wg.Add(opts.concurrency)
for i := 0; i < opts.concurrency; i++ {
go func(i int) {
for j := 0; j < opts.iterations; j++ {
switch opts.op {
case "ping":
var a pb.Duration
a.IntervalUs = 8 * 1000 * 1000 // default 8 seconds
if len(args) > 0 {
a.IntervalUs = args[0]
}
r, err := c.Ping(ctx, &a)
if err != nil {
log.Fatalf("Ping failed: %v", err)
}
if *opts.verbose {
log.Println("thr:", i, "entry:", r.Entry, "exit:", r.Exit)
}
case "getlightdinfo":
r, err := c.GetLightdInfo(ctx, &pb.Empty{})
if err != nil {
log.Fatalf("GetLightwalletdInfo failed: %v", err)
}
if *opts.verbose {
log.Println("thr:", i, r)
}
case "getblock":
blockid := &pb.BlockID{Height: 748400} // default (arbitrary)
if len(args) > 0 {
blockid.Height = uint64(args[0])
}
r, err := c.GetBlock(ctx, blockid)
if err != nil {
log.Fatalf("GetLightwalletdInfo failed: %v", err)
}
// Height is enough to see if it's working
if *opts.verbose {
log.Println("thr:", i, r.Height)
}
case "getblockrange":
blockrange := &pb.BlockRange{ // defaults (arbitrary)
Start: &pb.BlockID{Height: 738100},
End: &pb.BlockID{Height: 738199},
}
if len(args) > 0 {
blockrange.Start.Height = uint64(args[0])
blockrange.End.Height = uint64(args[1])
}
stream, err := c.GetBlockRange(ctx, blockrange)
if err != nil {
log.Fatalf("GetLightwalletdInfo failed: %v", err)
}
for {
// each call to Recv returns a compact block
r, err := stream.Recv()
if err == io.EOF {
break
}
if err != nil {
log.Fatal(err)
}
// Height is enough to see if it's working
if *opts.verbose {
log.Println("thr:", i, r.Height)
}
}
default:
log.Fatalf("unknown op %s", opts.op)
}
}
log.Printf("LightdInfo: %v", r)
wg.Done()
}()
}(i)
}
wg.Wait()
}

25
testclient/stress.sh Executable file
View File

@ -0,0 +1,25 @@
#!/bin/bash
#
# Create a CSV file with various performance measurements
#
set -e
test $# -eq 0 && { echo "usage: $0 iterations op(getlighdinfo|getblock|getblockrange)";exit 1;}
iterations=$1
op=$2
export p=`pidof server`
test -z $p && { echo 'is the server running?';exit 1;}
set -- $p
test $# -ne 1 && { echo 'server pid is not unique';exit 1;}
echo "concurrency,iterations per thread,utime before (ticks),stime before (ticks),memory before (pages),time (sec),utime after (ticks),stime after (ticks),memory after (pages)"
for i in 1 200 400 600 800 1000
do
csv="$i,$iterations"
csv="$csv,`cat /proc/$p/stat|field 14`" # utime in 10ms ticks
csv="$csv,`cat /proc/$p/stat|field 15`" # stime in 10ms ticks
csv="$csv,`cat /proc/$p/statm|field 2`" # resident size in pages (8k)
csv="$csv,`/usr/bin/time -f '%e' testclient/main -concurrency $i -iterations $iterations -op $op 2>&1`"
csv="$csv,`cat /proc/$p/stat|field 14`" # utime in 10ms ticks
csv="$csv,`cat /proc/$p/stat|field 15`" # stime in 10ms ticks
csv="$csv,`cat /proc/$p/statm|field 2`"
echo $csv
done

View File

@ -1892,7 +1892,9 @@ func (rl *clientConnReadLoop) handleResponse(cs *clientStream, f *MetaHeadersFra
return nil, errors.New("malformed response from server: malformed non-numeric status pseudo header")
}
header := make(http.Header)
regularFields := f.RegularFields()
strs := make([]string, len(regularFields))
header := make(http.Header, len(regularFields))
res := &http.Response{
Proto: "HTTP/2.0",
ProtoMajor: 2,
@ -1900,7 +1902,7 @@ func (rl *clientConnReadLoop) handleResponse(cs *clientStream, f *MetaHeadersFra
StatusCode: statusCode,
Status: status + " " + http.StatusText(statusCode),
}
for _, hf := range f.RegularFields() {
for _, hf := range regularFields {
key := http.CanonicalHeaderKey(hf.Name)
if key == "Trailer" {
t := res.Trailer
@ -1912,7 +1914,18 @@ func (rl *clientConnReadLoop) handleResponse(cs *clientStream, f *MetaHeadersFra
t[http.CanonicalHeaderKey(v)] = nil
})
} else {
header[key] = append(header[key], hf.Value)
vv := header[key]
if vv == nil && len(strs) > 0 {
// More than likely this will be a single-element key.
// Most headers aren't multi-valued.
// Set the capacity on strs[0] to 1, so any future append
// won't extend the slice into the other strings.
vv, strs = strs[:1:1], strs[1:]
vv[0] = hf.Value
header[key] = vv
} else {
header[key] = append(vv, hf.Value)
}
}
}

2
vendor/modules.txt vendored
View File

@ -66,7 +66,7 @@ github.com/spf13/viper
github.com/subosito/gotenv
# golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c
golang.org/x/crypto/ripemd160
# golang.org/x/net v0.0.0-20200301022130-244492dfa37a
# golang.org/x/net v0.0.0-20200319234117-63522dbf7eec
golang.org/x/net/http/httpguts
golang.org/x/net/http2
golang.org/x/net/http2/hpack

View File

@ -343,7 +343,7 @@ func (m *Empty) XXX_DiscardUnknown() {
var xxx_messageInfo_Empty proto.InternalMessageInfo
// The LightdInfo returns various information about this lightwalletd instance
// LightdInfo returns various information about this lightwalletd instance
// and the state of the blockchain.
type LightdInfo struct {
Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"`
@ -481,6 +481,97 @@ func (m *TransparentAddressBlockFilter) GetRange() *BlockRange {
return nil
}
// Duration is currently used only for testing, so that the Ping rpc
// can simulate a delay, to create many simultaneous connections. Units
// are microseconds.
type Duration struct {
IntervalUs int64 `protobuf:"varint,1,opt,name=intervalUs,proto3" json:"intervalUs,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Duration) Reset() { *m = Duration{} }
func (m *Duration) String() string { return proto.CompactTextString(m) }
func (*Duration) ProtoMessage() {}
func (*Duration) Descriptor() ([]byte, []int) {
return fileDescriptor_a0b84a42fa06f626, []int{9}
}
func (m *Duration) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Duration.Unmarshal(m, b)
}
func (m *Duration) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Duration.Marshal(b, m, deterministic)
}
func (m *Duration) XXX_Merge(src proto.Message) {
xxx_messageInfo_Duration.Merge(m, src)
}
func (m *Duration) XXX_Size() int {
return xxx_messageInfo_Duration.Size(m)
}
func (m *Duration) XXX_DiscardUnknown() {
xxx_messageInfo_Duration.DiscardUnknown(m)
}
var xxx_messageInfo_Duration proto.InternalMessageInfo
func (m *Duration) GetIntervalUs() int64 {
if m != nil {
return m.IntervalUs
}
return 0
}
// PingResponse is used to indicate concurrency, how many Ping rpcs
// are executing upon entry and upon exit (after the delay).
type PingResponse struct {
Entry int64 `protobuf:"varint,1,opt,name=entry,proto3" json:"entry,omitempty"`
Exit int64 `protobuf:"varint,2,opt,name=exit,proto3" json:"exit,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *PingResponse) Reset() { *m = PingResponse{} }
func (m *PingResponse) String() string { return proto.CompactTextString(m) }
func (*PingResponse) ProtoMessage() {}
func (*PingResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_a0b84a42fa06f626, []int{10}
}
func (m *PingResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PingResponse.Unmarshal(m, b)
}
func (m *PingResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_PingResponse.Marshal(b, m, deterministic)
}
func (m *PingResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_PingResponse.Merge(m, src)
}
func (m *PingResponse) XXX_Size() int {
return xxx_messageInfo_PingResponse.Size(m)
}
func (m *PingResponse) XXX_DiscardUnknown() {
xxx_messageInfo_PingResponse.DiscardUnknown(m)
}
var xxx_messageInfo_PingResponse proto.InternalMessageInfo
func (m *PingResponse) GetEntry() int64 {
if m != nil {
return m.Entry
}
return 0
}
func (m *PingResponse) GetExit() int64 {
if m != nil {
return m.Exit
}
return 0
}
func init() {
proto.RegisterType((*BlockID)(nil), "cash.z.wallet.sdk.rpc.BlockID")
proto.RegisterType((*BlockRange)(nil), "cash.z.wallet.sdk.rpc.BlockRange")
@ -491,6 +582,8 @@ func init() {
proto.RegisterType((*Empty)(nil), "cash.z.wallet.sdk.rpc.Empty")
proto.RegisterType((*LightdInfo)(nil), "cash.z.wallet.sdk.rpc.LightdInfo")
proto.RegisterType((*TransparentAddressBlockFilter)(nil), "cash.z.wallet.sdk.rpc.TransparentAddressBlockFilter")
proto.RegisterType((*Duration)(nil), "cash.z.wallet.sdk.rpc.Duration")
proto.RegisterType((*PingResponse)(nil), "cash.z.wallet.sdk.rpc.PingResponse")
}
func init() {
@ -498,48 +591,52 @@ func init() {
}
var fileDescriptor_a0b84a42fa06f626 = []byte{
// 641 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0xd1, 0x4e, 0x13, 0x4d,
0x14, 0x6e, 0x4b, 0x97, 0xd2, 0x43, 0x81, 0x30, 0xf9, 0xf9, 0x6d, 0x1a, 0xd4, 0x3a, 0xc6, 0x84,
0x0b, 0xb3, 0x21, 0x88, 0xd1, 0x0b, 0x6f, 0x00, 0x15, 0x49, 0xd0, 0xe8, 0xb4, 0x57, 0x78, 0x41,
0x86, 0x9d, 0x43, 0x77, 0xa5, 0x9d, 0xdd, 0xcc, 0x0c, 0xa5, 0xfa, 0x08, 0x3e, 0x84, 0x0f, 0xe2,
0xd3, 0x99, 0x3d, 0xbb, 0x85, 0x6d, 0x74, 0x69, 0xef, 0xf6, 0x9c, 0x39, 0xe7, 0xfb, 0xce, 0x9c,
0xf9, 0xbe, 0x85, 0x35, 0x8b, 0x66, 0x1c, 0x05, 0xe8, 0x27, 0x26, 0x76, 0x31, 0xdb, 0x0a, 0xa4,
0x0d, 0xfd, 0x1f, 0xfe, 0x8d, 0x1c, 0x0e, 0xd1, 0xf9, 0x56, 0x5d, 0xf9, 0x26, 0x09, 0x3a, 0x5b,
0x41, 0x3c, 0x4a, 0x64, 0xe0, 0xce, 0x2f, 0x63, 0x33, 0x92, 0xce, 0x66, 0xd5, 0xfc, 0x25, 0x34,
0x0e, 0x87, 0x71, 0x70, 0x75, 0xf2, 0x96, 0xfd, 0x0f, 0xcb, 0x21, 0x46, 0x83, 0xd0, 0xb5, 0xab,
0xdd, 0xea, 0x4e, 0x5d, 0xe4, 0x11, 0x63, 0x50, 0x0f, 0xa5, 0x0d, 0xdb, 0xb5, 0x6e, 0x75, 0xa7,
0x25, 0xe8, 0x9b, 0x3b, 0x00, 0x6a, 0x13, 0x52, 0x0f, 0x90, 0xed, 0x83, 0x67, 0x9d, 0x34, 0x59,
0xe3, 0xea, 0xde, 0x23, 0xff, 0x9f, 0x23, 0xf8, 0x39, 0x91, 0xc8, 0x8a, 0xd9, 0x2e, 0x2c, 0xa1,
0x56, 0x04, 0x3b, 0xbf, 0x27, 0x2d, 0xe5, 0xdf, 0x60, 0xa5, 0x3f, 0x79, 0x1f, 0x0d, 0x1d, 0x9a,
0x94, 0xf3, 0x22, 0x3d, 0x5b, 0x94, 0x93, 0x8a, 0xd9, 0x7f, 0xe0, 0x45, 0x5a, 0xe1, 0x84, 0x58,
0xeb, 0x22, 0x0b, 0x6e, 0x6f, 0xb8, 0x54, 0xb8, 0xe1, 0x1b, 0x58, 0x17, 0xf2, 0xa6, 0x6f, 0xa4,
0xb6, 0x32, 0x70, 0x51, 0xac, 0xd3, 0x2a, 0x25, 0x9d, 0x24, 0xc2, 0x96, 0xa0, 0xef, 0xc2, 0xce,
0x6a, 0xc5, 0x9d, 0xf1, 0xcf, 0xd0, 0xea, 0xa1, 0x56, 0x02, 0x6d, 0x12, 0x6b, 0x8b, 0x6c, 0x1b,
0x9a, 0x68, 0x4c, 0x6c, 0x8e, 0x62, 0x85, 0x04, 0xe0, 0x89, 0xbb, 0x04, 0xe3, 0xd0, 0xa2, 0xe0,
0x23, 0x5a, 0x2b, 0x07, 0x48, 0x58, 0x4d, 0x31, 0x93, 0xe3, 0xab, 0xd0, 0x3c, 0x0a, 0x65, 0xa4,
0x7b, 0x09, 0x06, 0xbc, 0x01, 0xde, 0xbb, 0x51, 0xe2, 0xbe, 0xf3, 0x9f, 0x35, 0x80, 0xd3, 0x94,
0x51, 0x9d, 0xe8, 0xcb, 0x98, 0xb5, 0xa1, 0x31, 0x46, 0x63, 0xa3, 0x58, 0x13, 0x49, 0x53, 0x4c,
0xc3, 0x74, 0xd0, 0x31, 0x6a, 0x15, 0x9b, 0x1c, 0x3c, 0x8f, 0x52, 0x6a, 0x27, 0x95, 0x32, 0xbd,
0xeb, 0x24, 0x89, 0x8d, 0xa3, 0x15, 0xac, 0x88, 0x99, 0x5c, 0x3a, 0x7c, 0x90, 0x52, 0x7f, 0x92,
0x23, 0x6c, 0xd7, 0xa9, 0xfd, 0x2e, 0xc1, 0x5e, 0xc3, 0x03, 0x2b, 0x93, 0x61, 0xa4, 0x07, 0x07,
0x81, 0x8b, 0xc6, 0x32, 0xdd, 0xd5, 0x87, 0x6c, 0x27, 0x1e, 0xed, 0xa4, 0xec, 0x98, 0x3d, 0x87,
0xcd, 0x20, 0xdd, 0x8e, 0xb6, 0xd7, 0xf6, 0xd0, 0x48, 0x1d, 0x84, 0x27, 0xaa, 0xbd, 0x4c, 0xf8,
0x7f, 0x1f, 0xb0, 0x2e, 0xac, 0xd2, 0x1b, 0xe6, 0xd8, 0x0d, 0xc2, 0x2e, 0xa6, 0xb8, 0x81, 0x87,
0xf4, 0x5e, 0x89, 0x34, 0xa8, 0xdd, 0x81, 0x52, 0x06, 0xad, 0x25, 0x01, 0xe4, 0x9a, 0x69, 0x43,
0x43, 0x66, 0xd9, 0xe9, 0x7a, 0xf2, 0x90, 0xbd, 0x02, 0xcf, 0xa4, 0x52, 0xce, 0xd5, 0xf8, 0xe4,
0x3e, 0x35, 0x91, 0xe6, 0x45, 0x56, 0xbf, 0xf7, 0xcb, 0x83, 0xcd, 0xa3, 0xcc, 0x59, 0xfd, 0x49,
0xcf, 0x19, 0x94, 0x23, 0x34, 0xac, 0x0f, 0xeb, 0xc7, 0xe8, 0x4e, 0xa5, 0x43, 0xeb, 0xa8, 0x87,
0x75, 0x4b, 0x10, 0x6f, 0xdf, 0xb4, 0x33, 0x47, 0xc1, 0xbc, 0xc2, 0xbe, 0xc0, 0xca, 0x31, 0xe6,
0x78, 0x73, 0xaa, 0x3b, 0x4f, 0xcb, 0xf8, 0xb2, 0x59, 0xa9, 0x8c, 0x57, 0xd8, 0x57, 0x58, 0x9b,
0x42, 0x66, 0x56, 0x9e, 0x7f, 0xf3, 0x05, 0xa1, 0x77, 0xab, 0xec, 0x8c, 0xb6, 0x50, 0xb4, 0xd0,
0xe3, 0x92, 0xd6, 0xa9, 0xab, 0x3b, 0xcf, 0x4a, 0x0a, 0x66, 0xad, 0xc8, 0x2b, 0xec, 0x1c, 0x36,
0x52, 0x83, 0x15, 0xc1, 0x17, 0xeb, 0x2d, 0x1d, 0xbf, 0xe8, 0x57, 0x5e, 0x61, 0x06, 0x36, 0x8e,
0x71, 0x2a, 0xa2, 0xfe, 0x24, 0x52, 0x96, 0xed, 0x97, 0x4d, 0x7f, 0x9f, 0xe8, 0x16, 0xbe, 0xd2,
0x6e, 0x95, 0x09, 0x7a, 0x8d, 0x82, 0x9f, 0xb7, 0x4b, 0x7a, 0xc9, 0xfc, 0x9d, 0xb2, 0xb7, 0xba,
0x03, 0xe0, 0x95, 0xc3, 0xf5, 0xb3, 0x66, 0x76, 0x6c, 0x92, 0xe0, 0x77, 0xad, 0x72, 0xb1, 0x4c,
0xff, 0xfd, 0x17, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0x08, 0x42, 0x5c, 0xfd, 0x36, 0x06, 0x00,
0x00,
// 708 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x55, 0x5f, 0x4f, 0x13, 0x41,
0x10, 0xef, 0xbf, 0xa3, 0xed, 0x50, 0x20, 0x6c, 0x40, 0x9b, 0x06, 0xb1, 0xae, 0x31, 0x21, 0xc6,
0x34, 0x04, 0x31, 0xf2, 0xe0, 0x0b, 0x7f, 0x14, 0x49, 0x90, 0xe0, 0xb6, 0xbe, 0xe0, 0x03, 0x59,
0xee, 0x86, 0xde, 0x49, 0xbb, 0x77, 0xd9, 0x5d, 0x4a, 0xf1, 0x23, 0xf8, 0x91, 0xfc, 0x50, 0x7e,
0x06, 0xb3, 0xbb, 0x57, 0x38, 0xa2, 0x47, 0xfb, 0x76, 0x33, 0x3b, 0xf3, 0x9b, 0xd9, 0xdf, 0xfe,
0x66, 0x0e, 0x16, 0x14, 0xca, 0x51, 0xe4, 0x63, 0x27, 0x91, 0xb1, 0x8e, 0xc9, 0xaa, 0xcf, 0x55,
0xd8, 0xf9, 0xd9, 0xb9, 0xe1, 0x83, 0x01, 0xea, 0x8e, 0x0a, 0xae, 0x3a, 0x32, 0xf1, 0x5b, 0xab,
0x7e, 0x3c, 0x4c, 0xb8, 0xaf, 0xcf, 0x2f, 0x63, 0x39, 0xe4, 0x5a, 0xb9, 0x68, 0xfa, 0x0e, 0xaa,
0x7b, 0x83, 0xd8, 0xbf, 0x3a, 0x3a, 0x20, 0x4f, 0x60, 0x2e, 0xc4, 0xa8, 0x1f, 0xea, 0x66, 0xb1,
0x5d, 0xdc, 0xa8, 0xb0, 0xd4, 0x22, 0x04, 0x2a, 0x21, 0x57, 0x61, 0xb3, 0xd4, 0x2e, 0x6e, 0x34,
0x98, 0xfd, 0xa6, 0x1a, 0xc0, 0xa6, 0x31, 0x2e, 0xfa, 0x48, 0xb6, 0xc1, 0x53, 0x9a, 0x4b, 0x97,
0x38, 0xbf, 0xb5, 0xde, 0xf9, 0x6f, 0x0b, 0x9d, 0xb4, 0x10, 0x73, 0xc1, 0x64, 0x13, 0xca, 0x28,
0x02, 0x0b, 0x3b, 0x3d, 0xc7, 0x84, 0xd2, 0x1f, 0x50, 0xeb, 0x8d, 0x3f, 0x45, 0x03, 0x8d, 0xd2,
0xd4, 0xbc, 0x30, 0x67, 0xb3, 0xd6, 0xb4, 0xc1, 0x64, 0x05, 0xbc, 0x48, 0x04, 0x38, 0xb6, 0x55,
0x2b, 0xcc, 0x19, 0x77, 0x37, 0x2c, 0x67, 0x6e, 0xf8, 0x01, 0x16, 0x19, 0xbf, 0xe9, 0x49, 0x2e,
0x14, 0xf7, 0x75, 0x14, 0x0b, 0x13, 0x15, 0x70, 0xcd, 0x6d, 0xc1, 0x06, 0xb3, 0xdf, 0x19, 0xce,
0x4a, 0x59, 0xce, 0xe8, 0x29, 0x34, 0xba, 0x28, 0x02, 0x86, 0x2a, 0x89, 0x85, 0x42, 0xb2, 0x06,
0x75, 0x94, 0x32, 0x96, 0xfb, 0x71, 0x80, 0x16, 0xc0, 0x63, 0xf7, 0x0e, 0x42, 0xa1, 0x61, 0x8d,
0x2f, 0xa8, 0x14, 0xef, 0xa3, 0xc5, 0xaa, 0xb3, 0x07, 0x3e, 0x3a, 0x0f, 0xf5, 0xfd, 0x90, 0x47,
0xa2, 0x9b, 0xa0, 0x4f, 0xab, 0xe0, 0x7d, 0x1c, 0x26, 0xfa, 0x96, 0xfe, 0x2a, 0x01, 0x1c, 0x9b,
0x8a, 0xc1, 0x91, 0xb8, 0x8c, 0x49, 0x13, 0xaa, 0x23, 0x94, 0x2a, 0x8a, 0x85, 0x2d, 0x52, 0x67,
0x13, 0xd3, 0x34, 0x3a, 0x42, 0x11, 0xc4, 0x32, 0x05, 0x4f, 0x2d, 0x53, 0x5a, 0xf3, 0x20, 0x90,
0xdd, 0xeb, 0x24, 0x89, 0xa5, 0xb6, 0x14, 0xd4, 0xd8, 0x03, 0x9f, 0x69, 0xde, 0x37, 0xa5, 0x4f,
0xf8, 0x10, 0x9b, 0x15, 0x9b, 0x7e, 0xef, 0x20, 0x3b, 0xf0, 0x54, 0xf1, 0x64, 0x10, 0x89, 0xfe,
0xae, 0xaf, 0xa3, 0x11, 0x37, 0x5c, 0x7d, 0x76, 0x9c, 0x78, 0x96, 0x93, 0xbc, 0x63, 0xf2, 0x06,
0x96, 0x7d, 0xc3, 0x8e, 0x50, 0xd7, 0x6a, 0x4f, 0x72, 0xe1, 0x87, 0x47, 0x41, 0x73, 0xce, 0xe2,
0xff, 0x7b, 0x40, 0xda, 0x30, 0x6f, 0xdf, 0x30, 0xc5, 0xae, 0x5a, 0xec, 0xac, 0x8b, 0x4a, 0x78,
0x66, 0xdf, 0x2b, 0xe1, 0x12, 0x85, 0xde, 0x0d, 0x02, 0x89, 0x4a, 0x59, 0x01, 0xa4, 0x9a, 0x69,
0x42, 0x95, 0x3b, 0xef, 0x84, 0x9e, 0xd4, 0x24, 0xef, 0xc1, 0x93, 0x46, 0xca, 0xa9, 0x1a, 0x5f,
0x3c, 0xa6, 0x26, 0xab, 0x79, 0xe6, 0xe2, 0xe9, 0x6b, 0xa8, 0x1d, 0x5c, 0x4b, 0x7b, 0x2b, 0xb2,
0x0e, 0x10, 0x09, 0x8d, 0x72, 0xc4, 0x07, 0xdf, 0x5c, 0x85, 0x32, 0xcb, 0x78, 0xe8, 0x0e, 0x34,
0x4e, 0x23, 0xd1, 0xbf, 0x13, 0xc5, 0x0a, 0x78, 0x28, 0xb4, 0xbc, 0x4d, 0x43, 0x9d, 0x61, 0x64,
0x86, 0xe3, 0xc8, 0x09, 0xaa, 0xcc, 0xec, 0xf7, 0xd6, 0x1f, 0x0f, 0x96, 0xf7, 0xdd, 0xfc, 0xf6,
0xc6, 0x5d, 0x2d, 0x91, 0x0f, 0x51, 0x92, 0x1e, 0x2c, 0x1e, 0xa2, 0x3e, 0xe6, 0x1a, 0x95, 0xb6,
0x9d, 0x91, 0x76, 0x4e, 0xdf, 0x77, 0xca, 0x69, 0x4d, 0x99, 0x13, 0x5a, 0x20, 0x5f, 0xa1, 0x76,
0x88, 0x29, 0xde, 0x94, 0xe8, 0xd6, 0xcb, 0xbc, 0x7a, 0xae, 0x57, 0x1b, 0x46, 0x0b, 0xe4, 0x3b,
0x2c, 0x4c, 0x20, 0xdd, 0xc2, 0x98, 0xce, 0xef, 0x8c, 0xd0, 0x9b, 0x45, 0x72, 0x66, 0x59, 0xc8,
0x0e, 0xea, 0xf3, 0x9c, 0xd4, 0xc9, 0xee, 0x68, 0xbd, 0xca, 0x09, 0x78, 0x38, 0xf0, 0xb4, 0x40,
0xce, 0x61, 0xc9, 0x8c, 0x71, 0x16, 0x7c, 0xb6, 0xdc, 0xdc, 0xf6, 0xb3, 0x5b, 0x81, 0x16, 0x88,
0x84, 0xa5, 0x43, 0x9c, 0x48, 0xb5, 0x37, 0x8e, 0x02, 0x45, 0xb6, 0xf3, 0xba, 0x7f, 0x4c, 0xda,
0x33, 0x5f, 0x69, 0xb3, 0x48, 0x98, 0x7d, 0x8d, 0xcc, 0xd6, 0x58, 0xcb, 0xc9, 0xb5, 0x2b, 0xa6,
0x95, 0xf7, 0x56, 0xf7, 0x00, 0xb4, 0x40, 0x4e, 0xa0, 0x62, 0xa4, 0x9d, 0x4b, 0xfd, 0x64, 0x46,
0x72, 0x79, 0xc9, 0x0e, 0x06, 0x2d, 0xec, 0x2d, 0x9e, 0xd5, 0x5d, 0x80, 0x4c, 0xfc, 0xdf, 0xa5,
0xc2, 0xc5, 0x9c, 0xfd, 0x5b, 0xbd, 0xfd, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x3f, 0xd2, 0xc0, 0xf7,
0xec, 0x06, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@ -565,6 +662,7 @@ type CompactTxStreamerClient interface {
GetAddressTxids(ctx context.Context, in *TransparentAddressBlockFilter, opts ...grpc.CallOption) (CompactTxStreamer_GetAddressTxidsClient, error)
// Misc
GetLightdInfo(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*LightdInfo, error)
Ping(ctx context.Context, in *Duration, opts ...grpc.CallOption) (*PingResponse, error)
}
type compactTxStreamerClient struct {
@ -684,6 +782,15 @@ func (c *compactTxStreamerClient) GetLightdInfo(ctx context.Context, in *Empty,
return out, nil
}
func (c *compactTxStreamerClient) Ping(ctx context.Context, in *Duration, opts ...grpc.CallOption) (*PingResponse, error) {
out := new(PingResponse)
err := c.cc.Invoke(ctx, "/cash.z.wallet.sdk.rpc.CompactTxStreamer/Ping", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// CompactTxStreamerServer is the server API for CompactTxStreamer service.
type CompactTxStreamerServer interface {
// Compact Blocks
@ -697,6 +804,7 @@ type CompactTxStreamerServer interface {
GetAddressTxids(*TransparentAddressBlockFilter, CompactTxStreamer_GetAddressTxidsServer) error
// Misc
GetLightdInfo(context.Context, *Empty) (*LightdInfo, error)
Ping(context.Context, *Duration) (*PingResponse, error)
}
// UnimplementedCompactTxStreamerServer can be embedded to have forward compatible implementations.
@ -724,6 +832,9 @@ func (*UnimplementedCompactTxStreamerServer) GetAddressTxids(req *TransparentAdd
func (*UnimplementedCompactTxStreamerServer) GetLightdInfo(ctx context.Context, req *Empty) (*LightdInfo, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetLightdInfo not implemented")
}
func (*UnimplementedCompactTxStreamerServer) Ping(ctx context.Context, req *Duration) (*PingResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Ping not implemented")
}
func RegisterCompactTxStreamerServer(s *grpc.Server, srv CompactTxStreamerServer) {
s.RegisterService(&_CompactTxStreamer_serviceDesc, srv)
@ -861,6 +972,24 @@ func _CompactTxStreamer_GetLightdInfo_Handler(srv interface{}, ctx context.Conte
return interceptor(ctx, in, info, handler)
}
func _CompactTxStreamer_Ping_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(Duration)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(CompactTxStreamerServer).Ping(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/Ping",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(CompactTxStreamerServer).Ping(ctx, req.(*Duration))
}
return interceptor(ctx, in, info, handler)
}
var _CompactTxStreamer_serviceDesc = grpc.ServiceDesc{
ServiceName: "cash.z.wallet.sdk.rpc.CompactTxStreamer",
HandlerType: (*CompactTxStreamerServer)(nil),
@ -885,6 +1014,10 @@ var _CompactTxStreamer_serviceDesc = grpc.ServiceDesc{
MethodName: "GetLightdInfo",
Handler: _CompactTxStreamer_GetLightdInfo_Handler,
},
{
MethodName: "Ping",
Handler: _CompactTxStreamer_Ping_Handler,
},
},
Streams: []grpc.StreamDesc{
{

View File

@ -52,7 +52,7 @@ message ChainSpec {}
// Empty is for gRPCs that take no arguments, currently only GetLightdInfo.
message Empty {}
// The LightdInfo returns various information about this lightwalletd instance
// LightdInfo returns various information about this lightwalletd instance
// and the state of the blockchain.
message LightdInfo {
string version = 1;
@ -71,6 +71,20 @@ message TransparentAddressBlockFilter {
BlockRange range = 2;
}
// Duration is currently used only for testing, so that the Ping rpc
// can simulate a delay, to create many simultaneous connections. Units
// are microseconds.
message Duration {
int64 intervalUs = 1;
}
// PingResponse is used to indicate concurrency, how many Ping rpcs
// are executing upon entry and upon exit (after the delay).
message PingResponse {
int64 entry = 1;
int64 exit = 2;
}
service CompactTxStreamer {
// Compact Blocks
rpc GetLatestBlock(ChainSpec) returns (BlockID) {}
@ -86,4 +100,5 @@ service CompactTxStreamer {
// Misc
rpc GetLightdInfo(Empty) returns (LightdInfo) {}
rpc Ping(Duration) returns (PingResponse) {}
}