From bdc471525045046eef97f06e15786e97c5d69b6c Mon Sep 17 00:00:00 2001 From: Karan Dhareshwar Date: Tue, 11 Apr 2023 09:48:10 -0500 Subject: [PATCH 1/5] Add get-era-summary subcommand --- Cargo.toml | 2 +- lib/lib.rs | 54 +++++++++++++++++++++++++++++++-- lib/rpc.rs | 29 ++++++++++++++---- src/get_era_summary.rs | 69 ++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 7 +++-- 5 files changed, 150 insertions(+), 11 deletions(-) create mode 100644 src/get_era_summary.rs diff --git a/Cargo.toml b/Cargo.toml index ec127cf3..ddb10e7e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ doc = false async-trait = "0.1.51" base16 = "0.2.1" base64 = "0.13.0" -casper-execution-engine = "1.4.4" +casper-execution-engine = "3.0.0" casper-node = "1.4.5" casper-hashing = "1.4.3" casper-types = "1.5.0" diff --git a/lib/lib.rs b/lib/lib.rs index 9a97ab7a..eecbf0cc 100644 --- a/lib/lib.rs +++ b/lib/lib.rs @@ -25,7 +25,7 @@ mod validation; use std::{convert::TryInto, fs, io::Cursor}; use jsonrpc_lite::JsonRpc; -use serde::Serialize; +use serde::{Deserialize, Serialize}; use casper_execution_engine::core::engine_state::ExecutableDeployItem; use casper_hashing::Digest; @@ -33,7 +33,8 @@ use casper_node::{ rpcs::state::{DictionaryIdentifier, GlobalStateIdentifier}, types::{BlockHash, Deploy}, }; -use casper_types::Key; +use casper_node::rpcs::chain::{BlockIdentifier, EraSummary}; +use casper_types::{Key, ProtocolVersion}; pub use cl_type::help; pub use deploy::ListDeploysResult; @@ -471,6 +472,32 @@ pub async fn get_era_info_by_switch_block( .await } +/// Retrieves era information under the stable EraSummary casper_types::Key. +/// +/// * `maybe_rpc_id` is the JSON-RPC identifier, applied to the request and returned in the +/// response. If it can be parsed as an `i64` it will be used as a JSON integer. If empty, a +/// random `i64` will be assigned. Otherwise the provided string will be used verbatim. +/// * `node_address` is the hostname or IP and port of the node on which the HTTP service is +/// running, e.g. `"http://127.0.0.1:7777"`. +/// * When `verbosity_level` is `1`, the JSON-RPC request will be printed to `stdout` with long +/// string fields (e.g. hex-formatted raw Wasm bytes) shortened to a string indicating the char +/// count of the field. When `verbosity_level` is greater than `1`, the request will be printed +/// to `stdout` with no abbreviation of long fields. When `verbosity_level` is `0`, the request +/// will not be printed to `stdout`. +/// * `maybe_block_id` must be a hex-encoded, 32-byte hash digest or a `u64` representing the +/// `Block` height or empty. If empty, era information from the latest block will be returned if +/// available. +pub async fn get_era_summary( + maybe_rpc_id: &str, + node_address: &str, + verbosity_level: u64, + maybe_block_id: &str, +) -> Result { + RpcCall::new(maybe_rpc_id, node_address, verbosity_level) + .get_era_summary(maybe_block_id) + .await +} + /// Retrieves the bids and validators as of the most recently added `Block`. /// /// * `maybe_rpc_id` is the JSON-RPC identifier, applied to the request and returned in the @@ -1194,6 +1221,29 @@ impl<'a> TryInto for GlobalStateStrParams<'a> { } } +/// Params for "chain_get_era_summary" RPC response. +#[derive(Serialize, Deserialize, Debug)] +#[serde(deny_unknown_fields)] +pub struct GetEraSummaryParams { + /// The block identifier. + pub block_identifier: BlockIdentifier, +} + +/// Result for "chain_get_era_summary" RPC response. +#[derive(Serialize, Deserialize, Debug)] +#[serde(deny_unknown_fields)] +pub struct GetEraSummaryResult { + /// The RPC API version. + pub api_version: ProtocolVersion, + /// The era summary. + pub era_summary: EraSummary, +} + + +/// "chain_get_era_summary" RPC +pub struct GetEraSummary {} + + /// When `verbosity_level` is `1`, the value will be printed to `stdout` with long string fields /// (e.g. hex-formatted raw Wasm bytes) shortened to a string indicating the char count of the /// field. When `verbosity_level` is greater than `1`, the value will be printed to `stdout` with diff --git a/lib/rpc.rs b/lib/rpc.rs index f03b027c..ae221ce5 100644 --- a/lib/rpc.rs +++ b/lib/rpc.rs @@ -4,7 +4,7 @@ use async_trait::async_trait; use jsonrpc_lite::{Id, JsonRpc, Params}; use rand::Rng; use reqwest::Client; -use serde::Serialize; +use serde::{Serialize, Serializer}; use serde_json::{json, Map, Value}; use casper_execution_engine::core::engine_state::ExecutableDeployItem; @@ -30,11 +30,7 @@ use casper_node::{ }; use casper_types::{AsymmetricType, Key, PublicKey, URef}; -use crate::{ - deploy::{DeployExt, DeployParams, SendDeploy, Transfer}, - error::{Error, Result}, - validation, DictionaryItemStrParams, GlobalStateStrParams, -}; +use crate::{deploy::{DeployExt, DeployParams, SendDeploy, Transfer}, error::{Error, Result}, validation, DictionaryItemStrParams, GlobalStateStrParams, GetEraSummary, GetEraSummaryParams}; /// Struct representing a single JSON-RPC call to the casper node. #[derive(Debug)] @@ -188,6 +184,22 @@ impl RpcCall { Ok(response) } + pub(crate) async fn get_era_summary( + self, + maybe_block_identifier: &str, + ) -> Result { + let response = match Self::block_identifier(maybe_block_identifier)? { + None => GetEraSummary::request(self).await, + Some(block_identifier) => { + let params = GetEraSummaryParams { block_identifier }; + GetEraSummary::request_with_map_params(self, params).await + } + }?; + Ok(response) + } + + + pub(crate) async fn get_auction_info(self, maybe_block_identifier: &str) -> Result { let response = match Self::block_identifier(maybe_block_identifier)? { None => GetAuctionInfo::request(self).await, @@ -479,6 +491,10 @@ impl RpcClient for GetValidatorChanges { const RPC_METHOD: &'static str = Self::METHOD; } +impl RpcClient for GetEraSummary { + const RPC_METHOD: &'static str = "chain_get_era_summary"; +} + pub(crate) trait IntoJsonMap: Serialize { fn into_json_map(self) -> Map where @@ -504,3 +520,4 @@ impl IntoJsonMap for GetAuctionInfoParams {} impl IntoJsonMap for GetAccountInfoParams {} impl IntoJsonMap for GetDictionaryItemParams {} impl IntoJsonMap for QueryGlobalStateParams {} +impl IntoJsonMap for GetEraSummaryParams {} \ No newline at end of file diff --git a/src/get_era_summary.rs b/src/get_era_summary.rs new file mode 100644 index 00000000..ef5b5754 --- /dev/null +++ b/src/get_era_summary.rs @@ -0,0 +1,69 @@ +use std::str; + +use async_trait::async_trait; +use clap::{App, ArgMatches, SubCommand}; +use serde::{Serialize, Deserialize}; + +use casper_client::{Error, GetEraSummary}; +use casper_types::ProtocolVersion; + +use crate::{command::ClientCommand, common, Success}; + + + + +enum DisplayOrder { + Verbose, + NodeAddress, + RpcId, + BlockIdentifier +} + +#[async_trait] +impl<'a, 'b> ClientCommand<'a, 'b> for GetEraSummary { + const NAME: &'static str = "get-era-summary"; + const ABOUT: &'static str = "Retrieves era information from the network"; + + fn build(display_order: usize) -> App<'a, 'b> { + SubCommand::with_name(Self::NAME) + .about(Self::ABOUT) + .display_order(display_order) + .arg(common::verbose::arg(DisplayOrder::Verbose as usize)) + .arg(common::node_address::arg( + DisplayOrder::NodeAddress as usize, + )) + .arg(common::rpc_id::arg(DisplayOrder::RpcId as usize)) + .arg(common::block_identifier::arg( + DisplayOrder::BlockIdentifier as usize, + )) + } + + async fn run(matches: &ArgMatches<'a>) -> Result { + let maybe_rpc_id = common::rpc_id::get(matches); + let node_address = common::node_address::get(matches); + let verbosity_level = common::verbose::get(matches); + let maybe_block_id = common::block_identifier::get(matches); + + casper_client::get_era_summary( + maybe_rpc_id, + node_address, + verbosity_level, + maybe_block_id, + ) + .await + .map(Success::from) + } + + + + +} + + + + + + + + + diff --git a/src/main.rs b/src/main.rs index 421d4931..1bc1d0a6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,13 +14,14 @@ mod get_state_hash; mod get_validator_changes; mod keygen; mod query_global_state; +mod get_era_summary; use std::process; use clap::{crate_version, App}; use once_cell::sync::Lazy; -use casper_client::Error; +use casper_client::{Error, GetEraSummary}; use casper_node::rpcs::{ account::PutDeploy, chain::{GetBlock, GetBlockTransfers, GetEraInfoBySwitchBlock, GetStateRootHash}, @@ -69,6 +70,7 @@ enum DisplayOrder { GetBalance, GetAccountInfo, GetEraInfo, + GetEraSummary, GetAuctionInfo, GetValidatorChanges, Keygen, @@ -117,6 +119,7 @@ fn cli<'a, 'b>() -> App<'a, 'b> { .subcommand( QueryGlobalState::build(DisplayOrder::QueryGlobalState as usize).alias("query-state"), ) + .subcommand(GetEraSummary::build(DisplayOrder::GetEraSummary as usize)) } #[tokio::main] @@ -155,7 +158,7 @@ async fn main() { (GetDictionaryItem::run(matches).await, matches) } (QueryGlobalState::NAME, Some(matches)) => (QueryGlobalState::run(matches).await, matches), - + (GetEraSummary::NAME, Some(matches)) => (GetEraSummary::run(matches).await, matches), _ => { let _ = cli().print_long_help(); println!(); From fc7a099cb9301d93bc007f49e34d38047cf5954c Mon Sep 17 00:00:00 2001 From: Karan Dhareshwar Date: Fri, 14 Apr 2023 15:49:38 -0500 Subject: [PATCH 2/5] Add get-era-summary tests --- lib/lib.rs | 4 +--- lib/rpc.rs | 21 +++++++++++---------- src/get_era_summary.rs | 27 ++------------------------- src/main.rs | 2 +- tests/integration_test.rs | 35 +++++++++++++++++++++++++++++++++++ 5 files changed, 50 insertions(+), 39 deletions(-) diff --git a/lib/lib.rs b/lib/lib.rs index eecbf0cc..43d62cb6 100644 --- a/lib/lib.rs +++ b/lib/lib.rs @@ -29,11 +29,11 @@ use serde::{Deserialize, Serialize}; use casper_execution_engine::core::engine_state::ExecutableDeployItem; use casper_hashing::Digest; +use casper_node::rpcs::chain::{BlockIdentifier, EraSummary}; use casper_node::{ rpcs::state::{DictionaryIdentifier, GlobalStateIdentifier}, types::{BlockHash, Deploy}, }; -use casper_node::rpcs::chain::{BlockIdentifier, EraSummary}; use casper_types::{Key, ProtocolVersion}; pub use cl_type::help; @@ -1239,11 +1239,9 @@ pub struct GetEraSummaryResult { pub era_summary: EraSummary, } - /// "chain_get_era_summary" RPC pub struct GetEraSummary {} - /// When `verbosity_level` is `1`, the value will be printed to `stdout` with long string fields /// (e.g. hex-formatted raw Wasm bytes) shortened to a string indicating the char count of the /// field. When `verbosity_level` is greater than `1`, the value will be printed to `stdout` with diff --git a/lib/rpc.rs b/lib/rpc.rs index ae221ce5..d14e49d6 100644 --- a/lib/rpc.rs +++ b/lib/rpc.rs @@ -4,7 +4,7 @@ use async_trait::async_trait; use jsonrpc_lite::{Id, JsonRpc, Params}; use rand::Rng; use reqwest::Client; -use serde::{Serialize, Serializer}; +use serde::Serialize; use serde_json::{json, Map, Value}; use casper_execution_engine::core::engine_state::ExecutableDeployItem; @@ -30,7 +30,13 @@ use casper_node::{ }; use casper_types::{AsymmetricType, Key, PublicKey, URef}; -use crate::{deploy::{DeployExt, DeployParams, SendDeploy, Transfer}, error::{Error, Result}, validation, DictionaryItemStrParams, GlobalStateStrParams, GetEraSummary, GetEraSummaryParams}; +use crate::{ + deploy::{DeployExt, DeployParams, SendDeploy, Transfer}, + error::{Error, Result}, + validation, DictionaryItemStrParams, GetEraSummary, GetEraSummaryParams, GlobalStateStrParams, +}; + +pub(crate) const GET_ERA_SUMMARY_METHOD: &str = "chain_get_era_summary"; /// Struct representing a single JSON-RPC call to the casper node. #[derive(Debug)] @@ -184,10 +190,7 @@ impl RpcCall { Ok(response) } - pub(crate) async fn get_era_summary( - self, - maybe_block_identifier: &str, - ) -> Result { + pub(crate) async fn get_era_summary(self, maybe_block_identifier: &str) -> Result { let response = match Self::block_identifier(maybe_block_identifier)? { None => GetEraSummary::request(self).await, Some(block_identifier) => { @@ -198,8 +201,6 @@ impl RpcCall { Ok(response) } - - pub(crate) async fn get_auction_info(self, maybe_block_identifier: &str) -> Result { let response = match Self::block_identifier(maybe_block_identifier)? { None => GetAuctionInfo::request(self).await, @@ -492,7 +493,7 @@ impl RpcClient for GetValidatorChanges { } impl RpcClient for GetEraSummary { - const RPC_METHOD: &'static str = "chain_get_era_summary"; + const RPC_METHOD: &'static str = GET_ERA_SUMMARY_METHOD; } pub(crate) trait IntoJsonMap: Serialize { @@ -520,4 +521,4 @@ impl IntoJsonMap for GetAuctionInfoParams {} impl IntoJsonMap for GetAccountInfoParams {} impl IntoJsonMap for GetDictionaryItemParams {} impl IntoJsonMap for QueryGlobalStateParams {} -impl IntoJsonMap for GetEraSummaryParams {} \ No newline at end of file +impl IntoJsonMap for GetEraSummaryParams {} diff --git a/src/get_era_summary.rs b/src/get_era_summary.rs index ef5b5754..47e49834 100644 --- a/src/get_era_summary.rs +++ b/src/get_era_summary.rs @@ -2,21 +2,16 @@ use std::str; use async_trait::async_trait; use clap::{App, ArgMatches, SubCommand}; -use serde::{Serialize, Deserialize}; use casper_client::{Error, GetEraSummary}; -use casper_types::ProtocolVersion; use crate::{command::ClientCommand, common, Success}; - - - enum DisplayOrder { Verbose, NodeAddress, RpcId, - BlockIdentifier + BlockIdentifier, } #[async_trait] @@ -44,26 +39,8 @@ impl<'a, 'b> ClientCommand<'a, 'b> for GetEraSummary { let verbosity_level = common::verbose::get(matches); let maybe_block_id = common::block_identifier::get(matches); - casper_client::get_era_summary( - maybe_rpc_id, - node_address, - verbosity_level, - maybe_block_id, - ) + casper_client::get_era_summary(maybe_rpc_id, node_address, verbosity_level, maybe_block_id) .await .map(Success::from) } - - - - } - - - - - - - - - diff --git a/src/main.rs b/src/main.rs index 1bc1d0a6..568b472f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,11 +10,11 @@ mod get_auction_info; mod get_balance; mod get_dictionary_item; mod get_era_info_by_switch_block; +mod get_era_summary; mod get_state_hash; mod get_validator_changes; mod keygen; mod query_global_state; -mod get_era_summary; use std::process; diff --git a/tests/integration_test.rs b/tests/integration_test.rs index 8db679bf..8dde8d35 100644 --- a/tests/integration_test.rs +++ b/tests/integration_test.rs @@ -236,6 +236,12 @@ impl MockServerHandle { .await .map(|_| ()) } + + async fn get_era_summary(&self, maybe_block_id: &str) -> Result<(), Error> { + casper_client::get_era_summary("1", &self.url(), 0, maybe_block_id) + .await + .map(|_| ()) + } } impl Drop for MockServerHandle { @@ -857,6 +863,35 @@ mod get_validator_changes { } } +mod get_era_summary { + use super::*; + + use casper_client::GetEraSummaryParams; + + const METHOD: &str = "chain_get_era_summary"; + + #[tokio::test(flavor = "multi_thread")] + async fn should_succeed_without_params() { + let server_handle = MockServerHandle::spawn_without_params(METHOD); + assert!(matches!(server_handle.get_era_summary("").await, Ok(()))) + } + + #[tokio::test(flavor = "multi_thread")] + async fn should_success_with_valid_block_hash() { + let server_handle = MockServerHandle::spawn::(METHOD); + assert!(matches!( + server_handle.get_era_summary(VALID_STATE_ROOT_HASH).await, + Ok(()) + )) + } + + #[tokio::test(flavor = "multi_thread")] + async fn should_succeed_with_valid_block_height() { + let server_handle = MockServerHandle::spawn::(METHOD); + assert!(matches!(server_handle.get_era_summary("1").await, Ok(()))) + } +} + mod make_deploy { use super::*; From e726fb37fdb86d9bc61fa0c3b9de2bdcef6d3dff Mon Sep 17 00:00:00 2001 From: Karan Dhareshwar Date: Thu, 20 Apr 2023 09:13:27 -0500 Subject: [PATCH 3/5] Pin casper dep versions --- Cargo.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ddb10e7e..02d31d1b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,10 +24,10 @@ doc = false async-trait = "0.1.51" base16 = "0.2.1" base64 = "0.13.0" -casper-execution-engine = "3.0.0" -casper-node = "1.4.5" -casper-hashing = "1.4.3" -casper-types = "1.5.0" +casper-execution-engine = "=3.0.0" +casper-node = "=1.4.13" +casper-hashing = "=1.4.3" +casper-types = "=1.5.0" clap = "2" humantime = "2" jsonrpc-lite = "0.5.0" From 8dce353e7b209c7e217437550220cfa959991836 Mon Sep 17 00:00:00 2001 From: Karan Dhareshwar Date: Thu, 20 Apr 2023 09:30:27 -0500 Subject: [PATCH 4/5] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1270beaf..114706cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,11 @@ All notable changes to this project will be documented in this file. The format ## [Unreleased] +### Add +* Added a new subcommand `get-era-summary` which optionally takes a block identifier and returns an era summary from a Casper network +### Changed +* Update dependencies. ## [1.5.1] - 2023-03-08 From 90222247793a3703662c8f83986b83cd79ef0c25 Mon Sep 17 00:00:00 2001 From: Joe Sacher <321623+sacherjj@users.noreply.github.com> Date: Fri, 21 Apr 2023 16:10:13 -0400 Subject: [PATCH 5/5] Update CHANGELOG.md Small change to kick CI. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 114706cd..826012c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ All notable changes to this project will be documented in this file. The format ## [Unreleased] ### Add -* Added a new subcommand `get-era-summary` which optionally takes a block identifier and returns an era summary from a Casper network +* Added a new subcommand `get-era-summary` which optionally takes a block identifier and returns an era summary from a Casper network. ### Changed * Update dependencies.