Skip to main content

rs_dapi_client/transport/
grpc.rs

1//! Listing of gRPC requests used in DAPI.
2
3use std::time::Duration;
4
5use super::create_channel;
6use super::{CanRetry, TransportClient, TransportError, TransportRequest};
7use super::{CoreGrpcClient, PlatformGrpcClient};
8use crate::connection_pool::{ConnectionPool, PoolPrefix};
9use crate::{request_settings::AppliedRequestSettings, RequestSettings, Uri};
10use dapi_grpc::core::v0::{self as core_proto};
11use dapi_grpc::platform::v0::{self as platform_proto};
12use dapi_grpc::tonic::{IntoRequest, Streaming};
13use futures::{future::BoxFuture, FutureExt, TryFutureExt};
14
15impl TransportClient for PlatformGrpcClient {
16    fn with_uri(uri: Uri, pool: &ConnectionPool) -> Result<Self, TransportError> {
17        Ok(pool
18            .get_or_create(PoolPrefix::Platform, &uri, None, || {
19                match create_channel(uri.clone(), None) {
20                    Ok(channel) => Ok(Self::new(channel).into()),
21                    Err(e) => Err(dapi_grpc::tonic::Status::invalid_argument(format!(
22                        "channel creation failed: {}",
23                        e
24                    ))),
25                }
26            })?
27            .into())
28    }
29
30    fn with_uri_and_settings(
31        uri: Uri,
32        settings: &AppliedRequestSettings,
33        pool: &ConnectionPool,
34    ) -> Result<Self, TransportError> {
35        Ok(pool
36            .get_or_create(
37                PoolPrefix::Platform,
38                &uri,
39                Some(settings),
40                || match create_channel(uri.clone(), Some(settings)) {
41                    Ok(channel) => {
42                        let mut client = Self::new(channel);
43                        if let Some(max_size) = settings.max_decoding_message_size {
44                            client = client.max_decoding_message_size(max_size);
45                        }
46                        Ok(client.into())
47                    }
48                    Err(e) => Err(dapi_grpc::tonic::Status::invalid_argument(format!(
49                        "Channel creation failed: {}",
50                        e
51                    ))),
52                },
53            )?
54            .into())
55    }
56}
57
58impl TransportClient for CoreGrpcClient {
59    fn with_uri(uri: Uri, pool: &ConnectionPool) -> Result<Self, TransportError> {
60        Ok(pool
61            .get_or_create(PoolPrefix::Core, &uri, None, || {
62                match create_channel(uri.clone(), None) {
63                    Ok(channel) => Ok(Self::new(channel).into()),
64                    Err(e) => Err(dapi_grpc::tonic::Status::invalid_argument(format!(
65                        "Channel creation failed: {}",
66                        e
67                    ))),
68                }
69            })?
70            .into())
71    }
72
73    fn with_uri_and_settings(
74        uri: Uri,
75        settings: &AppliedRequestSettings,
76        pool: &ConnectionPool,
77    ) -> Result<Self, TransportError> {
78        Ok(pool
79            .get_or_create(
80                PoolPrefix::Core,
81                &uri,
82                Some(settings),
83                || match create_channel(uri.clone(), Some(settings)) {
84                    Ok(channel) => {
85                        let mut client = Self::new(channel);
86                        if let Some(max_size) = settings.max_decoding_message_size {
87                            client = client.max_decoding_message_size(max_size);
88                        }
89                        Ok(client.into())
90                    }
91                    Err(e) => Err(dapi_grpc::tonic::Status::invalid_argument(format!(
92                        "Channel creation failed: {}",
93                        e
94                    ))),
95                },
96            )?
97            .into())
98    }
99}
100
101impl CanRetry for dapi_grpc::tonic::Status {
102    fn can_retry(&self) -> bool {
103        let code = self.code();
104
105        use dapi_grpc::tonic::Code::*;
106
107        matches!(
108            code,
109            Ok | DataLoss
110                | Cancelled
111                | Unknown
112                | DeadlineExceeded
113                | ResourceExhausted
114                | Aborted
115                | Internal
116                | Unavailable
117                // During a mixed-version network rollout, Unimplemented means this
118                // particular node runs an older build that doesn't expose the method
119                // yet; another node may serve it. Marking it retryable makes the
120                // executor ban the node (see `update_address_ban_status`) and retry
121                // elsewhere.
122                //
123                // When NO node implements the method, how the failure surfaces depends
124                // on which of `DapiClient::execute`'s two caps trips first:
125                //   * `live_addresses <= settings.retries` — the address list is
126                //     exhausted before the retry budget, so the error surfaces as the
127                //     non-retryable `NoAvailableAddressesToRetry`.
128                //   * `live_addresses > settings.retries` — the per-call retry budget
129                //     trips first, banning `settings.retries + 1` nodes and surfacing
130                //     the raw (still-retryable) `Unimplemented`. A caller that honors
131                //     `CanRetry` then re-enters and bans more nodes each round,
132                //     converging on the exhausted-addresses case above; rs-sdk also
133                //     bounds this via its own `total_retries` cap (see
134                //     `rs-sdk/src/sync.rs`). Either way the loop is bounded — it never
135                //     retries the same node forever.
136                //
137                // Caveat: bans are address-scoped, not (address, method)-scoped, and
138                // Unimplemented is also returned deliberately for genuinely unsupported
139                // / feature-gated endpoints (e.g. rs-drive-abci's
140                // broadcast_state_transition / wait_for_state_transition_result /
141                // get_consensus_params, and any rs-dapi `MethodNotFound`). Calling such
142                // an endpoint bans an otherwise-healthy node across ALL methods for the
143                // ban window. Acceptable for the targeted rollout case; per-method ban
144                // granularity is left as a follow-up so optional endpoints can't poison
145                // the shared address list. TODO(per-method-ban).
146                | Unimplemented
147        )
148    }
149
150    /// Returns the Envoy-advertised ban duration for a `ResourceExhausted`
151    /// response, or `None` if this is not a rate-limit or carries no usable
152    /// `RateLimit-Reset` header.
153    ///
154    /// Envoy's global rate-limit filter emits `RateLimit-Reset: <seconds>` when
155    /// `LIMIT_RESPONSE_HEADERS_ENABLED=true` is set on the Lyft RLS container
156    /// (see `packages/dashmate/docker-compose.rate_limiter.yml`).  The value is
157    /// the whole-second count until the per-IP window resets.
158    ///
159    /// Parse rules (adversarial-input safe):
160    /// * Non-`ResourceExhausted` code → `None`.
161    /// * Header absent, non-numeric, or `0` → `None` (caller uses normal ban
162    ///   ladder).
163    /// * Valid positive integer → clamped to
164    ///   [`[MIN_RATE_LIMIT_BAN_SECS, MAX_RATE_LIMIT_BAN_SECS]`]
165    ///   (`dapi_client.rs`) and returned as `Some(Duration)`.
166    fn rate_limit_ban_duration(&self) -> Option<std::time::Duration> {
167        use crate::dapi_client::{MAX_RATE_LIMIT_BAN_SECS, MIN_RATE_LIMIT_BAN_SECS};
168        use dapi_grpc::tonic::Code;
169        if self.code() != Code::ResourceExhausted {
170            return None;
171        }
172        let secs = self
173            .metadata()
174            .get("ratelimit-reset")
175            .and_then(|v| v.to_str().ok())
176            .and_then(|s| s.trim().parse::<u64>().ok())
177            .filter(|&s| s > 0)?;
178        Some(std::time::Duration::from_secs(
179            secs.clamp(MIN_RATE_LIMIT_BAN_SECS, MAX_RATE_LIMIT_BAN_SECS),
180        ))
181    }
182}
183
184/// Macro to implement the `TransportRequest` trait for a given request type, response type, client type, and settings.
185///
186/// # Parameters
187///
188/// - `$request:ty`: The request type for which the `TransportRequest` trait will be implemented.
189/// - `$response:ty`: The response type returned by the transport request.
190/// - `$client:ty`: The client type used to execute the transport request (eg. generated by `tonic` crate).
191/// - `$settings:expr`: The settings to be used for the transport request; these settings will override client's
192///   default settings, but can still be overridden by arguments to
193///   the [`DapiRequestExecutor::execute`](crate::DapiRequestExecutor::execute) method.
194/// - `$($method:tt)+`: The method of `$client` to be called to execute the request.
195///
196/// # Example
197///
198/// ```compile_fail
199/// impl_transport_request_grpc!(
200///     MyRequestType,
201///     MyResponseType,
202///     MyClientType,
203///     my_settings,
204///     my_method
205/// );
206/// ```
207///
208/// This will generate an implementation of the `TransportRequest` trait for `MyRequestType`
209/// that uses `MyClientType` to execute the `my_method` method, with the specified `my_settings`.
210///
211/// The generated implementation will:
212/// - Define the associated types `Client` and `Response`.
213/// - Set the `SETTINGS_OVERRIDES` constant to the provided settings.
214/// - Implement the `method_name` function to return the name of the method as a string.
215/// - Implement the `execute_transport` function to execute the transport request using the provided client and settings.
216macro_rules! impl_transport_request_grpc {
217    ($request:ty, $response:ty, $client:ty, $settings:expr, $($method:tt)+) => {
218        impl TransportRequest for $request {
219            type Client = $client;
220
221            type Response = $response;
222
223            const SETTINGS_OVERRIDES: RequestSettings = $settings;
224
225            fn method_name(&self) -> &'static str {
226                stringify!($($method)+)
227            }
228
229            fn execute_transport<'c>(
230                self,
231                client: &'c mut Self::Client,
232                settings: &AppliedRequestSettings,
233            ) -> BoxFuture<'c, Result<Self::Response, TransportError>>
234            {
235                let mut grpc_request = self.into_request();
236
237                if !settings.timeout.is_zero() {
238                    grpc_request.set_timeout(settings.timeout);
239                }
240
241                client
242                    .$($method)+(grpc_request)
243                    .map_err(TransportError::Grpc)
244                    .map_ok(|response| response.into_inner())
245                    .boxed()
246            }
247        }
248    };
249}
250
251// Link to each platform gRPC request what client and method to use:
252
253const STREAMING_TIMEOUT: Duration = Duration::from_secs(5 * 60);
254
255impl_transport_request_grpc!(
256    platform_proto::GetIdentityRequest,
257    platform_proto::GetIdentityResponse,
258    PlatformGrpcClient,
259    RequestSettings::default(),
260    get_identity
261);
262
263impl_transport_request_grpc!(
264    platform_proto::GetDocumentsRequest,
265    platform_proto::GetDocumentsResponse,
266    PlatformGrpcClient,
267    RequestSettings::default(),
268    get_documents
269);
270
271impl_transport_request_grpc!(
272    platform_proto::GetDataContractRequest,
273    platform_proto::GetDataContractResponse,
274    PlatformGrpcClient,
275    RequestSettings::default(),
276    get_data_contract
277);
278
279impl_transport_request_grpc!(
280    platform_proto::GetConsensusParamsRequest,
281    platform_proto::GetConsensusParamsResponse,
282    PlatformGrpcClient,
283    RequestSettings::default(),
284    get_consensus_params
285);
286
287impl_transport_request_grpc!(
288    platform_proto::GetDataContractHistoryRequest,
289    platform_proto::GetDataContractHistoryResponse,
290    PlatformGrpcClient,
291    RequestSettings::default(),
292    get_data_contract_history
293);
294
295impl_transport_request_grpc!(
296    platform_proto::GetDocumentHistoryRequest,
297    platform_proto::GetDocumentHistoryResponse,
298    PlatformGrpcClient,
299    RequestSettings::default(),
300    get_document_history
301);
302
303impl_transport_request_grpc!(
304    platform_proto::BroadcastStateTransitionRequest,
305    platform_proto::BroadcastStateTransitionResponse,
306    PlatformGrpcClient,
307    RequestSettings::default(),
308    broadcast_state_transition
309);
310
311impl_transport_request_grpc!(
312    platform_proto::WaitForStateTransitionResultRequest,
313    platform_proto::WaitForStateTransitionResultResponse,
314    PlatformGrpcClient,
315    RequestSettings {
316        timeout: Some(Duration::from_secs(30)),
317        retries: Some(3),
318        ban_failed_address: None,
319        connect_timeout: None,
320        max_decoding_message_size: None,
321    },
322    wait_for_state_transition_result
323);
324
325impl_transport_request_grpc!(
326    platform_proto::GetIdentityByPublicKeyHashRequest,
327    platform_proto::GetIdentityByPublicKeyHashResponse,
328    PlatformGrpcClient,
329    RequestSettings::default(),
330    get_identity_by_public_key_hash
331);
332
333impl_transport_request_grpc!(
334    platform_proto::GetIdentityBalanceRequest,
335    platform_proto::GetIdentityBalanceResponse,
336    PlatformGrpcClient,
337    RequestSettings::default(),
338    get_identity_balance
339);
340
341impl_transport_request_grpc!(
342    platform_proto::GetIdentitiesBalancesRequest,
343    platform_proto::GetIdentitiesBalancesResponse,
344    PlatformGrpcClient,
345    RequestSettings::default(),
346    get_identities_balances
347);
348
349impl_transport_request_grpc!(
350    platform_proto::GetIdentityNonceRequest,
351    platform_proto::GetIdentityNonceResponse,
352    PlatformGrpcClient,
353    RequestSettings::default(),
354    get_identity_nonce
355);
356
357impl_transport_request_grpc!(
358    platform_proto::GetIdentityContractNonceRequest,
359    platform_proto::GetIdentityContractNonceResponse,
360    PlatformGrpcClient,
361    RequestSettings::default(),
362    get_identity_contract_nonce
363);
364
365impl_transport_request_grpc!(
366    platform_proto::GetIdentityBalanceAndRevisionRequest,
367    platform_proto::GetIdentityBalanceAndRevisionResponse,
368    PlatformGrpcClient,
369    RequestSettings::default(),
370    get_identity_balance_and_revision
371);
372
373impl_transport_request_grpc!(
374    platform_proto::GetIdentitiesContractKeysRequest,
375    platform_proto::GetIdentitiesContractKeysResponse,
376    PlatformGrpcClient,
377    RequestSettings::default(),
378    get_identities_contract_keys
379);
380
381impl_transport_request_grpc!(
382    platform_proto::GetIdentityKeysRequest,
383    platform_proto::GetIdentityKeysResponse,
384    PlatformGrpcClient,
385    RequestSettings::default(),
386    get_identity_keys
387);
388
389impl_transport_request_grpc!(
390    platform_proto::GetEpochsInfoRequest,
391    platform_proto::GetEpochsInfoResponse,
392    PlatformGrpcClient,
393    RequestSettings::default(),
394    get_epochs_info
395);
396
397impl_transport_request_grpc!(
398    platform_proto::GetFinalizedEpochInfosRequest,
399    platform_proto::GetFinalizedEpochInfosResponse,
400    PlatformGrpcClient,
401    RequestSettings::default(),
402    get_finalized_epoch_infos
403);
404
405impl_transport_request_grpc!(
406    platform_proto::GetProtocolVersionUpgradeStateRequest,
407    platform_proto::GetProtocolVersionUpgradeStateResponse,
408    PlatformGrpcClient,
409    RequestSettings::default(),
410    get_protocol_version_upgrade_state
411);
412
413impl_transport_request_grpc!(
414    platform_proto::GetProtocolVersionUpgradeVoteStatusRequest,
415    platform_proto::GetProtocolVersionUpgradeVoteStatusResponse,
416    PlatformGrpcClient,
417    RequestSettings::default(),
418    get_protocol_version_upgrade_vote_status
419);
420
421impl_transport_request_grpc!(
422    platform_proto::GetDataContractsRequest,
423    platform_proto::GetDataContractsResponse,
424    PlatformGrpcClient,
425    RequestSettings::default(),
426    get_data_contracts
427);
428
429// rpc getContestedResources(GetContestedResourcesRequest) returns (GetContestedResourcesResponse);
430impl_transport_request_grpc!(
431    platform_proto::GetContestedResourcesRequest,
432    platform_proto::GetContestedResourcesResponse,
433    PlatformGrpcClient,
434    RequestSettings::default(),
435    get_contested_resources
436);
437
438//  rpc getContestedResourceVoteState(GetContestedResourceVoteStateRequest) returns (GetContestedResourceVoteStateResponse);
439impl_transport_request_grpc!(
440    platform_proto::GetContestedResourceVoteStateRequest,
441    platform_proto::GetContestedResourceVoteStateResponse,
442    PlatformGrpcClient,
443    RequestSettings::default(),
444    get_contested_resource_vote_state
445);
446
447// rpc getContestedResourceVotersForIdentity(GetContestedResourceVotersForIdentityRequest) returns (GetContestedResourceVotersForIdentityResponse);
448impl_transport_request_grpc!(
449    platform_proto::GetContestedResourceVotersForIdentityRequest,
450    platform_proto::GetContestedResourceVotersForIdentityResponse,
451    PlatformGrpcClient,
452    RequestSettings::default(),
453    get_contested_resource_voters_for_identity
454);
455// rpc getContestedResourceIdentityVoteStatus(GetContestedResourceIdentityVoteStatusRequest) returns (GetContestedResourceIdentityVoteStatusResponse);
456impl_transport_request_grpc!(
457    platform_proto::GetContestedResourceIdentityVotesRequest,
458    platform_proto::GetContestedResourceIdentityVotesResponse,
459    PlatformGrpcClient,
460    RequestSettings::default(),
461    get_contested_resource_identity_votes
462);
463// rpc GetVotePollsByEndDateRequest(GetVotePollsByEndDateRequest) returns (GetVotePollsByEndDateResponse);
464impl_transport_request_grpc!(
465    platform_proto::GetVotePollsByEndDateRequest,
466    platform_proto::GetVotePollsByEndDateResponse,
467    PlatformGrpcClient,
468    RequestSettings::default(),
469    get_vote_polls_by_end_date
470);
471
472// rpc GetEvonodesProposedEpochBlocksByIdsRequest(GetEvonodesProposedEpochBlocksByIdsRequest) returns (GetEvonodesProposedEpochBlocksResponse);
473impl_transport_request_grpc!(
474    platform_proto::GetEvonodesProposedEpochBlocksByIdsRequest,
475    platform_proto::GetEvonodesProposedEpochBlocksResponse,
476    PlatformGrpcClient,
477    RequestSettings::default(),
478    get_evonodes_proposed_epoch_blocks_by_ids
479);
480
481// rpc GetEvonodesProposedEpochBlocksByRangeRequest(GetEvonodesProposedEpochBlocksByRangeRequest) returns (GetEvonodesProposedEpochBlocksResponse);
482impl_transport_request_grpc!(
483    platform_proto::GetEvonodesProposedEpochBlocksByRangeRequest,
484    platform_proto::GetEvonodesProposedEpochBlocksResponse,
485    PlatformGrpcClient,
486    RequestSettings::default(),
487    get_evonodes_proposed_epoch_blocks_by_range
488);
489
490// rpc getPrefundedSpecializedBalance(GetPrefundedSpecializedBalanceRequest) returns (GetPrefundedSpecializedBalanceResponse);
491impl_transport_request_grpc!(
492    platform_proto::GetPrefundedSpecializedBalanceRequest,
493    platform_proto::GetPrefundedSpecializedBalanceResponse,
494    PlatformGrpcClient,
495    RequestSettings::default(),
496    get_prefunded_specialized_balance
497);
498
499// rpc getPathElements(GetPathElementsRequest) returns (GetPathElementsResponse);
500impl_transport_request_grpc!(
501    platform_proto::GetPathElementsRequest,
502    platform_proto::GetPathElementsResponse,
503    PlatformGrpcClient,
504    RequestSettings::default(),
505    get_path_elements
506);
507
508// rpc getTotalCreditsInPlatform(GetTotalCreditsInPlatformRequest) returns (GetTotalCreditsInPlatformResponse);
509impl_transport_request_grpc!(
510    platform_proto::GetTotalCreditsInPlatformRequest,
511    platform_proto::GetTotalCreditsInPlatformResponse,
512    PlatformGrpcClient,
513    RequestSettings::default(),
514    get_total_credits_in_platform
515);
516
517// rpc getCurrentQuorumsInfo(GetCurrentQuorumsInfoRequest) returns (GetCurrentQuorumsInfoResponse);
518impl_transport_request_grpc!(
519    platform_proto::GetCurrentQuorumsInfoRequest,
520    platform_proto::GetCurrentQuorumsInfoResponse,
521    PlatformGrpcClient,
522    RequestSettings::default(),
523    get_current_quorums_info
524);
525
526// rpc getShieldedEncryptedNotes(GetShieldedEncryptedNotesRequest) returns (GetShieldedEncryptedNotesResponse);
527impl_transport_request_grpc!(
528    platform_proto::GetShieldedEncryptedNotesRequest,
529    platform_proto::GetShieldedEncryptedNotesResponse,
530    PlatformGrpcClient,
531    RequestSettings::default(),
532    get_shielded_encrypted_notes
533);
534
535// rpc getShieldedAnchors(GetShieldedAnchorsRequest) returns (GetShieldedAnchorsResponse);
536impl_transport_request_grpc!(
537    platform_proto::GetShieldedAnchorsRequest,
538    platform_proto::GetShieldedAnchorsResponse,
539    PlatformGrpcClient,
540    RequestSettings::default(),
541    get_shielded_anchors
542);
543
544// rpc getMostRecentShieldedAnchor(GetMostRecentShieldedAnchorRequest) returns (GetMostRecentShieldedAnchorResponse);
545impl_transport_request_grpc!(
546    platform_proto::GetMostRecentShieldedAnchorRequest,
547    platform_proto::GetMostRecentShieldedAnchorResponse,
548    PlatformGrpcClient,
549    RequestSettings::default(),
550    get_most_recent_shielded_anchor
551);
552
553// rpc getShieldedPoolState(GetShieldedPoolStateRequest) returns (GetShieldedPoolStateResponse);
554impl_transport_request_grpc!(
555    platform_proto::GetShieldedPoolStateRequest,
556    platform_proto::GetShieldedPoolStateResponse,
557    PlatformGrpcClient,
558    RequestSettings::default(),
559    get_shielded_pool_state
560);
561
562// rpc getShieldedNotesCount(GetShieldedNotesCountRequest) returns (GetShieldedNotesCountResponse);
563impl_transport_request_grpc!(
564    platform_proto::GetShieldedNotesCountRequest,
565    platform_proto::GetShieldedNotesCountResponse,
566    PlatformGrpcClient,
567    RequestSettings::default(),
568    get_shielded_notes_count
569);
570
571// rpc getShieldedNullifiers(GetShieldedNullifiersRequest) returns (GetShieldedNullifiersResponse);
572impl_transport_request_grpc!(
573    platform_proto::GetShieldedNullifiersRequest,
574    platform_proto::GetShieldedNullifiersResponse,
575    PlatformGrpcClient,
576    RequestSettings::default(),
577    get_shielded_nullifiers
578);
579
580// Link to each core gRPC request what client and method to use:
581
582impl_transport_request_grpc!(
583    core_proto::GetTransactionRequest,
584    core_proto::GetTransactionResponse,
585    CoreGrpcClient,
586    RequestSettings::default(),
587    get_transaction
588);
589
590impl_transport_request_grpc!(
591    core_proto::GetBlockchainStatusRequest,
592    core_proto::GetBlockchainStatusResponse,
593    CoreGrpcClient,
594    RequestSettings::default(),
595    get_blockchain_status
596);
597
598impl_transport_request_grpc!(
599    core_proto::BroadcastTransactionRequest,
600    core_proto::BroadcastTransactionResponse,
601    CoreGrpcClient,
602    RequestSettings::default(),
603    broadcast_transaction
604);
605
606impl_transport_request_grpc!(
607    core_proto::TransactionsWithProofsRequest,
608    Streaming<core_proto::TransactionsWithProofsResponse>,
609    CoreGrpcClient,
610    RequestSettings {
611        timeout: Some(STREAMING_TIMEOUT),
612        ban_failed_address: None,
613        connect_timeout: None,
614        retries: None,
615        max_decoding_message_size: None,
616    },
617    subscribe_to_transactions_with_proofs
618);
619
620impl_transport_request_grpc!(
621    core_proto::MasternodeListRequest,
622    Streaming<core_proto::MasternodeListResponse>,
623    CoreGrpcClient,
624    RequestSettings {
625        timeout: Some(STREAMING_TIMEOUT),
626        ..RequestSettings::default()
627    },
628    subscribe_to_masternode_list
629);
630
631// rpc getStatus(GetStatusRequest) returns (GetStatusResponse);
632impl_transport_request_grpc!(
633    platform_proto::GetStatusRequest,
634    platform_proto::GetStatusResponse,
635    PlatformGrpcClient,
636    RequestSettings::default(),
637    get_status
638);
639
640//   rpc getIdentityByNonUniquePublicKeyHash(GetIdentityByNonUniquePublicKeyHashRequest) returns (GetIdentityByNonUniquePublicKeyHashResponse);
641impl_transport_request_grpc!(
642    platform_proto::GetIdentityByNonUniquePublicKeyHashRequest,
643    platform_proto::GetIdentityByNonUniquePublicKeyHashResponse,
644    PlatformGrpcClient,
645    RequestSettings::default(),
646    get_identity_by_non_unique_public_key_hash
647);
648
649// rpc getIdentityTokenBalances(GetIdentityTokenBalancesRequest) returns (GetIdentityTokenBalancesResponse);
650impl_transport_request_grpc!(
651    platform_proto::GetIdentityTokenBalancesRequest,
652    platform_proto::GetIdentityTokenBalancesResponse,
653    PlatformGrpcClient,
654    RequestSettings::default(),
655    get_identity_token_balances
656);
657
658// rpc getIdentitiesTokenBalances(GetIdentitiesTokenBalancesRequest) returns (GetIdentitiesTokenBalancesResponse);
659impl_transport_request_grpc!(
660    platform_proto::GetIdentitiesTokenBalancesRequest,
661    platform_proto::GetIdentitiesTokenBalancesResponse,
662    PlatformGrpcClient,
663    RequestSettings::default(),
664    get_identities_token_balances
665);
666
667// rpc getIdentityTokenInfos(GetIdentityTokenInfosRequest) returns (GetIdentityTokenInfosResponse);
668impl_transport_request_grpc!(
669    platform_proto::GetIdentityTokenInfosRequest,
670    platform_proto::GetIdentityTokenInfosResponse,
671    PlatformGrpcClient,
672    RequestSettings::default(),
673    get_identity_token_infos
674);
675
676// rpc getIdentitiesTokenInfos(GetIdentitiesTokenInfosRequest) returns (GetIdentitiesTokenInfosResponse);
677impl_transport_request_grpc!(
678    platform_proto::GetIdentitiesTokenInfosRequest,
679    platform_proto::GetIdentitiesTokenInfosResponse,
680    PlatformGrpcClient,
681    RequestSettings::default(),
682    get_identities_token_infos
683);
684
685// rpc getTokenStatuses(GetTokenStatusesRequest) returns (GetTokenStatusesResponse);
686impl_transport_request_grpc!(
687    platform_proto::GetTokenStatusesRequest,
688    platform_proto::GetTokenStatusesResponse,
689    PlatformGrpcClient,
690    RequestSettings::default(),
691    get_token_statuses
692);
693
694// rpc getTokenPreProgrammedDistributions(GetTokenPreProgrammedDistributionsRequest) returns (GetTokenPreProgrammedDistributionsResponse);
695impl_transport_request_grpc!(
696    platform_proto::GetTokenPreProgrammedDistributionsRequest,
697    platform_proto::GetTokenPreProgrammedDistributionsResponse,
698    PlatformGrpcClient,
699    RequestSettings::default(),
700    get_token_pre_programmed_distributions
701);
702
703// rpc getTokenTotalSupply(GetTokenTotalSupplyRequest) returns (GetTokenTotalSupplyResponse);
704impl_transport_request_grpc!(
705    platform_proto::GetTokenTotalSupplyRequest,
706    platform_proto::GetTokenTotalSupplyResponse,
707    PlatformGrpcClient,
708    RequestSettings::default(),
709    get_token_total_supply
710);
711
712// rpc getGroupInfo(GetGroupInfoRequest) returns (GetGroupInfoResponse);
713impl_transport_request_grpc!(
714    platform_proto::GetGroupInfoRequest,
715    platform_proto::GetGroupInfoResponse,
716    PlatformGrpcClient,
717    RequestSettings::default(),
718    get_group_info
719);
720
721// rpc getGroupInfos(GetGroupInfosRequest) returns (GetGroupInfosResponse);
722impl_transport_request_grpc!(
723    platform_proto::GetGroupInfosRequest,
724    platform_proto::GetGroupInfosResponse,
725    PlatformGrpcClient,
726    RequestSettings::default(),
727    get_group_infos
728);
729
730// rpc getGroupActions(GetGroupActionsRequest) returns (GetGroupActionsResponse);
731impl_transport_request_grpc!(
732    platform_proto::GetGroupActionsRequest,
733    platform_proto::GetGroupActionsResponse,
734    PlatformGrpcClient,
735    RequestSettings::default(),
736    get_group_actions
737);
738
739// rpc getGroupActionSigners(GetGroupActionSignersRequest) returns (GetGroupActionSignersResponse);
740impl_transport_request_grpc!(
741    platform_proto::GetGroupActionSignersRequest,
742    platform_proto::GetGroupActionSignersResponse,
743    PlatformGrpcClient,
744    RequestSettings::default(),
745    get_group_action_signers
746);
747
748// rpc getTokenDirectPurchasePrices(GetTokenDirectPurchasePricesRequest) returns (GetTokenDirectPurchasePricesResponse);
749impl_transport_request_grpc!(
750    platform_proto::GetTokenDirectPurchasePricesRequest,
751    platform_proto::GetTokenDirectPurchasePricesResponse,
752    PlatformGrpcClient,
753    RequestSettings::default(),
754    get_token_direct_purchase_prices
755);
756
757// rpc getTokenContractInfo(GetTokenContractInfoRequest) returns (GetTokenContractInfoResponse);
758impl_transport_request_grpc!(
759    platform_proto::GetTokenContractInfoRequest,
760    platform_proto::GetTokenContractInfoResponse,
761    PlatformGrpcClient,
762    RequestSettings::default(),
763    get_token_contract_info
764);
765
766// rpc getTokenPerpetualDistributionLastClaimRequest(GetTokenPerpetualDistributionLastClaimRequest) returns (GetTokenPerpetualDistributionLastClaimResponse);
767impl_transport_request_grpc!(
768    platform_proto::GetTokenPerpetualDistributionLastClaimRequest,
769    platform_proto::GetTokenPerpetualDistributionLastClaimResponse,
770    PlatformGrpcClient,
771    RequestSettings::default(),
772    get_token_perpetual_distribution_last_claim
773);
774
775// rpc getAddressInfo(GetAddressInfoRequest) returns (GetAddressInfoResponse);
776impl_transport_request_grpc!(
777    platform_proto::GetAddressInfoRequest,
778    platform_proto::GetAddressInfoResponse,
779    PlatformGrpcClient,
780    RequestSettings::default(),
781    get_address_info
782);
783
784// rpc getAddressesInfos(GetAddressesInfosRequest) returns (GetAddressesInfosResponse);
785impl_transport_request_grpc!(
786    platform_proto::GetAddressesInfosRequest,
787    platform_proto::GetAddressesInfosResponse,
788    PlatformGrpcClient,
789    RequestSettings::default(),
790    get_addresses_infos
791);
792
793// rpc getAddressesTrunkState(GetAddressesTrunkStateRequest) returns (GetAddressesTrunkStateResponse);
794impl_transport_request_grpc!(
795    platform_proto::GetAddressesTrunkStateRequest,
796    platform_proto::GetAddressesTrunkStateResponse,
797    PlatformGrpcClient,
798    RequestSettings::default(),
799    get_addresses_trunk_state
800);
801
802// rpc getAddressesBranchState(GetAddressesBranchStateRequest) returns (GetAddressesBranchStateResponse);
803impl_transport_request_grpc!(
804    platform_proto::GetAddressesBranchStateRequest,
805    platform_proto::GetAddressesBranchStateResponse,
806    PlatformGrpcClient,
807    RequestSettings::default(),
808    get_addresses_branch_state
809);
810
811// rpc getRecentAddressBalanceChanges(GetRecentAddressBalanceChangesRequest) returns (GetRecentAddressBalanceChangesResponse);
812impl_transport_request_grpc!(
813    platform_proto::GetRecentAddressBalanceChangesRequest,
814    platform_proto::GetRecentAddressBalanceChangesResponse,
815    PlatformGrpcClient,
816    RequestSettings::default(),
817    get_recent_address_balance_changes
818);
819
820// rpc getRecentCompactedAddressBalanceChanges(GetRecentCompactedAddressBalanceChangesRequest) returns (GetRecentCompactedAddressBalanceChangesResponse);
821impl_transport_request_grpc!(
822    platform_proto::GetRecentCompactedAddressBalanceChangesRequest,
823    platform_proto::GetRecentCompactedAddressBalanceChangesResponse,
824    PlatformGrpcClient,
825    RequestSettings {
826        // GetRecentCompactedAddressBalanceChangesResponse can have 100 values * 2048 addresses * ~44  bytes each = ~9MB
827        // We set it to 16MB to be safe
828        max_decoding_message_size: Some(16 * 1024 * 1024),
829        ..RequestSettings::default()
830    },
831    get_recent_compacted_address_balance_changes
832);