Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
### Protocol Changes

### Non-protocol Changes
* `/debug` page now has client_config linked. You can also check your client_config directly at /debug/client_config

## 1.31.0

Expand Down
29 changes: 28 additions & 1 deletion chain/client-primitives/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use actix::Message;
use chrono::DateTime;
use near_primitives::time::Utc;

use near_chain_configs::ProtocolConfigView;
use near_chain_configs::{ClientConfig, ProtocolConfigView};
use near_primitives::hash::CryptoHash;
use near_primitives::merkle::{MerklePath, PartialMerkleTree};
use near_primitives::network::PeerId;
Expand Down Expand Up @@ -940,6 +940,33 @@ impl From<near_chain_primitives::Error> for GetMaintenanceWindowsError {
}
}

pub struct GetClientConfig {}

impl Message for GetClientConfig {
type Result = Result<ClientConfig, GetClientConfigError>;
}

#[derive(thiserror::Error, Debug)]
pub enum GetClientConfigError {
#[error("IO Error: {0}")]
IOError(String),
// NOTE: Currently, the underlying errors are too broad, and while we tried to handle
// expected cases, we cannot statically guarantee that no other errors will be returned
// in the future.
// TODO #3851: Remove this variant once we can exhaustively match all the underlying errors
#[error("It is a bug if you receive this error type, please, report this incident: https://github.com/near/nearcore/issues/new/choose. Details: {0}")]
Unreachable(String),
}

impl From<near_chain_primitives::Error> for GetClientConfigError {
fn from(error: near_chain_primitives::Error) -> Self {
match error {
near_chain_primitives::Error::IOErr(error) => Self::IOError(error.to_string()),
_ => Self::Unreachable(error.to_string()),
}
}
}

#[cfg(feature = "sandbox")]
#[derive(Debug)]
pub enum SandboxMessage {
Expand Down
18 changes: 17 additions & 1 deletion chain/client/src/client_actor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ use near_chain_configs::ClientConfig;
use near_chunks::client::ShardsManagerResponse;
use near_chunks::logic::cares_about_shard_this_or_next_epoch;
use near_client_primitives::types::{
Error, GetNetworkInfo, NetworkInfoResponse, Status, StatusError, StatusSyncInfo, SyncStatus,
Error, GetClientConfig, GetClientConfigError, GetNetworkInfo, NetworkInfoResponse, Status,
StatusError, StatusSyncInfo, SyncStatus,
};
#[cfg(feature = "test_features")]
use near_network::types::NetworkAdversarialMessage;
Expand Down Expand Up @@ -1970,6 +1971,21 @@ impl Handler<WithSpanContext<ShardsManagerResponse>> for ClientActor {
}
}

impl Handler<WithSpanContext<GetClientConfig>> for ClientActor {
type Result = Result<ClientConfig, GetClientConfigError>;

fn handle(
&mut self,
msg: WithSpanContext<GetClientConfig>,
_: &mut Context<Self>,
) -> Self::Result {
let (_span, _msg) = handler_debug_span!(target: "client", msg);
let _d = delay_detector::DelayDetector::new(|| "client get client config".into());

Ok(self.client.config.clone())
}
}

/// Returns random seed sampled from the current thread
pub fn random_seed_from_thread() -> RngSeed {
let mut rng_seed: RngSeed = [0; 32];
Expand Down
7 changes: 4 additions & 3 deletions chain/client/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
pub use near_client_primitives::types::{
Error, GetBlock, GetBlockProof, GetBlockProofResponse, GetBlockWithMerkleTree, GetChunk,
GetExecutionOutcome, GetExecutionOutcomeResponse, GetExecutionOutcomesForBlock, GetGasPrice,
GetMaintenanceWindows, GetNetworkInfo, GetNextLightClientBlock, GetProtocolConfig, GetReceipt,
GetStateChanges, GetStateChangesInBlock, GetStateChangesWithCauseInBlock,
GetClientConfig, GetExecutionOutcome, GetExecutionOutcomeResponse,
GetExecutionOutcomesForBlock, GetGasPrice, GetMaintenanceWindows, GetNetworkInfo,
GetNextLightClientBlock, GetProtocolConfig, GetReceipt, GetStateChanges,
GetStateChangesInBlock, GetStateChangesWithCauseInBlock,
GetStateChangesWithCauseInBlockForTrackedShards, GetValidatorInfo, GetValidatorOrdered, Query,
QueryError, Status, StatusResponse, SyncStatus, TxStatus, TxStatusError,
};
Expand Down
38 changes: 38 additions & 0 deletions chain/jsonrpc-primitives/src/types/client_config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use serde::{Deserialize, Serialize};
use serde_json::Value;

#[derive(Serialize, Deserialize, Debug)]
pub struct RpcClientConfigRequest {}

#[derive(Serialize, Deserialize, Debug)]
pub struct RpcClientConfigResponse {
#[serde(flatten)]
pub client_config: near_chain_configs::ClientConfig,
}

#[derive(thiserror::Error, Debug, Serialize, Deserialize)]
#[serde(tag = "name", content = "info", rename_all = "SCREAMING_SNAKE_CASE")]
pub enum RpcClientConfigError {
#[error("The node reached its limits. Try again later. More details: {error_message}")]
InternalError { error_message: String },
}

impl From<RpcClientConfigError> for crate::errors::RpcError {
fn from(error: RpcClientConfigError) -> Self {
let error_data = match &error {
RpcClientConfigError::InternalError { .. } => Some(Value::String(error.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 RpcClientConfigError: {:?}", err),
)
}
};

Self::new_internal_or_handler_error(error_data, error_data_value)
}
}
1 change: 1 addition & 0 deletions chain/jsonrpc-primitives/src/types/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub mod blocks;
pub mod changes;
pub mod chunks;
pub mod client_config;
pub mod config;
pub mod gas_price;
pub mod light_client;
Expand Down
1 change: 1 addition & 0 deletions chain/jsonrpc/res/debug.html
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ <h1><a href="debug/pages/epoch_info">Epoch info</a></h1>
<h1><a href="debug/pages/chain_n_chunk_info">Chain & Chunk info</a></h1>
<h1><a href="debug/pages/sync">Sync info</a></h1>
<h1><a href="debug/pages/validator">Validator info</a></h1>
<h1><a href="debug/client_config">Client Config</a></h1>
</body>

</html>
25 changes: 25 additions & 0 deletions chain/jsonrpc/src/api/client_config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use near_client_primitives::types::GetClientConfigError;
use near_jsonrpc_primitives::types::client_config::RpcClientConfigError;

use super::RpcFrom;

impl RpcFrom<actix::MailboxError> for RpcClientConfigError {
fn rpc_from(error: actix::MailboxError) -> Self {
Self::InternalError { error_message: error.to_string() }
}
}

impl RpcFrom<GetClientConfigError> for RpcClientConfigError {
fn rpc_from(error: GetClientConfigError) -> Self {
match error {
GetClientConfigError::IOError(error_message) => Self::InternalError { error_message },
GetClientConfigError::Unreachable(ref error_message) => {
tracing::warn!(target: "jsonrpc", "Unreachable error occurred: {}", error_message);
crate::metrics::RPC_UNREACHABLE_ERROR_COUNT
.with_label_values(&["RpcClientConfigError"])
.inc();
Self::InternalError { error_message: error.to_string() }
}
}
}
}
1 change: 1 addition & 0 deletions chain/jsonrpc/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use near_primitives::borsh::BorshDeserialize;
mod blocks;
mod changes;
mod chunks;
mod client_config;
mod config;
mod gas_price;
mod light_client;
Expand Down
37 changes: 33 additions & 4 deletions chain/jsonrpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ use tracing::info;

use near_chain_configs::GenesisConfig;
use near_client::{
ClientActor, DebugStatus, GetBlock, GetBlockProof, GetChunk, GetExecutionOutcome, GetGasPrice,
GetMaintenanceWindows, GetNetworkInfo, GetNextLightClientBlock, GetProtocolConfig, GetReceipt,
GetStateChanges, GetStateChangesInBlock, GetValidatorInfo, GetValidatorOrdered,
ProcessTxRequest, ProcessTxResponse, Query, Status, TxStatus, ViewClientActor,
ClientActor, DebugStatus, GetBlock, GetBlockProof, GetChunk, GetClientConfig,
GetExecutionOutcome, GetGasPrice, GetMaintenanceWindows, GetNetworkInfo,
GetNextLightClientBlock, GetProtocolConfig, GetReceipt, GetStateChanges,
GetStateChangesInBlock, GetValidatorInfo, GetValidatorOrdered, ProcessTxRequest,
ProcessTxResponse, Query, Status, TxStatus, ViewClientActor,
};
pub use near_jsonrpc_client as client;
use near_jsonrpc_primitives::errors::RpcError;
Expand Down Expand Up @@ -313,6 +314,9 @@ impl JsonRpcHandler {
process_method_call(request, |params| self.tx_status_common(params, false)).await
}
"validators" => process_method_call(request, |params| self.validators(params)).await,
"client_config" => {
process_method_call(request, |_params: ()| self.client_config()).await
}
"EXPERIMENTAL_broadcast_tx_sync" => {
process_method_call(request, |params| self.send_tx_sync(params)).await
}
Expand Down Expand Up @@ -1089,6 +1093,16 @@ impl JsonRpcHandler {
let windows = self.view_client_send(GetMaintenanceWindows { account_id }).await?;
Ok(windows.iter().map(|r| (r.start, r.end)).collect())
}

async fn client_config(
&self,
) -> Result<
near_jsonrpc_primitives::types::client_config::RpcClientConfigResponse,
near_jsonrpc_primitives::types::client_config::RpcClientConfigError,
> {
let client_config = self.client_send(GetClientConfig {}).await?;
Ok(near_jsonrpc_primitives::types::client_config::RpcClientConfigResponse { client_config })
}
}

#[cfg(feature = "sandbox")]
Expand Down Expand Up @@ -1409,6 +1423,18 @@ pub async fn prometheus_handler() -> Result<HttpResponse, HttpError> {
}
}

fn client_config_handler(
handler: web::Data<JsonRpcHandler>,
) -> impl Future<Output = Result<HttpResponse, HttpError>> {
let response = async move {
match handler.client_config().await {
Ok(value) => Ok(HttpResponse::Ok().json(&value)),
Err(_) => Ok(HttpResponse::ServiceUnavailable().finish()),
}
};
response.boxed()
}

fn get_cors(cors_allowed_origins: &[String]) -> Cors {
let mut cors = Cors::permissive();
if cors_allowed_origins != ["*".to_string()] {
Expand Down