diff --git a/cmd/root.go b/cmd/root.go index 7fed4210..9e0d9b2a 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -212,6 +212,11 @@ func startServer(opts *common.Options) error { "error": err, }).Fatal("getting initial information from zebrad or zcashd") } + // Zebrad always supports lightwalletd (no special configuration needed); + // zcashd needs the lightwalletd=1 configuration option, so check that here. + if getLightdInfo.LightwalletdDisabled && !strings.Contains(getLightdInfo.ZcashdSubversion, "Zebra") { + common.Log.Fatal("zcashd is not configured as a lightwalletd server") + } common.Log.Info("Got sapling height ", getLightdInfo.SaplingActivationHeight, " block height ", getLightdInfo.BlockHeight, " chain ", getLightdInfo.ChainName, diff --git a/common/common.go b/common/common.go index 460ce6b6..9eff3ad9 100644 --- a/common/common.go +++ b/common/common.go @@ -16,6 +16,8 @@ import ( "github.com/sirupsen/logrus" "github.com/zcash/lightwalletd/parser" "github.com/zcash/lightwalletd/walletrpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) // 'make build' will overwrite this string with the output of git-describe (tag) @@ -93,9 +95,13 @@ type ( } // zcashd rpc "getinfo" + // If we're connected to an old version of zcashd that doesn't return + // LightwalletdDisabled, it will be false (the default bool value), + // and that will let us start up. ZcashdRpcReplyGetinfo struct { - Build string - Subversion string + Build string + Subversion string + LightwalletdDisabled bool } // zcashd rpc "getaddresstxids" @@ -294,6 +300,7 @@ func GetLightdInfo() (*walletrpc.LightdInfo, error) { EstimatedHeight: uint64(getblockchaininfoReply.EstimatedHeight), ZcashdBuild: getinfoReply.Build, ZcashdSubversion: getinfoReply.Subversion, + LightwalletdDisabled: getinfoReply.LightwalletdDisabled, }, nil } @@ -311,15 +318,13 @@ func getBlockFromRPC(height int) (*walletrpc.CompactBlock, error) { if err != nil { Log.Fatal("getBlockFromRPC bad height argument", height, err) } - params := make([]json.RawMessage, 2) - params[0] = heightJSON // Fetch the block using the verbose option ("1") because it provides // both the list of txids, which we're not yet able to compute for // Orchard (V5) transactions, and the block hash (block ID), which // we need to fetch the raw data format of the same block. Don't fetch // by height in case a reorg occurs between the two getblock calls; // using block hash ensures that we're fetching the same block. - params[1] = json.RawMessage("1") + params := []json.RawMessage{heightJSON, json.RawMessage("1")} result, rpcErr := RawRequest("getblock", params) if rpcErr != nil { // Check to see if we are requesting a height the zcashd doesn't have yet @@ -331,14 +336,14 @@ func getBlockFromRPC(height int) (*walletrpc.CompactBlock, error) { var block1 ZcashRpcReplyGetblock1 err = json.Unmarshal(result, &block1) if err != nil { - return nil, err + Log.Fatal("getBlockFromRPC: Can't unmarshal block:", err) } blockHash, err := json.Marshal(block1.Hash) if err != nil { Log.Fatal("getBlockFromRPC bad block hash", block1.Hash) } - params[0] = blockHash - params[1] = json.RawMessage("0") // non-verbose (raw hex) + // non-verbose (raw hex) version of block + params = []json.RawMessage{blockHash, json.RawMessage("0")} result, rpcErr = RawRequest("getblock", params) // For some reason, the error responses are not JSON @@ -476,6 +481,7 @@ func BlockIngestor(c *BlockCache, rep int) { // GetBlock returns the compact block at the requested height, first by querying // the cache, then, if not found, will request the block from zcashd. It returns // nil if no block exists at this height. +// This returns gRPC-compatible errors. func GetBlock(cache *BlockCache, height int) (*walletrpc.CompactBlock, error) { // First, check the cache to see if we have the block var block *walletrpc.CompactBlock @@ -489,11 +495,13 @@ func GetBlock(cache *BlockCache, height int) (*walletrpc.CompactBlock, error) { // Not in the cache block, err := getBlockFromRPC(height) if err != nil { - return nil, err + return nil, status.Errorf(codes.InvalidArgument, + "GetBlock: getblock failed, error: %s", err.Error()) } if block == nil { // Block height is too large - return nil, errors.New("block requested is newer than latest block") + return nil, status.Errorf(codes.OutOfRange, + "GetBlock: block requested is newer than latest block: %d", height) } return block, nil } @@ -537,27 +545,27 @@ func GetBlockRange(cache *BlockCache, blockOut chan<- *walletrpc.CompactBlock, e // the meanings of the `Height` field of the `RawTransaction` type are as // follows: // -// * height 0: the transaction is in the mempool -// * height 0xffffffffffffffff: the transaction has been mined on a fork that -// is not currently the main chain -// * any other height: the transaction has been mined in the main chain at the -// given height +// - height 0: the transaction is in the mempool +// - height 0xffffffffffffffff: the transaction has been mined on a fork that +// is not currently the main chain +// - any other height: the transaction has been mined in the main chain at the +// given height func ParseRawTransaction(message json.RawMessage) (*walletrpc.RawTransaction, error) { - // Many other fields are returned, but we need only these two. - var txinfo ZcashdRpcReplyGetrawtransaction - err := json.Unmarshal(message, &txinfo) - if err != nil { - return nil, err - } - txBytes, err := hex.DecodeString(txinfo.Hex) - if err != nil { - return nil, err - } + // Many other fields are returned, but we need only these two. + var txinfo ZcashdRpcReplyGetrawtransaction + err := json.Unmarshal(message, &txinfo) + if err != nil { + return nil, err + } + txBytes, err := hex.DecodeString(txinfo.Hex) + if err != nil { + return nil, err + } - return &walletrpc.RawTransaction{ - Data: txBytes, - Height: uint64(txinfo.Height), - }, nil + return &walletrpc.RawTransaction{ + Data: txBytes, + Height: uint64(txinfo.Height), + }, nil } func displayHash(hash []byte) string { diff --git a/common/common_test.go b/common/common_test.go index 4c4860ab..14d053e2 100644 --- a/common/common_test.go +++ b/common/common_test.go @@ -439,7 +439,7 @@ func TestGetBlockRange(t *testing.T) { select { case err := <-errChan: // this will also catch context.DeadlineExceeded from the timeout - if err.Error() != "block requested is newer than latest block" { + if !strings.Contains(err.Error(), "block requested is newer than latest block") { t.Fatal("unexpected error:", err) } case <-blockChan: @@ -605,7 +605,7 @@ func mempoolStub(method string, params []json.RawMessage) (json.RawMessage, erro if txid != "mempooltxid-1" { testT.Fatal("unexpected txid") } - r, _ := json.Marshal(map[string]string{"hex":"aabb"}) + r, _ := json.Marshal(map[string]string{"hex": "aabb"}) return r, nil case 5: // Simulate that still no new block has arrived ... @@ -637,7 +637,7 @@ func mempoolStub(method string, params []json.RawMessage) (json.RawMessage, erro if txid != "mempooltxid-2" { testT.Fatal("unexpected txid") } - r, _ := json.Marshal(map[string]string{"hex":"ccdd"}) + r, _ := json.Marshal(map[string]string{"hex": "ccdd"}) return r, nil case 8: // A new block arrives, this will cause these two tx to be returned @@ -713,59 +713,59 @@ func TestMempoolStream(t *testing.T) { } func TestZcashdRpcReplyUnmarshalling(t *testing.T) { - var txinfo0 ZcashdRpcReplyGetrawtransaction - err0 := json.Unmarshal([]byte("{\"hex\": \"deadbeef\", \"height\": 123456}"), &txinfo0) - if err0 != nil { - t.Fatal("Failed to unmarshal tx with known height.") - } - if txinfo0.Height != 123456 { - t.Errorf("Unmarshalled incorrect height: got: %d, want: 123456.", txinfo0.Height) - } + var txinfo0 ZcashdRpcReplyGetrawtransaction + err0 := json.Unmarshal([]byte("{\"hex\": \"deadbeef\", \"height\": 123456}"), &txinfo0) + if err0 != nil { + t.Fatal("Failed to unmarshal tx with known height.") + } + if txinfo0.Height != 123456 { + t.Errorf("Unmarshalled incorrect height: got: %d, want: 123456.", txinfo0.Height) + } - var txinfo1 ZcashdRpcReplyGetrawtransaction - err1 := json.Unmarshal([]byte("{\"hex\": \"deadbeef\", \"height\": -1}"), &txinfo1) - if err1 != nil { - t.Fatal("failed to unmarshal tx not in main chain") - } - if txinfo1.Height != -1 { - t.Errorf("Unmarshalled incorrect height: got: %d, want: -1.", txinfo1.Height) - } + var txinfo1 ZcashdRpcReplyGetrawtransaction + err1 := json.Unmarshal([]byte("{\"hex\": \"deadbeef\", \"height\": -1}"), &txinfo1) + if err1 != nil { + t.Fatal("failed to unmarshal tx not in main chain") + } + if txinfo1.Height != -1 { + t.Errorf("Unmarshalled incorrect height: got: %d, want: -1.", txinfo1.Height) + } - var txinfo2 ZcashdRpcReplyGetrawtransaction - err2 := json.Unmarshal([]byte("{\"hex\": \"deadbeef\"}"), &txinfo2) - if err2 != nil { - t.Fatal("failed to unmarshal reply lacking height data") - } - if txinfo2.Height != 0 { - t.Errorf("Unmarshalled incorrect height: got: %d, want: 0.", txinfo2.Height) - } + var txinfo2 ZcashdRpcReplyGetrawtransaction + err2 := json.Unmarshal([]byte("{\"hex\": \"deadbeef\"}"), &txinfo2) + if err2 != nil { + t.Fatal("failed to unmarshal reply lacking height data") + } + if txinfo2.Height != 0 { + t.Errorf("Unmarshalled incorrect height: got: %d, want: 0.", txinfo2.Height) + } } func TestParseRawTransaction(t *testing.T) { - rt0, err0 := ParseRawTransaction([]byte("{\"hex\": \"deadbeef\", \"height\": 123456}")) - if err0 != nil { - t.Fatal("Failed to parse raw transaction response with known height.") - } - if rt0.Height != 123456 { - t.Errorf("Unmarshalled incorrect height: got: %d, expected: 123456.", rt0.Height) - } + rt0, err0 := ParseRawTransaction([]byte("{\"hex\": \"deadbeef\", \"height\": 123456}")) + if err0 != nil { + t.Fatal("Failed to parse raw transaction response with known height.") + } + if rt0.Height != 123456 { + t.Errorf("Unmarshalled incorrect height: got: %d, expected: 123456.", rt0.Height) + } - rt1, err1 := ParseRawTransaction([]byte("{\"hex\": \"deadbeef\", \"height\": -1}")) - if err1 != nil { - t.Fatal("Failed to parse raw transaction response for a known tx not in the main chain.") - } - // We expect the int64 value `-1` to have been reinterpreted as a uint64 value in order - // to be representable as a uint64 in `RawTransaction`. The conversion from the twos-complement - // signed representation should map `-1` to `math.MaxUint64`. - if rt1.Height != math.MaxUint64 { - t.Errorf("Unmarshalled incorrect height: got: %d, want: 0x%X.", rt1.Height, uint64(math.MaxUint64)) - } + rt1, err1 := ParseRawTransaction([]byte("{\"hex\": \"deadbeef\", \"height\": -1}")) + if err1 != nil { + t.Fatal("Failed to parse raw transaction response for a known tx not in the main chain.") + } + // We expect the int64 value `-1` to have been reinterpreted as a uint64 value in order + // to be representable as a uint64 in `RawTransaction`. The conversion from the twos-complement + // signed representation should map `-1` to `math.MaxUint64`. + if rt1.Height != math.MaxUint64 { + t.Errorf("Unmarshalled incorrect height: got: %d, want: 0x%X.", rt1.Height, uint64(math.MaxUint64)) + } - rt2, err2 := ParseRawTransaction([]byte("{\"hex\": \"deadbeef\"}")) - if err2 != nil { - t.Fatal("Failed to parse raw transaction response for a tx in the mempool.") - } - if rt2.Height != 0 { - t.Errorf("Unmarshalled incorrect height: got: %d, expected: 0.", rt2.Height) - } + rt2, err2 := ParseRawTransaction([]byte("{\"hex\": \"deadbeef\"}")) + if err2 != nil { + t.Fatal("Failed to parse raw transaction response for a tx in the mempool.") + } + if rt2.Height != 0 { + t.Errorf("Unmarshalled incorrect height: got: %d, expected: 0.", rt2.Height) + } } diff --git a/docs/rtd/index.html b/docs/rtd/index.html index 35bf4bda..5d1345a0 100644 --- a/docs/rtd/index.html +++ b/docs/rtd/index.html @@ -1525,6 +1525,13 @@

LightdInfo

example: "/MagicBean:4.1.1/"

+ + lightwalletdDisabled + bool + +

whether zcashd is configured as a lwd server

+ + diff --git a/frontend/frontend_test.go b/frontend/frontend_test.go index 4d1d0593..a0e23cfd 100644 --- a/frontend/frontend_test.go +++ b/frontend/frontend_test.go @@ -115,7 +115,7 @@ func TestGetTransaction(t *testing.T) { if err == nil { testT.Fatal("GetTransaction unexpectedly succeeded") } - if err.Error() != "please call GetTransaction with txid" { + if !strings.Contains(err.Error(), "GetTransaction: specify a txid") { testT.Fatal("GetTransaction unexpected error message") } if rawtx != nil { @@ -127,7 +127,7 @@ func TestGetTransaction(t *testing.T) { if err == nil { testT.Fatal("GetTransaction unexpectedly succeeded") } - if err.Error() != "can't GetTransaction with a blockhash+num, please call GetTransaction with txid" { + if !strings.Contains(err.Error(), "GetTransaction: specify a txid, not a blockhash+num") { testT.Fatal("GetTransaction unexpected error message") } if rawtx != nil { @@ -302,7 +302,7 @@ func TestGetTaddressTxids(t *testing.T) { if err == nil { t.Fatal("GetTaddressTxids should have failed on bad address, case", i) } - if err.Error() != "invalid address" { + if !strings.Contains(err.Error(), "invalid characters") { t.Fatal("GetTaddressTxids incorrect error on bad address, case", i) } } @@ -408,7 +408,7 @@ func TestGetBlock(t *testing.T) { if err == nil { t.Fatal("GetBlock should have failed") } - if err.Error() != "gRPC GetBlock by Hash is not yet implemented" { + if !strings.Contains(err.Error(), "GetBlock: Block hash specifier is not yet implemented") { t.Fatal("GetBlock hash unimplemented error message failed") } diff --git a/frontend/service.go b/frontend/service.go index 00b36857..8e06741a 100644 --- a/frontend/service.go +++ b/frontend/service.go @@ -22,6 +22,8 @@ import ( "github.com/zcash/lightwalletd/common" "github.com/zcash/lightwalletd/parser" "github.com/zcash/lightwalletd/walletrpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) type lwdStreamer struct { @@ -48,11 +50,16 @@ func NewDarksideStreamer(cache *common.BlockCache) (walletrpc.DarksideStreamerSe return &DarksideStreamer{cache: cache}, nil } -// Test to make sure Address is a single t address +// Test to make sure Address is a single t address, return a gRPC error func checkTaddress(taddr string) error { match, err := regexp.Match("\\At[a-zA-Z0-9]{34}\\z", []byte(taddr)) - if err != nil || !match { - return errors.New("invalid address") + if err != nil { + return status.Errorf(codes.InvalidArgument, + "checkTaddress: invalid transparent address: %s error: %s", taddr, err.Error()) + } + if !match { + return status.Errorf(codes.InvalidArgument, + "checkTaddress: transparent address %s contains invalid characters", taddr) } return nil } @@ -64,11 +71,13 @@ func (s *lwdStreamer) GetLatestBlock(ctx context.Context, placeholder *walletrpc defer s.mutex.Unlock() blockChainInfo, err := common.GetBlockChainInfo() if err != nil { - return nil, err + return nil, status.Errorf(codes.Unavailable, + "GetLatestBlock: GetBlockChainInfo failed: %s", err.Error()) } bestBlockHash, err := hex.DecodeString(blockChainInfo.BestBlockHash) if err != nil { - return nil, err + return nil, status.Errorf(codes.Internal, + "GetLatestBlock: decode block hash %s failed: %s", blockChainInfo.BestBlockHash, err.Error()) } return &walletrpc.BlockID{Height: uint64(blockChainInfo.Blocks), Hash: []byte(bestBlockHash)}, nil } @@ -78,14 +87,15 @@ func (s *lwdStreamer) GetLatestBlock(ctx context.Context, placeholder *walletrpc // NB, this method is misnamed, it does not return txids. func (s *lwdStreamer) GetTaddressTxids(addressBlockFilter *walletrpc.TransparentAddressBlockFilter, resp walletrpc.CompactTxStreamer_GetTaddressTxidsServer) error { if err := checkTaddress(addressBlockFilter.Address); err != nil { + // This returns a gRPC-compatible error. return err } if addressBlockFilter.Range == nil { - return errors.New("must specify block range") + return status.Error(codes.InvalidArgument, "GetTaddressTxids: must specify block range") } if addressBlockFilter.Range.Start == nil { - return errors.New("must specify a start block height") + return status.Error(codes.InvalidArgument, "GetTaddressTxids: must specify a start block height") } request := &common.ZcashdRpcRequestGetaddresstxids{ @@ -98,7 +108,8 @@ func (s *lwdStreamer) GetTaddressTxids(addressBlockFilter *walletrpc.Transparent param, err := json.Marshal(request) if err != nil { - return err + return status.Errorf(codes.InvalidArgument, + "GetTaddressTxids: error marshalling request: %s", err.Error()) } params := []json.RawMessage{param} @@ -106,13 +117,15 @@ func (s *lwdStreamer) GetTaddressTxids(addressBlockFilter *walletrpc.Transparent // For some reason, the error responses are not JSON if rpcErr != nil { - return rpcErr + return status.Errorf(codes.InvalidArgument, + "GetTaddressTxids: getaddresstxids failed, error: %s", rpcErr.Error()) } var txids []string err = json.Unmarshal(result, &txids) if err != nil { - return err + return status.Errorf(codes.Unknown, + "GetSubtreeRoots: error unmarshalling getaddresstxids reply: %s", err.Error()) } timeout, cancel := context.WithTimeout(resp.Context(), 30*time.Second) @@ -137,14 +150,16 @@ func (s *lwdStreamer) GetTaddressTxids(addressBlockFilter *walletrpc.Transparent // block by hash is not yet supported. func (s *lwdStreamer) GetBlock(ctx context.Context, id *walletrpc.BlockID) (*walletrpc.CompactBlock, error) { if id.Height == 0 && id.Hash == nil { - return nil, errors.New("request for unspecified identifier") + return nil, status.Error(codes.InvalidArgument, + "GetBlock: request for unspecified identifier") } // Precedence: a hash is more specific than a height. If we have it, use it first. if id.Hash != nil { // TODO: Get block by hash // see https://github.com/zcash/lightwalletd/pull/309 - return nil, errors.New("gRPC GetBlock by Hash is not yet implemented") + return nil, status.Error(codes.InvalidArgument, + "GetBlock: Block hash specifier is not yet implemented") } cBlock, err := common.GetBlock(s.cache, int(id.Height)) @@ -158,18 +173,20 @@ func (s *lwdStreamer) GetBlock(ctx context.Context, id *walletrpc.BlockID) (*wal // with actions containing only the nullifiers (a subset of the full compact block). func (s *lwdStreamer) GetBlockNullifiers(ctx context.Context, id *walletrpc.BlockID) (*walletrpc.CompactBlock, error) { if id.Height == 0 && id.Hash == nil { - return nil, errors.New("request for unspecified identifier") + return nil, status.Error(codes.InvalidArgument, + "GetBlockNullifiers: must specify a block height") } // Precedence: a hash is more specific than a height. If we have it, use it first. if id.Hash != nil { // TODO: Get block by hash // see https://github.com/zcash/lightwalletd/pull/309 - return nil, errors.New("gRPC GetBlock by Hash is not yet implemented") + return nil, status.Error(codes.InvalidArgument, + "GetBlockNullifiers: GetBlock by Hash is not yet implemented") } cBlock, err := common.GetBlock(s.cache, int(id.Height)) - if err != nil { + // GetBlock() returns gRPC-compatible errors. return nil, err } for _, tx := range cBlock.Vtx { @@ -190,7 +207,8 @@ func (s *lwdStreamer) GetBlockNullifiers(ctx context.Context, id *walletrpc.Bloc func (s *lwdStreamer) GetBlockRange(span *walletrpc.BlockRange, resp walletrpc.CompactTxStreamer_GetBlockRangeServer) error { blockChan := make(chan *walletrpc.CompactBlock) if span.Start == nil || span.End == nil { - return errors.New("must specify start and end heights") + return status.Error(codes.InvalidArgument, + "GetBlockRange: must specify start and end heights") } errChan := make(chan error) go common.GetBlockRange(s.cache, blockChan, errChan, int(span.Start.Height), int(span.End.Height)) @@ -214,7 +232,7 @@ func (s *lwdStreamer) GetBlockRange(span *walletrpc.BlockRange, resp walletrpc.C func (s *lwdStreamer) GetBlockRangeNullifiers(span *walletrpc.BlockRange, resp walletrpc.CompactTxStreamer_GetBlockRangeNullifiersServer) error { blockChan := make(chan *walletrpc.CompactBlock) if span.Start == nil || span.End == nil { - return errors.New("must specify start and end heights") + return status.Error(codes.InvalidArgument, "GetBlockRangeNullifiers: must specify start and end heights") } errChan := make(chan error) go common.GetBlockRange(s.cache, blockChan, errChan, int(span.Start.Height), int(span.End.Height)) @@ -247,7 +265,8 @@ func (s *lwdStreamer) GetBlockRangeNullifiers(span *walletrpc.BlockRange, resp w // The block can be specified by either height or hash. func (s *lwdStreamer) GetTreeState(ctx context.Context, id *walletrpc.BlockID) (*walletrpc.TreeState, error) { if id.Height == 0 && id.Hash == nil { - return nil, errors.New("request for unspecified identifier") + return nil, status.Error(codes.InvalidArgument, + "GetTreeState: must specify a block height or ID (hash)") } // The Zcash z_gettreestate rpc accepts either a block height or block hash params := make([]json.RawMessage, 1) @@ -255,14 +274,15 @@ func (s *lwdStreamer) GetTreeState(ctx context.Context, id *walletrpc.BlockID) ( if id.Height > 0 { heightJSON, err := json.Marshal(strconv.Itoa(int(id.Height))) if err != nil { - return nil, err + return nil, status.Errorf(codes.InvalidArgument, + "GetTreeState: cannot parse block height: %s", err.Error()) } params[0] = heightJSON } else { // id.Hash is big-endian, keep in big-endian for the rpc hashJSON, err := json.Marshal(hex.EncodeToString(id.Hash)) if err != nil { - return nil, err + return nil, status.Errorf(codes.InvalidArgument, "GetTreeState: cannot marshal block hash: %s", err.Error()) } params[0] = hashJSON } @@ -270,11 +290,13 @@ func (s *lwdStreamer) GetTreeState(ctx context.Context, id *walletrpc.BlockID) ( for { result, rpcErr := common.RawRequest("z_gettreestate", params) if rpcErr != nil { - return nil, rpcErr + return nil, status.Errorf(codes.InvalidArgument, + "GetTreeState: z_gettreestate failed: %s", rpcErr.Error()) } err := json.Unmarshal(result, &gettreestateReply) if err != nil { - return nil, err + return nil, status.Errorf(codes.InvalidArgument, + "GetTreeState: cannot marshal treestate: %s", err.Error()) } if gettreestateReply.Sapling.Commitments.FinalState != "" { break @@ -284,12 +306,14 @@ func (s *lwdStreamer) GetTreeState(ctx context.Context, id *walletrpc.BlockID) ( } hashJSON, err = json.Marshal(gettreestateReply.Sapling.SkipHash) if err != nil { - return nil, err + return nil, status.Errorf(codes.InvalidArgument, + "GetTreeState: cannot marshal SkipHash: %s", err.Error()) } params[0] = hashJSON } if gettreestateReply.Sapling.Commitments.FinalState == "" { - return nil, errors.New(common.NodeName + " did not return treestate") + return nil, status.Error(codes.InvalidArgument, + "GetTreeState: z_gettreestate did not return treestate") } return &walletrpc.TreeState{ Network: s.chainName, @@ -304,7 +328,8 @@ func (s *lwdStreamer) GetTreeState(ctx context.Context, id *walletrpc.BlockID) ( func (s *lwdStreamer) GetLatestTreeState(ctx context.Context, in *walletrpc.Empty) (*walletrpc.TreeState, error) { blockChainInfo, err := common.GetBlockChainInfo() if err != nil { - return nil, err + return nil, status.Errorf(codes.Unavailable, + "GetLatestTreeState: getblockchaininfo failed, error: %s", err.Error()) } latestHeight := blockChainInfo.Blocks return s.GetTreeState(ctx, &walletrpc.BlockID{Height: uint64(latestHeight)}) @@ -315,33 +340,47 @@ func (s *lwdStreamer) GetLatestTreeState(ctx context.Context, in *walletrpc.Empt func (s *lwdStreamer) GetTransaction(ctx context.Context, txf *walletrpc.TxFilter) (*walletrpc.RawTransaction, error) { if txf.Hash != nil { if len(txf.Hash) != 32 { - return nil, errors.New("transaction ID has invalid length") + return nil, status.Errorf(codes.InvalidArgument, + "GetTransaction: transaction ID %s has invalid length: %d", string(txf.Hash), len(txf.Hash)) } - txidJSON, err := json.Marshal(hex.EncodeToString(parser.Reverse(txf.Hash))) + txidHex := hex.EncodeToString(parser.Reverse(txf.Hash)) + txidJSON, err := json.Marshal(txidHex) if err != nil { - return nil, err + return nil, status.Errorf(codes.InvalidArgument, + "GetTransaction: Cannot marshal txid: %s", err.Error()) } params := []json.RawMessage{txidJSON, json.RawMessage("1")} result, rpcErr := common.RawRequest("getrawtransaction", params) if rpcErr != nil { // For some reason, the error responses are not JSON - return nil, rpcErr + return nil, status.Errorf(codes.NotFound, + "GetTransaction: getrawtransaction %s failed: %s", txidHex, rpcErr.Error()) } - - return common.ParseRawTransaction(result) + tx, err := common.ParseRawTransaction(result) + if err != nil { + return nil, status.Errorf(codes.Internal, + "GetTransaction: Cannot parse transaction: %s", err.Error()) + } + return tx, err } if txf.Block != nil && txf.Block.Hash != nil { - return nil, errors.New("can't GetTransaction with a blockhash+num, please call GetTransaction with txid") + return nil, status.Error(codes.InvalidArgument, + "GetTransaction: specify a txid, not a blockhash+num") } - return nil, errors.New("please call GetTransaction with txid") + return nil, status.Error(codes.InvalidArgument, + "GetTransaction: specify a txid") } // GetLightdInfo gets the LightWalletD (this server) info, and includes information // it gets from its backend zcashd. func (s *lwdStreamer) GetLightdInfo(ctx context.Context, in *walletrpc.Empty) (*walletrpc.LightdInfo, error) { - return common.GetLightdInfo() + lightdinfo, err := common.GetLightdInfo() + if err != nil { + return nil, status.Errorf(codes.Internal, "GetLightdInfo failed: %s", err.Error()) + } + return lightdinfo, err } // SendTransaction forwards raw transaction bytes to a zcashd instance over JSON-RPC @@ -355,14 +394,14 @@ func (s *lwdStreamer) SendTransaction(ctx context.Context, rawtx *walletrpc.RawT // Verify rawtx if rawtx == nil || rawtx.Data == nil { - return nil, errors.New("bad transaction data") + return nil, status.Error(codes.InvalidArgument, "bad transaction data") } // Construct raw JSON-RPC params params := make([]json.RawMessage, 1) txJSON, err := json.Marshal(hex.EncodeToString(rawtx.Data)) if err != nil { - return &walletrpc.SendResponse{}, err + return nil, status.Errorf(codes.InvalidArgument, "cannot marshal tx: %s", err.Error()) } params[0] = txJSON result, rpcErr := common.RawRequest("sendrawtransaction", params) @@ -374,14 +413,16 @@ func (s *lwdStreamer) SendTransaction(ctx context.Context, rawtx *walletrpc.RawT if rpcErr != nil { errParts := strings.SplitN(rpcErr.Error(), ":", 2) if len(errParts) < 2 { - return nil, errors.New("sendTransaction couldn't parse error code") + return nil, status.Errorf(codes.Unknown, + "sendTransaction couldn't parse sendrawtransaction error code, error: %s", rpcErr.Error()) } errMsg = strings.TrimSpace(errParts[1]) errCode, err = strconv.ParseInt(errParts[0], 10, 32) if err != nil { // This should never happen. We can't panic here, but it's that class of error. // This is why we need integration testing to work better than regtest currently does. TODO. - return nil, errors.New("sendTransaction couldn't parse error code") + return nil, status.Errorf(codes.Unknown, + "sendTransaction couldn't parse error code, error: %s", err.Error()) } } else { // Return the transaction ID (txid) as hex string. @@ -399,7 +440,7 @@ func (s *lwdStreamer) SendTransaction(ctx context.Context, rawtx *walletrpc.RawT func getTaddressBalanceZcashdRpc(addressList []string) (*walletrpc.Balance, error) { for _, addr := range addressList { if err := checkTaddress(addr); err != nil { - return &walletrpc.Balance{}, err + return nil, err } } params := make([]json.RawMessage, 1) @@ -408,18 +449,27 @@ func getTaddressBalanceZcashdRpc(addressList []string) (*walletrpc.Balance, erro } param, err := json.Marshal(addrList) if err != nil { - return &walletrpc.Balance{}, err + return nil, err } params[0] = param result, rpcErr := common.RawRequest("getaddressbalance", params) if rpcErr != nil { - return &walletrpc.Balance{}, rpcErr + var code codes.Code + switch { + case strings.Contains(rpcErr.Error(), "Invalid address"): + code = codes.InvalidArgument + case strings.Contains(rpcErr.Error(), "No information available"): + code = codes.NotFound + } + return nil, status.Errorf(code, + "getTaddressBalanceZcashdRpc: getaddressbalance error: %s", rpcErr.Error()) } var balanceReply common.ZcashdRpcReplyGetaddressbalance err = json.Unmarshal(result, &balanceReply) if err != nil { - return &walletrpc.Balance{}, err + return nil, status.Errorf(codes.Unknown, + "getTaddressBalanceZcashdRpc: failed to unmarshal getaddressbalance reply, error: %s", err.Error()) } return &walletrpc.Balance{ValueZat: balanceReply.Balance}, nil } @@ -438,7 +488,7 @@ func (s *lwdStreamer) GetTaddressBalanceStream(addresses walletrpc.CompactTxStre break } if err != nil { - return err + return status.Errorf(codes.Internal, "GetTaddressBalanceStream Recv error: %s", err.Error()) } addressList = append(addressList, addr.Address) } @@ -474,11 +524,12 @@ func (s *lwdStreamer) GetMempoolTx(exclude *walletrpc.Exclude, resp walletrpc.Co params := make([]json.RawMessage, 0) result, rpcErr := common.RawRequest("getrawmempool", params) if rpcErr != nil { - return rpcErr + return status.Errorf(codes.Internal, "GetMempoolTx: getrawmempool error: %s", rpcErr.Error()) } err := json.Unmarshal(result, &mempoolList) if err != nil { - return err + return status.Errorf(codes.Unknown, + "GetMempoolTx: failed to unmarshal getrawmempool reply, error: %s", err.Error()) } newmempoolMap := make(map[string]*walletrpc.CompactTx) if mempoolMap == nil { @@ -492,7 +543,8 @@ func (s *lwdStreamer) GetMempoolTx(exclude *walletrpc.Exclude, resp walletrpc.Co } txidJSON, err := json.Marshal(txidstr) if err != nil { - return err + return status.Errorf(codes.Unknown, + "GetMempoolTx: failed to marshal txid, error: %s", err.Error()) } // The "0" is because we only need the raw hex, which is returned as // just a hex string, and not even a json string (with quotes). @@ -506,27 +558,32 @@ func (s *lwdStreamer) GetMempoolTx(exclude *walletrpc.Exclude, resp walletrpc.Co var txStr string err = json.Unmarshal(result, &txStr) if err != nil { - return err + return status.Errorf(codes.Internal, + "GetMempoolTx: failed to unmarshal getrawtransaction reply, error: %s", err.Error()) } // convert to binary txBytes, err := hex.DecodeString(txStr) if err != nil { - return err + return status.Errorf(codes.Internal, + "GetMempoolTx: failed decode getrawtransaction reply, error: %s", err.Error()) } tx := parser.NewTransaction() txdata, err := tx.ParseFromSlice(txBytes) if err != nil { - return err + return status.Errorf(codes.Internal, + "GetMempoolTx: failed to parse getrawtransaction reply, error: %s", err.Error()) } if len(txdata) > 0 { - return errors.New("extra data deserializing transaction") + return status.Error(codes.Internal, + "GetMempoolTx: extra data deserializing transaction") } newmempoolMap[txidstr] = &walletrpc.CompactTx{} if tx.HasShieldedElements() { txidBytes, err := hex.DecodeString(txidstr) if err != nil { - return err + return status.Errorf(codes.Internal, + "GetMempoolTx: failed decode txid, error: %s", err.Error()) } tx.SetTxID(txidBytes) newmempoolMap[txidstr] = tx.ToCompact( /* height */ 0) @@ -602,23 +659,32 @@ func getAddressUtxos(arg *walletrpc.GetAddressUtxosArg, f func(*walletrpc.GetAdd return err } } - params := make([]json.RawMessage, 1) addrList := &common.ZcashdRpcRequestGetaddressutxos{ Addresses: arg.Addresses, } param, err := json.Marshal(addrList) if err != nil { - return err + return status.Errorf(codes.Unknown, + "getAddressUtxos: failed to marshal addrList, error: %s", err.Error()) } - params[0] = param + params := []json.RawMessage{param} result, rpcErr := common.RawRequest("getaddressutxos", params) if rpcErr != nil { - return rpcErr + var code codes.Code + switch { + case strings.Contains(rpcErr.Error(), "Invalid address"): + code = codes.InvalidArgument + case strings.Contains(rpcErr.Error(), "No information available"): + code = codes.NotFound + } + return status.Errorf(code, + "getAddressUtxos: getaddressutxos error: %s", rpcErr.Error()) } var utxosReply []common.ZcashdRpcReplyGetaddressutxos err = json.Unmarshal(result, &utxosReply) if err != nil { - return err + return status.Errorf(codes.InvalidArgument, + "getAddressUtxos: failed to unmarshal getaddressutxos reply, error: %s", err.Error()) } n := 0 for _, utxo := range utxosReply { @@ -631,11 +697,13 @@ func getAddressUtxos(arg *walletrpc.GetAddressUtxosArg, f func(*walletrpc.GetAdd } txidBytes, err := hex.DecodeString(utxo.Txid) if err != nil { - return err + return status.Errorf(codes.Internal, + "getAddressUtxos: failed decode txid, error: %s", err.Error()) } scriptBytes, err := hex.DecodeString(utxo.Script) if err != nil { - return err + return status.Errorf(codes.Internal, + "getAddressUtxos: failed decode utxo script, error: %s", err.Error()) } err = f(&walletrpc.GetAddressUtxosReply{ Address: utxo.Address, @@ -659,7 +727,7 @@ func (s *lwdStreamer) GetAddressUtxos(ctx context.Context, arg *walletrpc.GetAdd return nil }) if err != nil { - return &walletrpc.GetAddressUtxosReplyList{}, err + return nil, err } return &walletrpc.GetAddressUtxosReplyList{AddressUtxos: addressUtxos}, nil } @@ -677,11 +745,13 @@ func (s *lwdStreamer) GetSubtreeRoots(arg *walletrpc.GetSubtreeRootsArg, resp wa } protocol, err := json.Marshal(arg.ShieldedProtocol.String()) if err != nil { - return errors.New("bad shielded protocol specifier") + return status.Errorf(codes.InvalidArgument, + "GetSubtreeRoots: bad shielded protocol specifier error: %s", err.Error()) } startIndexJSON, err := json.Marshal(arg.StartIndex) if err != nil { - return errors.New("bad startIndex") + return status.Errorf(codes.InvalidArgument, + "GetSubtreeRoots: bad startIndex, error: %s", err.Error()) } params := []json.RawMessage{ protocol, @@ -690,29 +760,33 @@ func (s *lwdStreamer) GetSubtreeRoots(arg *walletrpc.GetSubtreeRootsArg, resp wa if arg.MaxEntries > 0 { maxEntriesJSON, err := json.Marshal(arg.MaxEntries) if err != nil { - return errors.New("bad maxEntries") + return status.Errorf(codes.InvalidArgument, + "GetSubtreeRoots: bad maxEntries, error: %s", err.Error()) } params = append(params, maxEntriesJSON) } result, rpcErr := common.RawRequest("z_getsubtreesbyindex", params) - if rpcErr != nil { - return rpcErr + return status.Errorf(codes.InvalidArgument, + "GetSubtreeRoots: z_getsubtreesbyindex, error: %s", rpcErr.Error()) } var reply common.ZcashdRpcReplyGetsubtreebyindex err = json.Unmarshal(result, &reply) if err != nil { - return err + return status.Errorf(codes.Unknown, + "GetSubtreeRoots: failed to unmarshal z_getsubtreesbyindex reply, error: %s", err.Error()) } for i := 0; i < len(reply.Subtrees); i++ { subtree := reply.Subtrees[i] block, err := common.GetBlock(s.cache, subtree.End_height) if block == nil { - return errors.New("getblock failed") + // It may be worth trying to determine a more specific error code + return status.Error(codes.Internal, err.Error()) } roothash, err := hex.DecodeString(subtree.Root) if err != nil { - return errors.New("bad root hex string") + return status.Errorf(codes.Internal, + "GetSubtreeRoots: failed to decode subtree.Root %s, error: %s", subtree.Root, err.Error()) } r := walletrpc.SubtreeRoot{ RootHash: roothash, @@ -745,7 +819,8 @@ func (s *lwdStreamer) Ping(ctx context.Context, in *walletrpc.Duration) (*wallet // concurrent threads, which could run the server out of resources, // so only allow if explicitly enabled. if !s.pingEnable { - return nil, errors.New("ping not enabled, start lightwalletd with --ping-very-insecure") + return nil, status.Errorf(codes.FailedPrecondition, + "Ping not enabled, start lightwalletd with --ping-very-insecure") } var response walletrpc.PingResponse response.Entry = atomic.AddInt64(&concurrent, 1) @@ -758,7 +833,8 @@ func (s *lwdStreamer) Ping(ctx context.Context, in *walletrpc.Duration) (*wallet func (s *DarksideStreamer) Reset(ctx context.Context, ms *walletrpc.DarksideMetaState) (*walletrpc.Empty, error) { match, err := regexp.Match("\\A[a-fA-F0-9]+\\z", []byte(ms.BranchID)) if err != nil || !match { - return nil, errors.New("invalid branch ID") + return nil, status.Errorf(codes.InvalidArgument, + "Reset: invalid BranchID (must be hex): %s", ms.BranchID) } match, err = regexp.Match("\\A[a-zA-Z0-9]+\\z", []byte(ms.ChainName)) @@ -773,7 +849,7 @@ func (s *DarksideStreamer) Reset(ctx context.Context, ms *walletrpc.DarksideMeta ms.StartOrchardCommitmentTreeSize, ) if err != nil { - return nil, err + common.Log.Fatal("Reset failed, error: ", err.Error()) } mempoolMap = nil mempoolList = nil @@ -799,7 +875,8 @@ func (s *DarksideStreamer) StageBlocksStream(blocks walletrpc.DarksideStreamer_S // StageBlocks loads blocks from the given URL to the staging area. func (s *DarksideStreamer) StageBlocks(ctx context.Context, u *walletrpc.DarksideBlocksURL) (*walletrpc.Empty, error) { if err := common.DarksideStageBlocks(u.Url); err != nil { - return nil, err + return nil, status.Errorf(codes.Unknown, + "StageBlocks: DarksideStageBlocks failed, error: %s", err.Error()) } return &walletrpc.Empty{}, nil } @@ -807,7 +884,8 @@ func (s *DarksideStreamer) StageBlocks(ctx context.Context, u *walletrpc.Darksid // StageBlocksCreate stages a set of synthetic (manufactured on the fly) blocks. func (s *DarksideStreamer) StageBlocksCreate(ctx context.Context, e *walletrpc.DarksideEmptyBlocks) (*walletrpc.Empty, error) { if err := common.DarksideStageBlocksCreate(e.Height, e.Nonce, e.Count); err != nil { - return nil, err + return nil, status.Errorf(codes.Unknown, + "StageBlocksCreate: DarksideStageBlocksCreate failed, error: %s", err.Error()) } return &walletrpc.Empty{}, nil } @@ -824,11 +902,13 @@ func (s *DarksideStreamer) StageTransactionsStream(tx walletrpc.DarksideStreamer return nil } if err != nil { - return err + return status.Errorf(codes.Unknown, + "StageTransactionsStream: Recv failed, error: %s", err.Error()) } err = common.DarksideStageTransaction(int(transaction.Height), transaction.Data) if err != nil { - return err + return status.Errorf(codes.Unknown, + "StageTransactionsStream: DarksideStageTransaction failed, error: %s", err.Error()) } } } @@ -836,7 +916,8 @@ func (s *DarksideStreamer) StageTransactionsStream(tx walletrpc.DarksideStreamer // StageTransactions loads blocks from the given URL to the staging area. func (s *DarksideStreamer) StageTransactions(ctx context.Context, u *walletrpc.DarksideTransactionsURL) (*walletrpc.Empty, error) { if err := common.DarksideStageTransactionsURL(int(u.Height), u.Url); err != nil { - return nil, err + return nil, status.Errorf(codes.Unknown, + "StageTransactions: DarksideStageTransactionsURL failed, error: %s", err.Error()) } return &walletrpc.Empty{}, nil } @@ -875,7 +956,11 @@ func (s *DarksideStreamer) AddAddressUtxo(ctx context.Context, arg *walletrpc.Ge Height: int(arg.Height), } err := common.DarksideAddAddressUtxo(utxosReply) - return &walletrpc.Empty{}, err + if err != nil { + return nil, status.Errorf(codes.Unknown, + "AddAddressUtxo: DarksideAddAddressUtxo failed, error: %s", err.Error()) + } + return &walletrpc.Empty{}, nil } // ClearAddressUtxo removes the list of cached utxo entries @@ -902,19 +987,28 @@ func (s *DarksideStreamer) AddTreeState(ctx context.Context, arg *walletrpc.Tree // removes a TreeState from the cache if present func (s *DarksideStreamer) RemoveTreeState(ctx context.Context, arg *walletrpc.BlockID) (*walletrpc.Empty, error) { err := common.DarksideRemoveTreeState(arg) - + if err != nil { + return nil, status.Errorf(codes.Unknown, + "RemoveTreeState: DarksideRemoveTreeState failed, error: %s", err.Error()) + } return &walletrpc.Empty{}, err } // Clears all the TreeStates present in the cache. func (s *DarksideStreamer) ClearAllTreeStates(ctx context.Context, arg *walletrpc.Empty) (*walletrpc.Empty, error) { err := common.DarksideClearAllTreeStates() - + if err != nil { + return nil, status.Errorf(codes.Unknown, + "ClearAllTreeStates: DarksideClearAllTreeStates failed, error: %s", err.Error()) + } return &walletrpc.Empty{}, err } func (s *DarksideStreamer) SetSubtreeRoots(ctx context.Context, arg *walletrpc.DarksideSubtreeRoots) (*walletrpc.Empty, error) { err := common.DarksideSetSubtreeRoots(arg) - + if err != nil { + return nil, status.Errorf(codes.Unknown, + "SetSubtreeRoots: DarksideSetSubtreeRoots failed, error: %s", err.Error()) + } return &walletrpc.Empty{}, err } diff --git a/walletrpc/service.pb.go b/walletrpc/service.pb.go index b3dc73bc..7a09e61b 100644 --- a/walletrpc/service.pb.go +++ b/walletrpc/service.pb.go @@ -481,9 +481,10 @@ type LightdInfo struct { Branch string `protobuf:"bytes,9,opt,name=branch,proto3" json:"branch,omitempty"` BuildDate string `protobuf:"bytes,10,opt,name=buildDate,proto3" json:"buildDate,omitempty"` BuildUser string `protobuf:"bytes,11,opt,name=buildUser,proto3" json:"buildUser,omitempty"` - EstimatedHeight uint64 `protobuf:"varint,12,opt,name=estimatedHeight,proto3" json:"estimatedHeight,omitempty"` // less than tip height if zcashd is syncing - ZcashdBuild string `protobuf:"bytes,13,opt,name=zcashdBuild,proto3" json:"zcashdBuild,omitempty"` // example: "v4.1.1-877212414" - ZcashdSubversion string `protobuf:"bytes,14,opt,name=zcashdSubversion,proto3" json:"zcashdSubversion,omitempty"` // example: "/MagicBean:4.1.1/" + EstimatedHeight uint64 `protobuf:"varint,12,opt,name=estimatedHeight,proto3" json:"estimatedHeight,omitempty"` // less than tip height if zcashd is syncing + ZcashdBuild string `protobuf:"bytes,13,opt,name=zcashdBuild,proto3" json:"zcashdBuild,omitempty"` // example: "v4.1.1-877212414" + ZcashdSubversion string `protobuf:"bytes,14,opt,name=zcashdSubversion,proto3" json:"zcashdSubversion,omitempty"` // example: "/MagicBean:4.1.1/" + LightwalletdDisabled bool `protobuf:"varint,15,opt,name=lightwalletdDisabled,proto3" json:"lightwalletdDisabled,omitempty"` // whether zcashd is configured as a lwd server } func (x *LightdInfo) Reset() { @@ -616,6 +617,13 @@ func (x *LightdInfo) GetZcashdSubversion() string { return "" } +func (x *LightdInfo) GetLightwalletdDisabled() bool { + if x != nil { + return x.LightwalletdDisabled + } + return false +} + // TransparentAddressBlockFilter restricts the results to the given address // or block range. type TransparentAddressBlockFilter struct { @@ -1416,7 +1424,7 @@ var file_service_proto_rawDesc = []byte{ 0x64, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x0b, 0x0a, 0x09, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x53, - 0x70, 0x65, 0x63, 0x22, 0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0xf4, 0x03, 0x0a, + 0x70, 0x65, 0x63, 0x22, 0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0xa8, 0x04, 0x0a, 0x0a, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x18, @@ -1448,204 +1456,208 @@ var file_service_proto_rawDesc = []byte{ 0x68, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x2a, 0x0a, 0x10, 0x7a, 0x63, 0x61, 0x73, 0x68, 0x64, 0x53, 0x75, 0x62, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x7a, 0x63, 0x61, 0x73, 0x68, 0x64, 0x53, 0x75, 0x62, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x22, 0x72, 0x0a, 0x1d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x69, - 0x6c, 0x74, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x37, - 0x0a, 0x05, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, - 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, - 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x61, 0x6e, 0x67, 0x65, - 0x52, 0x05, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x22, 0x2a, 0x0a, 0x08, 0x44, 0x75, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x55, - 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, - 0x6c, 0x55, 0x73, 0x22, 0x38, 0x0a, 0x0c, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x78, 0x69, - 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x65, 0x78, 0x69, 0x74, 0x22, 0x23, 0x0a, - 0x07, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, + 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x14, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x77, 0x61, 0x6c, 0x6c, + 0x65, 0x74, 0x64, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x0f, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x14, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x44, + 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x72, 0x0a, 0x1d, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x22, 0x2b, 0x0a, 0x0b, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, - 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, - 0x25, 0x0a, 0x07, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x5a, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x5a, 0x61, 0x74, 0x22, 0x1d, 0x0a, 0x07, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64, - 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x69, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, - 0x04, 0x74, 0x78, 0x69, 0x64, 0x22, 0xa9, 0x01, 0x0a, 0x09, 0x54, 0x72, 0x65, 0x65, 0x53, 0x74, - 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x16, 0x0a, - 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x68, - 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x69, 0x6d, - 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x20, 0x0a, - 0x0b, 0x73, 0x61, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x65, 0x65, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0b, 0x73, 0x61, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x65, 0x65, 0x12, - 0x20, 0x0a, 0x0b, 0x6f, 0x72, 0x63, 0x68, 0x61, 0x72, 0x64, 0x54, 0x72, 0x65, 0x65, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x72, 0x63, 0x68, 0x61, 0x72, 0x64, 0x54, 0x72, 0x65, - 0x65, 0x22, 0xa9, 0x01, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x53, 0x75, 0x62, 0x74, 0x72, 0x65, 0x65, - 0x52, 0x6f, 0x6f, 0x74, 0x73, 0x41, 0x72, 0x67, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, - 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x73, 0x74, - 0x61, 0x72, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x53, 0x0a, 0x10, 0x73, 0x68, 0x69, 0x65, - 0x6c, 0x64, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, - 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x68, 0x69, 0x65, 0x6c, - 0x64, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x10, 0x73, 0x68, 0x69, - 0x65, 0x6c, 0x64, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x1e, 0x0a, - 0x0a, 0x6d, 0x61, 0x78, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x0a, 0x6d, 0x61, 0x78, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x22, 0x91, 0x01, - 0x0a, 0x0b, 0x53, 0x75, 0x62, 0x74, 0x72, 0x65, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x1a, 0x0a, - 0x08, 0x72, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x08, 0x72, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x30, 0x0a, 0x13, 0x63, 0x6f, 0x6d, - 0x70, 0x6c, 0x65, 0x74, 0x69, 0x6e, 0x67, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x13, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x69, - 0x6e, 0x67, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x12, 0x34, 0x0a, 0x15, 0x63, - 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x69, 0x6e, 0x67, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, - 0x69, 0x67, 0x68, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x15, 0x63, 0x6f, 0x6d, 0x70, - 0x6c, 0x65, 0x74, 0x69, 0x6e, 0x67, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x69, 0x67, 0x68, - 0x74, 0x22, 0x74, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, - 0x74, 0x78, 0x6f, 0x73, 0x41, 0x72, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x72, 0x74, 0x48, 0x65, - 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x73, 0x74, 0x61, 0x72, - 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x45, 0x6e, - 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x6d, 0x61, 0x78, - 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x22, 0xa6, 0x01, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, - 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x74, 0x78, 0x69, 0x64, 0x12, 0x14, - 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x69, - 0x6e, 0x64, 0x65, 0x78, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5a, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5a, 0x61, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, - 0x68, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, - 0x22, 0x6b, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, - 0x78, 0x6f, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x4f, 0x0a, 0x0c, - 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, - 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x52, - 0x0c, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x2a, 0x2c, 0x0a, - 0x10, 0x53, 0x68, 0x69, 0x65, 0x6c, 0x64, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, - 0x6c, 0x12, 0x0b, 0x0a, 0x07, 0x73, 0x61, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x10, 0x00, 0x12, 0x0b, - 0x0a, 0x07, 0x6f, 0x72, 0x63, 0x68, 0x61, 0x72, 0x64, 0x10, 0x01, 0x32, 0x9a, 0x0e, 0x0a, 0x11, - 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x54, 0x78, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x65, - 0x72, 0x12, 0x54, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x12, 0x20, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, - 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x69, - 0x6e, 0x53, 0x70, 0x65, 0x63, 0x1a, 0x1e, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, - 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x49, 0x44, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x12, 0x1e, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, - 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x49, 0x44, 0x1a, 0x23, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, - 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6d, 0x70, - 0x61, 0x63, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x5b, 0x0a, 0x12, 0x47, 0x65, - 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6c, 0x6c, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, - 0x12, 0x1e, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, - 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x44, - 0x1a, 0x23, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, - 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x5b, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x21, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, - 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, - 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x1a, 0x23, 0x2e, 0x63, 0x61, - 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, - 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x22, 0x00, 0x30, 0x01, 0x12, 0x65, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x52, 0x61, 0x6e, 0x67, 0x65, 0x4e, 0x75, 0x6c, 0x6c, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x12, - 0x21, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, - 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x61, 0x6e, - 0x67, 0x65, 0x1a, 0x23, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, - 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x61, - 0x63, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x00, 0x30, 0x01, 0x12, 0x5a, 0x0a, 0x0e, 0x47, - 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x2e, - 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, - 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x78, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x1a, 0x25, - 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, - 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x61, 0x77, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x12, 0x5f, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x2e, 0x63, 0x61, 0x73, - 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, - 0x70, 0x63, 0x2e, 0x52, 0x61, 0x77, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x1a, 0x23, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, - 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x73, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x54, - 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x54, 0x78, 0x69, 0x64, 0x73, 0x12, 0x34, 0x2e, 0x63, + 0x73, 0x73, 0x12, 0x37, 0x0a, 0x05, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, + 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, + 0x61, 0x6e, 0x67, 0x65, 0x52, 0x05, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x22, 0x2a, 0x0a, 0x08, 0x44, + 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x76, 0x61, 0x6c, 0x55, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x76, 0x61, 0x6c, 0x55, 0x73, 0x22, 0x38, 0x0a, 0x0c, 0x50, 0x69, 0x6e, 0x67, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x12, 0x0a, + 0x04, 0x65, 0x78, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x65, 0x78, 0x69, + 0x74, 0x22, 0x23, 0x0a, 0x07, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x2b, 0x0a, 0x0b, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x73, 0x22, 0x25, 0x0a, 0x07, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1a, + 0x0a, 0x08, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5a, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x08, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5a, 0x61, 0x74, 0x22, 0x1d, 0x0a, 0x07, 0x45, 0x78, + 0x63, 0x6c, 0x75, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0c, 0x52, 0x04, 0x74, 0x78, 0x69, 0x64, 0x22, 0xa9, 0x01, 0x0a, 0x09, 0x54, 0x72, + 0x65, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, + 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x12, 0x0a, + 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x74, 0x69, 0x6d, + 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x61, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x65, 0x65, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x61, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x54, + 0x72, 0x65, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x6f, 0x72, 0x63, 0x68, 0x61, 0x72, 0x64, 0x54, 0x72, + 0x65, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x72, 0x63, 0x68, 0x61, 0x72, + 0x64, 0x54, 0x72, 0x65, 0x65, 0x22, 0xa9, 0x01, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x53, 0x75, 0x62, + 0x74, 0x72, 0x65, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x73, 0x41, 0x72, 0x67, 0x12, 0x1e, 0x0a, 0x0a, + 0x73, 0x74, 0x61, 0x72, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x53, 0x0a, 0x10, + 0x73, 0x68, 0x69, 0x65, 0x6c, 0x64, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, + 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x53, + 0x68, 0x69, 0x65, 0x6c, 0x64, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, + 0x10, 0x73, 0x68, 0x69, 0x65, 0x6c, 0x64, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, + 0x6c, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x6d, 0x61, 0x78, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, + 0x73, 0x22, 0x91, 0x01, 0x0a, 0x0b, 0x53, 0x75, 0x62, 0x74, 0x72, 0x65, 0x65, 0x52, 0x6f, 0x6f, + 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x08, 0x72, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x30, 0x0a, + 0x13, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x69, 0x6e, 0x67, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x48, 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x13, 0x63, 0x6f, 0x6d, 0x70, + 0x6c, 0x65, 0x74, 0x69, 0x6e, 0x67, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x12, + 0x34, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x69, 0x6e, 0x67, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x15, + 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x69, 0x6e, 0x67, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, + 0x65, 0x69, 0x67, 0x68, 0x74, 0x22, 0x74, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x41, 0x72, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x74, 0x61, + 0x72, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, + 0x73, 0x74, 0x61, 0x72, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, + 0x61, 0x78, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x0a, 0x6d, 0x61, 0x78, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x22, 0xa6, 0x01, 0x0a, 0x14, + 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x52, + 0x65, 0x70, 0x6c, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, + 0x0a, 0x04, 0x74, 0x78, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x74, 0x78, + 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5a, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x08, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5a, 0x61, 0x74, 0x12, 0x16, 0x0a, 0x06, + 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x68, 0x65, + 0x69, 0x67, 0x68, 0x74, 0x22, 0x6b, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x4c, 0x69, 0x73, 0x74, + 0x12, 0x4f, 0x0a, 0x0c, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, + 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47, + 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, + 0x70, 0x6c, 0x79, 0x52, 0x0c, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, + 0x73, 0x2a, 0x2c, 0x0a, 0x10, 0x53, 0x68, 0x69, 0x65, 0x6c, 0x64, 0x65, 0x64, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x0b, 0x0a, 0x07, 0x73, 0x61, 0x70, 0x6c, 0x69, 0x6e, 0x67, + 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x6f, 0x72, 0x63, 0x68, 0x61, 0x72, 0x64, 0x10, 0x01, 0x32, + 0x9a, 0x0e, 0x0a, 0x11, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x54, 0x78, 0x53, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x65, 0x72, 0x12, 0x54, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x74, 0x65, + 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x20, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, + 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, + 0x43, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x70, 0x65, 0x63, 0x1a, 0x1e, 0x2e, 0x63, 0x61, 0x73, 0x68, + 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, + 0x63, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x44, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x08, 0x47, + 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x1e, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, + 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x44, 0x1a, 0x23, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, + 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, + 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x5b, + 0x0a, 0x12, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6c, 0x6c, 0x69, 0x66, + 0x69, 0x65, 0x72, 0x73, 0x12, 0x1e, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, + 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x49, 0x44, 0x1a, 0x23, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, + 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6d, + 0x70, 0x61, 0x63, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x5b, 0x0a, 0x0d, 0x47, + 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x21, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, - 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x74, + 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x1a, + 0x23, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, + 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x00, 0x30, 0x01, 0x12, 0x65, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x4e, 0x75, 0x6c, 0x6c, 0x69, 0x66, 0x69, + 0x65, 0x72, 0x73, 0x12, 0x21, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, + 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x1a, 0x23, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, + 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x43, + 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x00, 0x30, 0x01, 0x12, + 0x5a, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x1f, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, + 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x78, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x1a, 0x25, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x61, 0x77, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x30, 0x01, 0x12, 0x5a, 0x0a, - 0x12, 0x47, 0x65, 0x74, 0x54, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x61, 0x6c, 0x61, - 0x6e, 0x63, 0x65, 0x12, 0x22, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, - 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x12, 0x5f, 0x0a, 0x0f, 0x53, + 0x65, 0x6e, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, + 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, + 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x61, 0x77, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x23, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, + 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, + 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x73, 0x0a, 0x10, + 0x47, 0x65, 0x74, 0x54, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x54, 0x78, 0x69, 0x64, 0x73, + 0x12, 0x34, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, + 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, + 0x72, 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x1a, 0x25, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, + 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x52, + 0x61, 0x77, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x30, + 0x01, 0x12, 0x5a, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x54, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x22, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, - 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x22, 0x00, 0x12, 0x5e, 0x0a, 0x18, 0x47, 0x65, 0x74, - 0x54, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x53, - 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1e, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, - 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x1a, 0x1e, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, - 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, - 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x22, 0x00, 0x28, 0x01, 0x12, 0x54, 0x0a, 0x0c, 0x47, 0x65, 0x74, - 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x54, 0x78, 0x12, 0x1e, 0x2e, 0x63, 0x61, 0x73, 0x68, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x63, 0x61, + 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, + 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x22, 0x00, 0x12, 0x5e, 0x0a, + 0x18, 0x47, 0x65, 0x74, 0x54, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x61, 0x6c, 0x61, + 0x6e, 0x63, 0x65, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1e, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, - 0x63, 0x2e, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x1a, 0x20, 0x2e, 0x63, 0x61, 0x73, 0x68, + 0x63, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x1a, 0x1e, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, - 0x63, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x54, 0x78, 0x22, 0x00, 0x30, 0x01, 0x12, - 0x5b, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x53, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x12, 0x1c, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, - 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x45, 0x6d, 0x70, 0x74, - 0x79, 0x1a, 0x25, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, - 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x61, 0x77, 0x54, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x30, 0x01, 0x12, 0x52, 0x0a, 0x0c, - 0x47, 0x65, 0x74, 0x54, 0x72, 0x65, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1e, 0x2e, 0x63, - 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, - 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x44, 0x1a, 0x20, 0x2e, 0x63, - 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, - 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0x00, - 0x12, 0x56, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x54, 0x72, 0x65, - 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1c, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, - 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x45, - 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x20, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, - 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x65, - 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0x00, 0x12, 0x64, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x53, - 0x75, 0x62, 0x74, 0x72, 0x65, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x73, 0x12, 0x29, 0x2e, 0x63, 0x61, - 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, - 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x75, 0x62, 0x74, 0x72, 0x65, 0x65, 0x52, 0x6f, - 0x6f, 0x74, 0x73, 0x41, 0x72, 0x67, 0x1a, 0x22, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, - 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x53, - 0x75, 0x62, 0x74, 0x72, 0x65, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x00, 0x30, 0x01, 0x12, 0x6f, - 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, - 0x73, 0x12, 0x29, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, - 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x41, 0x72, 0x67, 0x1a, 0x2f, 0x2e, 0x63, + 0x63, 0x2e, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x22, 0x00, 0x28, 0x01, 0x12, 0x54, 0x0a, + 0x0c, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x54, 0x78, 0x12, 0x1e, 0x2e, + 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, + 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x1a, 0x20, 0x2e, + 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, + 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x54, 0x78, 0x22, + 0x00, 0x30, 0x01, 0x12, 0x5b, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, + 0x6c, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1c, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, + 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x25, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, + 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x61, + 0x77, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x30, 0x01, + 0x12, 0x52, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x54, 0x72, 0x65, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x12, 0x1e, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, + 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x44, + 0x1a, 0x20, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, + 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x22, 0x00, 0x12, 0x56, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x74, 0x65, 0x73, + 0x74, 0x54, 0x72, 0x65, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1c, 0x2e, 0x63, 0x61, 0x73, + 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, + 0x70, 0x63, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x20, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, + 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, + 0x2e, 0x54, 0x72, 0x65, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0x00, 0x12, 0x64, 0x0a, 0x0f, + 0x47, 0x65, 0x74, 0x53, 0x75, 0x62, 0x74, 0x72, 0x65, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x73, 0x12, + 0x29, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, + 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x75, 0x62, 0x74, 0x72, + 0x65, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x73, 0x41, 0x72, 0x67, 0x1a, 0x22, 0x2e, 0x63, 0x61, 0x73, + 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, + 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x74, 0x72, 0x65, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x00, + 0x30, 0x01, 0x12, 0x6f, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x55, 0x74, 0x78, 0x6f, 0x73, 0x12, 0x29, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, + 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, + 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x41, 0x72, 0x67, + 0x1a, 0x2f, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, + 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x4c, 0x69, 0x73, + 0x74, 0x22, 0x00, 0x12, 0x73, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x29, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, - 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x00, 0x12, - 0x73, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, - 0x6f, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x29, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, - 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, - 0x2e, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, - 0x41, 0x72, 0x67, 0x1a, 0x2b, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, - 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, - 0x22, 0x00, 0x30, 0x01, 0x12, 0x52, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x4c, 0x69, 0x67, 0x68, 0x74, - 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, - 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x1a, 0x21, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, - 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x67, 0x68, - 0x74, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x00, 0x12, 0x4e, 0x0a, 0x04, 0x50, 0x69, 0x6e, 0x67, - 0x12, 0x1f, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, - 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x1a, 0x23, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, - 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x1b, 0x5a, 0x16, 0x6c, 0x69, 0x67, 0x68, - 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2f, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, - 0x70, 0x63, 0xba, 0x02, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x78, 0x6f, 0x73, 0x41, 0x72, 0x67, 0x1a, 0x2b, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, + 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, + 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x52, + 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x30, 0x01, 0x12, 0x52, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x4c, + 0x69, 0x67, 0x68, 0x74, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x2e, 0x63, 0x61, 0x73, 0x68, + 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, + 0x63, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x21, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, + 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, + 0x4c, 0x69, 0x67, 0x68, 0x74, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x00, 0x12, 0x4e, 0x0a, 0x04, + 0x50, 0x69, 0x6e, 0x67, 0x12, 0x1f, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, + 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x75, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x23, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, + 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x69, + 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x1b, 0x5a, 0x16, + 0x6c, 0x69, 0x67, 0x68, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2f, 0x77, 0x61, 0x6c, + 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0xba, 0x02, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( diff --git a/walletrpc/service.proto b/walletrpc/service.proto index 2f7c9caf..21e7fe5e 100644 --- a/walletrpc/service.proto +++ b/walletrpc/service.proto @@ -89,6 +89,7 @@ message LightdInfo { uint64 estimatedHeight = 12; // less than tip height if zcashd is syncing string zcashdBuild = 13; // example: "v4.1.1-877212414" string zcashdSubversion = 14; // example: "/MagicBean:4.1.1/" + bool lightwalletdDisabled = 15; // whether zcashd is configured as a lwd server } // TransparentAddressBlockFilter restricts the results to the given address