1#![doc(
26 html_root_url = "https://docs.rs/casper-client/2.0.0",
27 html_favicon_url = "https://raw.githubusercontent.com/CasperLabs/casper-node/master/images/CasperLabs_Logo_Favicon_RGB_50px.png",
28 html_logo_url = "https://raw.githubusercontent.com/CasperLabs/casper-node/master/images/CasperLabs_Logo_Symbol_RGB.png",
29 test(attr(forbid(warnings)))
30)]
31#![warn(
32 missing_docs,
33 trivial_casts,
34 trivial_numeric_casts,
35 unused_qualifications
36)]
37
38pub mod cli;
39mod error;
40mod json_rpc;
41pub mod keygen;
42mod output_kind;
43pub mod rpcs;
44mod transfer_target;
45pub mod types;
46mod validation;
47mod verbosity;
48
49use std::{
50 fs,
51 io::{Cursor, Read, Write},
52 path::Path,
53};
54
55use serde::Serialize;
56
57use casper_hashing::Digest;
58#[cfg(doc)]
59use casper_types::Transfer;
60use casper_types::{Key, PublicKey, SecretKey, URef};
61
62pub use error::Error;
63use json_rpc::JsonRpcCall;
64pub use json_rpc::{JsonRpcId, SuccessResponse};
65pub use output_kind::OutputKind;
66use rpcs::{
67 common::{BlockIdentifier, GlobalStateIdentifier},
68 results::{
69 GetAccountResult, GetAuctionInfoResult, GetBalanceResult, GetBlockResult,
70 GetBlockTransfersResult, GetChainspecResult, GetDeployResult, GetDictionaryItemResult,
71 GetEraInfoResult, GetEraSummaryResult, GetNodeStatusResult, GetPeersResult,
72 GetStateRootHashResult, GetValidatorChangesResult, ListRpcsResult, PutDeployResult,
73 QueryBalanceResult, QueryGlobalStateResult, SpeculativeExecResult,
74 },
75 v1_5_0::{
76 get_account::{GetAccountParams, GET_ACCOUNT_METHOD},
77 get_auction_info::{GetAuctionInfoParams, GET_AUCTION_INFO_METHOD},
78 get_balance::{GetBalanceParams, GET_BALANCE_METHOD},
79 get_block::{GetBlockParams, GET_BLOCK_METHOD},
80 get_block_transfers::{GetBlockTransfersParams, GET_BLOCK_TRANSFERS_METHOD},
81 get_chainspec::GET_CHAINSPEC_METHOD,
82 get_deploy::{GetDeployParams, GET_DEPLOY_METHOD},
83 get_dictionary_item::{GetDictionaryItemParams, GET_DICTIONARY_ITEM_METHOD},
84 get_era_info::{GetEraInfoParams, GET_ERA_INFO_METHOD},
85 get_era_summary::{GetEraSummaryParams, GET_ERA_SUMMARY_METHOD},
86 get_node_status::GET_NODE_STATUS_METHOD,
87 get_peers::GET_PEERS_METHOD,
88 get_state_root_hash::{GetStateRootHashParams, GET_STATE_ROOT_HASH_METHOD},
89 get_validator_changes::GET_VALIDATOR_CHANGES_METHOD,
90 list_rpcs::LIST_RPCS_METHOD,
91 put_deploy::{PutDeployParams, PUT_DEPLOY_METHOD},
92 query_balance::{PurseIdentifier, QueryBalanceParams, QUERY_BALANCE_METHOD},
93 query_global_state::{QueryGlobalStateParams, QUERY_GLOBAL_STATE_METHOD},
94 speculative_exec::{SpeculativeExecParams, SPECULATIVE_EXEC_METHOD},
95 },
96 DictionaryItemIdentifier,
97};
98pub use transfer_target::TransferTarget;
99#[cfg(doc)]
100use types::{Account, Block, StoredValue};
101use types::{Deploy, DeployHash, MAX_SERIALIZED_SIZE_OF_DEPLOY};
102pub use validation::ValidateResponseError;
103pub use verbosity::Verbosity;
104
105pub async fn put_deploy(
111 rpc_id: JsonRpcId,
112 node_address: &str,
113 verbosity: Verbosity,
114 deploy: Deploy,
115) -> Result<SuccessResponse<PutDeployResult>, Error> {
116 JsonRpcCall::new(rpc_id, node_address, verbosity)
117 .send_request(PUT_DEPLOY_METHOD, Some(PutDeployParams::new(deploy)))
118 .await
119}
120
121pub async fn speculative_exec(
127 rpc_id: JsonRpcId,
128 node_address: &str,
129 block_identifier: Option<BlockIdentifier>,
130 verbosity: Verbosity,
131 deploy: Deploy,
132) -> Result<SuccessResponse<SpeculativeExecResult>, Error> {
133 JsonRpcCall::new(rpc_id, node_address, verbosity)
134 .send_request(
135 SPECULATIVE_EXEC_METHOD,
136 Some(SpeculativeExecParams::new(block_identifier, deploy)),
137 )
138 .await
139}
140
141pub fn output_deploy(output: OutputKind, deploy: &Deploy) -> Result<(), Error> {
150 write_deploy(deploy, output.get()?)?;
151 output.commit()
152}
153
154pub fn read_deploy_file<P: AsRef<Path>>(deploy_path: P) -> Result<Deploy, Error> {
156 let input = fs::read(deploy_path.as_ref()).map_err(|error| Error::IoError {
157 context: format!(
158 "unable to read deploy file at '{}'",
159 deploy_path.as_ref().display()
160 ),
161 error,
162 })?;
163 read_deploy(Cursor::new(input))
164}
165
166pub fn sign_deploy_file<P: AsRef<Path>>(
175 input_path: P,
176 secret_key: &SecretKey,
177 output: OutputKind,
178) -> Result<(), Error> {
179 let mut deploy = read_deploy_file(input_path)?;
180
181 deploy.sign(secret_key);
182 deploy.is_valid_size(MAX_SERIALIZED_SIZE_OF_DEPLOY)?;
183
184 write_deploy(&deploy, output.get()?)?;
185 output.commit()
186}
187
188pub async fn get_deploy(
197 rpc_id: JsonRpcId,
198 node_address: &str,
199 verbosity: Verbosity,
200 deploy_hash: DeployHash,
201 finalized_approvals: bool,
202) -> Result<SuccessResponse<GetDeployResult>, Error> {
203 JsonRpcCall::new(rpc_id, node_address, verbosity)
204 .send_request(
205 GET_DEPLOY_METHOD,
206 Some(GetDeployParams::new(deploy_hash, finalized_approvals)),
207 )
208 .await
209}
210
211pub async fn get_block(
217 rpc_id: JsonRpcId,
218 node_address: &str,
219 verbosity: Verbosity,
220 maybe_block_identifier: Option<BlockIdentifier>,
221) -> Result<SuccessResponse<GetBlockResult>, Error> {
222 let params = maybe_block_identifier.map(GetBlockParams::new);
223 let success_response = JsonRpcCall::new(rpc_id, node_address, verbosity)
224 .send_request(GET_BLOCK_METHOD, params)
225 .await?;
226 validation::validate_get_block_result(maybe_block_identifier, &success_response.result)?;
227 Ok(success_response)
228}
229
230pub async fn get_block_transfers(
236 rpc_id: JsonRpcId,
237 node_address: &str,
238 verbosity: Verbosity,
239 maybe_block_identifier: Option<BlockIdentifier>,
240) -> Result<SuccessResponse<GetBlockTransfersResult>, Error> {
241 let params = maybe_block_identifier.map(GetBlockTransfersParams::new);
242 JsonRpcCall::new(rpc_id, node_address, verbosity)
243 .send_request(GET_BLOCK_TRANSFERS_METHOD, params)
244 .await
245}
246
247pub async fn get_state_root_hash(
253 rpc_id: JsonRpcId,
254 node_address: &str,
255 verbosity: Verbosity,
256 maybe_block_identifier: Option<BlockIdentifier>,
257) -> Result<SuccessResponse<GetStateRootHashResult>, Error> {
258 let params = maybe_block_identifier.map(GetStateRootHashParams::new);
259 JsonRpcCall::new(rpc_id, node_address, verbosity)
260 .send_request(GET_STATE_ROOT_HASH_METHOD, params)
261 .await
262}
263
264pub async fn get_era_summary(
270 rpc_id: JsonRpcId,
271 node_address: &str,
272 verbosity: Verbosity,
273 maybe_block_identifier: Option<BlockIdentifier>,
274) -> Result<SuccessResponse<GetEraSummaryResult>, Error> {
275 let params = maybe_block_identifier.map(GetEraSummaryParams::new);
276 JsonRpcCall::new(rpc_id, node_address, verbosity)
277 .send_request(GET_ERA_SUMMARY_METHOD, params)
278 .await
279}
280
281pub async fn query_global_state(
296 rpc_id: JsonRpcId,
297 node_address: &str,
298 verbosity: Verbosity,
299 global_state_identifier: GlobalStateIdentifier,
300 key: Key,
301 path: Vec<String>,
302) -> Result<SuccessResponse<QueryGlobalStateResult>, Error> {
303 let params = QueryGlobalStateParams::new(global_state_identifier, key, path);
304 JsonRpcCall::new(rpc_id, node_address, verbosity)
305 .send_request(QUERY_GLOBAL_STATE_METHOD, Some(params))
306 .await
307}
308
309pub async fn query_balance(
315 rpc_id: JsonRpcId,
316 node_address: &str,
317 verbosity: Verbosity,
318 maybe_global_state_identifier: Option<GlobalStateIdentifier>,
319 purse_identifier: PurseIdentifier,
320) -> Result<SuccessResponse<QueryBalanceResult>, Error> {
321 let params = QueryBalanceParams::new(maybe_global_state_identifier, purse_identifier);
322 JsonRpcCall::new(rpc_id, node_address, verbosity)
323 .send_request(QUERY_BALANCE_METHOD, Some(params))
324 .await
325}
326
327pub async fn get_dictionary_item(
333 rpc_id: JsonRpcId,
334 node_address: &str,
335 verbosity: Verbosity,
336 state_root_hash: Digest,
337 dictionary_item_identifier: DictionaryItemIdentifier,
338) -> Result<SuccessResponse<GetDictionaryItemResult>, Error> {
339 let params = GetDictionaryItemParams::new(state_root_hash, dictionary_item_identifier);
340 JsonRpcCall::new(rpc_id, node_address, verbosity)
341 .send_request(GET_DICTIONARY_ITEM_METHOD, Some(params))
342 .await
343}
344
345pub async fn get_balance(
351 rpc_id: JsonRpcId,
352 node_address: &str,
353 verbosity: Verbosity,
354 state_root_hash: Digest,
355 purse: URef,
356) -> Result<SuccessResponse<GetBalanceResult>, Error> {
357 let params = GetBalanceParams::new(state_root_hash, purse);
358 JsonRpcCall::new(rpc_id, node_address, verbosity)
359 .send_request(GET_BALANCE_METHOD, Some(params))
360 .await
361}
362
363pub async fn get_account(
369 rpc_id: JsonRpcId,
370 node_address: &str,
371 verbosity: Verbosity,
372 maybe_block_identifier: Option<BlockIdentifier>,
373 account_identifier: PublicKey,
374) -> Result<SuccessResponse<GetAccountResult>, Error> {
375 let params = GetAccountParams::new(account_identifier, maybe_block_identifier);
376 JsonRpcCall::new(rpc_id, node_address, verbosity)
377 .send_request(GET_ACCOUNT_METHOD, Some(params))
378 .await
379}
380
381pub async fn get_auction_info(
387 rpc_id: JsonRpcId,
388 node_address: &str,
389 verbosity: Verbosity,
390 maybe_block_identifier: Option<BlockIdentifier>,
391) -> Result<SuccessResponse<GetAuctionInfoResult>, Error> {
392 let params = maybe_block_identifier.map(GetAuctionInfoParams::new);
393 JsonRpcCall::new(rpc_id, node_address, verbosity)
394 .send_request(GET_AUCTION_INFO_METHOD, params)
395 .await
396}
397
398pub async fn get_validator_changes(
404 rpc_id: JsonRpcId,
405 node_address: &str,
406 verbosity: Verbosity,
407) -> Result<SuccessResponse<GetValidatorChangesResult>, Error> {
408 JsonRpcCall::new(rpc_id, node_address, verbosity)
409 .send_request::<(), _>(GET_VALIDATOR_CHANGES_METHOD, None)
410 .await
411}
412
413pub async fn get_peers(
419 rpc_id: JsonRpcId,
420 node_address: &str,
421 verbosity: Verbosity,
422) -> Result<SuccessResponse<GetPeersResult>, Error> {
423 JsonRpcCall::new(rpc_id, node_address, verbosity)
424 .send_request::<(), _>(GET_PEERS_METHOD, None)
425 .await
426}
427
428pub async fn get_node_status(
434 rpc_id: JsonRpcId,
435 node_address: &str,
436 verbosity: Verbosity,
437) -> Result<SuccessResponse<GetNodeStatusResult>, Error> {
438 JsonRpcCall::new(rpc_id, node_address, verbosity)
439 .send_request::<(), _>(GET_NODE_STATUS_METHOD, None)
440 .await
441}
442
443pub async fn get_chainspec(
449 rpc_id: JsonRpcId,
450 node_address: &str,
451 verbosity: Verbosity,
452) -> Result<SuccessResponse<GetChainspecResult>, Error> {
453 JsonRpcCall::new(rpc_id, node_address, verbosity)
454 .send_request::<(), _>(GET_CHAINSPEC_METHOD, None)
455 .await
456}
457
458pub async fn list_rpcs(
465 rpc_id: JsonRpcId,
466 node_address: &str,
467 verbosity: Verbosity,
468) -> Result<SuccessResponse<ListRpcsResult>, Error> {
469 JsonRpcCall::new(rpc_id, node_address, verbosity)
470 .send_request::<(), _>(LIST_RPCS_METHOD, None)
471 .await
472}
473
474pub(crate) fn json_pretty_print<T: ?Sized + Serialize>(
480 value: &T,
481 verbosity: Verbosity,
482) -> Result<(), Error> {
483 let output = match verbosity {
484 Verbosity::Low => return Ok(()),
485 Verbosity::Medium => casper_types::json_pretty_print(value),
486 Verbosity::High => serde_json::to_string_pretty(value),
487 }
488 .map_err(|error| Error::FailedToEncodeToJson {
489 context: "in json_pretty_print",
490 error,
491 })?;
492 println!("{}", output);
493 Ok(())
494}
495
496fn write_deploy<W: Write>(deploy: &Deploy, mut output: W) -> Result<(), Error> {
497 let content =
498 serde_json::to_string_pretty(deploy).map_err(|error| Error::FailedToEncodeToJson {
499 context: "writing deploy",
500 error,
501 })?;
502 output
503 .write_all(content.as_bytes())
504 .map_err(|error| Error::IoError {
505 context: "unable to write deploy".to_owned(),
506 error,
507 })
508}
509
510fn read_deploy<R: Read>(input: R) -> Result<Deploy, Error> {
511 let deploy: Deploy =
512 serde_json::from_reader(input).map_err(|error| Error::FailedToDecodeFromJson {
513 context: "reading deploy",
514 error,
515 })?;
516 deploy.is_valid_size(MAX_SERIALIZED_SIZE_OF_DEPLOY)?;
517 Ok(deploy)
518}
519
520#[deprecated(
527 since = "2.0.0",
528 note = "prefer 'get_era_summary' as it doesn't require a switch block"
529)]
530pub async fn get_era_info(
531 rpc_id: JsonRpcId,
532 node_address: &str,
533 verbosity: Verbosity,
534 maybe_block_identifier: Option<BlockIdentifier>,
535) -> Result<SuccessResponse<GetEraInfoResult>, Error> {
536 let params = maybe_block_identifier.map(GetEraInfoParams::new);
537 JsonRpcCall::new(rpc_id, node_address, verbosity)
538 .send_request(GET_ERA_INFO_METHOD, params)
539 .await
540}