#![doc(
html_root_url = "https://docs.rs/casper-client/1.5.0",
html_favicon_url = "https://raw.githubusercontent.com/CasperLabs/casper-node/master/images/CasperLabs_Logo_Favicon_RGB_50px.png",
html_logo_url = "https://raw.githubusercontent.com/CasperLabs/casper-node/master/images/CasperLabs_Logo_Symbol_RGB.png",
test(attr(forbid(warnings)))
)]
#![warn(
missing_docs,
trivial_casts,
trivial_numeric_casts,
unused_qualifications
)]
mod cl_type;
mod deploy;
mod error;
#[cfg(feature = "ffi")]
pub mod ffi;
pub mod keygen;
mod parsing;
mod rpc;
mod validation;
use std::{convert::TryInto, fs, io::Cursor};
use jsonrpc_lite::JsonRpc;
use serde::Serialize;
use casper_execution_engine::core::engine_state::ExecutableDeployItem;
use casper_hashing::Digest;
use casper_node::{
rpcs::state::{DictionaryIdentifier, GlobalStateIdentifier},
types::{BlockHash, Deploy},
};
use casper_types::Key;
pub use cl_type::help;
pub use deploy::ListDeploysResult;
use deploy::{DeployExt, DeployParams, OutputKind};
pub use error::Error;
use error::Result;
pub use rpc::map_hashing_error;
use rpc::RpcCall;
pub use validation::ValidateResponseError;
pub async fn put_deploy(
maybe_rpc_id: &str,
node_address: &str,
verbosity_level: u64,
deploy_params: DeployStrParams<'_>,
session_params: SessionStrParams<'_>,
payment_params: PaymentStrParams<'_>,
) -> Result<JsonRpc> {
let deploy = Deploy::with_payment_and_session(
deploy_params.try_into()?,
payment_params.try_into()?,
session_params.try_into()?,
)?;
RpcCall::new(maybe_rpc_id, node_address, verbosity_level)
.put_deploy(deploy)
.await
}
pub fn make_deploy(
maybe_output_path: &str,
deploy_params: DeployStrParams<'_>,
session_params: SessionStrParams<'_>,
payment_params: PaymentStrParams<'_>,
force: bool,
) -> Result<()> {
let output = if maybe_output_path.is_empty() {
OutputKind::Stdout
} else {
OutputKind::file(maybe_output_path, force)
};
Deploy::with_payment_and_session(
deploy_params.try_into()?,
payment_params.try_into()?,
session_params.try_into()?,
)?
.write_deploy(output.get()?)?;
output.commit()
}
pub fn sign_deploy_file(
input_path: &str,
secret_key: &str,
maybe_output_path: &str,
force: bool,
) -> Result<()> {
let secret_key = parsing::secret_key(secret_key)?;
let input = fs::read(input_path).map_err(|error| Error::IoError {
context: format!("unable to read deploy file at '{}'", input_path),
error,
})?;
let output = if maybe_output_path.is_empty() {
OutputKind::Stdout
} else {
OutputKind::file(maybe_output_path, force)
};
Deploy::sign_and_write_deploy(Cursor::new(input), secret_key, output.get()?)?;
output.commit()
}
pub async fn send_deploy_file(
maybe_rpc_id: &str,
node_address: &str,
verbosity_level: u64,
input_path: &str,
) -> Result<JsonRpc> {
RpcCall::new(maybe_rpc_id, node_address, verbosity_level)
.send_deploy_file(input_path)
.await
}
#[allow(clippy::too_many_arguments)]
pub async fn transfer(
maybe_rpc_id: &str,
node_address: &str,
verbosity_level: u64,
amount: &str,
target_account: &str,
transfer_id: &str,
deploy_params: DeployStrParams<'_>,
payment_params: PaymentStrParams<'_>,
) -> Result<JsonRpc> {
RpcCall::new(maybe_rpc_id, node_address, verbosity_level)
.transfer(
amount,
None,
target_account,
transfer_id,
deploy_params.try_into()?,
payment_params.try_into()?,
)
.await
}
pub fn make_transfer(
maybe_output_path: &str,
amount: &str,
target_account: &str,
transfer_id: &str,
deploy_params: DeployStrParams<'_>,
payment_params: PaymentStrParams<'_>,
force: bool,
) -> Result<()> {
let output = if maybe_output_path.is_empty() {
OutputKind::Stdout
} else {
OutputKind::file(maybe_output_path, force)
};
Deploy::new_transfer(
amount,
None,
target_account,
transfer_id,
deploy_params.try_into()?,
payment_params.try_into()?,
)?
.write_deploy(output.get()?)?;
output.commit()
}
pub async fn get_deploy(
maybe_rpc_id: &str,
node_address: &str,
verbosity_level: u64,
deploy_hash: &str,
) -> Result<JsonRpc> {
RpcCall::new(maybe_rpc_id, node_address, verbosity_level)
.get_deploy(deploy_hash)
.await
}
pub async fn get_block(
maybe_rpc_id: &str,
node_address: &str,
verbosity_level: u64,
maybe_block_id: &str,
) -> Result<JsonRpc> {
RpcCall::new(maybe_rpc_id, node_address, verbosity_level)
.get_block(maybe_block_id)
.await
}
pub async fn get_block_transfers(
maybe_rpc_id: &str,
node_address: &str,
verbosity_level: u64,
maybe_block_id: &str,
) -> Result<JsonRpc> {
RpcCall::new(maybe_rpc_id, node_address, verbosity_level)
.get_block_transfers(maybe_block_id)
.await
}
pub async fn get_state_root_hash(
maybe_rpc_id: &str,
node_address: &str,
verbosity_level: u64,
maybe_block_id: &str,
) -> Result<JsonRpc> {
RpcCall::new(maybe_rpc_id, node_address, verbosity_level)
.get_state_root_hash(maybe_block_id)
.await
}
#[deprecated(note = "Users should use `casper_client::query_global_state` instead.")]
pub async fn get_item(
maybe_rpc_id: &str,
node_address: &str,
verbosity_level: u64,
state_root_hash: &str,
key: &str,
path: &str,
) -> Result<JsonRpc> {
RpcCall::new(maybe_rpc_id, node_address, verbosity_level)
.get_item(state_root_hash, key, path)
.await
}
pub async fn get_balance(
maybe_rpc_id: &str,
node_address: &str,
verbosity_level: u64,
state_root_hash: &str,
purse: &str,
) -> Result<JsonRpc> {
RpcCall::new(maybe_rpc_id, node_address, verbosity_level)
.get_balance(state_root_hash, purse)
.await
}
pub async fn get_era_info_by_switch_block(
maybe_rpc_id: &str,
node_address: &str,
verbosity_level: u64,
maybe_block_id: &str,
) -> Result<JsonRpc> {
RpcCall::new(maybe_rpc_id, node_address, verbosity_level)
.get_era_info_by_switch_block(maybe_block_id)
.await
}
pub async fn get_auction_info(
maybe_rpc_id: &str,
node_address: &str,
verbosity_level: u64,
maybe_block_id: &str,
) -> Result<JsonRpc> {
RpcCall::new(maybe_rpc_id, node_address, verbosity_level)
.get_auction_info(maybe_block_id)
.await
}
pub async fn get_account_info(
maybe_rpc_id: &str,
node_address: &str,
verbosity_level: u64,
public_key: &str,
maybe_block_id: &str,
) -> Result<JsonRpc> {
RpcCall::new(maybe_rpc_id, node_address, verbosity_level)
.get_account_info(public_key, maybe_block_id)
.await
}
pub async fn query_global_state(
maybe_rpc_id: &str,
node_address: &str,
verbosity_level: u64,
global_state_str_params: GlobalStateStrParams<'_>,
key: &str,
path: &str,
) -> Result<JsonRpc> {
RpcCall::new(maybe_rpc_id, node_address, verbosity_level)
.query_global_state(global_state_str_params, key, path)
.await
}
pub async fn list_rpcs(
maybe_rpc_id: &str,
node_address: &str,
verbosity_level: u64,
) -> Result<JsonRpc> {
RpcCall::new(maybe_rpc_id, node_address, verbosity_level)
.list_rpcs()
.await
}
pub async fn get_dictionary_item(
maybe_rpc_id: &str,
node_address: &str,
verbosity_level: u64,
state_root_hash: &str,
dictionary_str_params: DictionaryItemStrParams<'_>,
) -> Result<JsonRpc> {
RpcCall::new(maybe_rpc_id, node_address, verbosity_level)
.get_dictionary_item(state_root_hash, dictionary_str_params)
.await
}
pub async fn get_validator_changes(
maybe_rpc_id: &str,
node_address: &str,
verbosity_level: u64,
) -> Result<JsonRpc> {
RpcCall::new(maybe_rpc_id, node_address, verbosity_level)
.get_validator_changes()
.await
}
#[derive(Default, Debug)]
pub struct DeployStrParams<'a> {
pub secret_key: &'a str,
pub timestamp: &'a str,
pub ttl: &'a str,
pub gas_price: &'a str,
pub dependencies: Vec<&'a str>,
pub chain_name: &'a str,
pub session_account: &'a str,
}
impl<'a> TryInto<DeployParams> for DeployStrParams<'a> {
type Error = Error;
fn try_into(self) -> Result<DeployParams> {
let DeployStrParams {
secret_key,
timestamp,
ttl,
gas_price,
dependencies,
chain_name,
session_account,
} = self;
parsing::parse_deploy_params(
secret_key,
timestamp,
ttl,
gas_price,
&dependencies,
chain_name,
session_account,
)
}
}
#[derive(Default)]
pub struct PaymentStrParams<'a> {
payment_amount: &'a str,
payment_hash: &'a str,
payment_name: &'a str,
payment_package_hash: &'a str,
payment_package_name: &'a str,
payment_path: &'a str,
payment_args_simple: Vec<&'a str>,
payment_args_complex: &'a str,
payment_version: &'a str,
payment_entry_point: &'a str,
}
impl<'a> TryInto<ExecutableDeployItem> for PaymentStrParams<'a> {
type Error = Error;
fn try_into(self) -> Result<ExecutableDeployItem> {
parsing::parse_payment_info(self)
}
}
impl<'a> PaymentStrParams<'a> {
pub fn with_path(
payment_path: &'a str,
payment_args_simple: Vec<&'a str>,
payment_args_complex: &'a str,
) -> Self {
Self {
payment_path,
payment_args_simple,
payment_args_complex,
..Default::default()
}
}
pub fn with_amount(payment_amount: &'a str) -> Self {
Self {
payment_amount,
..Default::default()
}
}
pub fn with_name(
payment_name: &'a str,
payment_entry_point: &'a str,
payment_args_simple: Vec<&'a str>,
payment_args_complex: &'a str,
) -> Self {
Self {
payment_name,
payment_args_simple,
payment_args_complex,
payment_entry_point,
..Default::default()
}
}
pub fn with_hash(
payment_hash: &'a str,
payment_entry_point: &'a str,
payment_args_simple: Vec<&'a str>,
payment_args_complex: &'a str,
) -> Self {
Self {
payment_hash,
payment_args_simple,
payment_args_complex,
payment_entry_point,
..Default::default()
}
}
pub fn with_package_name(
payment_package_name: &'a str,
payment_version: &'a str,
payment_entry_point: &'a str,
payment_args_simple: Vec<&'a str>,
payment_args_complex: &'a str,
) -> Self {
Self {
payment_package_name,
payment_args_simple,
payment_args_complex,
payment_version,
payment_entry_point,
..Default::default()
}
}
pub fn with_package_hash(
payment_package_hash: &'a str,
payment_version: &'a str,
payment_entry_point: &'a str,
payment_args_simple: Vec<&'a str>,
payment_args_complex: &'a str,
) -> Self {
Self {
payment_package_hash,
payment_args_simple,
payment_args_complex,
payment_version,
payment_entry_point,
..Default::default()
}
}
}
impl<'a> TryInto<ExecutableDeployItem> for SessionStrParams<'a> {
type Error = Error;
fn try_into(self) -> Result<ExecutableDeployItem> {
parsing::parse_session_info(self)
}
}
#[derive(Default)]
pub struct SessionStrParams<'a> {
session_hash: &'a str,
session_name: &'a str,
session_package_hash: &'a str,
session_package_name: &'a str,
session_path: &'a str,
session_args_simple: Vec<&'a str>,
session_args_complex: &'a str,
session_version: &'a str,
session_entry_point: &'a str,
is_session_transfer: bool,
}
impl<'a> SessionStrParams<'a> {
pub fn with_path(
session_path: &'a str,
session_args_simple: Vec<&'a str>,
session_args_complex: &'a str,
) -> Self {
Self {
session_path,
session_args_simple,
session_args_complex,
..Default::default()
}
}
pub fn with_name(
session_name: &'a str,
session_entry_point: &'a str,
session_args_simple: Vec<&'a str>,
session_args_complex: &'a str,
) -> Self {
Self {
session_name,
session_args_simple,
session_args_complex,
session_entry_point,
..Default::default()
}
}
pub fn with_hash(
session_hash: &'a str,
session_entry_point: &'a str,
session_args_simple: Vec<&'a str>,
session_args_complex: &'a str,
) -> Self {
Self {
session_hash,
session_args_simple,
session_args_complex,
session_entry_point,
..Default::default()
}
}
pub fn with_package_name(
session_package_name: &'a str,
session_version: &'a str,
session_entry_point: &'a str,
session_args_simple: Vec<&'a str>,
session_args_complex: &'a str,
) -> Self {
Self {
session_package_name,
session_args_simple,
session_args_complex,
session_version,
session_entry_point,
..Default::default()
}
}
pub fn with_package_hash(
session_package_hash: &'a str,
session_version: &'a str,
session_entry_point: &'a str,
session_args_simple: Vec<&'a str>,
session_args_complex: &'a str,
) -> Self {
Self {
session_package_hash,
session_args_simple,
session_args_complex,
session_version,
session_entry_point,
..Default::default()
}
}
pub fn with_transfer(session_args_simple: Vec<&'a str>, session_args_complex: &'a str) -> Self {
Self {
is_session_transfer: true,
session_args_simple,
session_args_complex,
..Default::default()
}
}
}
pub enum DictionaryItemStrParams<'a> {
AccountNamedKey {
key: &'a str,
dictionary_name: &'a str,
dictionary_item_key: &'a str,
},
ContractNamedKey {
key: &'a str,
dictionary_name: &'a str,
dictionary_item_key: &'a str,
},
URef {
seed_uref: &'a str,
dictionary_item_key: &'a str,
},
Dictionary(&'a str),
}
impl<'a> TryInto<DictionaryIdentifier> for DictionaryItemStrParams<'a> {
type Error = Error;
fn try_into(self) -> Result<DictionaryIdentifier> {
match self {
DictionaryItemStrParams::AccountNamedKey {
key,
dictionary_item_key,
dictionary_name,
} => {
let key = Key::from_formatted_str(key)
.map_err(|_| Error::FailedToParseDictionaryIdentifier)?;
Ok(DictionaryIdentifier::AccountNamedKey {
key: key.to_formatted_string(),
dictionary_name: dictionary_name.to_string(),
dictionary_item_key: dictionary_item_key.to_string(),
})
}
DictionaryItemStrParams::ContractNamedKey {
key,
dictionary_item_key,
dictionary_name,
} => {
let key = Key::from_formatted_str(key)
.map_err(|_| Error::FailedToParseDictionaryIdentifier)?;
Ok(DictionaryIdentifier::ContractNamedKey {
key: key.to_formatted_string(),
dictionary_name: dictionary_name.to_string(),
dictionary_item_key: dictionary_item_key.to_string(),
})
}
DictionaryItemStrParams::URef {
seed_uref,
dictionary_item_key,
} => {
let uref = Key::from_formatted_str(seed_uref)
.map_err(|_| Error::FailedToParseDictionaryIdentifier)?;
Ok(DictionaryIdentifier::URef {
seed_uref: uref.to_formatted_string(),
dictionary_item_key: dictionary_item_key.to_string(),
})
}
DictionaryItemStrParams::Dictionary(dictionary_key) => {
let dictionary_key = Key::from_formatted_str(dictionary_key)
.map_err(|_| Error::FailedToParseDictionaryIdentifier)?;
Ok(DictionaryIdentifier::Dictionary(
dictionary_key.to_formatted_string(),
))
}
}
}
}
#[derive(Default, Debug)]
pub struct GlobalStateStrParams<'a> {
pub is_block_hash: bool,
pub hash_value: &'a str,
}
impl<'a> TryInto<GlobalStateIdentifier> for GlobalStateStrParams<'a> {
type Error = Error;
fn try_into(self) -> Result<GlobalStateIdentifier> {
let hash = Digest::from_hex(self.hash_value)
.map_err(|error| map_hashing_error(error)("global_state_identifier"))?;
if self.is_block_hash {
Ok(GlobalStateIdentifier::BlockHash(BlockHash::new(hash)))
} else {
Ok(GlobalStateIdentifier::StateRootHash(hash))
}
}
}
pub fn pretty_print_at_level<T: ?Sized + Serialize>(value: &T, verbosity_level: u64) {
match verbosity_level {
0 => (),
1 => {
println!(
"{}",
casper_types::json_pretty_print(value).expect("should encode to JSON")
);
}
_ => {
println!(
"{}",
serde_json::to_string_pretty(value).expect("should encode to JSON")
);
}
}
}
#[cfg(test)]
mod param_tests {
use super::*;
const HASH: &str = "09dcee4b212cfd53642ab323fbef07dafafc6f945a80a00147f62910a915c4e6";
const NAME: &str = "name";
const PKG_NAME: &str = "pkg_name";
const PKG_HASH: &str = "09dcee4b212cfd53642ab323fbef07dafafc6f945a80a00147f62910a915c4e6";
const ENTRYPOINT: &str = "entrypoint";
const VERSION: &str = "0.1.0";
fn args_simple() -> Vec<&'static str> {
vec!["name_01:bool='false'", "name_02:u32='42'"]
}
mod session_params {
use std::collections::BTreeMap;
use casper_types::CLValue;
use super::*;
#[test]
pub fn with_hash() {
let params: Result<ExecutableDeployItem> =
SessionStrParams::with_hash(HASH, ENTRYPOINT, args_simple(), "").try_into();
match params {
Ok(item @ ExecutableDeployItem::StoredContractByHash { .. }) => {
let actual: BTreeMap<String, CLValue> = item.args().clone().into();
let mut expected = BTreeMap::new();
expected.insert("name_01".to_owned(), CLValue::from_t(false).unwrap());
expected.insert("name_02".to_owned(), CLValue::from_t(42u32).unwrap());
assert_eq!(actual, expected);
}
other => panic!("incorrect type parsed {:?}", other),
}
}
#[test]
pub fn with_name() {
let params: Result<ExecutableDeployItem> =
SessionStrParams::with_name(NAME, ENTRYPOINT, args_simple(), "").try_into();
match params {
Ok(item @ ExecutableDeployItem::StoredContractByName { .. }) => {
let actual: BTreeMap<String, CLValue> = item.args().clone().into();
let mut expected = BTreeMap::new();
expected.insert("name_01".to_owned(), CLValue::from_t(false).unwrap());
expected.insert("name_02".to_owned(), CLValue::from_t(42u32).unwrap());
assert_eq!(actual, expected);
}
other => panic!("incorrect type parsed {:?}", other),
}
}
#[test]
pub fn with_package_name() {
let params: Result<ExecutableDeployItem> = SessionStrParams::with_package_name(
PKG_NAME,
VERSION,
ENTRYPOINT,
args_simple(),
"",
)
.try_into();
match params {
Ok(item @ ExecutableDeployItem::StoredVersionedContractByName { .. }) => {
let actual: BTreeMap<String, CLValue> = item.args().clone().into();
let mut expected = BTreeMap::new();
expected.insert("name_01".to_owned(), CLValue::from_t(false).unwrap());
expected.insert("name_02".to_owned(), CLValue::from_t(42u32).unwrap());
assert_eq!(actual, expected);
}
other => panic!("incorrect type parsed {:?}", other),
}
}
#[test]
pub fn with_package_hash() {
let params: Result<ExecutableDeployItem> = SessionStrParams::with_package_hash(
PKG_HASH,
VERSION,
ENTRYPOINT,
args_simple(),
"",
)
.try_into();
match params {
Ok(item @ ExecutableDeployItem::StoredVersionedContractByHash { .. }) => {
let actual: BTreeMap<String, CLValue> = item.args().clone().into();
let mut expected = BTreeMap::new();
expected.insert("name_01".to_owned(), CLValue::from_t(false).unwrap());
expected.insert("name_02".to_owned(), CLValue::from_t(42u32).unwrap());
assert_eq!(actual, expected);
}
other => panic!("incorrect type parsed {:?}", other),
}
}
}
mod payment_params {
use std::collections::BTreeMap;
use casper_types::{CLValue, U512};
use super::*;
#[test]
pub fn with_amount() {
let params: Result<ExecutableDeployItem> =
PaymentStrParams::with_amount("100").try_into();
match params {
Ok(item @ ExecutableDeployItem::ModuleBytes { .. }) => {
let amount = CLValue::from_t(U512::from(100)).unwrap();
assert_eq!(item.args().get("amount"), Some(&amount));
}
other => panic!("incorrect type parsed {:?}", other),
}
}
#[test]
pub fn with_hash() {
let params: Result<ExecutableDeployItem> =
PaymentStrParams::with_hash(HASH, ENTRYPOINT, args_simple(), "").try_into();
match params {
Ok(item @ ExecutableDeployItem::StoredContractByHash { .. }) => {
let actual: BTreeMap<String, CLValue> = item.args().clone().into();
let mut expected = BTreeMap::new();
expected.insert("name_01".to_owned(), CLValue::from_t(false).unwrap());
expected.insert("name_02".to_owned(), CLValue::from_t(42u32).unwrap());
assert_eq!(actual, expected);
}
other => panic!("incorrect type parsed {:?}", other),
}
}
#[test]
pub fn with_name() {
let params: Result<ExecutableDeployItem> =
PaymentStrParams::with_name(NAME, ENTRYPOINT, args_simple(), "").try_into();
match params {
Ok(item @ ExecutableDeployItem::StoredContractByName { .. }) => {
let actual: BTreeMap<String, CLValue> = item.args().clone().into();
let mut expected = BTreeMap::new();
expected.insert("name_01".to_owned(), CLValue::from_t(false).unwrap());
expected.insert("name_02".to_owned(), CLValue::from_t(42u32).unwrap());
assert_eq!(actual, expected);
}
other => panic!("incorrect type parsed {:?}", other),
}
}
#[test]
pub fn with_package_name() {
let params: Result<ExecutableDeployItem> = PaymentStrParams::with_package_name(
PKG_NAME,
VERSION,
ENTRYPOINT,
args_simple(),
"",
)
.try_into();
match params {
Ok(item @ ExecutableDeployItem::StoredVersionedContractByName { .. }) => {
let actual: BTreeMap<String, CLValue> = item.args().clone().into();
let mut expected = BTreeMap::new();
expected.insert("name_01".to_owned(), CLValue::from_t(false).unwrap());
expected.insert("name_02".to_owned(), CLValue::from_t(42u32).unwrap());
assert_eq!(actual, expected);
}
other => panic!("incorrect type parsed {:?}", other),
}
}
#[test]
pub fn with_package_hash() {
let params: Result<ExecutableDeployItem> = PaymentStrParams::with_package_hash(
PKG_HASH,
VERSION,
ENTRYPOINT,
args_simple(),
"",
)
.try_into();
match params {
Ok(item @ ExecutableDeployItem::StoredVersionedContractByHash { .. }) => {
let actual: BTreeMap<String, CLValue> = item.args().clone().into();
let mut expected = BTreeMap::new();
expected.insert("name_01".to_owned(), CLValue::from_t(false).unwrap());
expected.insert("name_02".to_owned(), CLValue::from_t(42u32).unwrap());
assert_eq!(actual, expected);
}
other => panic!("incorrect type parsed {:?}", other),
}
}
}
mod deploy_str_params {
use humantime::{DurationError, TimestampError};
use super::*;
use std::{convert::TryInto, result::Result as StdResult};
use crate::DeployStrParams;
fn test_value() -> DeployStrParams<'static> {
DeployStrParams {
secret_key: "resources/test.pem",
ttl: "10s",
chain_name: "casper-test-chain-name-1",
gas_price: "1",
..Default::default()
}
}
#[test]
fn should_convert_into_deploy_params() {
let deploy_params: StdResult<DeployParams, _> = test_value().try_into();
assert!(deploy_params.is_ok());
}
#[test]
fn should_fail_to_convert_with_bad_timestamp() {
let mut params = test_value();
params.timestamp = "garbage";
let result: StdResult<DeployParams, Error> = params.try_into();
assert!(matches!(
result,
Err(Error::FailedToParseTimestamp {
context: "timestamp",
error: TimestampError::InvalidFormat
})
));
}
#[test]
fn should_fail_to_convert_with_bad_gas_price() {
let mut params = test_value();
params.gas_price = "fifteen";
let result: StdResult<DeployParams, Error> = params.try_into();
let result = result.map(|_| ());
if let Err(Error::FailedToParseInt { context, error: _ }) = result {
assert_eq!(context, "gas_price");
} else {
panic!("should be an error");
}
}
#[test]
fn should_fail_to_convert_with_bad_chain_name() {
let mut params = test_value();
params.chain_name = "";
let result: StdResult<DeployParams, Error> = params.try_into();
assert!(matches!(result, Ok(_)));
}
#[test]
fn should_fail_to_convert_with_bad_ttl() {
let mut params = test_value();
params.ttl = "not_a_ttl";
let result: StdResult<DeployParams, Error> = params.try_into();
assert!(matches!(
result,
Err(Error::FailedToParseTimeDiff {
context: "ttl",
error: DurationError::NumberExpected(0)
})
));
}
#[test]
fn should_fail_to_convert_with_bad_secret_key_path() {
let mut params = test_value();
params.secret_key = "";
let result: StdResult<DeployParams, Error> = params.try_into();
if let Err(Error::CryptoError { context, .. }) = result {
assert_eq!(context, "secret_key");
} else {
panic!("should be an error")
}
}
#[test]
fn should_fail_to_convert_with_bad_dependencies() {
use casper_node::crypto::Error as CryptoError;
let mut params = test_value();
params.dependencies = vec!["invalid dep"];
let result: StdResult<DeployParams, Error> = params.try_into();
assert!(matches!(
result,
Err(Error::CryptoError {
context: "dependencies",
error: CryptoError::FromHex(base16::DecodeError::InvalidLength { length: 11 })
})
));
}
}
}