casper_client/
lib.rs

1//! # Casper client library
2//!
3//! The crate provides functions for interacting with a Casper network.
4//!
5//! Most of the functions involve sending a JSON-RPC request to a specified node on the chosen
6//! network, and providing the RPC response.
7//!
8//! # Common Parameters
9//!
10//! Many of the functions have similar parameters.  Descriptions for these common ones follow:
11//!
12//! * <code>rpc_id: <a href="enum.JsonRpcId.html">JsonRpcId</a></code> - The JSON-RPC identifier,
13//!   applied to the request and returned in the response.
14//! * <code>node_address: &<a href="https://doc.rust-lang.org/std/primitive.str.html">str</a></code> -
15//!   The hostname or IP and port of the server, e.g. `http://127.0.0.1:7777`.
16//! * <code>verbosity: <a href="enum.Verbosity.html">Verbosity</a></code> - When `Low`, nothing is
17//!   printed to stdout.  For `Medium`, the request and response are printed to `stdout` with long
18//!   string fields (e.g. hex-formatted raw Wasm bytes) shortened to a string indicating the char
19//!   count of the field.  `High` verbosity is the same as `Medium` except without abbreviation of
20//!   long fields.
21//! * <code>maybe_block_identifier: <a href="https://doc.rust-lang.org/core/option/enum.Option.html">Option</a><<a href="rpcs/common/enum.BlockIdentifier.html">BlockIdentifier</a>></code> -
22//!   The identifier of the [`Block`] to use, either block height or block hash.  If `None`, the
23//!   latest `Block` known on the server will be used.
24
25#![doc(
26    html_root_url = "https://docs.rs/casper-client/3.1.0",
27    html_favicon_url = "https://raw.githubusercontent.com/casper-network/casper-node/master/images/CasperLabs_Logo_Favicon_RGB_50px.png",
28    html_logo_url = "https://raw.githubusercontent.com/casper-network/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;
41#[cfg(feature = "std-fs-io")]
42pub mod keygen;
43#[cfg(any(feature = "std-fs-io", test))]
44mod output_kind;
45pub mod rpcs;
46pub mod types;
47mod validation;
48mod verbosity;
49mod verification;
50mod verification_types;
51
52extern crate alloc;
53
54#[cfg(any(feature = "std-fs-io", test))]
55use std::{
56    env::current_dir,
57    fs,
58    io::{Cursor, Read, Write},
59    path::Path,
60};
61
62#[cfg(feature = "std-fs-io")]
63use serde::Serialize;
64
65#[cfg(any(feature = "std-fs-io", test))]
66use casper_types::SecretKey;
67#[cfg(doc)]
68use casper_types::{account::Account, Block, StoredValue, Transfer};
69use casper_types::{
70    Deploy, DeployHash, Digest, Key, PublicKey, Transaction, TransactionHash, URef,
71};
72
73#[cfg(any(feature = "std-fs-io", test))]
74use base64::{engine::general_purpose::STANDARD, Engine};
75pub use error::Error;
76use json_rpc::JsonRpcCall;
77pub use json_rpc::{JsonRpcId, SuccessResponse};
78#[cfg(any(feature = "std-fs-io", test))]
79pub use output_kind::OutputKind;
80use rpcs::{
81    common::{BlockIdentifier, GlobalStateIdentifier},
82    results::{
83        GetAccountResult, GetAddressableEntityResult, GetAuctionInfoResult, GetBalanceResult,
84        GetBlockResult, GetBlockTransfersResult, GetChainspecResult, GetDeployResult,
85        GetDictionaryItemResult, GetEraInfoResult, GetEraSummaryResult, GetNodeStatusResult,
86        GetPeersResult, GetRewardResult, GetStateRootHashResult, GetTransactionResult,
87        GetValidatorChangesResult, ListRpcsResult, PutDeployResult, PutTransactionResult,
88        QueryBalanceDetailsResult, QueryBalanceResult, QueryGlobalStateResult,
89        SpeculativeExecResult, SpeculativeExecTxnResult,
90    },
91    v2_0_0::{
92        get_account::{AccountIdentifier, GetAccountParams, GET_ACCOUNT_METHOD},
93        get_auction_info::{GetAuctionInfoParams, GET_AUCTION_INFO_METHOD},
94        get_balance::{GetBalanceParams, GET_BALANCE_METHOD},
95        get_block::{GetBlockParams, GET_BLOCK_METHOD},
96        get_block_transfers::{GetBlockTransfersParams, GET_BLOCK_TRANSFERS_METHOD},
97        get_chainspec::GET_CHAINSPEC_METHOD,
98        get_deploy::{GetDeployParams, GET_DEPLOY_METHOD},
99        get_dictionary_item::{GetDictionaryItemParams, GET_DICTIONARY_ITEM_METHOD},
100        get_entity::{EntityIdentifier, GetAddressableEntityParams, GET_ENTITY_METHOD},
101        get_era_info::{GetEraInfoParams, GET_ERA_INFO_METHOD},
102        get_era_summary::{GetEraSummaryParams, GET_ERA_SUMMARY_METHOD},
103        get_node_status::GET_NODE_STATUS_METHOD,
104        get_peers::GET_PEERS_METHOD,
105        get_reward::{GetRewardParams, GET_REWARD_METHOD},
106        get_state_root_hash::{GetStateRootHashParams, GET_STATE_ROOT_HASH_METHOD},
107        get_transaction::{GetTransactionParams, GET_TRANSACTION_METHOD},
108        get_validator_changes::GET_VALIDATOR_CHANGES_METHOD,
109        list_rpcs::LIST_RPCS_METHOD,
110        put_deploy::{PutDeployParams, PUT_DEPLOY_METHOD},
111        put_transaction::{PutTransactionParams, PUT_TRANSACTION_METHOD},
112        query_balance::{PurseIdentifier, QueryBalanceParams, QUERY_BALANCE_METHOD},
113        query_balance_details::{QueryBalanceDetailsParams, QUERY_BALANCE_DETAILS_METHOD},
114        query_global_state::{QueryGlobalStateParams, QUERY_GLOBAL_STATE_METHOD},
115        speculative_exec::{SpeculativeExecParams, SPECULATIVE_EXEC_METHOD},
116        speculative_exec_transaction::{SpeculativeExecTxnParams, SPECULATIVE_EXEC_TXN_METHOD},
117    },
118    DictionaryItemIdentifier, EraIdentifier,
119};
120pub use validation::ValidateResponseError;
121pub use verbosity::Verbosity;
122pub use verification::{build_archive, send_verification_request};
123#[cfg(any(feature = "std-fs-io", test))]
124use verification_types::VerificationDetails;
125
126/// The maximum permissible size in bytes of a Deploy when serialized via `ToBytes`.
127///
128/// Note: this should be kept in sync with the value of `[deploys.max_deploy_size]` in the
129/// production chainspec.
130pub const MAX_SERIALIZED_SIZE_OF_DEPLOY: u32 = 1_024 * 1_024;
131
132/// Puts a [`Deploy`] to the network for execution.
133///
134/// Sends a JSON-RPC `account_put_deploy` request to the specified node.
135///
136/// For details of the parameters, see [the module docs](crate#common-parameters).
137#[deprecated(since = "3.0.0", note = "use `put_transaction` instead")]
138pub async fn put_deploy(
139    rpc_id: JsonRpcId,
140    node_address: &str,
141    verbosity: Verbosity,
142    deploy: Deploy,
143) -> Result<SuccessResponse<PutDeployResult>, Error> {
144    JsonRpcCall::new(rpc_id, node_address, verbosity)?
145        .send_request(PUT_DEPLOY_METHOD, Some(PutDeployParams::new(deploy)))
146        .await
147}
148
149/// Puts a [`Transaction`] to the network for execution
150///
151/// Sends a JSON-RPC `account_put_transaction` request to the specified node.
152///
153/// For details of the parameters, see [the module docs](crate#common-parameters).
154pub async fn put_transaction(
155    rpc_id: JsonRpcId,
156    node_address: &str,
157    verbosity: Verbosity,
158    transaction: Transaction,
159) -> Result<SuccessResponse<PutTransactionResult>, Error> {
160    JsonRpcCall::new(rpc_id, node_address, verbosity)?
161        .send_request(
162            PUT_TRANSACTION_METHOD,
163            Some(PutTransactionParams::new(transaction)),
164        )
165        .await
166}
167
168/// Puts a [`Deploy`] to a single node for speculative execution on that node only.
169///
170/// Sends a JSON-RPC `speculative_exec` request to the specified node.
171///
172/// For details of the parameters, see [the module docs](crate#common-parameters).
173#[deprecated(since = "3.0.0", note = "use `speculative_exec_txn` instead")]
174pub async fn speculative_exec(
175    rpc_id: JsonRpcId,
176    node_address: &str,
177    verbosity: Verbosity,
178    deploy: Deploy,
179) -> Result<SuccessResponse<SpeculativeExecResult>, Error> {
180    JsonRpcCall::new(rpc_id, node_address, verbosity)?
181        .send_request(
182            SPECULATIVE_EXEC_METHOD,
183            Some(SpeculativeExecParams::new(deploy)),
184        )
185        .await
186}
187
188/// Puts a [`Transaction`] to a single node for speculative execution on that node only.
189///
190/// Sends a JSON-RPC speculative_exec request to the specified node.
191///
192/// For details of the parameters, see [the module docs](crate#common-parameters).
193pub async fn speculative_exec_txn(
194    rpc_id: JsonRpcId,
195    node_address: &str,
196    verbosity: Verbosity,
197    transaction: Transaction,
198) -> Result<SuccessResponse<SpeculativeExecTxnResult>, Error> {
199    JsonRpcCall::new(rpc_id, node_address, verbosity)?
200        .send_request(
201            SPECULATIVE_EXEC_TXN_METHOD,
202            Some(SpeculativeExecTxnParams::new(transaction)),
203        )
204        .await
205}
206
207/// Outputs a [`Deploy`] to a file or stdout.
208///
209/// As a file, the `Deploy` can subsequently be signed by other parties using [`sign_deploy_file`]
210/// and then read and sent to the network for execution using [`read_deploy_file`] and
211/// [`put_deploy`] respectively.
212///
213/// `output` specifies the output file and corresponding overwrite behaviour, or if
214/// `OutputKind::Stdout`, causes the `Deploy` to be printed `stdout`.
215#[deprecated(since = "3.0.0", note = "use `output_transaction` instead")]
216#[cfg(any(feature = "std-fs-io", test))]
217pub fn output_deploy(output: OutputKind, deploy: &Deploy) -> Result<(), Error> {
218    write_deploy(deploy, output.get()?)?;
219    output.commit()
220}
221
222/// Outputs a [`Transaction`] to a file or stdout.
223///
224/// As a file, the `Transaction` can subsequently be signed by other parties using [`sign_transaction_file`]
225/// and then read and sent to the network for execution using [`read_transaction_file`] and
226/// [`put_transaction`] respectively.
227///
228/// `output` specifies the output file and corresponding overwrite behaviour, or if
229/// `OutputKind::Stdout`, causes the `Transaction` to be printed `stdout`.
230#[cfg(any(feature = "std-fs-io", test))]
231pub fn output_transaction(output: OutputKind, transaction: &Transaction) -> Result<(), Error> {
232    write_transaction(transaction, output.get()?)?;
233    output.commit()
234}
235
236/// Reads a previously-saved [`Deploy`] from a file.
237#[deprecated(since = "3.0.0", note = "use `read_transaction_file` instead")]
238#[cfg(any(feature = "std-fs-io", test))]
239pub fn read_deploy_file<P: AsRef<Path>>(deploy_path: P) -> Result<Deploy, Error> {
240    let input = fs::read(deploy_path.as_ref()).map_err(|error| Error::IoError {
241        context: format!(
242            "unable to read deploy file at '{}'",
243            deploy_path.as_ref().display()
244        ),
245        error,
246    })?;
247    read_deploy(Cursor::new(input))
248}
249
250/// Reads a previously-saved [`Transaction`] from a file.
251#[cfg(any(feature = "std-fs-io", test))]
252pub fn read_transaction_file<P: AsRef<Path>>(transaction_path: P) -> Result<Transaction, Error> {
253    let input = fs::read(transaction_path.as_ref()).map_err(|error| Error::IoError {
254        context: format!(
255            "unable to read transaction file at '{}'",
256            transaction_path.as_ref().display()
257        ),
258        error,
259    })?;
260    read_transaction(Cursor::new(input))
261}
262
263/// Reads a previously-saved [`Deploy`] from a file, cryptographically signs it, and outputs it
264/// to a file or stdout.
265///
266/// `output` specifies the output file and corresponding overwrite behaviour, or if
267/// `OutputKind::Stdout`, causes the `Deploy` to be printed `stdout`.
268///
269/// The same path can be specified for input and output, and if the operation fails, the original
270/// input file will be left unmodified.
271#[deprecated(since = "3.0.0", note = "use `sign_transaction_file` instead")]
272#[cfg(any(feature = "std-fs-io", test))]
273pub fn sign_deploy_file<P: AsRef<Path>>(
274    input_path: P,
275    secret_key: &SecretKey,
276    output: OutputKind,
277) -> Result<(), Error> {
278    #[allow(deprecated)]
279    let mut deploy = read_deploy_file(input_path)?;
280
281    deploy.sign(secret_key);
282    deploy.is_valid_size(MAX_SERIALIZED_SIZE_OF_DEPLOY)?;
283
284    write_deploy(&deploy, output.get()?)?;
285    output.commit()
286}
287
288/// Reads a previously-saved [`Transaction`] from a file, cryptographically signs it, and outputs it to a file or stdout.
289///
290/// `output` specifies the output file and corresponding overwrite behaviour, or if OutputKind::Stdout,
291/// causes the `Transaction` to be printed `stdout`.
292#[cfg(any(feature = "std-fs-io", test))]
293pub fn sign_transaction_file<P: AsRef<Path>>(
294    input_path: P,
295    secret_key: &SecretKey,
296    output: OutputKind,
297) -> Result<(), Error> {
298    let mut transaction = read_transaction_file(input_path)?;
299
300    transaction.sign(secret_key);
301
302    write_transaction(&transaction, output.get()?)?;
303    output.commit()
304}
305
306/// Retrieves a [`Deploy`] and its metadata (i.e. execution results) from the network.
307///
308/// Sends a JSON-RPC `info_get_deploy` request to the specified node.
309///
310/// `finalized_approvals` defines whether to return the `Deploy` with its approvals as finalized by
311/// consensus of the validators on the network, or as originally received by the specified node.
312///
313/// For details of the other parameters, see [the module docs](crate#common-parameters).
314pub async fn get_deploy(
315    rpc_id: JsonRpcId,
316    node_address: &str,
317    verbosity: Verbosity,
318    deploy_hash: DeployHash,
319    finalized_approvals: bool,
320) -> Result<SuccessResponse<GetDeployResult>, Error> {
321    JsonRpcCall::new(rpc_id, node_address, verbosity)?
322        .send_request(
323            GET_DEPLOY_METHOD,
324            Some(GetDeployParams::new(deploy_hash, finalized_approvals)),
325        )
326        .await
327}
328
329/// Retrieves a [`Transaction`] and its metadata (i.e. execution results) from the network.
330///
331/// Sends a JSON-RPC `info_get_transaction` request to the specified node.
332///
333/// `finalized_approvals` defines whether to return the `Transaction` with its approvals as finalized by
334/// consensus of the validators on the network, or as originally received by the specified node.
335///
336/// For details of the other parameters, see [the module docs](crate#common-parameters).
337pub async fn get_transaction(
338    rpc_id: JsonRpcId,
339    node_address: &str,
340    verbosity: Verbosity,
341    transaction_hash: TransactionHash,
342    finalized_approvals: bool,
343) -> Result<SuccessResponse<GetTransactionResult>, Error> {
344    JsonRpcCall::new(rpc_id, node_address, verbosity)?
345        .send_request(
346            GET_TRANSACTION_METHOD,
347            Some(GetTransactionParams::new(
348                transaction_hash,
349                finalized_approvals,
350            )),
351        )
352        .await
353}
354
355/// Retrieves a [`Block`] from the network.
356///
357/// Sends a JSON-RPC `chain_get_block` request to the specified node.
358///
359/// For details of the parameters, see [the module docs](crate#common-parameters).
360pub async fn get_block(
361    rpc_id: JsonRpcId,
362    node_address: &str,
363    verbosity: Verbosity,
364    maybe_block_identifier: Option<BlockIdentifier>,
365) -> Result<SuccessResponse<GetBlockResult>, Error> {
366    let params = maybe_block_identifier.map(GetBlockParams::new);
367    let success_response = JsonRpcCall::new(rpc_id, node_address, verbosity)?
368        .send_request(GET_BLOCK_METHOD, params)
369        .await?;
370    validation::validate_get_block_result(maybe_block_identifier, &success_response.result)?;
371    Ok(success_response)
372}
373
374/// Retrieves all [`Transfer`] items for a given [`Block`].
375///
376/// Sends a JSON-RPC `chain_get_block_transfers` request to the specified node.
377///
378/// For details of the parameters, see [the module docs](crate#common-parameters).
379pub async fn get_block_transfers(
380    rpc_id: JsonRpcId,
381    node_address: &str,
382    verbosity: Verbosity,
383    maybe_block_identifier: Option<BlockIdentifier>,
384) -> Result<SuccessResponse<GetBlockTransfersResult>, Error> {
385    let params = maybe_block_identifier.map(GetBlockTransfersParams::new);
386    JsonRpcCall::new(rpc_id, node_address, verbosity)?
387        .send_request(GET_BLOCK_TRANSFERS_METHOD, params)
388        .await
389}
390
391/// Retrieves a state root hash at a given [`Block`].
392///
393/// Sends a JSON-RPC `chain_get_state_root_hash` request to the specified node.
394///
395/// For details of the parameters, see [the module docs](crate#common-parameters).
396pub async fn get_state_root_hash(
397    rpc_id: JsonRpcId,
398    node_address: &str,
399    verbosity: Verbosity,
400    maybe_block_identifier: Option<BlockIdentifier>,
401) -> Result<SuccessResponse<GetStateRootHashResult>, Error> {
402    let params = maybe_block_identifier.map(GetStateRootHashParams::new);
403    JsonRpcCall::new(rpc_id, node_address, verbosity)?
404        .send_request(GET_STATE_ROOT_HASH_METHOD, params)
405        .await
406}
407
408/// Retrieves era information from the network at a given [`Block`].
409///
410/// Sends a JSON-RPC `chain_get_era_summary` request to the specified node.
411///
412/// For details of the parameters, see [the module docs](crate#common-parameters).
413pub async fn get_era_summary(
414    rpc_id: JsonRpcId,
415    node_address: &str,
416    verbosity: Verbosity,
417    maybe_block_identifier: Option<BlockIdentifier>,
418) -> Result<SuccessResponse<GetEraSummaryResult>, Error> {
419    let params = maybe_block_identifier.map(GetEraSummaryParams::new);
420    JsonRpcCall::new(rpc_id, node_address, verbosity)?
421        .send_request(GET_ERA_SUMMARY_METHOD, params)
422        .await
423}
424
425/// Retrieves a [`StoredValue`] from global state at a given [`Block`] or state root hash.
426///
427/// Sends a JSON-RPC `query_global_state` request to the specified node.
428///
429/// `key` specifies the key under which the value is stored in global state.
430///
431/// `path` defines the further path (if any) from `key` to navigate to during the query.  This is
432/// only applicable in the case where the value under `key` is an account or contract.  In this
433/// case, the first `path` element represents a name in the account/contract's named keys.  If that
434/// second `Key` also points to an account or contract, then a second path element can be added to
435/// continue the query into that account/contract's named keys.  This can continue up to the
436/// server's configured maximum query depth (5 by default).
437///
438/// For details of the other parameters, see [the module docs](crate#common-parameters).
439pub async fn query_global_state(
440    rpc_id: JsonRpcId,
441    node_address: &str,
442    verbosity: Verbosity,
443    global_state_identifier: GlobalStateIdentifier,
444    key: Key,
445    path: Vec<String>,
446) -> Result<SuccessResponse<QueryGlobalStateResult>, Error> {
447    let params = QueryGlobalStateParams::new(global_state_identifier, key, path);
448    JsonRpcCall::new(rpc_id, node_address, verbosity)?
449        .send_request(QUERY_GLOBAL_STATE_METHOD, Some(params))
450        .await
451}
452
453/// Retrieves a purse's balance from global state at a given [`Block`] or state root hash.
454///
455/// Sends a JSON-RPC `query_balance` request to the specified node.
456///
457/// For details of the parameters, see [the module docs](crate#common-parameters).
458pub async fn query_balance(
459    rpc_id: JsonRpcId,
460    node_address: &str,
461    verbosity: Verbosity,
462    maybe_global_state_identifier: Option<GlobalStateIdentifier>,
463    purse_identifier: PurseIdentifier,
464) -> Result<SuccessResponse<QueryBalanceResult>, Error> {
465    let params = QueryBalanceParams::new(maybe_global_state_identifier, purse_identifier);
466    JsonRpcCall::new(rpc_id, node_address, verbosity)?
467        .send_request(QUERY_BALANCE_METHOD, Some(params))
468        .await
469}
470
471/// Retrieves a purse's balance from global state at a given [`Block`] or state root hash.
472///
473/// Sends a JSON-RPC `query_balance_details` request to the specified node.
474///
475/// For details of the parameters, see [the module docs](crate#common-parameters).
476pub async fn query_balance_details(
477    rpc_id: JsonRpcId,
478    node_address: &str,
479    verbosity: Verbosity,
480    maybe_global_state_identifier: Option<GlobalStateIdentifier>,
481    purse_identifier: PurseIdentifier,
482) -> Result<SuccessResponse<QueryBalanceDetailsResult>, Error> {
483    let params = QueryBalanceDetailsParams::new(maybe_global_state_identifier, purse_identifier);
484    JsonRpcCall::new(rpc_id, node_address, verbosity)?
485        .send_request(QUERY_BALANCE_DETAILS_METHOD, Some(params))
486        .await
487}
488
489/// Retrieves a [`StoredValue`] from a dictionary at a given state root hash.
490///
491/// Sends a JSON-RPC `state_get_dictionary_item` request to the specified node.
492///
493/// For details of the parameters, see [the module docs](crate#common-parameters).
494pub async fn get_dictionary_item(
495    rpc_id: JsonRpcId,
496    node_address: &str,
497    verbosity: Verbosity,
498    state_root_hash: Digest,
499    dictionary_item_identifier: DictionaryItemIdentifier,
500) -> Result<SuccessResponse<GetDictionaryItemResult>, Error> {
501    let params = GetDictionaryItemParams::new(state_root_hash, dictionary_item_identifier);
502    JsonRpcCall::new(rpc_id, node_address, verbosity)?
503        .send_request(GET_DICTIONARY_ITEM_METHOD, Some(params))
504        .await
505}
506
507/// Retrieves a purse's balance at a given state root hash.
508///
509/// Sends a JSON-RPC `state_get_balance` request to the specified node.
510///
511/// For details of the parameters, see [the module docs](crate#common-parameters).
512pub async fn get_balance(
513    rpc_id: JsonRpcId,
514    node_address: &str,
515    verbosity: Verbosity,
516    state_root_hash: Digest,
517    purse: URef,
518) -> Result<SuccessResponse<GetBalanceResult>, Error> {
519    let params = GetBalanceParams::new(state_root_hash, purse);
520    JsonRpcCall::new(rpc_id, node_address, verbosity)?
521        .send_request(GET_BALANCE_METHOD, Some(params))
522        .await
523}
524
525/// Retrieves an [`Account`] at a given [`Block`].
526///
527/// Sends a JSON-RPC `state_get_account_info` request to the specified node.
528///
529/// For details of the parameters, see [the module docs](crate#common-parameters).
530pub async fn get_account(
531    rpc_id: JsonRpcId,
532    node_address: &str,
533    verbosity: Verbosity,
534    maybe_block_identifier: Option<BlockIdentifier>,
535    account_identifier: AccountIdentifier,
536) -> Result<SuccessResponse<GetAccountResult>, Error> {
537    let params = GetAccountParams::new(account_identifier, maybe_block_identifier);
538    JsonRpcCall::new(rpc_id, node_address, verbosity)?
539        .send_request(GET_ACCOUNT_METHOD, Some(params))
540        .await
541}
542
543/// Retrieves an [`crate::rpcs::v2_0_0::get_entity::EntityOrAccount`] at a given [`Block`].
544///
545/// Sends a JSON-RPC `state_get_entity` request to the specified node.
546///
547/// For details of the parameters, see [the module docs](crate#common-parameters).
548pub async fn get_entity(
549    rpc_id: JsonRpcId,
550    node_address: &str,
551    verbosity: Verbosity,
552    maybe_block_identifier: Option<BlockIdentifier>,
553    entity_identifier: EntityIdentifier,
554) -> Result<SuccessResponse<GetAddressableEntityResult>, Error> {
555    let params = GetAddressableEntityParams::new(entity_identifier, maybe_block_identifier);
556    JsonRpcCall::new(rpc_id, node_address, verbosity)?
557        .send_request(GET_ENTITY_METHOD, Some(params))
558        .await
559}
560
561/// Retrieves a [`GetRewardResult`] at a given [`EraIdentifier`].
562///
563/// Sends a JSON-RPC `info_get_reward` request to the specified node.
564///
565/// For details of the parameters, see [the module docs](crate#common-parameters).
566pub async fn get_reward(
567    rpc_id: JsonRpcId,
568    node_address: &str,
569    verbosity: Verbosity,
570    maybe_era_identifier: Option<EraIdentifier>,
571    validator: PublicKey,
572    delegator: Option<PublicKey>,
573) -> Result<SuccessResponse<GetRewardResult>, Error> {
574    let params = GetRewardParams::new(maybe_era_identifier, validator, delegator);
575    JsonRpcCall::new(rpc_id, node_address, verbosity)?
576        .send_request(GET_REWARD_METHOD, Some(params))
577        .await
578}
579
580/// Retrieves the bids and validators at a given [`Block`].
581///
582/// Sends a JSON-RPC `state_get_auction_info` request to the specified node.
583///
584/// For details of the parameters, see [the module docs](crate#common-parameters).
585pub async fn get_auction_info(
586    rpc_id: JsonRpcId,
587    node_address: &str,
588    verbosity: Verbosity,
589    maybe_block_identifier: Option<BlockIdentifier>,
590) -> Result<SuccessResponse<GetAuctionInfoResult>, Error> {
591    let params = maybe_block_identifier.map(GetAuctionInfoParams::new);
592    JsonRpcCall::new(rpc_id, node_address, verbosity)?
593        .send_request(GET_AUCTION_INFO_METHOD, params)
594        .await
595}
596
597/// Retrieves the status changes of the active validators on the network.
598///
599/// Sends a JSON-RPC `info_get_validator_changes` request to the specified node.
600///
601/// For details of the parameters, see [the module docs](crate#common-parameters).
602pub async fn get_validator_changes(
603    rpc_id: JsonRpcId,
604    node_address: &str,
605    verbosity: Verbosity,
606) -> Result<SuccessResponse<GetValidatorChangesResult>, Error> {
607    JsonRpcCall::new(rpc_id, node_address, verbosity)?
608        .send_request::<(), _>(GET_VALIDATOR_CHANGES_METHOD, None)
609        .await
610}
611
612/// Retrieves the IDs and addresses of the specified node's peers.
613///
614/// Sends a JSON-RPC `info_get_peers` request to the specified node.
615///
616/// For details of the parameters, see [the module docs](crate#common-parameters).
617pub async fn get_peers(
618    rpc_id: JsonRpcId,
619    node_address: &str,
620    verbosity: Verbosity,
621) -> Result<SuccessResponse<GetPeersResult>, Error> {
622    JsonRpcCall::new(rpc_id, node_address, verbosity)?
623        .send_request::<(), _>(GET_PEERS_METHOD, None)
624        .await
625}
626
627/// Retrieves the status of the specified node.
628///
629/// Sends a JSON-RPC `info_get_status` request to the specified node.
630///
631/// For details of the parameters, see [the module docs](crate#common-parameters).
632pub async fn get_node_status(
633    rpc_id: JsonRpcId,
634    node_address: &str,
635    verbosity: Verbosity,
636) -> Result<SuccessResponse<GetNodeStatusResult>, Error> {
637    JsonRpcCall::new(rpc_id, node_address, verbosity)?
638        .send_request::<(), _>(GET_NODE_STATUS_METHOD, None)
639        .await
640}
641
642/// Retrieves the Chainspec of the network.
643///
644/// Sends a JSON-RPC `info_get_chainspec` request to the specified node.
645///
646/// For details of the parameters, see [the module docs](crate#common-parameters).
647pub async fn get_chainspec(
648    rpc_id: JsonRpcId,
649    node_address: &str,
650    verbosity: Verbosity,
651) -> Result<SuccessResponse<GetChainspecResult>, Error> {
652    JsonRpcCall::new(rpc_id, node_address, verbosity)?
653        .send_request::<(), _>(GET_CHAINSPEC_METHOD, None)
654        .await
655}
656
657/// Retrieves the interface description (the schema including examples in OpenRPC format) of the
658/// JSON-RPC server's API.
659///
660/// Sends a JSON-RPC `rpc.discover` request to the specified node.
661///
662/// For details of the parameters, see [the module docs](crate#common-parameters).
663pub async fn list_rpcs(
664    rpc_id: JsonRpcId,
665    node_address: &str,
666    verbosity: Verbosity,
667) -> Result<SuccessResponse<ListRpcsResult>, Error> {
668    JsonRpcCall::new(rpc_id, node_address, verbosity)?
669        .send_request::<(), _>(LIST_RPCS_METHOD, None)
670        .await
671}
672
673/// JSON-encode and pretty-print the given value to stdout at the given verbosity level.
674///
675/// When `verbosity` is `Low`, nothing is printed.  For `Medium`, the value is printed with long
676/// string fields shortened to a string indicating the character count of the field.  `High`
677/// verbosity is the same as `Medium` except without abbreviation of long fields.
678#[cfg(feature = "std-fs-io")]
679pub(crate) fn json_pretty_print<T: ?Sized + Serialize>(
680    value: &T,
681    verbosity: Verbosity,
682) -> Result<(), Error> {
683    let output = match verbosity {
684        Verbosity::Low => return Ok(()),
685        Verbosity::Medium => casper_types::json_pretty_print(value),
686        Verbosity::High => serde_json::to_string_pretty(value),
687    }
688    .map_err(|error| Error::FailedToEncodeToJson {
689        context: "in json_pretty_print",
690        error,
691    })?;
692    println!("{}", output);
693    Ok(())
694}
695
696#[cfg(any(feature = "std-fs-io", test))]
697fn write_deploy<W: Write>(deploy: &Deploy, mut output: W) -> Result<(), Error> {
698    let content =
699        serde_json::to_string_pretty(deploy).map_err(|error| Error::FailedToEncodeToJson {
700            context: "writing deploy",
701            error,
702        })?;
703    output
704        .write_all(content.as_bytes())
705        .map_err(|error| Error::IoError {
706            context: "unable to write deploy".to_owned(),
707            error,
708        })
709}
710
711#[cfg(any(feature = "std-fs-io", test))]
712fn write_transaction<W: Write>(transaction: &Transaction, mut output: W) -> Result<(), Error> {
713    let content =
714        serde_json::to_string_pretty(transaction).map_err(|error| Error::FailedToEncodeToJson {
715            context: "writing transaction",
716            error,
717        })?;
718    output
719        .write_all(content.as_bytes())
720        .map_err(|error| Error::IoError {
721            context: "unable to write transaction".to_owned(),
722            error,
723        })
724}
725
726#[cfg(any(feature = "std-fs-io", test))]
727fn read_deploy<R: Read>(input: R) -> Result<Deploy, Error> {
728    let deploy: Deploy =
729        serde_json::from_reader(input).map_err(|error| Error::FailedToDecodeFromJson {
730            context: "reading deploy",
731            error,
732        })?;
733    deploy.is_valid_size(MAX_SERIALIZED_SIZE_OF_DEPLOY)?;
734    Ok(deploy)
735}
736
737#[cfg(any(feature = "std-fs-io", test))]
738fn read_transaction<R: Read>(input: R) -> Result<Transaction, Error> {
739    let transaction: Transaction =
740        serde_json::from_reader(input).map_err(|error| Error::FailedToDecodeFromJson {
741            context: "reading transaction",
742            error,
743        })?;
744    Ok(transaction)
745}
746
747/// Retrieves era information from the network at a given switch [`Block`].
748///
749/// Sends a JSON-RPC `chain_get_era_info_by_switch_block` request to the specified node.
750///
751/// For details of the parameters, see [the module docs](crate#common-parameters).  Note that if the
752/// specified block is not a switch block then the response will have no era info.
753#[deprecated(
754    since = "2.0.0",
755    note = "prefer 'get_era_summary' as it doesn't require a switch block"
756)]
757pub async fn get_era_info(
758    rpc_id: JsonRpcId,
759    node_address: &str,
760    verbosity: Verbosity,
761    maybe_block_identifier: Option<BlockIdentifier>,
762) -> Result<SuccessResponse<GetEraInfoResult>, Error> {
763    let params = maybe_block_identifier.map(GetEraInfoParams::new);
764    JsonRpcCall::new(rpc_id, node_address, verbosity)?
765        .send_request(GET_ERA_INFO_METHOD, params)
766        .await
767}
768
769/// Verifies the smart contract code against the one deployed at given deploy or transaction hash.
770#[cfg(any(feature = "std-fs-io", test))]
771pub async fn verify_contract(
772    hash_str: &str,
773    verification_url_base_path: &str,
774    project_path: Option<&str>,
775    verbosity: Verbosity,
776) -> Result<VerificationDetails, Error> {
777    if verbosity == Verbosity::Medium || verbosity == Verbosity::High {
778        println!("Hash: {hash_str}");
779        println!("Verification service base path: {verification_url_base_path}",);
780    }
781
782    let project_path = match project_path {
783        Some(path) => Path::new(path).to_path_buf(),
784        None => match current_dir() {
785            Ok(path) => path,
786            Err(error) => {
787                eprintln!("Cannot get current directory: {error}");
788                return Err(Error::ContractVerificationFailed);
789            }
790        },
791    };
792
793    let archive = match build_archive(&project_path) {
794        Ok(archive) => {
795            if verbosity == Verbosity::Medium || verbosity == Verbosity::High {
796                println!("Created project archive (size: {})", archive.len());
797            }
798            archive
799        }
800        Err(error) => {
801            eprintln!("Cannot create project archive: {error}");
802            return Err(Error::ContractVerificationFailed);
803        }
804    };
805
806    send_verification_request(
807        hash_str,
808        verification_url_base_path,
809        STANDARD.encode(&archive),
810        verbosity,
811    )
812    .await
813}