Skip to content

Commit

Permalink
Revert "json: remove deprecated old style path+data request format" (#…
Browse files Browse the repository at this point in the history
…7797)

Turns out there still are users of the old query format.  Bring it back.

This reverts commit be8a1ea.

Fixes: #7769
  • Loading branch information
mina86 authored and nikurt committed Nov 9, 2022
1 parent 3d4ab75 commit 58ad51f
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 5 deletions.
3 changes: 0 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,6 @@
* Backtraces on panics are enabled by default, so you no longer need to set
`RUST_BACKTRACE=1` environmental variable. To disable backtraces, set
`RUST_BACKTRACE=0`.
* A `[path, data]` JSON RPC query format has been removed. It has been
deprecated for over two years and not documented anywhere. Use proper
structured queries with `rquest_type` set instead.
* Enable receipt prefetching by default. This feature makes receipt processing
faster by parallelizing IO requests, which has been introduced in
[#7590](https://github.com/near/nearcore/pull/7590) and enabled by default
Expand Down
10 changes: 10 additions & 0 deletions chain/jsonrpc/client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,16 @@ jsonrpc_client!(pub struct JsonRpcClient {
});

impl JsonRpcClient {
/// This is a soft-deprecated method to do query RPC request with a path and data positional
/// parameters.
pub fn query_by_path(
&self,
path: String,
data: String,
) -> RpcRequest<near_jsonrpc_primitives::types::query::RpcQueryResponse> {
call_method(&self.client, &self.server_addr, "query", [path, data])
}

pub fn query(
&self,
request: near_jsonrpc_primitives::types::query::RpcQueryRequest,
Expand Down
64 changes: 64 additions & 0 deletions chain/jsonrpc/jsonrpc-tests/tests/rpc_query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,29 @@ fn test_chunk_invalid_shard_id() {
});
}

/// Connect to json rpc and query account info with soft-deprecated query API.
#[test]
fn test_query_by_path_account() {
test_with_client!(test_utils::NodeType::NonValidator, client, async move {
let status = client.status().await.unwrap();
let block_hash = status.sync_info.latest_block_hash;
let query_response =
client.query_by_path("account/test".to_string(), "".to_string()).await.unwrap();
assert_eq!(query_response.block_height, 0);
assert_eq!(query_response.block_hash, block_hash);
let account_info = if let QueryResponseKind::ViewAccount(account) = query_response.kind {
account
} else {
panic!("queried account, but received something else: {:?}", query_response.kind);
};
assert_eq!(account_info.amount, 0);
assert_eq!(account_info.code_hash.as_ref(), &[0; 32]);
assert_eq!(account_info.locked, 0);
assert_eq!(account_info.storage_paid_at, 0);
assert_eq!(account_info.storage_usage, 0);
});
}

/// Connect to json rpc and query account info.
#[test]
fn test_query_account() {
Expand Down Expand Up @@ -173,6 +196,25 @@ fn test_query_account() {
});
}

/// Connect to json rpc and query account info with soft-deprecated query API.
#[test]
fn test_query_by_path_access_keys() {
test_with_client!(test_utils::NodeType::NonValidator, client, async move {
let query_response =
client.query_by_path("access_key/test".to_string(), "".to_string()).await.unwrap();
assert_eq!(query_response.block_height, 0);
let access_keys = if let QueryResponseKind::AccessKeyList(access_keys) = query_response.kind
{
access_keys
} else {
panic!("queried access keys, but received something else: {:?}", query_response.kind);
};
assert_eq!(access_keys.keys.len(), 1);
assert_eq!(access_keys.keys[0].access_key, AccessKey::full_access().into());
assert_eq!(access_keys.keys[0].public_key, PublicKey::empty(KeyType::ED25519));
});
}

/// Connect to json rpc and query account info.
#[test]
fn test_query_access_keys() {
Expand All @@ -197,6 +239,28 @@ fn test_query_access_keys() {
});
}

/// Connect to json rpc and query account info with soft-deprecated query API.
#[test]
fn test_query_by_path_access_key() {
test_with_client!(test_utils::NodeType::NonValidator, client, async move {
let query_response = client
.query_by_path(
"access_key/test/ed25519:23vYngy8iL7q94jby3gszBnZ9JptpMf5Hgf7KVVa2yQ2".to_string(),
"".to_string(),
)
.await
.unwrap();
assert_eq!(query_response.block_height, 0);
let access_key = if let QueryResponseKind::AccessKey(access_keys) = query_response.kind {
access_keys
} else {
panic!("queried access keys, but received something else: {:?}", query_response.kind);
};
assert_eq!(access_key.nonce, 0);
assert_eq!(access_key.permission, AccessKeyPermission::FullAccess.into());
});
}

/// Connect to json rpc and query account info.
#[test]
fn test_query_access_key() {
Expand Down
67 changes: 65 additions & 2 deletions chain/jsonrpc/src/api/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,76 @@ use serde_json::Value;
use near_client_primitives::types::QueryError;
use near_jsonrpc_primitives::errors::RpcParseError;
use near_jsonrpc_primitives::types::query::{RpcQueryError, RpcQueryRequest, RpcQueryResponse};
use near_primitives::views::QueryResponse;
use near_primitives::serialize;
use near_primitives::types::BlockReference;
use near_primitives::views::{QueryRequest, QueryResponse};

use super::{parse_params, RpcFrom, RpcRequest};

/// Max size of the query path (soft-deprecated)
const QUERY_DATA_MAX_SIZE: usize = 10 * 1024;

impl RpcRequest for RpcQueryRequest {
fn parse(value: Option<Value>) -> Result<Self, RpcParseError> {
Ok(parse_params::<Self>(value)?)
let params = parse_params::<(String, String)>(value.clone());
let query_request = if let Ok((path, data)) = params {
// Handle a soft-deprecated version of the query API, which is based on
// positional arguments with a "path"-style first argument.
//
// This whole block can be removed one day, when the new API is 100% adopted.
let data =
serialize::from_base58(&data).map_err(|err| RpcParseError(err.to_string()))?;
let query_data_size = path.len() + data.len();
if query_data_size > QUERY_DATA_MAX_SIZE {
return Err(RpcParseError(format!(
"Query data size {} is too large",
query_data_size
)));
}

let mut path_parts = path.splitn(3, '/');
let make_err = || RpcParseError("Not enough query parameters provided".to_string());
let query_command = path_parts.next().ok_or_else(make_err)?;
let account_id = path_parts
.next()
.ok_or_else(make_err)?
.parse()
.map_err(|err| RpcParseError(format!("{}", err)))?;
let maybe_extra_arg = path_parts.next();

let request = match query_command {
"account" => QueryRequest::ViewAccount { account_id },
"access_key" => match maybe_extra_arg {
None => QueryRequest::ViewAccessKeyList { account_id },
Some(pk) => QueryRequest::ViewAccessKey {
account_id,
public_key: pk
.parse()
.map_err(|_| RpcParseError("Invalid public key".to_string()))?,
},
},
"code" => QueryRequest::ViewCode { account_id },
"contract" => QueryRequest::ViewState {
account_id,
prefix: data.into(),
include_proof: false,
},
"call" => match maybe_extra_arg {
Some(method_name) => QueryRequest::CallFunction {
account_id,
method_name: method_name.to_string(),
args: data.into(),
},
None => return Err(RpcParseError("Method name is missing".to_string())),
},
_ => return Err(RpcParseError(format!("Unknown path {}", query_command))),
};
// Use Finality::None here to make backward compatibility tests work
Self { request, block_reference: BlockReference::latest() }
} else {
parse_params::<Self>(value)?
};
Ok(query_request)
}
}

Expand Down
7 changes: 7 additions & 0 deletions core/primitives-core/src/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@ pub fn to_base58<T: AsRef<[u8]>>(input: T) -> String {
bs58::encode(input).into_string()
}

/// Deprecated. If you want to decode a CryptoHash, use CryptoHash::from_str.
/// For anything else, don’t use base58. This is still here because of
/// deprecated RPC query format in RpcQueryRequest::parse.
pub fn from_base58(s: &str) -> Result<Vec<u8>, Box<dyn std::error::Error + Send + Sync>> {
bs58::decode(s).into_vec().map_err(|err| err.into())
}

pub fn to_base64<T: AsRef<[u8]>>(input: T) -> String {
base64::encode(&input)
}
Expand Down

0 comments on commit 58ad51f

Please sign in to comment.