1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ChunkReference {
BlockShardId {
block_id: near_primitives_v01::types::BlockId,
shard_id: near_primitives_v01::types::ShardId,
},
ChunkHash {
chunk_id: near_primitives_v01::hash::CryptoHash,
},
}
#[derive(Serialize, Deserialize)]
pub struct RpcChunkRequest {
#[serde(flatten)]
pub chunk_reference: ChunkReference,
}
#[derive(Serialize, Deserialize)]
pub struct RpcChunkResponse {
#[serde(flatten)]
pub chunk_view: near_primitives_v01::views::ChunkView,
}
#[derive(thiserror::Error, Debug, Serialize, Deserialize)]
#[serde(tag = "name", content = "info", rename_all = "SCREAMING_SNAKE_CASE")]
pub enum RpcChunkError {
#[error("The node reached its limits. Try again later. More details: {error_message}")]
InternalError { error_message: String },
#[error("Block either has never been observed on the node or has been garbage collected: {error_message}")]
UnknownBlock {
#[serde(skip_serializing)]
error_message: String,
},
#[error("Shard id {shard_id} does not exist")]
InvalidShardId { shard_id: u64 },
#[error("Chunk with hash {chunk_hash:?} has never been observed on this node")]
UnknownChunk { chunk_hash: near_primitives_v01::sharding::ChunkHash },
}
impl From<ChunkReference> for near_client_primitives::types::GetChunk {
fn from(chunk_reference: ChunkReference) -> Self {
match chunk_reference {
ChunkReference::BlockShardId { block_id, shard_id } => match block_id {
near_primitives_v01::types::BlockId::Height(height) => Self::Height(height, shard_id),
near_primitives_v01::types::BlockId::Hash(block_hash) => {
Self::BlockHash(block_hash.into(), shard_id)
}
},
ChunkReference::ChunkHash { chunk_id } => Self::ChunkHash(chunk_id.into()),
}
}
}
impl RpcChunkRequest {
pub fn parse(value: Option<Value>) -> Result<Self, crate::errors::RpcParseError> {
let chunk_reference = if let Ok((chunk_id,)) =
crate::utils::parse_params::<(near_primitives_v01::hash::CryptoHash,)>(value.clone())
{
ChunkReference::ChunkHash { chunk_id }
} else if let Ok(((block_id, shard_id),)) = crate::utils::parse_params::<((
near_primitives_v01::types::BlockId,
near_primitives_v01::types::ShardId,
),)>(value.clone())
{
ChunkReference::BlockShardId { block_id, shard_id }
} else {
crate::utils::parse_params::<ChunkReference>(value)?
};
Ok(Self { chunk_reference })
}
}
impl From<near_client_primitives::types::GetChunkError> for RpcChunkError {
fn from(error: near_client_primitives::types::GetChunkError) -> Self {
match error {
near_client_primitives::types::GetChunkError::IOError { error_message } => {
Self::InternalError { error_message }
}
near_client_primitives::types::GetChunkError::UnknownBlock { error_message } => {
Self::UnknownBlock { error_message }
}
near_client_primitives::types::GetChunkError::InvalidShardId { shard_id } => {
Self::InvalidShardId { shard_id }
}
near_client_primitives::types::GetChunkError::UnknownChunk { chunk_hash } => {
Self::UnknownChunk { chunk_hash }
}
near_client_primitives::types::GetChunkError::Unreachable { ref error_message } => {
tracing::warn!(target: "jsonrpc", "Unreachable error occurred: {}", &error_message);
near_metrics::inc_counter_vec(
&crate::metrics::RPC_UNREACHABLE_ERROR_COUNT,
&["RpcChunkError"],
);
Self::InternalError { error_message: error.to_string() }
}
}
}
}
impl From<actix::MailboxError> for RpcChunkError {
fn from(error: actix::MailboxError) -> Self {
Self::InternalError { error_message: error.to_string() }
}
}
impl From<RpcChunkError> for crate::errors::RpcError {
fn from(error: RpcChunkError) -> Self {
let error_data = match &error {
RpcChunkError::InternalError { .. } => Some(Value::String(error.to_string())),
RpcChunkError::UnknownBlock { error_message } => Some(Value::String(format!(
"DB Not Found Error: {} \n Cause: Unknown",
error_message
))),
RpcChunkError::InvalidShardId { .. } => Some(Value::String(error.to_string())),
RpcChunkError::UnknownChunk { chunk_hash } => Some(Value::String(format!(
"Chunk Missing (unavailable on the node): ChunkHash(`{}`) \n Cause: Unknown",
chunk_hash.0.to_string()
))),
};
let error_data_value = match serde_json::to_value(error) {
Ok(value) => value,
Err(err) => {
return Self::new_internal_error(
None,
format!("Failed to serialize RpcStateChangesError: {:?}", err),
)
}
};
Self::new_internal_or_handler_error(error_data, error_data_value)
}
}