concordium_rust_sdk/
endpoints.rs

1//! Wrapper for the node's GRPC API. The return values are parsed and wrapped in
2//! structured values.
3use crate::types;
4use derive_more::From;
5use thiserror::Error;
6use tonic::metadata::errors::InvalidMetadataValue;
7pub use tonic::transport::{Endpoint, Error};
8
9#[derive(Error, Debug)]
10/// Authentication, connection, or response parsing error.
11pub enum RPCError {
12    #[error("Call failed: {0}")]
13    CallError(#[from] tonic::Status),
14    #[error(transparent)]
15    InvalidMetadata(#[from] InvalidMetadataValue),
16    #[error("Error parsing JSON result: {0}")]
17    ParseError(#[from] anyhow::Error),
18}
19
20impl From<serde_json::Error> for RPCError {
21    fn from(x: serde_json::Error) -> Self { Self::ParseError(x.into()) }
22}
23
24impl From<semver::Error> for RPCError {
25    fn from(x: semver::Error) -> Self { Self::ParseError(x.into()) }
26}
27
28impl RPCError {
29    /// Return whether the error indicates the item being sent is invalid.
30    /// Retrying a request in this case will likely not succeed.
31    ///
32    /// Although some conditions like that are transient.
33    pub fn is_invalid_argument(&self) -> bool {
34        match self {
35            RPCError::CallError(e) => {
36                matches!(e.code(), tonic::Code::InvalidArgument)
37            }
38            RPCError::InvalidMetadata(_) => false,
39            RPCError::ParseError(_) => false,
40        }
41    }
42
43    /// Return whether the object already exists at the node.
44    /// Retrying a request in this case will likely not succeed.
45    pub fn is_duplicate(&self) -> bool {
46        match self {
47            RPCError::CallError(e) => {
48                matches!(e.code(), tonic::Code::AlreadyExists)
49            }
50            RPCError::InvalidMetadata(_) => false,
51            RPCError::ParseError(_) => false,
52        }
53    }
54}
55
56#[derive(Error, Debug)]
57/// Errors that can occur when making queries. This can either be a general
58/// connection/authentication error, or the requested item is not found.
59pub enum QueryError {
60    #[error("RPC error: {0}")]
61    /// A general RPC error occurred.
62    RPCError(#[from] RPCError),
63    #[error("Requested object not found.")]
64    /// The requested item was not found.
65    NotFound,
66}
67
68impl QueryError {
69    /// Whether this error indicates an object was not found.
70    pub fn is_not_found(&self) -> bool {
71        match self {
72            QueryError::RPCError(c) => {
73                if let RPCError::CallError(ce) = c {
74                    ce.code() == tonic::Code::NotFound
75                } else {
76                    false
77                }
78            }
79            QueryError::NotFound => true,
80        }
81    }
82}
83
84impl From<tonic::Status> for QueryError {
85    fn from(s: tonic::Status) -> Self { Self::RPCError(s.into()) }
86}
87
88impl From<InvalidMetadataValue> for QueryError {
89    fn from(s: InvalidMetadataValue) -> Self { Self::RPCError(s.into()) }
90}
91
92/// Result a GRPC query. This is a simple alias for [std::Result](https://doc.rust-lang.org/std/result/enum.Result.html)
93/// that fixes the error type to be [RPCError].
94pub type RPCResult<A> = Result<A, RPCError>;
95
96/// Result a GRPC query where the item lookup might fail.
97/// This is a simple alias for [std::Result](https://doc.rust-lang.org/std/result/enum.Result.html) that fixes the error type to be [`QueryError`].
98pub type QueryResult<A> = Result<A, QueryError>;
99
100/// Input to the
101/// [`get_blocks_at_height`](crate::v2::Client::get_blocks_at_height) query.
102#[derive(Clone, Copy, Debug, From)]
103pub enum BlocksAtHeightInput {
104    Absolute {
105        /// Height from the beginning of the chain.
106        height: types::AbsoluteBlockHeight,
107    },
108    /// Query relative to an explicit genesis index.
109    Relative {
110        /// Genesis index to start from.
111        genesis_index: types::GenesisIndex,
112        /// Height starting from the genesis block at the genesis index.
113        height:        types::BlockHeight,
114        /// Whether to return results only from the specified genesis index
115        /// (`true`), or allow results from more recent genesis indices
116        /// as well (`false`).
117        restrict:      bool,
118    },
119}