diff --git a/cli/src/commands/ledger.rs b/cli/src/commands/ledger.rs index b82bb5aee7..da47f4ca46 100644 --- a/cli/src/commands/ledger.rs +++ b/cli/src/commands/ledger.rs @@ -2042,6 +2042,89 @@ pub mod get_acceptance_mechanisms_command { } } +pub mod ledgers_freeze_command { + use super::*; + + command!(CommandMetadata::build("ledgers-freeze", r#"Freeze ledgers"#) + .add_required_param("ledgers_ids", "List of ledgers IDs for freezing.") + .add_example("ledger ledgers-freeze ledgers_ids=1,2,3") + .finalize() + ); + + fn execute(ctx: &CommandContext, params: &CommandParams) -> Result<(), ()> { + trace!("execute >> ctx {:?} params {:?}", ctx, params); + let ledgers_ids = get_number_tuple_array_param("ledgers_ids", params); + let submitter_did = ensure_active_did(&ctx)?; + let (wallet_handle, wallet_name) = ensure_opened_wallet(&ctx)?; + + let request = Ledger::build_ledgers_freeze_request(&submitter_did, ledgers_ids?) + .map_err(|err| handle_indy_error(err, None, None, None))?; + + let (_, response) = send_write_request!(&ctx, params, &request, wallet_handle, &wallet_name, &submitter_did); + + let result = handle_transaction_response(response)?; + + println!("result {:?}", result); + + trace!("execute <<"); + Ok(()) + } +} + +pub mod get_frozen_ledgers_command { + use super::*; + + command!(CommandMetadata::build("get-frozen-ledgers", r#"Get a list of frozen ledgers"#) + .add_example("ledger get-frozen-ledgers") + .finalize() + ); + + fn execute(ctx: &CommandContext, params: &CommandParams) -> Result<(), ()> { + trace!("execute >> ctx {:?} params {:?}", ctx, params); + + let submitter_did = ensure_active_did(&ctx)?; + + let request = Ledger::build_get_frozen_ledgers_request(&submitter_did) + .map_err(|err| handle_indy_error(err, None, None, None))?; + + let (_, response) = send_read_request!(&ctx, params, &request, Some(&submitter_did)); + let handle_response = handle_transaction_response(response)?; + + // Flattering ap into vector + let handle_response = handle_response.as_object() + .expect("top level object is not a map"); + + let mut result = Vec::new(); + for (response_ledger_key, response_ledger_value) in handle_response { + let mut ledger_info = response_ledger_value.as_object() + .expect("inner object is not a map").clone(); + + let ledger_id = serde_json::to_value(&response_ledger_key) + .map_err(|_| println_err!("Invalid format of Outputs: Ledger ID is incorrect."))?; + ledger_info.insert("ledger_id".to_owned(), ledger_id); + + result.push(serde_json::to_value(&ledger_info) + .map_err(|_| println_err!("Invalid format of Outputs: result is incorrect."))?); + } + + print_frozen_ledgers(result)?; + trace!("execute <<"); + Ok(()) + } + + fn print_frozen_ledgers(frozen_ledgers: Vec) -> Result<(), ()> { + println_succ!("Frozen ledgers has been received."); + print_list_table(&frozen_ledgers, + &[("ledger_id", "Ledger id"), + ("ledger", "Ledger root hash"), + ("state", "State root hash"), + ("seq_no", "Last sequance number")], + "No frozen ledgers found."); + + Ok(()) + } +} + pub fn set_author_agreement(ctx: &CommandContext, request: &mut String) -> Result<(), ()> { if let Some((text, version, acc_mech_type, time_of_acceptance)) = get_transaction_author_info(&ctx) { if acc_mech_type.is_empty() { @@ -2251,6 +2334,8 @@ fn get_txn_title(role: &serde_json::Value) -> serde_json::Value { Some("5") => "TXN_AUTHR_AGRMT_AML", Some("6") => "GET_TXN_AUTHR_AGRMT", Some("7") => "GET_TXN_AUTHR_AGRMT_AML", + Some("9") => "LEDGERS_FREEZE", + Some("10") => "GET_FROZEN_LEDGERS", Some("100") => "ATTRIB", Some("101") => "SCHEMA", Some("104") => "GET_ATTR", @@ -5079,6 +5164,37 @@ pub mod tests { } } + mod frozen_ledgers { + use super::*; + + #[test] + pub fn ledgers_freeze() { + let ctx = setup(); + + { + let cmd = ledgers_freeze_command::new(); + let mut params = CommandParams::new(); + params.insert("ledgers_ids", "0,1,10,237".to_string()); + cmd.execute(&ctx, ¶ms).unwrap_err(); + } + + tear_down(); + } + + #[test] + pub fn get_frozen_ledgers() { + let ctx = setup(); + + { + let cmd = get_frozen_ledgers_command::new(); + let params = CommandParams::new(); + cmd.execute(&ctx, ¶ms).unwrap_err(); + } + + tear_down(); + } + } + fn _path() -> (::std::path::PathBuf, String) { let mut path = crate::utils::environment::EnvironmentUtils::indy_home_path(); path.push("transaction"); diff --git a/cli/src/commands/mod.rs b/cli/src/commands/mod.rs index 34f237c4e8..3f1a8fd607 100644 --- a/cli/src/commands/mod.rs +++ b/cli/src/commands/mod.rs @@ -166,6 +166,30 @@ pub fn get_str_tuple_array_param<'a>(name: &'a str, params: &'a CommandParams) - } } +pub fn get_number_tuple_array_param<'a>(name: &'a str, params: &'a CommandParams) -> Result, ()> { + match params.get(name) { + Some(v) if !v.is_empty() => { + let tuples: Vec<&str> = v.split(",").collect(); + if tuples.is_empty() { + println_err!("Parameter \"{}\" has invalid format", name); + Err(()) + } else { + let mut result: Vec = Vec::new(); + for item in tuples { + println!("{:?}",item); + result.push(item.parse::().map_err(|err| + println_err!("Can't parse number parameter \"{}\": value: \"{}\", err \"{}\"", name, item, err))?); + } + Ok(result) + } + } + _ => { + println_err!("No required \"{}\" parameter present", name); + Err(()) + } + } +} + pub fn get_opt_str_tuple_array_param<'a>(name: &'a str, params: &'a CommandParams) -> Result>, ()> { match params.get(name) { Some(v) => diff --git a/cli/src/libindy/ledger.rs b/cli/src/libindy/ledger.rs index dfca1c03ae..4b1e2e543e 100644 --- a/cli/src/libindy/ledger.rs +++ b/cli/src/libindy/ledger.rs @@ -147,4 +147,12 @@ impl Ledger { endorser_did: &str) -> Result { ledger::append_request_endorser(request_json, endorser_did).wait() } + + pub fn build_ledgers_freeze_request(submitter_did: &str, ledgers_ids: Vec) -> Result { + ledger::build_ledgers_freeze_request(submitter_did, ledgers_ids).wait() + } + + pub fn build_get_frozen_ledgers_request(submitter_did: &str) -> Result { + ledger::build_get_frozen_ledgers_request(submitter_did).wait() + } } \ No newline at end of file diff --git a/cli/src/main.rs b/cli/src/main.rs index 9881c49844..d66e5884c4 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -188,6 +188,8 @@ fn build_executor() -> CommandExecutor { .add_command(ledger::get_acceptance_mechanisms_command::new()) .add_command(ledger::endorse_transaction_command::new()) .add_command(ledger::taa_disable_all_command::new()) + .add_command(ledger::ledgers_freeze_command::new()) + .add_command(ledger::get_frozen_ledgers_command::new()) .finalize_group() .add_group(payment_address::group::new()) .add_command(payment_address::new_command::new()) diff --git a/experimental/plugins/postgres_storage/Cargo.toml b/experimental/plugins/postgres_storage/Cargo.toml index ad7d69339f..42ed839a1a 100644 --- a/experimental/plugins/postgres_storage/Cargo.toml +++ b/experimental/plugins/postgres_storage/Cargo.toml @@ -68,6 +68,7 @@ log-panics = "2.0.0" postgres = "0.15.2" r2d2 = "0.8.2" r2d2_postgres = "0.14.0" +percent-encoding = "2.1.0" [dependencies.uuid] version = "0.5.0" diff --git a/experimental/plugins/postgres_storage/src/postgres_storage.rs b/experimental/plugins/postgres_storage/src/postgres_storage.rs index 225f37482e..14e9b18ff4 100644 --- a/experimental/plugins/postgres_storage/src/postgres_storage.rs +++ b/experimental/plugins/postgres_storage/src/postgres_storage.rs @@ -2,6 +2,7 @@ extern crate owning_ref; extern crate sodiumoxide; extern crate r2d2; extern crate r2d2_postgres; +extern crate percent_encoding; use ::std::sync::RwLock; @@ -13,6 +14,8 @@ use self::owning_ref::OwningHandle; use std::rc::Rc; use std::time::Duration; +use self::percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC}; + use errors::wallet::WalletStorageError; use errors::common::CommonError; use wql::language; @@ -193,7 +196,7 @@ const _CREATE_SCHEMA_MULTI: [&str; 14] = [ ON UPDATE CASCADE )", "CREATE INDEX IF NOT EXISTS ix_tags_encrypted_name ON tags_encrypted(wallet_id, name)", - "CREATE INDEX IF NOT EXISTS ix_tags_encrypted_value ON tags_encrypted(wallet_id, value)", + "CREATE INDEX IF NOT EXISTS ix_tags_encrypted_value ON tags_encrypted(wallet_id, md5(value))", "CREATE INDEX IF NOT EXISTS ix_tags_encrypted_wallet_id_item_id ON tags_encrypted(wallet_id, item_id)", "CREATE TABLE IF NOT EXISTS tags_plaintext( wallet_id VARCHAR(64) NOT NULL, @@ -1037,11 +1040,12 @@ impl PostgresStorageType { } url_base.push_str(":"); match credentials.admin_password { - Some(ref password) => url_base.push_str(&password[..]), + Some(ref password) => url_base.push_str(&utf8_percent_encode(&password[..], &NON_ALPHANUMERIC).to_string()), None => () } url_base.push_str("@"); url_base.push_str(&config.url[..]); + url_base.push_str("/postgres"); url_base } @@ -1049,7 +1053,7 @@ impl PostgresStorageType { let mut url_base = "postgresql://".to_owned(); url_base.push_str(&credentials.account[..]); url_base.push_str(":"); - url_base.push_str(&credentials.password[..]); + url_base.push_str(&utf8_percent_encode(&credentials.password[..], &NON_ALPHANUMERIC).to_string()); url_base.push_str("@"); url_base.push_str(&config.url[..]); url_base diff --git a/libindy/Cargo.toml b/libindy/Cargo.toml index 4ad717b98b..2e50820eab 100644 --- a/libindy/Cargo.toml +++ b/libindy/Cargo.toml @@ -30,7 +30,7 @@ fatal_warnings = [] env_logger = "0.7" etcommon-rlp = "0.2.4" failure = "0.1.7" -hex = "0.3.2" +hex = "0.4.0" libc = "0.2.66" log = "0.4.8" log-derive = "0.3.0" @@ -41,8 +41,8 @@ rust-base58 = {version = "0.0.4", optional = true} serde = "1.0.99" serde_json = "1.0.40" serde_derive = "1.0.99" -sha2 = "0.8" -sha3 = "0.8" +sha2 = "0.9" +sha3 = "0.9" rmp-serde = "0.13.7" time = "0.1.42" threadpool = "1.7.1" @@ -133,4 +133,4 @@ depends = "libindy (= 1.16.0)" assets = [ ["include/*.h", "usr/include/indy/", "644"], ["target/release/libindy.a", "usr/lib/", "644"], -] \ No newline at end of file +] diff --git a/libindy/ci/centos.dockerfile b/libindy/ci/centos.dockerfile index 5abfaf930b..ad30e81328 100755 --- a/libindy/ci/centos.dockerfile +++ b/libindy/ci/centos.dockerfile @@ -63,13 +63,13 @@ RUN cd /usr/src && \ RUN yum install -y ncurses-devel RUN cd /tmp && \ - wget https://github.com/zeromq/libzmq/releases/download/v4.2.2/zeromq-4.2.2.tar.gz && \ - tar xfz zeromq-4.2.2.tar.gz && rm zeromq-4.2.2.tar.gz && \ - cd /tmp/zeromq-4.2.2 && \ + wget https://github.com/zeromq/libzmq/releases/download/v4.3.3/zeromq-4.3.3.tar.gz && \ + tar xfz zeromq-4.3.3.tar.gz && rm zeromq-4.3.3.tar.gz && \ + cd /tmp/zeromq-4.3.3 && \ ./configure && \ make && \ make install && \ - rm -rf /tmp/zeromq-4.2.2 + rm -rf /tmp/zeromq-4.3.3 RUN yum install fakeroot -y diff --git a/libindy/include/indy_ledger.h b/libindy/include/indy_ledger.h index ac530d1d43..01e5c50bfa 100644 --- a/libindy/include/indy_ledger.h +++ b/libindy/include/indy_ledger.h @@ -1256,6 +1256,57 @@ extern "C" { const char* request_json) ); + /// Builds a LEDGERS_FREEZE request. Request to freeze list of ledgers. + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// submitter_did: (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). + /// ledgers_ids: list of ledgers IDs for freezing ledgers (json format). + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + extern indy_error_t indy_build_ledgers_freeze_request(indy_handle_t command_handle, + const char * submitter_did, + const char * ledgers_ids, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_json) + ); + + /// Builds a GET_FROZEN_LEDGERS request. Request to get list of frozen ledgers. + /// frozen ledgers are defined by LEDGERS_FREEZE request. + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// submitter_did: (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// { + /// : { + /// "ledger": String - Ledger root hash, + /// "state": String - State root hash, + /// "seq_no": u64 - the latest transaction seqNo for particular Node, + /// }, + /// ... + /// } + /// + /// #Errors + /// Common* + extern indy_error_t indy_build_get_frozen_ledgers_request(indy_handle_t command_handle, + const char * submitter_did, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_json) + ); + /// Builds a GET_TXN_AUTHR_AGRMT_AML request. Request to get a list of acceptance mechanisms from the ledger /// valid for specified time or the latest one. /// diff --git a/libindy/src/api/ledger.rs b/libindy/src/api/ledger.rs index 9ce9e78873..fc1bc0872f 100644 --- a/libindy/src/api/ledger.rs +++ b/libindy/src/api/ledger.rs @@ -1792,6 +1792,91 @@ pub extern fn indy_get_response_metadata(command_handle: CommandHandle, res } +/// Builds a LEDGERS_FREEZE request. Request to freeze list of ledgers. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// submitter_did: (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). +/// ledgers_ids: list of ledgers IDs for freezing ledgers (json format). +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern fn indy_build_ledgers_freeze_request(command_handle: CommandHandle, + submitter_did: *const c_char, + ledgers_ids: *const c_char, + cb: Option) -> ErrorCode { + trace!("indy_build_ledgers_freeze_request: entities >>> submitter_did: {:?}, ledgers_ids: {:?}", submitter_did, ledgers_ids); + + check_useful_validatable_string!(submitter_did, ErrorCode::CommonInvalidParam2, DidValue); + check_useful_json!(ledgers_ids, ErrorCode::CommonInvalidParam3, Vec); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + let result = CommandExecutor::instance() + .send(Command::Ledger(LedgerCommand::BuildLedgersFreezeRequest( + submitter_did, + ledgers_ids, + boxed_callback_string!("indy_build_ledgers_freeze_request", cb, command_handle) + ))); + + let res = prepare_result!(result); + + trace!("indy_build_ledgers_freeze_request: <<< res: {:?}", res); + + res +} + +/// Builds a GET_FROZEN_LEDGERS request. Request to get list of frozen ledgers. +/// frozen ledgers are defined by LEDGERS_FREEZE request. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// submitter_did: (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// { +/// : { +/// "ledger": String - Ledger root hash, +/// "state": String - State root hash, +/// "seq_no": u64 - the latest transaction seqNo for particular Node, +/// }, +/// ... +/// } +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern fn indy_build_get_frozen_ledgers_request(command_handle: CommandHandle, + submitter_did: *const c_char, + cb: Option) -> ErrorCode { + trace!("indy_build_get_frozen_ledgers_request: entities >>> submitter_did: {:?}", submitter_did); + + check_useful_validatable_string!(submitter_did, ErrorCode::CommonInvalidParam2, DidValue); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + let result = CommandExecutor::instance() + .send(Command::Ledger(LedgerCommand::BuildGetFrozenLedgersRequest( + submitter_did, + boxed_callback_string!("indy_build_get_frozen_ledgers_request", cb, command_handle) + ))); + + let res = prepare_result!(result); + + trace!("indy_build_get_frozen_ledgers_request: <<< res: {:?}", res); + + res +} + /// Builds a AUTH_RULE request. Request to change authentication rules for a ledger transaction. /// /// #Params diff --git a/libindy/src/commands/anoncreds/prover.rs b/libindy/src/commands/anoncreds/prover.rs index 3796440cfd..2c90c2eb6e 100644 --- a/libindy/src/commands/anoncreds/prover.rs +++ b/libindy/src/commands/anoncreds/prover.rs @@ -532,12 +532,12 @@ impl ProverCommandExecutor { let mut credentials_for_proof_request: CredentialsForProofRequest = CredentialsForProofRequest::default(); for (attr_id, requested_attr) in proof_req.requested_attributes.iter() { - let query = self.anoncreds_service.prover.extend_proof_request_restrictions(&proof_req_version, - &requested_attr.name, - &requested_attr.names, - &attr_id, - &requested_attr.restrictions, - &None)?; + let query = self.anoncreds_service.prover.process_proof_request_restrictions(&proof_req_version, + &requested_attr.name, + &requested_attr.names, + &attr_id, + &requested_attr.restrictions, + &None)?; let interval = get_non_revoc_interval(&proof_req.non_revoked, &requested_attr.non_revoked); let credentials_for_attribute = self._query_requested_credentials(wallet_handle, &query, None, &interval)?; @@ -546,12 +546,12 @@ impl ProverCommandExecutor { } for (predicate_id, requested_predicate) in proof_req.requested_predicates.iter() { - let query = self.anoncreds_service.prover.extend_proof_request_restrictions(&proof_req_version, - &Some(requested_predicate.name.clone()), - &None, - &predicate_id, - &requested_predicate.restrictions, - &None)?; + let query = self.anoncreds_service.prover.process_proof_request_restrictions(&proof_req_version, + &Some(requested_predicate.name.clone()), + &None, + &predicate_id, + &requested_predicate.restrictions, + &None)?; let interval = get_non_revoc_interval(&proof_req.non_revoked, &requested_predicate.non_revoked); @@ -581,12 +581,12 @@ impl ProverCommandExecutor { let mut credentials_for_proof_request_search = HashMap::::new(); for (attr_id, requested_attr) in proof_req.requested_attributes.iter() { - let query = self.anoncreds_service.prover.extend_proof_request_restrictions(&version, - &requested_attr.name, - &requested_attr.names, - &attr_id, - &requested_attr.restrictions, - &extra_query)?; + let query = self.anoncreds_service.prover.process_proof_request_restrictions(&version, + &requested_attr.name, + &requested_attr.names, + &attr_id, + &requested_attr.restrictions, + &extra_query)?; let credentials_search = self.wallet_service.search_indy_records::(wallet_handle, &query.to_string(), &SearchOptions::id_value())?; @@ -599,12 +599,12 @@ impl ProverCommandExecutor { } for (predicate_id, requested_predicate) in proof_req.requested_predicates.iter() { - let query = self.anoncreds_service.prover.extend_proof_request_restrictions(&version, - &Some(requested_predicate.name.clone()), - &None, - &predicate_id, - &requested_predicate.restrictions, - &extra_query)?; + let query = self.anoncreds_service.prover.process_proof_request_restrictions(&version, + &Some(requested_predicate.name.clone()), + &None, + &predicate_id, + &requested_predicate.restrictions, + &extra_query)?; let credentials_search = self.wallet_service.search_indy_records::(wallet_handle, &query.to_string(), &SearchOptions::id_value())?; diff --git a/libindy/src/commands/ledger.rs b/libindy/src/commands/ledger.rs index 79bca4ccc2..50647a8f70 100644 --- a/libindy/src/commands/ledger.rs +++ b/libindy/src/commands/ledger.rs @@ -276,6 +276,13 @@ pub enum LedgerCommand { String, // request json DidValue, // endorser did Box) + Send>), + BuildGetFrozenLedgersRequest( + DidValue, // submitter did + Box) + Send>), + BuildLedgersFreezeRequest( + DidValue, // submitter did + Vec, // ledgers ids + Box) + Send>), } pub struct LedgerCommandExecutor { @@ -528,6 +535,14 @@ impl LedgerCommandExecutor { cb(self.append_request_endorser(&request_json, &endorser_did)); } + LedgerCommand::BuildLedgersFreezeRequest(submitter_did, ledgers_ids, cb) => { + debug!(target: "ledger_command_executor", "BuildLedgersFreezeRequest command received"); + cb(self.build_ledgers_freeze_request(&submitter_did, ledgers_ids)); + } + LedgerCommand::BuildGetFrozenLedgersRequest(submitter_did, cb) => { + debug!(target: "ledger_command_executor", "BuildGetFrozenLedgersRequest command received"); + cb(self.build_get_frozen_ledgers_request(&submitter_did)); + } }; } @@ -1308,6 +1323,30 @@ impl LedgerCommandExecutor { let pool_response = try_cb!(pool_response, cb); cb(self.ledger_service.parse_get_cred_def_response(&pool_response, id.get_method().as_ref().map(String::as_str))) } + + fn build_ledgers_freeze_request(&self, submitter_did: &DidValue, ledgers_ids: Vec) -> IndyResult{ + debug!("build_ledgers_freeze_request >>> submitter_did: {:?}, ledgers_ids: {:?}", submitter_did, ledgers_ids); + + self.crypto_service.validate_did(&submitter_did)?; + + let res = self.ledger_service.build_ledgers_freeze_request(&submitter_did, ledgers_ids)?; + + debug!("build_ledgers_freeze_request <<< res: {:?}", res); + + Ok(res) + } + + fn build_get_frozen_ledgers_request(&self, submitter_did: &DidValue) -> IndyResult { + debug!("build_get_frozen_ledgers_request >>> submitter_did: {:?}", submitter_did); + + self.crypto_service.validate_did(&submitter_did)?; + + let res = self.ledger_service.build_get_frozen_ledgers_request(&submitter_did)?; + + debug!("build_get_frozen_ledgers_request <<< res: {:?}", res); + + Ok(res) + } } enum SignatureType { diff --git a/libindy/src/commands/metrics.rs b/libindy/src/commands/metrics.rs index d01834c8e0..bc6b9af6ce 100644 --- a/libindy/src/commands/metrics.rs +++ b/libindy/src/commands/metrics.rs @@ -1,33 +1,37 @@ +use crate::services::metrics::models::MetricsValue; +use crate::services::metrics::MetricsService; use indy_api_types::errors::prelude::*; use indy_wallet::WalletService; -use std::rc::Rc; -use crate::services::metrics::MetricsService; use serde_json::{Map, Value}; +use std::collections::HashMap; +use std::rc::Rc; -const THREADPOOL_ACTIVE_COUNT: &str = "threadpool_active_count"; -const THREADPOOL_QUEUED_COUNT: &str = "threadpool_queued_count"; -const THREADPOOL_MAX_COUNT: &str = "threadpool_max_count"; -const THREADPOOL_PANIC_COUNT: &str = "threadpool_panic_count"; -const OPENED_WALLETS_COUNT: &str = "opened_wallets_count"; -const OPENED_WALLET_IDS_COUNT: &str = "opened_wallet_ids_count"; -const PENDING_FOR_IMPORT_WALLETS_COUNT: &str = "pending_for_import_wallets_count"; -const PENDING_FOR_OPEN_WALLETS_COUNT: &str = "pending_for_open_wallets_count"; +const THREADPOOL_ACTIVE_COUNT: &str = "active"; +const THREADPOOL_QUEUED_COUNT: &str = "queued"; +const THREADPOOL_MAX_COUNT: &str = "max"; +const THREADPOOL_PANIC_COUNT: &str = "panic"; +const OPENED_WALLETS_COUNT: &str = "opened"; +const OPENED_WALLET_IDS_COUNT: &str = "opened_ids"; +const PENDING_FOR_IMPORT_WALLETS_COUNT: &str = "pending_for_import"; +const PENDING_FOR_OPEN_WALLETS_COUNT: &str = "pending_for_open"; pub enum MetricsCommand { - CollectMetrics(Box) + Send>) + CollectMetrics(Box) + Send>), } pub struct MetricsCommandExecutor { wallet_service: Rc, - metrics_service: Rc + metrics_service: Rc, } impl MetricsCommandExecutor { - pub fn new(wallet_service: Rc, - metrics_service: Rc) -> MetricsCommandExecutor { + pub fn new( + wallet_service: Rc, + metrics_service: Rc, + ) -> MetricsCommandExecutor { MetricsCommandExecutor { wallet_service, - metrics_service + metrics_service, } } @@ -42,39 +46,99 @@ impl MetricsCommandExecutor { fn collect(&self) -> IndyResult { trace!("_collect >>>"); - let mut metrics_map= serde_json::Map::new(); - self.append_threapool_metrics(&mut metrics_map); - self.append_wallet_metrics(&mut metrics_map); - self.metrics_service.append_command_metrics(&mut metrics_map); + let mut metrics_map = serde_json::Map::new(); + self.append_threapool_metrics(&mut metrics_map)?; + self.append_wallet_metrics(&mut metrics_map)?; + self.metrics_service + .append_command_metrics(&mut metrics_map)?; let res = serde_json::to_string(&metrics_map) - .to_indy(IndyErrorKind::InvalidState,"Can't serialize a metrics map")?; + .to_indy(IndyErrorKind::InvalidState, "Can't serialize a metrics map")?; trace!("_collect <<< res: {:?}", res); debug!("collecting metrics from command thread"); Ok(res) } - fn append_threapool_metrics(&self, metrics_map: &mut Map) { + fn append_threapool_metrics(&self, metrics_map: &mut Map) -> IndyResult<()> { + #[derive(Serialize, Deserialize)] + struct MetricsTags { + label: String, + } + let tp_instance = crate::commands::THREADPOOL.lock().unwrap(); - metrics_map.insert(String::from(THREADPOOL_ACTIVE_COUNT), - Value::from(tp_instance.active_count())); - metrics_map.insert(String::from(THREADPOOL_QUEUED_COUNT), - Value::from(tp_instance.queued_count())); - metrics_map.insert(String::from(THREADPOOL_MAX_COUNT), - Value::from(tp_instance.max_count())); - metrics_map.insert(String::from(THREADPOOL_PANIC_COUNT), - Value::from(tp_instance.panic_count())); + let mut threadpool_threads_count: Vec = Vec::new(); + + threadpool_threads_count.push( self.get_metric_json( + THREADPOOL_ACTIVE_COUNT, + tp_instance.active_count() + )?); + + threadpool_threads_count.push(self.get_metric_json( + THREADPOOL_QUEUED_COUNT, + tp_instance.queued_count() + )?); + + threadpool_threads_count.push(self.get_metric_json( + THREADPOOL_MAX_COUNT, + tp_instance.max_count() + )?); + + threadpool_threads_count.push(self.get_metric_json( + THREADPOOL_PANIC_COUNT, + tp_instance.panic_count() + )?); + + metrics_map.insert( + String::from("threadpool_threads_count"), + serde_json::to_value(threadpool_threads_count) + .to_indy(IndyErrorKind::IOError, "Unable to convert json")?, + ); + + Ok(()) } - fn append_wallet_metrics(&self, metrics_map: &mut Map) { - metrics_map.insert(String::from(OPENED_WALLETS_COUNT), - Value::from(self.wallet_service.get_wallets_count())); - metrics_map.insert(String::from(OPENED_WALLET_IDS_COUNT), - Value::from(self.wallet_service.get_wallet_ids_count())); - metrics_map.insert(String::from(PENDING_FOR_IMPORT_WALLETS_COUNT), - Value::from(self.wallet_service.get_pending_for_import_count())); - metrics_map.insert(String::from(PENDING_FOR_OPEN_WALLETS_COUNT), - Value::from(self.wallet_service.get_pending_for_open_count())); + fn append_wallet_metrics(&self, metrics_map: &mut Map) -> IndyResult<()> { + #[derive(Serialize, Deserialize)] + struct MetricsTags { + label: String, + } + let mut wallet_count = Vec::new(); + + wallet_count.push(self.get_metric_json( + OPENED_WALLETS_COUNT, + self.wallet_service.get_wallets_count() + )?); + + wallet_count.push(self.get_metric_json( + OPENED_WALLET_IDS_COUNT, + self.wallet_service.get_wallet_ids_count() + )?); + + wallet_count.push(self.get_metric_json( + PENDING_FOR_IMPORT_WALLETS_COUNT, + self.wallet_service.get_pending_for_import_count() + )?); + + wallet_count.push(self.get_metric_json( + PENDING_FOR_OPEN_WALLETS_COUNT, + self.wallet_service.get_pending_for_open_count() + )?); + + metrics_map.insert( + String::from("wallet_count"), + serde_json::to_value(wallet_count) + .to_indy(IndyErrorKind::IOError, "Unable to convert json")?, + ); + + Ok(()) } -} + fn get_metric_json(&self, label: &str, value: usize) -> IndyResult { + let mut tag = HashMap::::new(); + tag.insert(String::from("label"), String::from(label)); + let res = serde_json::to_value(MetricsValue::new(value, tag)) + .to_indy(IndyErrorKind::IOError, "Unable to convert json")?; + + Ok(res) + } +} \ No newline at end of file diff --git a/libindy/src/commands/mod.rs b/libindy/src/commands/mod.rs index 4755051d73..00532514d4 100644 --- a/libindy/src/commands/mod.rs +++ b/libindy/src/commands/mod.rs @@ -28,7 +28,7 @@ use crate::services::ledger::LedgerService; use crate::services::payments::PaymentsService; use crate::services::pool::{PoolService, set_freshness_threshold}; use crate::services::metrics::MetricsService; -use crate::services::metrics::command_index::CommandIndex; +use crate::services::metrics::command_metrics::CommandMetric; use indy_wallet::WalletService; use self::threadpool::ThreadPool; @@ -158,7 +158,7 @@ impl CommandExecutor { panic!("Failed to get command! {:?}", err) } }; - let cmd_index: CommandIndex = (&instrumented_cmd.command).into(); + let cmd_index: CommandMetric = (&instrumented_cmd.command).into(); let start_execution_ts = get_cur_time(); metrics_service.cmd_left_queue(cmd_index, start_execution_ts - instrumented_cmd.enqueue_ts); diff --git a/libindy/src/domain/ledger/constants.rs b/libindy/src/domain/ledger/constants.rs index 6ce73b8fc3..d918c13ade 100644 --- a/libindy/src/domain/ledger/constants.rs +++ b/libindy/src/domain/ledger/constants.rs @@ -6,6 +6,8 @@ pub const TXN_AUTHR_AGRMT_AML: &str = "5"; pub const GET_TXN_AUTHR_AGRMT: &str = "6"; pub const GET_TXN_AUTHR_AGRMT_AML: &str = "7"; pub const DISABLE_ALL_TXN_AUTHR_AGRMTS: &str = "8"; +pub const LEDGERS_FREEZE: &str = "9"; +pub const GET_FROZEN_LEDGERS: &str = "10"; pub const ATTRIB: &str = "100"; pub const SCHEMA: &str = "101"; pub const CRED_DEF: &str = "102"; @@ -27,10 +29,10 @@ pub const GET_AUTH_RULE: &str = "121"; pub const AUTH_RULES: &str = "122"; pub const GET_DDO: &str = "120";//TODO change number -pub const REQUESTS: [&str; 25] = [NODE, NYM, GET_TXN, ATTRIB, SCHEMA, CRED_DEF, GET_ATTR, GET_NYM, GET_SCHEMA, +pub const REQUESTS: [&str; 27] = [NODE, NYM, GET_TXN, ATTRIB, SCHEMA, CRED_DEF, GET_ATTR, GET_NYM, GET_SCHEMA, GET_CRED_DEF, POOL_UPGRADE, POOL_RESTART, POOL_CONFIG, REVOC_REG_DEF, REVOC_REG_ENTRY, GET_REVOC_REG_DEF, GET_REVOC_REG, GET_REVOC_REG_DELTA, GET_VALIDATOR_INFO, AUTH_RULE, GET_DDO, TXN_AUTHR_AGRMT, TXN_AUTHR_AGRMT_AML, - GET_TXN_AUTHR_AGRMT, GET_TXN_AUTHR_AGRMT_AML]; + GET_TXN_AUTHR_AGRMT, GET_TXN_AUTHR_AGRMT_AML, LEDGERS_FREEZE, GET_FROZEN_LEDGERS]; pub const TRUSTEE: &str = "0"; pub const STEWARD: &str = "2"; @@ -71,6 +73,8 @@ pub fn txn_name_to_code(txn: &str) -> Option<&str> { "TXN_AUTHR_AGRMT_AML" => Some(TXN_AUTHR_AGRMT_AML), "GET_TXN_AUTHR_AGRMT" => Some(GET_TXN_AUTHR_AGRMT), "GET_TXN_AUTHR_AGRMT_AML" => Some(GET_TXN_AUTHR_AGRMT_AML), + "LEDGERS_FREEZE" => Some(LEDGERS_FREEZE), + "GET_FROZEN_LEDGERS" => Some(GET_FROZEN_LEDGERS), val => Some(val) } } \ No newline at end of file diff --git a/libindy/src/domain/ledger/ledgers_freeze.rs b/libindy/src/domain/ledger/ledgers_freeze.rs new file mode 100644 index 0000000000..4d01576c5b --- /dev/null +++ b/libindy/src/domain/ledger/ledgers_freeze.rs @@ -0,0 +1,31 @@ +use super::constants::{LEDGERS_FREEZE, GET_FROZEN_LEDGERS}; + +#[derive(Serialize, PartialEq, Debug)] +pub struct LedgersFreezeOperation { + #[serde(rename = "type")] + pub _type: String, + pub ledgers_ids: Vec, +} + +impl LedgersFreezeOperation { + pub fn new(ledgers_ids: Vec) -> LedgersFreezeOperation { + LedgersFreezeOperation { + _type: LEDGERS_FREEZE.to_string(), + ledgers_ids + } + } +} + +#[derive(Serialize, PartialEq, Debug)] +pub struct GetFrozenLedgersOperation { + #[serde(rename = "type")] + pub _type: String +} + +impl GetFrozenLedgersOperation { + pub fn new() -> GetFrozenLedgersOperation { + GetFrozenLedgersOperation { + _type: GET_FROZEN_LEDGERS.to_string() + } + } +} diff --git a/libindy/src/domain/ledger/mod.rs b/libindy/src/domain/ledger/mod.rs index c2b0309a77..d85faad860 100644 --- a/libindy/src/domain/ledger/mod.rs +++ b/libindy/src/domain/ledger/mod.rs @@ -14,3 +14,4 @@ pub mod validator_info; pub mod constants; pub mod auth_rule; pub mod author_agreement; +pub mod ledgers_freeze; diff --git a/libindy/src/services/anoncreds/prover.rs b/libindy/src/services/anoncreds/prover.rs index 28bef4518e..a353140719 100644 --- a/libindy/src/services/anoncreds/prover.rs +++ b/libindy/src/services/anoncreds/prover.rs @@ -28,6 +28,7 @@ use crate::domain::anoncreds::schema::{SchemaV1, SchemaId}; use indy_api_types::errors::prelude::*; use crate::services::anoncreds::helpers::*; use crate::utils::wql::Query; +use crate::services::anoncreds::verifier::Verifier; const ATTRIBUTE_EXISTENCE_MARKER: &str = "1"; @@ -306,8 +307,8 @@ impl Prover { .for_each(|(attr, values)| { if catpol.map(|cp| cp.is_taggable(attr.as_str())).unwrap_or(true) { // abstain for attrs policy marks untaggable - res.insert(format!("attr::{}::marker", attr_common_view(&attr)), ATTRIBUTE_EXISTENCE_MARKER.to_string()); - res.insert(format!("attr::{}::value", attr_common_view(&attr)), values.raw.clone()); + res.insert(Self::_build_attr_marker_tag(attr), ATTRIBUTE_EXISTENCE_MARKER.to_string()); + res.insert(Self::_build_attr_value_tag(attr), values.raw.clone()); } }); @@ -316,6 +317,14 @@ impl Prover { Ok(res) } + fn _build_attr_marker_tag(attr: &str) -> String { + format!("attr::{}::marker", attr_common_view(&attr)) + } + + fn _build_attr_value_tag(attr: &str) -> String { + format!("attr::{}::value", attr_common_view(&attr)) + } + pub fn attribute_satisfy_predicate(&self, predicate: &PredicateInfo, attribute_value: &str) -> IndyResult { @@ -435,20 +444,20 @@ impl Prover { Ok(sub_proof_request) } - pub fn extend_proof_request_restrictions(&self, - version: &ProofRequestsVersion, - name: &Option, - names: &Option>, - referent: &str, - restrictions: &Option, - extra_query: &Option<&ProofRequestExtraQuery>) -> IndyResult { + pub fn process_proof_request_restrictions(&self, + version: &ProofRequestsVersion, + name: &Option, + names: &Option>, + referent: &str, + restrictions: &Option, + extra_query: &Option<&ProofRequestExtraQuery>) -> IndyResult { info!("name: {:?}, names: {:?}", name, names); let mut queries: Vec = Vec::new(); let mut attr_queries: Vec = if let Some(names) = names.as_ref().or(name.as_ref().map(|s| vec![s.clone()]).as_ref()) { names.iter().map(|name| { - Query::Eq(format!("attr::{}::marker", &attr_common_view(name)), ATTRIBUTE_EXISTENCE_MARKER.to_string()) + Query::Eq(Self::_build_attr_marker_tag(name), ATTRIBUTE_EXISTENCE_MARKER.to_string()) }).collect() } else { return Err(IndyError::from_msg(IndyErrorKind::InvalidStructure, r#"Proof Request attribute restriction should contain "name" or "names" param"#)); @@ -457,10 +466,12 @@ impl Prover { if let Some(restrictions_) = restrictions.clone() { match version { ProofRequestsVersion::V1 => { - queries.push(self.double_restrictions(restrictions_)?) + let insensitive_restrictions = Self::_make_restrictions_by_internal_tags_case_insensitive(restrictions_)?; + queries.push(self.double_restrictions(insensitive_restrictions)?) } ProofRequestsVersion::V2 => { - queries.push(restrictions_) + let insensitive_restrictions = Self::_make_restrictions_by_internal_tags_case_insensitive(restrictions_)?; + queries.push(insensitive_restrictions) } }; } @@ -476,6 +487,58 @@ impl Prover { Ok(Query::And(queries)) } + fn _make_restrictions_by_internal_tags_case_insensitive(operator: Query) -> IndyResult { + Ok(match operator { + Query::Eq(tag_name, tag_value) => { + if let Some(tag_name) = Verifier::attr_request_by_value(&tag_name) { + Query::Eq(Self::_build_attr_value_tag(tag_name), tag_value) + } else if let Some(tag_name) = Verifier::attr_request_by_marker(&tag_name) { + Query::Eq(Self::_build_attr_marker_tag(tag_name), tag_value) + } else { + Query::Eq(tag_name, tag_value) + } + } + Query::Neq(tag_name, tag_value) => { + if let Some(tag_name) = Verifier::attr_request_by_value(&tag_name) { + Query::Neq(Self::_build_attr_value_tag(tag_name), tag_value) + } else if let Some(tag_name) = Verifier::attr_request_by_marker(&tag_name) { + Query::Neq(Self::_build_attr_marker_tag(tag_name), tag_value) + } else { + Query::Neq(tag_name, tag_value) + } + } + Query::In(tag_name, tag_values) => { + if let Some(tag_name) = Verifier::attr_request_by_value(&tag_name) { + Query::In(Self::_build_attr_value_tag(tag_name), tag_values) + } else if let Some(tag_name) = Verifier::attr_request_by_marker(&tag_name) { + Query::In(Self::_build_attr_marker_tag(tag_name), tag_values) + } else { + Query::In(tag_name, tag_values) + } + } + Query::And(operators) => { + Query::And( + operators + .into_iter() + .map(|op| Self::_make_restrictions_by_internal_tags_case_insensitive(op)) + .collect::>>()? + ) + } + Query::Or(operators) => { + Query::Or( + operators + .into_iter() + .map(|op| Self::_make_restrictions_by_internal_tags_case_insensitive(op)) + .collect::>>()? + ) + } + Query::Not(operator) => { + Query::Not(::std::boxed::Box::new(Self::_make_restrictions_by_internal_tags_case_insensitive(*operator)?)) + } + _ => return Err(IndyError::from_msg(IndyErrorKind::InvalidStructure, "unsupported operator")) + }) + } + fn double_restrictions(&self, operator: Query) -> IndyResult { Ok(match operator { Query::Eq(tag_name, tag_value) => { @@ -980,12 +1043,12 @@ mod tests { fn build_query_works() { let ps = Prover::new(); - let query = ps.extend_proof_request_restrictions(&ProofRequestsVersion::V2, - &Some(ATTR_NAME.to_string()), - &None, - ATTR_REFERENT, - &None, - &None).unwrap(); + let query = ps.process_proof_request_restrictions(&ProofRequestsVersion::V2, + &Some(ATTR_NAME.to_string()), + &None, + ATTR_REFERENT, + &None, + &None).unwrap(); let expected_query = Query::And(vec![ Query::Eq("attr::name::marker".to_string(), ATTRIBUTE_EXISTENCE_MARKER.to_string()) @@ -998,12 +1061,12 @@ mod tests { fn build_query_works_for_name() { let ps = Prover::new(); - let query = ps.extend_proof_request_restrictions(&ProofRequestsVersion::V2, - &None, - &Some(vec![ATTR_NAME.to_string(), ATTR_NAME_2.to_string()]), - ATTR_REFERENT, - &None, - &None).unwrap(); + let query = ps.process_proof_request_restrictions(&ProofRequestsVersion::V2, + &None, + &Some(vec![ATTR_NAME.to_string(), ATTR_NAME_2.to_string()]), + ATTR_REFERENT, + &None, + &None).unwrap(); let expected_query = Query::And(vec![ Query::Eq("attr::name::marker".to_string(), ATTRIBUTE_EXISTENCE_MARKER.to_string()), @@ -1022,12 +1085,12 @@ mod tests { Query::Eq("cred_def_id".to_string(), CRED_DEF_ID.to_string()), ]); - let query = ps.extend_proof_request_restrictions(&ProofRequestsVersion::V2, - &Some(ATTR_NAME.to_string()), - &None, - ATTR_REFERENT, - &Some(restriction), - &None).unwrap(); + let query = ps.process_proof_request_restrictions(&ProofRequestsVersion::V2, + &Some(ATTR_NAME.to_string()), + &None, + ATTR_REFERENT, + &Some(restriction), + &None).unwrap(); let expected_query = Query::And(vec![ Query::And(vec![ @@ -1048,12 +1111,12 @@ mod tests { ATTR_REFERENT.to_string() => Query::Eq("name".to_string(), "Alex".to_string()) ); - let query = ps.extend_proof_request_restrictions(&ProofRequestsVersion::V2, - &Some(ATTR_NAME.to_string()), - &None, - ATTR_REFERENT, - &None, - &Some(&extra_query)).unwrap(); + let query = ps.process_proof_request_restrictions(&ProofRequestsVersion::V2, + &Some(ATTR_NAME.to_string()), + &None, + ATTR_REFERENT, + &None, + &Some(&extra_query)).unwrap(); let expected_query = Query::And(vec![ Query::Eq("name".to_string(), "Alex".to_string()), @@ -1076,12 +1139,12 @@ mod tests { ATTR_REFERENT.to_string() => Query::Eq("name".to_string(), "Alex".to_string()) ); - let query = ps.extend_proof_request_restrictions(&ProofRequestsVersion::V2, - &Some(ATTR_NAME.to_string()), - &None, - ATTR_REFERENT, - &Some(restriction), - &Some(&extra_query)).unwrap(); + let query = ps.process_proof_request_restrictions(&ProofRequestsVersion::V2, + &Some(ATTR_NAME.to_string()), + &None, + ATTR_REFERENT, + &Some(restriction), + &Some(&extra_query)).unwrap(); let expected_query = Query::And(vec![ Query::And(vec![ @@ -1103,12 +1166,12 @@ mod tests { "other_attr_referent".to_string() => Query::Eq("name".to_string(), "Alex".to_string()) ); - let query = ps.extend_proof_request_restrictions(&ProofRequestsVersion::V2, - &Some(ATTR_NAME.to_string()), - &None, - ATTR_REFERENT, - &None, - &Some(&extra_query)).unwrap(); + let query = ps.process_proof_request_restrictions(&ProofRequestsVersion::V2, + &Some(ATTR_NAME.to_string()), + &None, + ATTR_REFERENT, + &None, + &Some(&extra_query)).unwrap(); let expected_query = Query::And(vec![ Query::Eq("attr::name::marker".to_string(), ATTRIBUTE_EXISTENCE_MARKER.to_string()), @@ -1134,12 +1197,12 @@ mod tests { ]) ); - let query = ps.extend_proof_request_restrictions(&ProofRequestsVersion::V2, - &Some(ATTR_NAME.to_string()), - &None, - ATTR_REFERENT, - &Some(restriction), - &Some(&extra_query)).unwrap(); + let query = ps.process_proof_request_restrictions(&ProofRequestsVersion::V2, + &Some(ATTR_NAME.to_string()), + &None, + ATTR_REFERENT, + &Some(restriction), + &Some(&extra_query)).unwrap(); let expected_query = Query::And(vec![ Query::Or(vec![ @@ -1155,5 +1218,38 @@ mod tests { assert_eq!(expected_query, query); } + + #[test] + fn build_query_works_for_restriction_by_internal_tags() { + let ps = Prover::new(); + + let restriction = Query::And(vec![ + Query::Eq("schema_id".to_string(), SCHEMA_ID.to_string()), + Query::Eq("attr::firstname::value".to_string(), "firstname_value".to_string()), + Query::Eq("attr::Last Name::value".to_string(), "lastname_value".to_string()), + Query::Eq("attr::File Name::marker".to_string(), "1".to_string()), + Query::Eq("attr::textresult::marker".to_string(), "1".to_string()), + ]); + + let query = ps.process_proof_request_restrictions(&ProofRequestsVersion::V2, + &Some(ATTR_NAME.to_string()), + &None, + ATTR_REFERENT, + &Some(restriction), + &None).unwrap(); + + let expected_query = Query::And(vec![ + Query::And(vec![ + Query::Eq("schema_id".to_string(), SCHEMA_ID.to_string()), + Query::Eq("attr::firstname::value".to_string(), "firstname_value".to_string()), + Query::Eq("attr::lastname::value".to_string(), "lastname_value".to_string()), + Query::Eq("attr::filename::marker".to_string(), "1".to_string()), + Query::Eq("attr::textresult::marker".to_string(), "1".to_string()), + ]), + Query::Eq("attr::name::marker".to_string(), ATTRIBUTE_EXISTENCE_MARKER.to_string()), + ]); + + assert_eq!(expected_query, query); + } } } diff --git a/libindy/src/services/anoncreds/verifier.rs b/libindy/src/services/anoncreds/verifier.rs index 7baa624d55..71cdcc0872 100644 --- a/libindy/src/services/anoncreds/verifier.rs +++ b/libindy/src/services/anoncreds/verifier.rs @@ -26,7 +26,8 @@ pub struct Filter { } lazy_static! { - static ref INTERNAL_TAG_MATCHER: Regex = Regex::new("^attr::([^:]+)::(value|marker)$").unwrap(); + pub static ref VALUE_TAG_MATCHER: Regex = Regex::new("^attr::([^:]+)::value$").unwrap(); + pub static ref MARKER_TAG_MATCHER: Regex = Regex::new("^attr::([^:]+)::marker$").unwrap(); } pub struct Verifier {} @@ -578,8 +579,14 @@ impl Verifier { tag_ @ "schema_version" => Verifier::_precess_filed(tag_, &filter.schema_version, tag_value), tag_ @ "cred_def_id" => Verifier::_precess_filed(tag_, &filter.cred_def_id, tag_value), tag_ @ "issuer_did" => Verifier::_precess_filed(tag_, &filter.issuer_did, tag_value), - x if Verifier::_is_attr_internal_tag(x, attr_value_map) => Verifier::_check_internal_tag_revealed_value(x, tag_value, attr_value_map), - x if Verifier::_is_attr_operator(x) => Ok(()), + x if Verifier::_is_attr_with_revealed_value(x, attr_value_map) => { + // attr::::value -> check revealed value + Verifier::_check_internal_tag_revealed_value(x, tag_value, attr_value_map) + }, + x if Verifier::_is_attr_marker_operator(x) => { + // attr::::marker -> ok + Ok(()) + }, _ => Err(err_msg(IndyErrorKind::InvalidStructure, "Unknown Filter Type")) } } @@ -592,28 +599,59 @@ impl Verifier { } } - fn _is_attr_internal_tag(key: &str, attr_value_map: &HashMap>) -> bool { - INTERNAL_TAG_MATCHER.captures(key).map( |caps| - caps.get(1).map(|s| attr_value_map.contains_key(&s.as_str().to_string())).unwrap_or(false) + pub fn attr_request_by_value(key: &str) -> Option<&str> { + VALUE_TAG_MATCHER.captures(key).and_then( |caps| + caps.get(1).map(|s| s.as_str()) + ) + } + + pub fn attr_request_by_marker(key: &str) -> Option<&str> { + MARKER_TAG_MATCHER.captures(key).and_then( |caps| + caps.get(1).map(|s| s.as_str()) + ) + } + + fn _is_attr_with_revealed_value(key: &str, attr_value_map: &HashMap>) -> bool { + VALUE_TAG_MATCHER.captures(key).map( |caps| + caps.get(1).map(|s| + attr_value_map.keys().any(|key| attr_common_view(key) == attr_common_view(s.as_str())) + ).unwrap_or(false) ).unwrap_or(false) } fn _check_internal_tag_revealed_value(key: &str, tag_value: &str, attr_value_map: &HashMap>) -> IndyResult<()> { - let attr_name = INTERNAL_TAG_MATCHER.captures(key) - .ok_or(IndyError::from_msg(IndyErrorKind::InvalidState, format!("Attribute name became unparseable")))? + let captures = VALUE_TAG_MATCHER.captures(key) + .ok_or(IndyError::from_msg(IndyErrorKind::InvalidState, format!("Attribute name became unparseable")))?; + + let attr_name = captures .get(1) .ok_or(IndyError::from_msg(IndyErrorKind::InvalidState, format!("No name has been parsed")))? .as_str(); - if let Some(Some(revealed_value)) = attr_value_map.get(attr_name) { + + let revealed_value = + attr_value_map + .iter() + .find(|(key, _)| attr_common_view(key) == attr_common_view(attr_name)); + + if let Some((_key, Some(revealed_value))) = revealed_value { if *revealed_value != tag_value { return Err(IndyError::from_msg(IndyErrorKind::ProofRejected, format!("\"{}\" values are different: expected: \"{}\", actual: \"{}\"", key, tag_value, revealed_value))); } + } else { + return Err(IndyError::from_msg(IndyErrorKind::ProofRejected, + format!("Revealed value hasn't been find by key: expected key: \"{}\", attr_value_map: \"{:?}\"", key, attr_value_map))); } Ok(()) } - fn _is_attr_operator(key: &str) -> bool { key.starts_with("attr::") && key.ends_with("::marker") } + fn _is_attr_marker_operator(key: &str) -> bool { + MARKER_TAG_MATCHER.is_match(key) + } + + fn _is_attr_value_operator(key: &str) -> bool { + VALUE_TAG_MATCHER.is_match(key) + } } #[cfg(test)] @@ -892,6 +930,21 @@ mod tests { assert!(Verifier::_process_operator("zip", &op, &filter, Some("NOT HERE")).is_err()); } + #[test] + fn test_process_op_eq_revealed_value_case_insensitive() { + let filter = filter(); + let value = "Alice Clark"; + + let mut op = Query::Eq("attr::givenname::value".to_string(), value.to_string()); + Verifier::_process_operator("Given Name", &op, &filter, Some(value)).unwrap(); + + op = Query::And(vec![ + Query::Eq("attr::givenname::value".to_string(), value.to_string()), + Query::Eq(schema_issuer_did_tag(), SCHEMA_ISSUER_DID.to_string()), + ]); + Verifier::_process_operator("Given Name", &op, &filter, Some(value)).unwrap(); + } + fn _received() -> HashMap { let mut res: HashMap = HashMap::new(); res.insert("referent_1".to_string(), Identifier { timestamp: Some(1234), schema_id: SchemaId(String::new()), cred_def_id: CredentialDefinitionId(String::new()), rev_reg_id: Some(RevocationRegistryId(String::new())) }); diff --git a/libindy/src/services/blob_storage/mod.rs b/libindy/src/services/blob_storage/mod.rs index 0d60830c7e..c8328332d4 100644 --- a/libindy/src/services/blob_storage/mod.rs +++ b/libindy/src/services/blob_storage/mod.rs @@ -5,7 +5,7 @@ use indy_api_types::errors::prelude::*; use indy_utils::sequence; use sha2::Sha256; -use sha2::digest::{FixedOutput, Input}; +use sha2::digest::{FixedOutput, Update}; mod default_writer; mod default_reader; @@ -95,7 +95,7 @@ impl BlobStorageService { let &mut (ref mut writer, ref mut hasher) = writers .get_mut(&handle).ok_or_else(|| err_msg(IndyErrorKind::InvalidStructure, "Invalid BlobStorage handle"))?; // FIXME: Review error kind - hasher.input(bytes); + hasher.update(bytes); writer.append(bytes) } @@ -104,7 +104,7 @@ impl BlobStorageService { let (mut writer, hasher) = writers .remove(&handle).ok_or_else(|| err_msg(IndyErrorKind::InvalidStructure, "Invalid BlobStorage handle"))?; // FIXME: Review error kind - let hash = hasher.fixed_result().to_vec(); + let hash = hasher.finalize_fixed().to_vec(); writer.finalize(hash.as_slice()) .map(|location| (location, hash)) diff --git a/libindy/src/services/ledger/mod.rs b/libindy/src/services/ledger/mod.rs index 610ea68745..7d944b0f55 100644 --- a/libindy/src/services/ledger/mod.rs +++ b/libindy/src/services/ledger/mod.rs @@ -27,6 +27,7 @@ use crate::domain::ledger::txn::{GetTxnOperation, LedgerType}; use crate::domain::ledger::validator_info::GetValidatorInfoOperation; use crate::domain::ledger::auth_rule::*; use crate::domain::ledger::author_agreement::*; +use crate::domain::ledger::ledgers_freeze::{LedgersFreezeOperation, GetFrozenLedgersOperation}; use indy_api_types::errors::prelude::*; use indy_utils::crypto::hash::hash as openssl_hash; @@ -394,6 +395,16 @@ impl LedgerService { old_value.map(String::from), new_value.map(String::from), constraint) } + #[logfn(Info)] + pub fn build_ledgers_freeze_request(&self, submitter_did: &DidValue, ledgers_ids: Vec) -> IndyResult { + build_result!(LedgersFreezeOperation, Some(submitter_did), ledgers_ids) + } + + #[logfn(Info)] + pub fn build_get_frozen_ledgers_request(&self, submitter_did: &DidValue) -> IndyResult { + build_result!(GetFrozenLedgersOperation, Some(submitter_did)) + } + #[logfn(Info)] pub fn build_auth_rules_request(&self, submitter_did: &DidValue, rules: AuthRules) -> IndyResult { build_result!(AuthRulesOperation, Some(submitter_did), rules) @@ -866,6 +877,47 @@ mod tests { ledger_service.validate_action(&request).unwrap(); } + #[test] + fn build_ledgers_freeze_request_work_with_valid_data() { + let ledger_service = LedgerService::new(); + let ledgers_ids = vec![0,1,50,873]; + let res = ledger_service.build_ledgers_freeze_request(&identifier(), ledgers_ids); + + match res { + Ok(_) => {}, + Err(ec) => { + assert!(false, "build_ledgers_freeze_request_work_with_valid_data returned error_code {:?}", ec); + } + } + } + + #[test] + fn build_get_frozen_ledgers_request_work_with_valid_data() { + let ledger_service = LedgerService::new(); + let res = ledger_service.build_get_frozen_ledgers_request(&identifier()); + + match res { + Ok(_) => {}, + Err(ec) => { + assert!(false, "build_get_frozen_ledgers_request_work_with_valid_data returned error_code {:?}", ec); + } + } + } + + #[test] + fn build_ledgers_freeze_request_work_with_empty_data() { + let ledger_service = LedgerService::new(); + let ledgers_ids = vec![]; + let res = ledger_service.build_ledgers_freeze_request(&identifier(), ledgers_ids); + + match res { + Ok(_) => {}, + Err(ec) => { + assert!(false, "build_ledgers_freeze_request_work_with_empty_data returned error_code {:?}", ec); + } + } + } + mod auth_rule { use super::*; diff --git a/libindy/src/services/metrics/command_index.rs b/libindy/src/services/metrics/command_metrics.rs similarity index 63% rename from libindy/src/services/metrics/command_index.rs rename to libindy/src/services/metrics/command_metrics.rs index a8a3adfd5c..66768b82d7 100644 --- a/libindy/src/services/metrics/command_index.rs +++ b/libindy/src/services/metrics/command_metrics.rs @@ -17,13 +17,13 @@ use crate::commands::cache::CacheCommand; use std::fmt; use crate::commands::metrics::MetricsCommand; -impl fmt::Display for CommandIndex { +impl fmt::Display for CommandMetric { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:?}", self) } } -impl From for CommandIndex { +impl From for CommandMetric { fn from(i: usize) -> Self { let conversion = num_traits::FromPrimitive::from_usize(i); if conversion.is_some() { @@ -34,290 +34,292 @@ impl From for CommandIndex { } } -impl From<&IssuerCommand> for CommandIndex { +impl From<&IssuerCommand> for CommandMetric { fn from(cmd: &IssuerCommand) -> Self { match cmd { IssuerCommand::CreateSchema(_, _, _, _, _) => { - CommandIndex::IssuerCommandCreateSchema + CommandMetric::IssuerCommandCreateSchema } IssuerCommand::CreateAndStoreCredentialDefinition(_, _, _, _, _, _, _) => { - CommandIndex::IssuerCommandCreateAndStoreCredentialDefinition + CommandMetric::IssuerCommandCreateAndStoreCredentialDefinition } IssuerCommand::CreateAndStoreCredentialDefinitionContinue(_, _, _, _, _, _, _, _) => { - CommandIndex::IssuerCommandCreateAndStoreCredentialDefinitionContinue + CommandMetric::IssuerCommandCreateAndStoreCredentialDefinitionContinue } IssuerCommand::RotateCredentialDefinitionStart(_, _, _, _) => { - CommandIndex::IssuerCommandRotateCredentialDefinitionStart + CommandMetric::IssuerCommandRotateCredentialDefinitionStart } IssuerCommand::RotateCredentialDefinitionStartComplete(_, _, _, _, _, _, _) => { - CommandIndex::IssuerCommandRotateCredentialDefinitionStartComplete + CommandMetric::IssuerCommandRotateCredentialDefinitionStartComplete } IssuerCommand::RotateCredentialDefinitionApply(_, _, _) => { - CommandIndex::IssuerCommandRotateCredentialDefinitionApply + CommandMetric::IssuerCommandRotateCredentialDefinitionApply } IssuerCommand::CreateAndStoreRevocationRegistry(_, _, _, _, _, _, _, _) => { - CommandIndex::IssuerCommandCreateAndStoreRevocationRegistry + CommandMetric::IssuerCommandCreateAndStoreRevocationRegistry } IssuerCommand::CreateCredentialOffer(_, _, _) => { - CommandIndex::IssuerCommandCreateCredentialOffer + CommandMetric::IssuerCommandCreateCredentialOffer } IssuerCommand::CreateCredential(_, _, _, _, _, _, _) => { - CommandIndex::IssuerCommandCreateCredential + CommandMetric::IssuerCommandCreateCredential } IssuerCommand::RevokeCredential(_, _, _, _, _) => { - CommandIndex::IssuerCommandRevokeCredential + CommandMetric::IssuerCommandRevokeCredential } IssuerCommand::MergeRevocationRegistryDeltas(_, _, _) => { - CommandIndex::IssuerCommandMergeRevocationRegistryDeltas + CommandMetric::IssuerCommandMergeRevocationRegistryDeltas } } } } -impl From<&ProverCommand> for CommandIndex { +impl From<&ProverCommand> for CommandMetric { fn from(cmd: &ProverCommand) -> Self { match cmd { - ProverCommand::CreateMasterSecret(_, _, _) => { CommandIndex::ProverCommandCreateMasterSecret } - ProverCommand::CreateCredentialRequest(_, _, _, _, _, _) => { CommandIndex::ProverCommandCreateCredentialRequest } - ProverCommand::SetCredentialAttrTagPolicy(_, _, _, _, _) => { CommandIndex::ProverCommandSetCredentialAttrTagPolicy } - ProverCommand::GetCredentialAttrTagPolicy(_, _, _) => { CommandIndex::ProverCommandGetCredentialAttrTagPolicy } - ProverCommand::StoreCredential(_, _, _, _, _, _, _) => { CommandIndex::ProverCommandStoreCredential } - ProverCommand::GetCredentials(_, _, _) => { CommandIndex::ProverCommandGetCredentials } - ProverCommand::GetCredential(_, _, _) => { CommandIndex::ProverCommandGetCredential } - ProverCommand::DeleteCredential(_, _, _) => { CommandIndex::ProverCommandDeleteCredential } - ProverCommand::SearchCredentials(_, _, _) => { CommandIndex::ProverCommandSearchCredentials } - ProverCommand::FetchCredentials(_, _, _) => { CommandIndex::ProverCommandFetchCredentials } - ProverCommand::CloseCredentialsSearch(_, _) => { CommandIndex::ProverCommandCloseCredentialsSearch } - ProverCommand::GetCredentialsForProofReq(_, _, _) => { CommandIndex::ProverCommandGetCredentialsForProofReq } - ProverCommand::SearchCredentialsForProofReq(_, _, _, _) => { CommandIndex::ProverCommandSearchCredentialsForProofReq } - ProverCommand::FetchCredentialForProofReq(_, _, _, _) => { CommandIndex::ProverCommandFetchCredentialForProofReq } - ProverCommand::CloseCredentialsSearchForProofReq(_, _) => { CommandIndex::ProverCommandCloseCredentialsSearchForProofReq } - ProverCommand::CreateProof(_, _, _, _, _, _, _, _) => { CommandIndex::ProverCommandCreateProof } - ProverCommand::CreateRevocationState(_, _, _, _, _, _) => { CommandIndex::ProverCommandCreateRevocationState } - ProverCommand::UpdateRevocationState(_, _, _, _, _, _, _) => { CommandIndex::ProverCommandUpdateRevocationState } + ProverCommand::CreateMasterSecret(_, _, _) => { CommandMetric::ProverCommandCreateMasterSecret } + ProverCommand::CreateCredentialRequest(_, _, _, _, _, _) => { CommandMetric::ProverCommandCreateCredentialRequest } + ProverCommand::SetCredentialAttrTagPolicy(_, _, _, _, _) => { CommandMetric::ProverCommandSetCredentialAttrTagPolicy } + ProverCommand::GetCredentialAttrTagPolicy(_, _, _) => { CommandMetric::ProverCommandGetCredentialAttrTagPolicy } + ProverCommand::StoreCredential(_, _, _, _, _, _, _) => { CommandMetric::ProverCommandStoreCredential } + ProverCommand::GetCredentials(_, _, _) => { CommandMetric::ProverCommandGetCredentials } + ProverCommand::GetCredential(_, _, _) => { CommandMetric::ProverCommandGetCredential } + ProverCommand::DeleteCredential(_, _, _) => { CommandMetric::ProverCommandDeleteCredential } + ProverCommand::SearchCredentials(_, _, _) => { CommandMetric::ProverCommandSearchCredentials } + ProverCommand::FetchCredentials(_, _, _) => { CommandMetric::ProverCommandFetchCredentials } + ProverCommand::CloseCredentialsSearch(_, _) => { CommandMetric::ProverCommandCloseCredentialsSearch } + ProverCommand::GetCredentialsForProofReq(_, _, _) => { CommandMetric::ProverCommandGetCredentialsForProofReq } + ProverCommand::SearchCredentialsForProofReq(_, _, _, _) => { CommandMetric::ProverCommandSearchCredentialsForProofReq } + ProverCommand::FetchCredentialForProofReq(_, _, _, _) => { CommandMetric::ProverCommandFetchCredentialForProofReq } + ProverCommand::CloseCredentialsSearchForProofReq(_, _) => { CommandMetric::ProverCommandCloseCredentialsSearchForProofReq } + ProverCommand::CreateProof(_, _, _, _, _, _, _, _) => { CommandMetric::ProverCommandCreateProof } + ProverCommand::CreateRevocationState(_, _, _, _, _, _) => { CommandMetric::ProverCommandCreateRevocationState } + ProverCommand::UpdateRevocationState(_, _, _, _, _, _, _) => { CommandMetric::ProverCommandUpdateRevocationState } } } } -impl From<&VerifierCommand> for CommandIndex { +impl From<&VerifierCommand> for CommandMetric { fn from(cmd: &VerifierCommand) -> Self { match cmd { - VerifierCommand::VerifyProof(_, _, _, _, _, _, _) => { CommandIndex::VerifierCommandVerifyProof } - VerifierCommand::GenerateNonce(_) => { CommandIndex::VerifierCommandGenerateNonce } + VerifierCommand::VerifyProof(_, _, _, _, _, _, _) => { CommandMetric::VerifierCommandVerifyProof } + VerifierCommand::GenerateNonce(_) => { CommandMetric::VerifierCommandGenerateNonce } } } } -impl From<&Command> for CommandIndex { +impl From<&Command> for CommandMetric { fn from(cmd: &Command) -> Self { match cmd { - Command::Exit => { CommandIndex::Exit } + Command::Exit => { CommandMetric::Exit } Command::Anoncreds(cmd) => { match cmd { AnoncredsCommand::Issuer(cmd) => { cmd.into() } AnoncredsCommand::Prover(cmd) => { cmd.into() } AnoncredsCommand::Verifier(cmd) => { cmd.into() } - AnoncredsCommand::ToUnqualified(_, _) => { CommandIndex::AnoncredsCommandToUnqualified } + AnoncredsCommand::ToUnqualified(_, _) => { CommandMetric::AnoncredsCommandToUnqualified } } } Command::BlobStorage(cmd) => { match cmd { - BlobStorageCommand::OpenReader(_, _, _) => { CommandIndex::BlobStorageCommandOpenReader } - BlobStorageCommand::OpenWriter(_, _, _) => { CommandIndex::BlobStorageCommandOpenWriter } + BlobStorageCommand::OpenReader(_, _, _) => { CommandMetric::BlobStorageCommandOpenReader } + BlobStorageCommand::OpenWriter(_, _, _) => { CommandMetric::BlobStorageCommandOpenWriter } } } Command::Crypto(cmd) => { match cmd { - CryptoCommand::CreateKey(_, _, _) => { CommandIndex::CryptoCommandCreateKey } - CryptoCommand::SetKeyMetadata(_, _, _, _) => { CommandIndex::CryptoCommandSetKeyMetadata } - CryptoCommand::GetKeyMetadata(_, _, _) => { CommandIndex::CryptoCommandGetKeyMetadata } - CryptoCommand::CryptoSign(_, _, _, _) => { CommandIndex::CryptoCommandCryptoSign } - CryptoCommand::CryptoVerify(_, _, _, _) => { CommandIndex::CryptoCommandCryptoVerify } - CryptoCommand::AuthenticatedEncrypt(_, _, _, _, _) => { CommandIndex::CryptoCommandAuthenticatedEncrypt } - CryptoCommand::AuthenticatedDecrypt(_, _, _, _) => { CommandIndex::CryptoCommandAuthenticatedDecrypt } - CryptoCommand::AnonymousEncrypt(_, _, _) => { CommandIndex::CryptoCommandAnonymousEncrypt } - CryptoCommand::AnonymousDecrypt(_, _, _, _) => { CommandIndex::CryptoCommandAnonymousDecrypt } - CryptoCommand::PackMessage(_, _, _, _, _) => { CommandIndex::CryptoCommandPackMessage } - CryptoCommand::UnpackMessage(_, _, _) => { CommandIndex::CryptoCommandUnpackMessage } + CryptoCommand::CreateKey(_, _, _) => { CommandMetric::CryptoCommandCreateKey } + CryptoCommand::SetKeyMetadata(_, _, _, _) => { CommandMetric::CryptoCommandSetKeyMetadata } + CryptoCommand::GetKeyMetadata(_, _, _) => { CommandMetric::CryptoCommandGetKeyMetadata } + CryptoCommand::CryptoSign(_, _, _, _) => { CommandMetric::CryptoCommandCryptoSign } + CryptoCommand::CryptoVerify(_, _, _, _) => { CommandMetric::CryptoCommandCryptoVerify } + CryptoCommand::AuthenticatedEncrypt(_, _, _, _, _) => { CommandMetric::CryptoCommandAuthenticatedEncrypt } + CryptoCommand::AuthenticatedDecrypt(_, _, _, _) => { CommandMetric::CryptoCommandAuthenticatedDecrypt } + CryptoCommand::AnonymousEncrypt(_, _, _) => { CommandMetric::CryptoCommandAnonymousEncrypt } + CryptoCommand::AnonymousDecrypt(_, _, _, _) => { CommandMetric::CryptoCommandAnonymousDecrypt } + CryptoCommand::PackMessage(_, _, _, _, _) => { CommandMetric::CryptoCommandPackMessage } + CryptoCommand::UnpackMessage(_, _, _) => { CommandMetric::CryptoCommandUnpackMessage } } } Command::Ledger(cmd) => { match cmd { - LedgerCommand::SignAndSubmitRequest(_, _, _, _, _) => { CommandIndex::LedgerCommandSignAndSubmitRequest } - LedgerCommand::SubmitRequest(_, _, _) => { CommandIndex::LedgerCommandSubmitRequest } - LedgerCommand::SubmitAck(_, _) => { CommandIndex::LedgerCommandSubmitAck } - LedgerCommand::SubmitAction(_, _, _, _, _) => { CommandIndex::LedgerCommandSubmitAction } - LedgerCommand::SignRequest(_, _, _, _) => { CommandIndex::LedgerCommandSignRequest } - LedgerCommand::MultiSignRequest(_, _, _, _) => { CommandIndex::LedgerCommandMultiSignRequest } - LedgerCommand::BuildGetDdoRequest(_, _, _) => { CommandIndex::LedgerCommandBuildGetDdoRequest } - LedgerCommand::BuildNymRequest(_, _, _, _, _, _) => { CommandIndex::LedgerCommandBuildNymRequest } - LedgerCommand::BuildAttribRequest(_, _, _, _, _, _) => { CommandIndex::LedgerCommandBuildAttribRequest } - LedgerCommand::BuildGetAttribRequest(_, _, _, _, _, _) => { CommandIndex::LedgerCommandBuildGetAttribRequest } - LedgerCommand::BuildGetNymRequest(_, _, _) => { CommandIndex::LedgerCommandBuildGetNymRequest } - LedgerCommand::ParseGetNymResponse(_, _) => { CommandIndex::LedgerCommandParseGetNymResponse } - LedgerCommand::BuildSchemaRequest(_, _, _) => { CommandIndex::LedgerCommandBuildSchemaRequest } - LedgerCommand::BuildGetSchemaRequest(_, _, _) => { CommandIndex::LedgerCommandBuildGetSchemaRequest } - LedgerCommand::ParseGetSchemaResponse(_, _) => { CommandIndex::LedgerCommandParseGetSchemaResponse } - LedgerCommand::BuildCredDefRequest(_, _, _) => { CommandIndex::LedgerCommandBuildCredDefRequest } - LedgerCommand::BuildGetCredDefRequest(_, _, _) => { CommandIndex::LedgerCommandBuildGetCredDefRequest } - LedgerCommand::ParseGetCredDefResponse(_, _) => { CommandIndex::LedgerCommandParseGetCredDefResponse } - LedgerCommand::BuildNodeRequest(_, _, _, _) => { CommandIndex::LedgerCommandBuildNodeRequest } - LedgerCommand::BuildGetValidatorInfoRequest(_, _) => { CommandIndex::LedgerCommandBuildGetValidatorInfoRequest } - LedgerCommand::BuildGetTxnRequest(_, _, _, _) => { CommandIndex::LedgerCommandBuildGetTxnRequest } - LedgerCommand::BuildPoolConfigRequest(_, _, _, _) => { CommandIndex::LedgerCommandBuildPoolConfigRequest } - LedgerCommand::BuildPoolRestartRequest(_, _, _, _) => { CommandIndex::LedgerCommandBuildPoolRestartRequest } - LedgerCommand::BuildPoolUpgradeRequest(_, _, _, _, _, _, _, _, _, _, _, _) => { CommandIndex::LedgerCommandBuildPoolUpgradeRequest } - LedgerCommand::BuildRevocRegDefRequest(_, _, _) => { CommandIndex::LedgerCommandBuildRevocRegDefRequest } - LedgerCommand::BuildGetRevocRegDefRequest(_, _, _) => { CommandIndex::LedgerCommandBuildGetRevocRegDefRequest } - LedgerCommand::ParseGetRevocRegDefResponse(_, _) => { CommandIndex::LedgerCommandParseGetRevocRegDefResponse } - LedgerCommand::BuildRevocRegEntryRequest(_, _, _, _, _) => { CommandIndex::LedgerCommandBuildRevocRegEntryRequest } - LedgerCommand::BuildGetRevocRegRequest(_, _, _, _) => { CommandIndex::LedgerCommandBuildGetRevocRegRequest } - LedgerCommand::ParseGetRevocRegResponse(_, _) => { CommandIndex::LedgerCommandParseGetRevocRegResponse } - LedgerCommand::BuildGetRevocRegDeltaRequest(_, _, _, _, _) => { CommandIndex::LedgerCommandBuildGetRevocRegDeltaRequest } - LedgerCommand::ParseGetRevocRegDeltaResponse(_, _) => { CommandIndex::LedgerCommandParseGetRevocRegDeltaResponse } - LedgerCommand::RegisterSPParser(_, _, _, _) => { CommandIndex::LedgerCommandRegisterSPParser } - LedgerCommand::GetResponseMetadata(_, _) => { CommandIndex::LedgerCommandGetResponseMetadata } - LedgerCommand::BuildAuthRuleRequest(_, _, _, _, _, _, _, _) => { CommandIndex::LedgerCommandBuildAuthRuleRequest } - LedgerCommand::BuildAuthRulesRequest(_, _, _) => { CommandIndex::LedgerCommandBuildAuthRulesRequest } - LedgerCommand::BuildGetAuthRuleRequest(_, _, _, _, _, _, _) => { CommandIndex::LedgerCommandBuildGetAuthRuleRequest } - LedgerCommand::GetSchema(_, _, _, _) => { CommandIndex::LedgerCommandGetSchema } - LedgerCommand::GetSchemaContinue(_, _, _) => { CommandIndex::LedgerCommandGetSchemaContinue } - LedgerCommand::GetCredDef(_, _, _, _) => { CommandIndex::LedgerCommandGetCredDef } - LedgerCommand::GetCredDefContinue(_, _, _) => { CommandIndex::LedgerCommandGetCredDefContinue } - LedgerCommand::BuildTxnAuthorAgreementRequest(_, _, _, _, _, _) => { CommandIndex::LedgerCommandBuildTxnAuthorAgreementRequest } - LedgerCommand::BuildDisableAllTxnAuthorAgreementsRequest(_, _) => { CommandIndex::LedgerCommandBuildDisableAllTxnAuthorAgreementsRequest } - LedgerCommand::BuildGetTxnAuthorAgreementRequest(_, _, _) => { CommandIndex::LedgerCommandBuildGetTxnAuthorAgreementRequest } - LedgerCommand::BuildAcceptanceMechanismRequests(_, _, _, _, _) => { CommandIndex::LedgerCommandBuildAcceptanceMechanismRequests } - LedgerCommand::BuildGetAcceptanceMechanismsRequest(_, _, _, _) => { CommandIndex::LedgerCommandBuildGetAcceptanceMechanismsRequest } - LedgerCommand::AppendTxnAuthorAgreementAcceptanceToRequest(_, _, _, _, _, _, _) => { CommandIndex::LedgerCommandAppendTxnAuthorAgreementAcceptanceToRequest } - LedgerCommand::AppendRequestEndorser(_, _, _) => { CommandIndex::LedgerCommandAppendRequestEndorser } + LedgerCommand::SignAndSubmitRequest(_, _, _, _, _) => { CommandMetric::LedgerCommandSignAndSubmitRequest } + LedgerCommand::SubmitRequest(_, _, _) => { CommandMetric::LedgerCommandSubmitRequest } + LedgerCommand::SubmitAck(_, _) => { CommandMetric::LedgerCommandSubmitAck } + LedgerCommand::SubmitAction(_, _, _, _, _) => { CommandMetric::LedgerCommandSubmitAction } + LedgerCommand::SignRequest(_, _, _, _) => { CommandMetric::LedgerCommandSignRequest } + LedgerCommand::MultiSignRequest(_, _, _, _) => { CommandMetric::LedgerCommandMultiSignRequest } + LedgerCommand::BuildGetDdoRequest(_, _, _) => { CommandMetric::LedgerCommandBuildGetDdoRequest } + LedgerCommand::BuildNymRequest(_, _, _, _, _, _) => { CommandMetric::LedgerCommandBuildNymRequest } + LedgerCommand::BuildAttribRequest(_, _, _, _, _, _) => { CommandMetric::LedgerCommandBuildAttribRequest } + LedgerCommand::BuildGetAttribRequest(_, _, _, _, _, _) => { CommandMetric::LedgerCommandBuildGetAttribRequest } + LedgerCommand::BuildGetNymRequest(_, _, _) => { CommandMetric::LedgerCommandBuildGetNymRequest } + LedgerCommand::ParseGetNymResponse(_, _) => { CommandMetric::LedgerCommandParseGetNymResponse } + LedgerCommand::BuildSchemaRequest(_, _, _) => { CommandMetric::LedgerCommandBuildSchemaRequest } + LedgerCommand::BuildGetSchemaRequest(_, _, _) => { CommandMetric::LedgerCommandBuildGetSchemaRequest } + LedgerCommand::ParseGetSchemaResponse(_, _) => { CommandMetric::LedgerCommandParseGetSchemaResponse } + LedgerCommand::BuildCredDefRequest(_, _, _) => { CommandMetric::LedgerCommandBuildCredDefRequest } + LedgerCommand::BuildGetCredDefRequest(_, _, _) => { CommandMetric::LedgerCommandBuildGetCredDefRequest } + LedgerCommand::ParseGetCredDefResponse(_, _) => { CommandMetric::LedgerCommandParseGetCredDefResponse } + LedgerCommand::BuildNodeRequest(_, _, _, _) => { CommandMetric::LedgerCommandBuildNodeRequest } + LedgerCommand::BuildGetValidatorInfoRequest(_, _) => { CommandMetric::LedgerCommandBuildGetValidatorInfoRequest } + LedgerCommand::BuildGetTxnRequest(_, _, _, _) => { CommandMetric::LedgerCommandBuildGetTxnRequest } + LedgerCommand::BuildPoolConfigRequest(_, _, _, _) => { CommandMetric::LedgerCommandBuildPoolConfigRequest } + LedgerCommand::BuildPoolRestartRequest(_, _, _, _) => { CommandMetric::LedgerCommandBuildPoolRestartRequest } + LedgerCommand::BuildPoolUpgradeRequest(_, _, _, _, _, _, _, _, _, _, _, _) => { CommandMetric::LedgerCommandBuildPoolUpgradeRequest } + LedgerCommand::BuildRevocRegDefRequest(_, _, _) => { CommandMetric::LedgerCommandBuildRevocRegDefRequest } + LedgerCommand::BuildGetRevocRegDefRequest(_, _, _) => { CommandMetric::LedgerCommandBuildGetRevocRegDefRequest } + LedgerCommand::ParseGetRevocRegDefResponse(_, _) => { CommandMetric::LedgerCommandParseGetRevocRegDefResponse } + LedgerCommand::BuildRevocRegEntryRequest(_, _, _, _, _) => { CommandMetric::LedgerCommandBuildRevocRegEntryRequest } + LedgerCommand::BuildGetRevocRegRequest(_, _, _, _) => { CommandMetric::LedgerCommandBuildGetRevocRegRequest } + LedgerCommand::ParseGetRevocRegResponse(_, _) => { CommandMetric::LedgerCommandParseGetRevocRegResponse } + LedgerCommand::BuildGetRevocRegDeltaRequest(_, _, _, _, _) => { CommandMetric::LedgerCommandBuildGetRevocRegDeltaRequest } + LedgerCommand::ParseGetRevocRegDeltaResponse(_, _) => { CommandMetric::LedgerCommandParseGetRevocRegDeltaResponse } + LedgerCommand::RegisterSPParser(_, _, _, _) => { CommandMetric::LedgerCommandRegisterSPParser } + LedgerCommand::GetResponseMetadata(_, _) => { CommandMetric::LedgerCommandGetResponseMetadata } + LedgerCommand::BuildAuthRuleRequest(_, _, _, _, _, _, _, _) => { CommandMetric::LedgerCommandBuildAuthRuleRequest } + LedgerCommand::BuildAuthRulesRequest(_, _, _) => { CommandMetric::LedgerCommandBuildAuthRulesRequest } + LedgerCommand::BuildGetAuthRuleRequest(_, _, _, _, _, _, _) => { CommandMetric::LedgerCommandBuildGetAuthRuleRequest } + LedgerCommand::GetSchema(_, _, _, _) => { CommandMetric::LedgerCommandGetSchema } + LedgerCommand::GetSchemaContinue(_, _, _) => { CommandMetric::LedgerCommandGetSchemaContinue } + LedgerCommand::GetCredDef(_, _, _, _) => { CommandMetric::LedgerCommandGetCredDef } + LedgerCommand::GetCredDefContinue(_, _, _) => { CommandMetric::LedgerCommandGetCredDefContinue } + LedgerCommand::BuildTxnAuthorAgreementRequest(_, _, _, _, _, _) => { CommandMetric::LedgerCommandBuildTxnAuthorAgreementRequest } + LedgerCommand::BuildDisableAllTxnAuthorAgreementsRequest(_, _) => { CommandMetric::LedgerCommandBuildDisableAllTxnAuthorAgreementsRequest } + LedgerCommand::BuildGetTxnAuthorAgreementRequest(_, _, _) => { CommandMetric::LedgerCommandBuildGetTxnAuthorAgreementRequest } + LedgerCommand::BuildAcceptanceMechanismRequests(_, _, _, _, _) => { CommandMetric::LedgerCommandBuildAcceptanceMechanismRequests } + LedgerCommand::BuildGetAcceptanceMechanismsRequest(_, _, _, _) => { CommandMetric::LedgerCommandBuildGetAcceptanceMechanismsRequest } + LedgerCommand::AppendTxnAuthorAgreementAcceptanceToRequest(_, _, _, _, _, _, _) => { CommandMetric::LedgerCommandAppendTxnAuthorAgreementAcceptanceToRequest } + LedgerCommand::AppendRequestEndorser(_, _, _) => { CommandMetric::LedgerCommandAppendRequestEndorser } + LedgerCommand::BuildGetFrozenLedgersRequest(_,_,) => { CommandMetric::LedgerCommandBuildGetFrozenLedgersRequest } + LedgerCommand::BuildLedgersFreezeRequest(_,_,_,) => { CommandMetric::LedgerCommandBuildLedgersFreezeRequest } } } Command::Pool(cmd) => { match cmd { - PoolCommand::Create(_, _, _) => { CommandIndex::PoolCommandCreate } - PoolCommand::Delete(_, _) => { CommandIndex::PoolCommandDelete } - PoolCommand::Open(_, _, _) => { CommandIndex::PoolCommandOpen } - PoolCommand::OpenAck(_, _, _) => { CommandIndex::PoolCommandOpenAck } - PoolCommand::List(_) => { CommandIndex::PoolCommandList } - PoolCommand::Close(_, _) => { CommandIndex::PoolCommandClose } - PoolCommand::CloseAck(_, _) => { CommandIndex::PoolCommandCloseAck } - PoolCommand::Refresh(_, _) => { CommandIndex::PoolCommandRefresh } - PoolCommand::RefreshAck(_, _) => { CommandIndex::PoolCommandRefreshAck } - PoolCommand::SetProtocolVersion(_, _) => { CommandIndex::PoolCommandSetProtocolVersion } + PoolCommand::Create(_, _, _) => { CommandMetric::PoolCommandCreate } + PoolCommand::Delete(_, _) => { CommandMetric::PoolCommandDelete } + PoolCommand::Open(_, _, _) => { CommandMetric::PoolCommandOpen } + PoolCommand::OpenAck(_, _, _) => { CommandMetric::PoolCommandOpenAck } + PoolCommand::List(_) => { CommandMetric::PoolCommandList } + PoolCommand::Close(_, _) => { CommandMetric::PoolCommandClose } + PoolCommand::CloseAck(_, _) => { CommandMetric::PoolCommandCloseAck } + PoolCommand::Refresh(_, _) => { CommandMetric::PoolCommandRefresh } + PoolCommand::RefreshAck(_, _) => { CommandMetric::PoolCommandRefreshAck } + PoolCommand::SetProtocolVersion(_, _) => { CommandMetric::PoolCommandSetProtocolVersion } } } Command::Did(cmd) => { match cmd { - DidCommand::CreateAndStoreMyDid(_, _, _) => { CommandIndex::DidCommandCreateAndStoreMyDid } - DidCommand::ReplaceKeysStart(_, _, _, _) => { CommandIndex::DidCommandReplaceKeysStart } - DidCommand::ReplaceKeysApply(_, _, _) => { CommandIndex::DidCommandReplaceKeysApply } - DidCommand::StoreTheirDid(_, _, _) => { CommandIndex::DidCommandStoreTheirDid } - DidCommand::GetMyDidWithMeta(_, _, _) => { CommandIndex::DidCommandGetMyDidWithMeta } - DidCommand::ListMyDidsWithMeta(_, _) => { CommandIndex::DidCommandListMyDidsWithMeta } - DidCommand::KeyForDid(_, _, _, _) => { CommandIndex::DidCommandKeyForDid } - DidCommand::KeyForLocalDid(_, _, _) => { CommandIndex::DidCommandKeyForLocalDid } - DidCommand::SetEndpointForDid(_, _, _, _) => { CommandIndex::DidCommandSetEndpointForDid } - DidCommand::GetEndpointForDid(_, _, _, _) => { CommandIndex::DidCommandGetEndpointForDid } - DidCommand::SetDidMetadata(_, _, _, _) => { CommandIndex::DidCommandSetDidMetadata } - DidCommand::GetDidMetadata(_, _, _) => { CommandIndex::DidCommandGetDidMetadata } - DidCommand::AbbreviateVerkey(_, _, _) => { CommandIndex::DidCommandAbbreviateVerkey } - DidCommand::GetNymAck(_, _, _, _) => { CommandIndex::DidCommandGetNymAck } - DidCommand::GetAttribAck(_, _, _) => { CommandIndex::DidCommandGetAttribAck } - DidCommand::QualifyDid(_, _, _, _) => { CommandIndex::DidCommandQualifyDid } + DidCommand::CreateAndStoreMyDid(_, _, _) => { CommandMetric::DidCommandCreateAndStoreMyDid } + DidCommand::ReplaceKeysStart(_, _, _, _) => { CommandMetric::DidCommandReplaceKeysStart } + DidCommand::ReplaceKeysApply(_, _, _) => { CommandMetric::DidCommandReplaceKeysApply } + DidCommand::StoreTheirDid(_, _, _) => { CommandMetric::DidCommandStoreTheirDid } + DidCommand::GetMyDidWithMeta(_, _, _) => { CommandMetric::DidCommandGetMyDidWithMeta } + DidCommand::ListMyDidsWithMeta(_, _) => { CommandMetric::DidCommandListMyDidsWithMeta } + DidCommand::KeyForDid(_, _, _, _) => { CommandMetric::DidCommandKeyForDid } + DidCommand::KeyForLocalDid(_, _, _) => { CommandMetric::DidCommandKeyForLocalDid } + DidCommand::SetEndpointForDid(_, _, _, _) => { CommandMetric::DidCommandSetEndpointForDid } + DidCommand::GetEndpointForDid(_, _, _, _) => { CommandMetric::DidCommandGetEndpointForDid } + DidCommand::SetDidMetadata(_, _, _, _) => { CommandMetric::DidCommandSetDidMetadata } + DidCommand::GetDidMetadata(_, _, _) => { CommandMetric::DidCommandGetDidMetadata } + DidCommand::AbbreviateVerkey(_, _, _) => { CommandMetric::DidCommandAbbreviateVerkey } + DidCommand::GetNymAck(_, _, _, _) => { CommandMetric::DidCommandGetNymAck } + DidCommand::GetAttribAck(_, _, _) => { CommandMetric::DidCommandGetAttribAck } + DidCommand::QualifyDid(_, _, _, _) => { CommandMetric::DidCommandQualifyDid } } } Command::Wallet(cmd) => { match cmd { - WalletCommand::RegisterWalletType(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) => { CommandIndex::WalletCommandRegisterWalletType } - WalletCommand::Create(_, _, _) => { CommandIndex::WalletCommandCreate } - WalletCommand::CreateContinue(_, _, _, _, _) => { CommandIndex::WalletCommandCreateContinue } - WalletCommand::Open(_, _, _) => { CommandIndex::WalletCommandOpen } - WalletCommand::OpenContinue(_, _) => { CommandIndex::WalletCommandOpenContinue } - WalletCommand::Close(_, _) => { CommandIndex::WalletCommandClose } - WalletCommand::Delete(_, _, _) => { CommandIndex::WalletCommandDelete } - WalletCommand::DeleteContinue(_, _, _, _, _) => { CommandIndex::WalletCommandDeleteContinue } - WalletCommand::Export(_, _, _) => { CommandIndex::WalletCommandExport } - WalletCommand::ExportContinue(_, _, _, _, _) => { CommandIndex::WalletCommandExportContinue } - WalletCommand::Import(_, _, _, _) => { CommandIndex::WalletCommandImport } - WalletCommand::ImportContinue(_, _, _, _, _) => { CommandIndex::WalletCommandImportContinue } - WalletCommand::GenerateKey(_, _) => { CommandIndex::WalletCommandGenerateKey } - WalletCommand::DeriveKey(_, _) => { CommandIndex::WalletCommandDeriveKey } + WalletCommand::RegisterWalletType(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) => { CommandMetric::WalletCommandRegisterWalletType } + WalletCommand::Create(_, _, _) => { CommandMetric::WalletCommandCreate } + WalletCommand::CreateContinue(_, _, _, _, _) => { CommandMetric::WalletCommandCreateContinue } + WalletCommand::Open(_, _, _) => { CommandMetric::WalletCommandOpen } + WalletCommand::OpenContinue(_, _) => { CommandMetric::WalletCommandOpenContinue } + WalletCommand::Close(_, _) => { CommandMetric::WalletCommandClose } + WalletCommand::Delete(_, _, _) => { CommandMetric::WalletCommandDelete } + WalletCommand::DeleteContinue(_, _, _, _, _) => { CommandMetric::WalletCommandDeleteContinue } + WalletCommand::Export(_, _, _) => { CommandMetric::WalletCommandExport } + WalletCommand::ExportContinue(_, _, _, _, _) => { CommandMetric::WalletCommandExportContinue } + WalletCommand::Import(_, _, _, _) => { CommandMetric::WalletCommandImport } + WalletCommand::ImportContinue(_, _, _, _, _) => { CommandMetric::WalletCommandImportContinue } + WalletCommand::GenerateKey(_, _) => { CommandMetric::WalletCommandGenerateKey } + WalletCommand::DeriveKey(_, _) => { CommandMetric::WalletCommandDeriveKey } } } Command::Pairwise(cmd) => { match cmd { - PairwiseCommand::PairwiseExists(_, _, _) => { CommandIndex::PairwiseCommandPairwiseExists } - PairwiseCommand::CreatePairwise(_, _, _, _, _) => { CommandIndex::PairwiseCommandCreatePairwise } - PairwiseCommand::ListPairwise(_, _) => { CommandIndex::PairwiseCommandListPairwise } - PairwiseCommand::GetPairwise(_, _, _) => { CommandIndex::PairwiseCommandGetPairwise } - PairwiseCommand::SetPairwiseMetadata(_, _, _, _) => { CommandIndex::PairwiseCommandSetPairwiseMetadata } + PairwiseCommand::PairwiseExists(_, _, _) => { CommandMetric::PairwiseCommandPairwiseExists } + PairwiseCommand::CreatePairwise(_, _, _, _, _) => { CommandMetric::PairwiseCommandCreatePairwise } + PairwiseCommand::ListPairwise(_, _) => { CommandMetric::PairwiseCommandListPairwise } + PairwiseCommand::GetPairwise(_, _, _) => { CommandMetric::PairwiseCommandGetPairwise } + PairwiseCommand::SetPairwiseMetadata(_, _, _, _) => { CommandMetric::PairwiseCommandSetPairwiseMetadata } } } Command::NonSecrets(cmd) => { match cmd { - NonSecretsCommand::AddRecord(_, _, _, _, _, _) => { CommandIndex::NonSecretsCommandAddRecord } - NonSecretsCommand::UpdateRecordValue(_, _, _, _, _) => { CommandIndex::NonSecretsCommandUpdateRecordValue } - NonSecretsCommand::UpdateRecordTags(_, _, _, _, _) => { CommandIndex::NonSecretsCommandUpdateRecordTags } - NonSecretsCommand::AddRecordTags(_, _, _, _, _) => { CommandIndex::NonSecretsCommandAddRecordTags } - NonSecretsCommand::DeleteRecordTags(_, _, _, _, _) => { CommandIndex::NonSecretsCommandDeleteRecordTags } - NonSecretsCommand::DeleteRecord(_, _, _, _) => { CommandIndex::NonSecretsCommandDeleteRecord } - NonSecretsCommand::GetRecord(_, _, _, _, _) => { CommandIndex::NonSecretsCommandGetRecord } - NonSecretsCommand::OpenSearch(_, _, _, _, _) => { CommandIndex::NonSecretsCommandOpenSearch } - NonSecretsCommand::FetchSearchNextRecords(_, _, _, _) => { CommandIndex::NonSecretsCommandFetchSearchNextRecords } - NonSecretsCommand::CloseSearch(_, _) => { CommandIndex::NonSecretsCommandCloseSearch } + NonSecretsCommand::AddRecord(_, _, _, _, _, _) => { CommandMetric::NonSecretsCommandAddRecord } + NonSecretsCommand::UpdateRecordValue(_, _, _, _, _) => { CommandMetric::NonSecretsCommandUpdateRecordValue } + NonSecretsCommand::UpdateRecordTags(_, _, _, _, _) => { CommandMetric::NonSecretsCommandUpdateRecordTags } + NonSecretsCommand::AddRecordTags(_, _, _, _, _) => { CommandMetric::NonSecretsCommandAddRecordTags } + NonSecretsCommand::DeleteRecordTags(_, _, _, _, _) => { CommandMetric::NonSecretsCommandDeleteRecordTags } + NonSecretsCommand::DeleteRecord(_, _, _, _) => { CommandMetric::NonSecretsCommandDeleteRecord } + NonSecretsCommand::GetRecord(_, _, _, _, _) => { CommandMetric::NonSecretsCommandGetRecord } + NonSecretsCommand::OpenSearch(_, _, _, _, _) => { CommandMetric::NonSecretsCommandOpenSearch } + NonSecretsCommand::FetchSearchNextRecords(_, _, _, _) => { CommandMetric::NonSecretsCommandFetchSearchNextRecords } + NonSecretsCommand::CloseSearch(_, _) => { CommandMetric::NonSecretsCommandCloseSearch } } } Command::Payments(cmd) => { match cmd { - PaymentsCommand::RegisterMethod(_, _, _) => { CommandIndex::PaymentsCommandRegisterMethod } - PaymentsCommand::CreateAddress(_, _, _, _) => { CommandIndex::PaymentsCommandCreateAddress } - PaymentsCommand::CreateAddressAck(_, _, _) => { CommandIndex::PaymentsCommandCreateAddressAck } - PaymentsCommand::ListAddresses(_, _) => { CommandIndex::PaymentsCommandListAddresses } - PaymentsCommand::AddRequestFees(_, _, _, _, _, _, _) => { CommandIndex::PaymentsCommandAddRequestFees } - PaymentsCommand::AddRequestFeesAck(_, _) => { CommandIndex::PaymentsCommandAddRequestFeesAck } - PaymentsCommand::ParseResponseWithFees(_, _, _) => { CommandIndex::PaymentsCommandParseResponseWithFees } - PaymentsCommand::ParseResponseWithFeesAck(_, _) => { CommandIndex::PaymentsCommandParseResponseWithFeesAck } - PaymentsCommand::BuildGetPaymentSourcesRequest(_, _, _, _, _) => { CommandIndex::PaymentsCommandBuildGetPaymentSourcesRequest } - PaymentsCommand::BuildGetPaymentSourcesRequestAck(_, _) => { CommandIndex::PaymentsCommandBuildGetPaymentSourcesRequestAck } - PaymentsCommand::ParseGetPaymentSourcesResponse(_, _, _) => { CommandIndex::PaymentsCommandParseGetPaymentSourcesResponse } - PaymentsCommand::ParseGetPaymentSourcesResponseAck(_, _) => { CommandIndex::PaymentsCommandParseGetPaymentSourcesResponseAck } - PaymentsCommand::BuildPaymentReq(_, _, _, _, _, _) => { CommandIndex::PaymentsCommandBuildPaymentReq } - PaymentsCommand::BuildPaymentReqAck(_, _) => { CommandIndex::PaymentsCommandBuildPaymentReqAck } - PaymentsCommand::ParsePaymentResponse(_, _, _) => { CommandIndex::PaymentsCommandParsePaymentResponse } - PaymentsCommand::ParsePaymentResponseAck(_, _) => { CommandIndex::PaymentsCommandParsePaymentResponseAck } - PaymentsCommand::AppendTxnAuthorAgreementAcceptanceToExtra(_, _, _, _, _, _, _) => { CommandIndex::PaymentsCommandAppendTxnAuthorAgreementAcceptanceToExtra } - PaymentsCommand::BuildMintReq(_, _, _, _, _) => { CommandIndex::PaymentsCommandBuildMintReq } - PaymentsCommand::BuildMintReqAck(_, _) => { CommandIndex::PaymentsCommandBuildMintReqAck } - PaymentsCommand::BuildSetTxnFeesReq(_, _, _, _, _) => { CommandIndex::PaymentsCommandBuildSetTxnFeesReq } - PaymentsCommand::BuildSetTxnFeesReqAck(_, _) => { CommandIndex::PaymentsCommandBuildSetTxnFeesReqAck } - PaymentsCommand::BuildGetTxnFeesReq(_, _, _, _) => { CommandIndex::PaymentsCommandBuildGetTxnFeesReq } - PaymentsCommand::BuildGetTxnFeesReqAck(_, _) => { CommandIndex::PaymentsCommandBuildGetTxnFeesReqAck } - PaymentsCommand::ParseGetTxnFeesResponse(_, _, _) => { CommandIndex::PaymentsCommandParseGetTxnFeesResponse } - PaymentsCommand::ParseGetTxnFeesResponseAck(_, _) => { CommandIndex::PaymentsCommandParseGetTxnFeesResponseAck } - PaymentsCommand::BuildVerifyPaymentReq(_, _, _, _) => { CommandIndex::PaymentsCommandBuildVerifyPaymentReq } - PaymentsCommand::BuildVerifyPaymentReqAck(_, _) => { CommandIndex::PaymentsCommandBuildVerifyPaymentReqAck } - PaymentsCommand::ParseVerifyPaymentResponse(_, _, _) => { CommandIndex::PaymentsCommandParseVerifyPaymentResponse } - PaymentsCommand::ParseVerifyPaymentResponseAck(_, _) => { CommandIndex::PaymentsCommandParseVerifyPaymentResponseAck } - PaymentsCommand::GetRequestInfo(_, _, _, _) => { CommandIndex::PaymentsCommandGetRequestInfo } - PaymentsCommand::SignWithAddressReq(_, _, _, _) => { CommandIndex::PaymentsCommandSignWithAddressReq } - PaymentsCommand::SignWithAddressAck(_, _) => { CommandIndex::PaymentsCommandSignWithAddressAck } - PaymentsCommand::VerifyWithAddressReq(_, _, _, _) => { CommandIndex::PaymentsCommandVerifyWithAddressReq } - PaymentsCommand::VerifyWithAddressAck(_, _) => { CommandIndex::PaymentsCommandVerifyWithAddressAck } + PaymentsCommand::RegisterMethod(_, _, _) => { CommandMetric::PaymentsCommandRegisterMethod } + PaymentsCommand::CreateAddress(_, _, _, _) => { CommandMetric::PaymentsCommandCreateAddress } + PaymentsCommand::CreateAddressAck(_, _, _) => { CommandMetric::PaymentsCommandCreateAddressAck } + PaymentsCommand::ListAddresses(_, _) => { CommandMetric::PaymentsCommandListAddresses } + PaymentsCommand::AddRequestFees(_, _, _, _, _, _, _) => { CommandMetric::PaymentsCommandAddRequestFees } + PaymentsCommand::AddRequestFeesAck(_, _) => { CommandMetric::PaymentsCommandAddRequestFeesAck } + PaymentsCommand::ParseResponseWithFees(_, _, _) => { CommandMetric::PaymentsCommandParseResponseWithFees } + PaymentsCommand::ParseResponseWithFeesAck(_, _) => { CommandMetric::PaymentsCommandParseResponseWithFeesAck } + PaymentsCommand::BuildGetPaymentSourcesRequest(_, _, _, _, _) => { CommandMetric::PaymentsCommandBuildGetPaymentSourcesRequest } + PaymentsCommand::BuildGetPaymentSourcesRequestAck(_, _) => { CommandMetric::PaymentsCommandBuildGetPaymentSourcesRequestAck } + PaymentsCommand::ParseGetPaymentSourcesResponse(_, _, _) => { CommandMetric::PaymentsCommandParseGetPaymentSourcesResponse } + PaymentsCommand::ParseGetPaymentSourcesResponseAck(_, _) => { CommandMetric::PaymentsCommandParseGetPaymentSourcesResponseAck } + PaymentsCommand::BuildPaymentReq(_, _, _, _, _, _) => { CommandMetric::PaymentsCommandBuildPaymentReq } + PaymentsCommand::BuildPaymentReqAck(_, _) => { CommandMetric::PaymentsCommandBuildPaymentReqAck } + PaymentsCommand::ParsePaymentResponse(_, _, _) => { CommandMetric::PaymentsCommandParsePaymentResponse } + PaymentsCommand::ParsePaymentResponseAck(_, _) => { CommandMetric::PaymentsCommandParsePaymentResponseAck } + PaymentsCommand::AppendTxnAuthorAgreementAcceptanceToExtra(_, _, _, _, _, _, _) => { CommandMetric::PaymentsCommandAppendTxnAuthorAgreementAcceptanceToExtra } + PaymentsCommand::BuildMintReq(_, _, _, _, _) => { CommandMetric::PaymentsCommandBuildMintReq } + PaymentsCommand::BuildMintReqAck(_, _) => { CommandMetric::PaymentsCommandBuildMintReqAck } + PaymentsCommand::BuildSetTxnFeesReq(_, _, _, _, _) => { CommandMetric::PaymentsCommandBuildSetTxnFeesReq } + PaymentsCommand::BuildSetTxnFeesReqAck(_, _) => { CommandMetric::PaymentsCommandBuildSetTxnFeesReqAck } + PaymentsCommand::BuildGetTxnFeesReq(_, _, _, _) => { CommandMetric::PaymentsCommandBuildGetTxnFeesReq } + PaymentsCommand::BuildGetTxnFeesReqAck(_, _) => { CommandMetric::PaymentsCommandBuildGetTxnFeesReqAck } + PaymentsCommand::ParseGetTxnFeesResponse(_, _, _) => { CommandMetric::PaymentsCommandParseGetTxnFeesResponse } + PaymentsCommand::ParseGetTxnFeesResponseAck(_, _) => { CommandMetric::PaymentsCommandParseGetTxnFeesResponseAck } + PaymentsCommand::BuildVerifyPaymentReq(_, _, _, _) => { CommandMetric::PaymentsCommandBuildVerifyPaymentReq } + PaymentsCommand::BuildVerifyPaymentReqAck(_, _) => { CommandMetric::PaymentsCommandBuildVerifyPaymentReqAck } + PaymentsCommand::ParseVerifyPaymentResponse(_, _, _) => { CommandMetric::PaymentsCommandParseVerifyPaymentResponse } + PaymentsCommand::ParseVerifyPaymentResponseAck(_, _) => { CommandMetric::PaymentsCommandParseVerifyPaymentResponseAck } + PaymentsCommand::GetRequestInfo(_, _, _, _) => { CommandMetric::PaymentsCommandGetRequestInfo } + PaymentsCommand::SignWithAddressReq(_, _, _, _) => { CommandMetric::PaymentsCommandSignWithAddressReq } + PaymentsCommand::SignWithAddressAck(_, _) => { CommandMetric::PaymentsCommandSignWithAddressAck } + PaymentsCommand::VerifyWithAddressReq(_, _, _, _) => { CommandMetric::PaymentsCommandVerifyWithAddressReq } + PaymentsCommand::VerifyWithAddressAck(_, _) => { CommandMetric::PaymentsCommandVerifyWithAddressAck } } } Command::Cache(cmd) => { match cmd { - CacheCommand::GetSchema(_, _, _, _, _, _) => { CommandIndex::CacheCommandGetSchema } - CacheCommand::GetSchemaContinue(_, _, _, _) => { CommandIndex::CacheCommandGetSchemaContinue } - CacheCommand::GetCredDef(_, _, _, _, _, _) => { CommandIndex::CacheCommandGetCredDef } - CacheCommand::GetCredDefContinue(_, _, _, _) => { CommandIndex::CacheCommandGetCredDefContinue } - CacheCommand::PurgeSchemaCache(_, _, _) => { CommandIndex::CacheCommandPurgeSchemaCache } - CacheCommand::PurgeCredDefCache(_, _, _) => { CommandIndex::CacheCommandPurgeCredDefCache } + CacheCommand::GetSchema(_, _, _, _, _, _) => { CommandMetric::CacheCommandGetSchema } + CacheCommand::GetSchemaContinue(_, _, _, _) => { CommandMetric::CacheCommandGetSchemaContinue } + CacheCommand::GetCredDef(_, _, _, _, _, _) => { CommandMetric::CacheCommandGetCredDef } + CacheCommand::GetCredDefContinue(_, _, _, _) => { CommandMetric::CacheCommandGetCredDefContinue } + CacheCommand::PurgeSchemaCache(_, _, _) => { CommandMetric::CacheCommandPurgeSchemaCache } + CacheCommand::PurgeCredDefCache(_, _, _) => { CommandMetric::CacheCommandPurgeCredDefCache } } } Command::Metrics(cmd) => { - match cmd { MetricsCommand::CollectMetrics(_) => { CommandIndex::MetricsCommandCollectMetrics } } + match cmd { MetricsCommand::CollectMetrics(_) => { CommandMetric::MetricsCommandCollectMetrics } } } } } @@ -325,8 +327,8 @@ impl From<&Command> for CommandIndex { #[derive(Debug, PartialEq, Copy, Clone, FromPrimitive, ToPrimitive, VariantCount)] -#[repr(i32)] -pub enum CommandIndex { +#[repr(usize)] +pub enum CommandMetric { // IssuerCommand IssuerCommandCreateSchema, IssuerCommandCreateAndStoreCredentialDefinition, @@ -427,6 +429,8 @@ pub enum CommandIndex { LedgerCommandBuildGetAcceptanceMechanismsRequest, LedgerCommandAppendTxnAuthorAgreementAcceptanceToRequest, LedgerCommandAppendRequestEndorser, + LedgerCommandBuildGetFrozenLedgersRequest, + LedgerCommandBuildLedgersFreezeRequest, // PoolCommand PoolCommandCreate, PoolCommandDelete, @@ -533,5 +537,4 @@ pub enum CommandIndex { MetricsCommandCollectMetrics, // Exit Exit, -} - +} \ No newline at end of file diff --git a/libindy/src/services/metrics/mod.rs b/libindy/src/services/metrics/mod.rs index f63acdb624..a7635b1cd2 100644 --- a/libindy/src/services/metrics/mod.rs +++ b/libindy/src/services/metrics/mod.rs @@ -1,64 +1,112 @@ -use crate::services::metrics::command_index::CommandIndex; +use crate::services::metrics::command_metrics::CommandMetric; use convert_case::{Case, Casing}; +use indy_api_types::errors::{IndyErrorKind, IndyResult, IndyResultExt}; +use models::{MetricsValue, CommandCounters}; use serde_json::{Map, Value}; use std::cell::RefCell; +use std::collections::HashMap; -pub mod command_index; - -const QUEUED_COMMANDS_COUNT: &str = "queued_commands_count"; -const QUEUED_COMMANDS_DURATION_MS: &str = "queued_commands_duration_ms"; -const EXECUTED_COMMANDS_COUNT: &str = "executed_commands_count"; -const EXECUTED_COMMANDS_DURATION_MS: &str = "executed_commands_duration_ms"; +pub mod command_metrics; +pub mod models; const COMMANDS_COUNT: usize = MetricsService::commands_count(); pub struct MetricsService { - queued_commands_count: RefCell<[u128; COMMANDS_COUNT]>, - queued_commands_duration_ms: RefCell<[u128; COMMANDS_COUNT]>, - - executed_commands_count: RefCell<[u128; COMMANDS_COUNT]>, - executed_commands_duration_ms: RefCell<[u128; COMMANDS_COUNT]>, + queued_counters: RefCell<[CommandCounters; COMMANDS_COUNT]>, + executed_counters: RefCell<[CommandCounters; COMMANDS_COUNT]>, } impl MetricsService { pub fn new() -> Self { MetricsService { - queued_commands_count: RefCell::new([u128::MIN; COMMANDS_COUNT]), - queued_commands_duration_ms: RefCell::new([u128::MIN; COMMANDS_COUNT]), - - executed_commands_count: RefCell::new([u128::MIN; COMMANDS_COUNT]), - executed_commands_duration_ms: RefCell::new([u128::MIN; COMMANDS_COUNT]), + queued_counters: RefCell::new([CommandCounters::new(); COMMANDS_COUNT]), + executed_counters: RefCell::new([CommandCounters::new(); COMMANDS_COUNT]), } } - pub fn cmd_left_queue(&self, command_index: CommandIndex, duration: u128) { - self.queued_commands_count.borrow_mut()[command_index as usize] += 1; - self.queued_commands_duration_ms.borrow_mut()[command_index as usize] += duration; + pub fn cmd_left_queue(&self, command_metric: CommandMetric, duration: u128) { + self.queued_counters.borrow_mut()[command_metric as usize].add(duration); } - pub fn cmd_executed(&self, command_index: CommandIndex, duration: u128) { - self.executed_commands_count.borrow_mut()[command_index as usize] += 1; - self.executed_commands_duration_ms.borrow_mut()[command_index as usize] += duration; + pub fn cmd_executed(&self, command_metric: CommandMetric, duration: u128) { + self.executed_counters.borrow_mut()[command_metric as usize].add(duration); } + pub fn cmd_name(index: usize) -> String { - CommandIndex::from(index).to_string().to_case(Case::Snake) + CommandMetric::from(index).to_string().to_case(Case::Snake) } + const fn commands_count() -> usize { - CommandIndex::VARIANT_COUNT + CommandMetric::VARIANT_COUNT } - pub fn append_command_metrics(&self, metrics_map: &mut Map) { + pub fn get_command_tags( + command: String, + stage: String, + ) -> HashMap { + let mut tags = HashMap::::new(); + tags.insert("command".to_owned(), command.to_owned()); + tags.insert("stage".to_owned(), stage.to_owned()); + tags + } + + pub fn append_command_metrics(&self, metrics_map: &mut Map) -> IndyResult<()> { + let mut commands_count = Vec::new(); + let mut commands_duration_ms = Vec::new(); + let mut commands_duration_ms_bucket = Vec::new(); + for index in (0..MetricsService::commands_count()).rev() { - let cmd_name = MetricsService::cmd_name(index); - metrics_map.insert(format!("{}_{}", cmd_name.as_str(), EXECUTED_COMMANDS_COUNT).as_str().to_string(), - Value::from(self.executed_commands_count.borrow()[index] as usize)); - metrics_map.insert(format!("{}_{}", cmd_name.as_str(), EXECUTED_COMMANDS_DURATION_MS).as_str().to_string(), - Value::from(self.executed_commands_duration_ms.borrow()[index] as usize)); - metrics_map.insert(format!("{}_{}", cmd_name.as_str(), QUEUED_COMMANDS_COUNT).as_str().to_string(), - Value::from(self.queued_commands_count.borrow()[index] as usize)); - metrics_map.insert(format!("{}_{}", cmd_name.as_str(), QUEUED_COMMANDS_DURATION_MS).as_str().to_string(), - Value::from(self.queued_commands_duration_ms.borrow()[index] as usize)); + let command_name = MetricsService::cmd_name(index); + let tags_executed = MetricsService::get_command_tags( + command_name.to_owned(), + String::from("executed"), + ); + let tags_queued = MetricsService::get_command_tags( + command_name.to_owned(), + String::from("queued"), + ); + + commands_count.push(self.get_metric_json(self.executed_counters.borrow()[index].count as usize, tags_executed.clone())?); + commands_count.push(self.get_metric_json(self.queued_counters.borrow()[index].count as usize, tags_queued.clone())?); + + commands_duration_ms.push(self.get_metric_json(self.executed_counters.borrow()[index].duration_ms_sum as usize, tags_executed.clone())?); + commands_duration_ms.push(self.get_metric_json(self.queued_counters.borrow()[index].duration_ms_sum as usize,tags_queued.clone())?); + + for index_bucket in (0..self.executed_counters.borrow()[index].duration_ms_bucket.len()).rev() { + let executed_bucket = self.executed_counters.borrow()[index].duration_ms_bucket[index_bucket]; + let queued_bucket = self.queued_counters.borrow()[index].duration_ms_bucket[index_bucket]; + + commands_duration_ms_bucket.push(self.get_metric_json(executed_bucket as usize, tags_executed.clone())?); + commands_duration_ms_bucket.push(self.get_metric_json(queued_bucket as usize, tags_queued.clone())?); + } } + + metrics_map.insert( + String::from("commands_count"), + serde_json::to_value(commands_count) + .to_indy(IndyErrorKind::IOError, "Unable to convert json")?, + ); + metrics_map.insert( + String::from("commands_duration_ms"), + serde_json::to_value(commands_duration_ms) + .to_indy(IndyErrorKind::IOError, "Unable to convert json")?, + ); + metrics_map.insert( + String::from("commands_duration_ms_bucket"), + serde_json::to_value(commands_duration_ms_bucket) + .to_indy(IndyErrorKind::IOError, "Unable to convert json")?, + ); + + Ok(()) + } + + fn get_metric_json(&self, value: usize, tags: HashMap) -> IndyResult { + let res = serde_json::to_value(MetricsValue::new( + value, + tags, + )).to_indy(IndyErrorKind::IOError, "Unable to convert json")?; + + Ok(res) } } @@ -67,55 +115,73 @@ mod test { use super::*; #[test] - fn test_counters_are_initialized_as_zeros() { + fn test_counters_are_initialized() { let metrics_service = MetricsService::new(); - for index in (0..MetricsService::commands_count()).rev() { - assert_eq!(metrics_service.queued_commands_count.borrow()[index as usize], 0); - assert_eq!(metrics_service.queued_commands_duration_ms.borrow()[index as usize], 0); - assert_eq!(metrics_service.executed_commands_count.borrow()[index as usize], 0); - assert_eq!(metrics_service.executed_commands_duration_ms.borrow()[index as usize], 0); - } + assert_eq!(metrics_service.queued_counters.borrow().len(), COMMANDS_COUNT); + assert_eq!(metrics_service.executed_counters.borrow().len(), COMMANDS_COUNT); } #[test] fn test_cmd_left_queue_increments_relevant_queued_counters() { let metrics_service = MetricsService::new(); - let index = CommandIndex::IssuerCommandCreateSchema; + let index = CommandMetric::IssuerCommandCreateSchema; let duration1 = 5u128; let duration2 = 2u128; metrics_service.cmd_left_queue(index, duration1); - assert_eq!(metrics_service.queued_commands_count.borrow()[index as usize], 1); - assert_eq!(metrics_service.queued_commands_duration_ms.borrow()[index as usize], duration1); + assert_eq!(metrics_service.queued_counters.borrow()[index as usize].count, 1); + assert_eq!(metrics_service.queued_counters.borrow()[index as usize].duration_ms_sum, duration1); + assert_eq!(metrics_service.queued_counters.borrow()[index as usize] + .duration_ms_bucket[ + metrics_service.queued_counters.borrow()[index as usize] + .duration_ms_bucket.len()-1 + ], + 1 + ); metrics_service.cmd_left_queue(index, duration2); - assert_eq!(metrics_service.queued_commands_count.borrow()[index as usize], 1 + 1); - assert_eq!(metrics_service.queued_commands_duration_ms.borrow()[index as usize], + assert_eq!(metrics_service.queued_counters.borrow()[index as usize].count, 1 + 1); + assert_eq!(metrics_service.queued_counters.borrow()[index as usize].duration_ms_sum, duration1 + duration2); - assert_eq!(metrics_service.executed_commands_count.borrow()[index as usize], 0); - assert_eq!(metrics_service.executed_commands_duration_ms.borrow()[index as usize], 0); + assert_eq!(metrics_service.queued_counters.borrow()[index as usize] + .duration_ms_bucket[ + metrics_service.queued_counters.borrow()[index as usize] + .duration_ms_bucket.len()-1 + ], + 2 + ); + + assert_eq!(metrics_service.executed_counters.borrow()[index as usize].count, 0); + assert_eq!(metrics_service.executed_counters.borrow()[index as usize].duration_ms_sum, 0); + assert_eq!(metrics_service.executed_counters.borrow()[index as usize] + .duration_ms_bucket[ + metrics_service.executed_counters.borrow()[index as usize] + .duration_ms_bucket.len()-1 + ], + 0 + ); } #[test] fn test_cmd_executed_increments_relevant_executed_counters() { let metrics_service = MetricsService::new(); - let index = CommandIndex::IssuerCommandCreateSchema; + let index = CommandMetric::IssuerCommandCreateSchema; let duration1 = 5u128; let duration2 = 2u128; metrics_service.cmd_executed(index, duration1); - assert_eq!(metrics_service.executed_commands_count.borrow()[index as usize], 1); - assert_eq!(metrics_service.executed_commands_duration_ms.borrow()[index as usize], duration1); + assert_eq!(metrics_service.executed_counters.borrow()[index as usize].count, 1); + assert_eq!(metrics_service.executed_counters.borrow()[index as usize].duration_ms_sum, duration1); metrics_service.cmd_executed(index, duration2); - assert_eq!(metrics_service.queued_commands_count.borrow()[index as usize], 0); - assert_eq!(metrics_service.queued_commands_duration_ms.borrow()[index as usize], 0); - assert_eq!(metrics_service.executed_commands_count.borrow()[index as usize], 1+1); - assert_eq!(metrics_service.executed_commands_duration_ms.borrow()[index as usize], duration1 + duration2); + assert_eq!(metrics_service.queued_counters.borrow()[index as usize].count, 0); + assert_eq!(metrics_service.queued_counters.borrow()[index as usize].duration_ms_sum, 0); + assert_eq!(metrics_service.executed_counters.borrow()[index as usize].count, 1 + 1); + assert_eq!(metrics_service.executed_counters.borrow()[index as usize].duration_ms_sum, duration1 + duration2); } #[test] @@ -123,12 +189,91 @@ mod test { let metrics_service = MetricsService::new(); let mut metrics_map = serde_json::Map::new(); - metrics_service.append_command_metrics(&mut metrics_map); + metrics_service.append_command_metrics(&mut metrics_map).unwrap(); + + assert!(metrics_map.contains_key("commands_count")); + assert!(metrics_map.contains_key("commands_duration_ms")); + assert!(metrics_map.contains_key("commands_duration_ms_bucket")); + + assert_eq!( + metrics_map + .get("commands_count") + .unwrap() + .as_array() + .unwrap() + .len(), + COMMANDS_COUNT * 2 + ); + assert_eq!( + metrics_map + .get("commands_duration_ms") + .unwrap() + .as_array() + .unwrap() + .len(), + COMMANDS_COUNT * 2 + ); + assert_eq!( + metrics_map + .get("commands_duration_ms_bucket") + .unwrap() + .as_array() + .unwrap() + .len(), + COMMANDS_COUNT * 32 + ); + + let commands_count = metrics_map + .get("commands_count") + .unwrap() + .as_array() + .unwrap(); + let commands_duration_ms = metrics_map + .get("commands_duration_ms") + .unwrap() + .as_array() + .unwrap(); + let commands_duration_ms_bucket = metrics_map + .get("commands_duration_ms_bucket") + .unwrap() + .as_array() + .unwrap(); + + let expected_commands_count = [ + generate_json("payments_command_build_set_txn_fees_req_ack", "executed", 0), + generate_json("metrics_command_collect_metrics", "queued", 0), + generate_json("cache_command_purge_cred_def_cache", "executed", 0), + generate_json("non_secrets_command_fetch_search_next_records", "queued", 0) + ]; + + let expected_commands_duration_ms = [ + generate_json("payments_command_build_set_txn_fees_req_ack", "executed", 0), + generate_json("metrics_command_collect_metrics", "queued", 0), + generate_json("cache_command_purge_cred_def_cache", "executed", 0), + generate_json("non_secrets_command_fetch_search_next_records", "queued", 0) + ]; + + let expected_commands_duration_ms_bucket = [ + generate_json("payments_command_build_set_txn_fees_req_ack", "executed", 0), + generate_json("metrics_command_collect_metrics", "queued", 0), + generate_json("cache_command_purge_cred_def_cache", "executed", 0), + generate_json("non_secrets_command_fetch_search_next_records", "queued", 0) + ]; + + for command in &expected_commands_count { + assert!(commands_count.contains(&command)); + } + + for command in &expected_commands_duration_ms { + assert!(commands_duration_ms.contains(&command)); + } + + for command in &expected_commands_duration_ms_bucket { + assert!(commands_duration_ms_bucket.contains(&command)); + } + } - assert_eq!(metrics_map.len(), COMMANDS_COUNT * 4); - assert!(metrics_map.contains_key("issuer_command_create_schema_queued_commands_count")); - assert!(metrics_map.contains_key("issuer_command_create_schema_queued_commands_duration_ms")); - assert!(metrics_map.contains_key("issuer_command_create_schema_executed_commands_count")); - assert!(metrics_map.contains_key("issuer_command_create_schema_executed_commands_duration_ms")); + fn generate_json(command: &str, stage: &str, value: usize) -> Value { + json!({"tags":{"command": command, "stage": stage} ,"value": value}) } } \ No newline at end of file diff --git a/libindy/src/services/metrics/models.rs b/libindy/src/services/metrics/models.rs new file mode 100644 index 0000000000..4df2dbcc32 --- /dev/null +++ b/libindy/src/services/metrics/models.rs @@ -0,0 +1,58 @@ +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; + +const BUCKET_COUNT: usize = 16; +const LIST_LE: [f64; BUCKET_COUNT-1] = [0.5, 1.0, 2.0, 5.0, 10.0, 20.0, 50.0, 100.0, 200.0, 500.0, 1000.0, 2000.0, 5000.0, 10000.0, 20000.0]; + +#[derive(Serialize, Deserialize)] +pub struct MetricsValue { + value: usize, + tags: HashMap, +} + +impl MetricsValue { + pub fn new(value: usize, tags: HashMap) -> Self { + MetricsValue { value, tags } + } +} + +#[derive(Serialize, Deserialize, Copy, Clone, Debug)] +pub struct CommandCounters { + pub count: u128, + pub duration_ms_sum: u128, + pub duration_ms_bucket: [u128; BUCKET_COUNT], +} + +impl CommandCounters { + pub fn new() -> Self { + CommandCounters {count: 0, duration_ms_sum: 0, duration_ms_bucket: [0; BUCKET_COUNT]} + } + + pub fn add(&mut self, duration: u128) { + self.count += 1; + self.duration_ms_sum += duration; + self.add_buckets(duration); + } + + fn add_buckets(&mut self, duration: u128) { + for (le_index, le_value) in LIST_LE.iter().enumerate() { + if duration <= *le_value as u128 { + self.duration_ms_bucket[le_index] += 1; + } + } + self.duration_ms_bucket[self.duration_ms_bucket.len()-1] += 1; + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_counters_are_initialized_as_zeros() { + let command_counters = CommandCounters::new(); + assert_eq!(command_counters.count, 0); + assert_eq!(command_counters.duration_ms_sum, 0); + assert_eq!(command_counters.duration_ms_bucket, [0; BUCKET_COUNT]); + } +} diff --git a/libindy/src/services/pool/state_proof/node.rs b/libindy/src/services/pool/state_proof/node.rs index a29a44ef81..05735e6fb5 100644 --- a/libindy/src/services/pool/state_proof/node.rs +++ b/libindy/src/services/pool/state_proof/node.rs @@ -148,8 +148,8 @@ impl Node { use sha3::Digest; let encoded = rlp_encode(self); let mut hasher = sha3::Sha3_256::default(); - hasher.input(encoded.to_vec().as_slice()); - hasher.fixed_result() + hasher.update(encoded.to_vec().as_slice()); + hasher.finalize_fixed() } pub fn get_str_value<'a, 'b>(&'a self, db: &'a TrieDB, path: &'b [u8]) -> IndyResult> { let value = self.get_value(db, path)?; diff --git a/libindy/tests/anoncreds_demos.rs b/libindy/tests/anoncreds_demos.rs index d838a628ba..e3f7746bdf 100644 --- a/libindy/tests/anoncreds_demos.rs +++ b/libindy/tests/anoncreds_demos.rs @@ -3952,4 +3952,137 @@ mod demos { wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); wallet::close_and_delete_wallet(prover_wallet_handle, &prover_wallet_config).unwrap(); } + + #[test] + fn anoncreds_proof_req_with_attr_value_restrict_by_attribute_value() { + Setup::empty(); + + //1. Create Issuer wallet, gets wallet handle + let (issuer_wallet_handle, issuer_wallet_config) = wallet::create_and_open_default_wallet("anoncreds_proof_req_with_attr_value_restrict_by_attribute_value").unwrap(); + + //2. Create Prover wallet, gets wallet handle + let (prover_wallet_handle, prover_wallet_config) = wallet::create_and_open_default_wallet("anoncreds_proof_req_with_attr_value_restrict_by_attribute_value").unwrap(); + + //3. Issuer creates Schema and Credential Definition + let schema_attr = r#"["First Name", "Age", "Last Name", "Sex", "Serial Number"]"#; + let (schema_id, schema_json, cred_def_id, cred_def_json) = anoncreds::multi_steps_issuer_preparation(issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + schema_attr); + + //4. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + //5. Issuance 2 credentials for Prover + let cred_values = json!({ + "First Name": {"raw": "Alexander", "encoded": "1139481716457488690172217916278103335"}, + "Last Name": {"raw": "Brown", "encoded": "43252312987618532132148541932185371"}, + "Age": {"raw": "28", "encoded": "28"}, + "Sex": {"raw": "male", "encoded": "3123124343252454252"}, + "Serial Number": {"raw": "A184D632VSF", "encoded": "123426788715432763124345182351419"}, + }).to_string(); + anoncreds::multi_steps_create_credential(COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &cred_values, + &cred_def_id, + &cred_def_json); + + //6. Proof request restricting attr value to gvt_credential + let nonce = anoncreds::generate_nonce().unwrap(); + let proof_req_json = json!({ + "nonce": nonce, + "name":"proof_req_1", + "version":"0.1", + "requested_attributes":{ + "attr1_referent":{ + "name":"First Name", + "restrictions": json!({ + // restrict by exact value of requested field (case insensitive) + "attr::firstname::value": "Alexander", + "cred_def_id": cred_def_id + }) + }, + "attr2_referent":{ + "names":["Last Name", "Serial Number"], + "restrictions": json!({ + // restrict by exact value of one of fields + "attr::Serial Number::value": "A184D632VSF", + }) + }, + "attr3_referent":{ + "name":"Age", + "restrictions": json!({ + // restrict by existance of different field + "attr::Serial Number::marker": "1", + }) + }, + "attr4_referent":{ + "names": ["Sex", "Serial Number"], + "restrictions": json!({ + // restrict by exact value of one of fields (case insensitive) + "attr::serialnumber::value": "A184D632VSF", + // restrict by existance of different field (case insensitive) + "attr::firstname::marker": "1", + }) + }, + }, + "requested_predicates":{ + } + }).to_string(); + + //7. Prover gets Credentials for Proof Request + let credentials_json = anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json).unwrap(); + let credential_1 = anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + let credential_2 = anoncreds::get_credential_for_attr_referent(&credentials_json, "attr2_referent"); + let credential_3 = anoncreds::get_credential_for_attr_referent(&credentials_json, "attr3_referent"); + let credential_4 = anoncreds::get_credential_for_attr_referent(&credentials_json, "attr4_referent"); + + //8. Prover creates Proof containing gvt2_credential + let requested_credentials_json = json!({ + "self_attested_attributes": {}, + "requested_attributes": { + "attr1_referent": {"cred_id": credential_1.referent, "revealed":true}, + "attr2_referent": {"cred_id": credential_2.referent, "revealed":true}, + "attr3_referent": {"cred_id": credential_3.referent, "revealed":true}, + "attr4_referent": {"cred_id": credential_4.referent, "revealed":true}, + }, + "requested_predicates": {} + }).to_string(); + + let schemas_json = json!({schema_id: serde_json::from_str::(&schema_json).unwrap()}).to_string(); + let cred_defs_json = json!({cred_def_id: serde_json::from_str::(&cred_def_json).unwrap()}).to_string(); + let rev_states_json = json!({}).to_string(); + + let proof_json = anoncreds::prover_create_proof(prover_wallet_handle, + &proof_req_json, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &cred_defs_json, + &rev_states_json).unwrap(); + println!("{:?}", proof_json); + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + //9. Verifier verifies proof + assert_eq!("Alexander", proof.requested_proof.revealed_attrs.get("attr1_referent").unwrap().raw); + assert_eq!("Brown", proof.requested_proof.revealed_attr_groups.get("attr2_referent").unwrap().values.get("Last Name").unwrap().raw); + assert_eq!("28", proof.requested_proof.revealed_attrs.get("attr3_referent").unwrap().raw); + assert_eq!("male", proof.requested_proof.revealed_attr_groups.get("attr4_referent").unwrap().values.get("Sex").unwrap().raw); + + let rev_reg_defs_json = json!({}).to_string(); + let rev_regs_json = json!({}).to_string(); + + let valid = anoncreds::verifier_verify_proof(&proof_req_json, + &proof_json, + &schemas_json, + &cred_defs_json, + &rev_reg_defs_json, + &rev_regs_json).unwrap(); + assert!(valid); + + wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); + wallet::close_and_delete_wallet(prover_wallet_handle, &prover_wallet_config).unwrap(); + } } diff --git a/libindy/tests/ledger.rs b/libindy/tests/ledger.rs index b8ef9a6c7a..4133253c20 100644 --- a/libindy/tests/ledger.rs +++ b/libindy/tests/ledger.rs @@ -201,6 +201,35 @@ mod high_cases { } } + mod frozen_ledgers { + use super::*; + + #[test] + fn indy_build_ledgers_freeze_request() { + let ledgers_ids = vec![0u64, 1u64, 10u64, 23u64]; + let res = ledger::build_ledgers_freeze_request(DID_TRUSTEE, ledgers_ids); + + match res { + Ok(_) => {}, + Err(ec) => { + assert!(false, "indy_build_ledgers_freeze_request returned error_code {:?}", ec); + } + } + } + + #[test] + fn indy_get_frozen_ledgers_request() { + let res = ledger::get_frozen_ledgers_request(DID_TRUSTEE); + + match res { + Ok(_) => {}, + Err(ec) => { + assert!(false, "indy_get_frozen_ledgers_request returned error_code {:?}", ec); + } + } + } + } + mod multi_sign_request { use super::*; diff --git a/libindy/tests/metrics.rs b/libindy/tests/metrics.rs index 2d83d81a83..1fda4ac087 100644 --- a/libindy/tests/metrics.rs +++ b/libindy/tests/metrics.rs @@ -3,48 +3,146 @@ mod utils; inject_indy_dependencies!(); -extern crate indyrs as indy; extern crate indyrs as api; -use crate::utils::wallet; -use crate::utils::metrics; +extern crate indyrs as indy; use crate::utils::constants::*; +use crate::utils::metrics; +use crate::utils::wallet; use crate::utils::Setup; - - mod collect { use super::*; use std::collections::HashMap; + use serde_json::Value; #[test] - fn collect_metrics_contains_thread_pool_and_wallet_service_statistics() { + fn test_metrics_schema() { + let setup = Setup::empty(); + let config = config(&setup.name); + wallet::create_wallet(&config, WALLET_CREDENTIALS).unwrap(); + let result_metrics = metrics::collect_metrics().unwrap(); - let metrics_map = serde_json::from_str::>(&result_metrics).unwrap(); - assert!(metrics_map.contains_key("threadpool_active_count")); - assert!(metrics_map.contains_key("threadpool_queued_count")); - assert!(metrics_map.contains_key("threadpool_max_count")); - assert!(metrics_map.contains_key("threadpool_panic_count")); - assert!(metrics_map.contains_key("opened_wallets_count")); - assert!(metrics_map.contains_key("opened_wallet_ids_count")); - assert!(metrics_map.contains_key("pending_for_import_wallets_count")); - assert!(metrics_map.contains_key("pending_for_open_wallets_count")); + let metrics_map = serde_json::from_str::>(&result_metrics) + .expect("Top level object should be a dictionary"); + + for metrics_set in metrics_map.values() { + let metrics_set = metrics_set.as_array().expect("Metrics set should be an array"); + + for metric in metrics_set.iter() { + let metrics = metric.as_object().expect("Metrics should be an object"); + metrics.contains_key("value"); + metrics.contains_key("tags"); + } + } } #[test] - fn collect_metrics_includes_statistics_for_wallet_command() { + fn collect_metrics_contains_wallet_service_statistics() { + let result_metrics = metrics::collect_metrics().unwrap(); + let metrics_map = serde_json::from_str::>(&result_metrics).unwrap(); + + assert!(metrics_map.contains_key("wallet_count")); + + let wallet_count = metrics_map + .get("wallet_count") + .unwrap() + .as_array() + .unwrap(); + + assert!(wallet_count.contains(&json!({"tags":{"label":"opened"},"value":0}))); + assert!(wallet_count.contains(&json!({"tags":{"label":"opened_ids"},"value":0}))); + assert!(wallet_count.contains(&json!({"tags":{"label":"pending_for_import"},"value":0}))); + assert!(wallet_count.contains(&json!({"tags":{"label":"pending_for_open"},"value":0}))); + } + + #[test] + fn collect_metrics_contains_thread_pool_service_statistics() { + let result_metrics = metrics::collect_metrics().unwrap(); + let metrics_map = serde_json::from_str::>(&result_metrics).unwrap(); + + assert!(metrics_map.contains_key("threadpool_threads_count")); + + let threadpool_threads_count = metrics_map + .get("threadpool_threads_count") + .unwrap() + .as_array() + .unwrap(); + + assert!(threadpool_threads_count.contains(&json!({"tags":{"label":"active"},"value":0}))); + assert!(threadpool_threads_count.contains(&json!({"tags":{"label":"queued"},"value":0}))); + assert!(threadpool_threads_count.contains(&json!({"tags":{"label":"panic"},"value":0}))); + } + + #[test] + fn collect_metrics_includes_commands_count() { + let setup = Setup::empty(); + let config = config(&setup.name); + wallet::create_wallet(&config, WALLET_CREDENTIALS).unwrap(); + + let result_metrics = metrics::collect_metrics().unwrap(); + let metrics_map = serde_json::from_str::>(&result_metrics).unwrap(); + + assert!(metrics_map.contains_key("commands_count")); + + let commands_count = metrics_map + .get("commands_count") + .unwrap() + .as_array() + .unwrap(); + + assert!(commands_count.contains(&json!({"tags":{"command": "pairwise_command_pairwise_exists", "stage": "executed"} ,"value": 0}))); + assert!(commands_count.contains(&json!({"tags":{"command": "pairwise_command_pairwise_exists", "stage": "queued"} ,"value": 0}))); + assert!(commands_count.contains(&json!({"tags":{"command": "payments_command_build_set_txn_fees_req_ack", "stage": "executed"} ,"value": 0}))); + assert!(commands_count.contains(&json!({"tags":{"command": "payments_command_build_set_txn_fees_req_ack", "stage": "queued"} ,"value": 0}))); + } + + #[test] + fn collect_metrics_includes_commands_duration_ms() { + let setup = Setup::empty(); + let config = config(&setup.name); + wallet::create_wallet(&config, WALLET_CREDENTIALS).unwrap(); + + let result_metrics = metrics::collect_metrics().unwrap(); + let metrics_map = serde_json::from_str::>(&result_metrics).unwrap(); + + assert!(metrics_map.contains_key("commands_duration_ms")); + + let commands_duration_ms = metrics_map + .get("commands_duration_ms") + .unwrap() + .as_array() + .unwrap(); + + assert!(commands_duration_ms.contains(&json!({"tags":{"command": "pairwise_command_pairwise_exists", "stage": "executed"} ,"value": 0}))); + assert!(commands_duration_ms.contains(&json!({"tags":{"command": "pairwise_command_pairwise_exists", "stage": "queued"} ,"value": 0}))); + assert!(commands_duration_ms.contains(&json!({"tags":{"command": "payments_command_build_set_txn_fees_req_ack", "stage": "executed"} ,"value": 0}))); + assert!(commands_duration_ms.contains(&json!({"tags":{"command": "payments_command_build_set_txn_fees_req_ack", "stage": "queued"} ,"value": 0}))); + } + + #[test] + fn collect_metrics_includes_commands_duration_ms_bucket() { let setup = Setup::empty(); let config = config(&setup.name); wallet::create_wallet(&config, WALLET_CREDENTIALS).unwrap(); let result_metrics = metrics::collect_metrics().unwrap(); - let metrics_map = serde_json::from_str::>(&result_metrics).unwrap(); + let metrics_map = serde_json::from_str::>(&result_metrics).unwrap(); - assert_eq!(metrics_map.get("wallet_command_create_queued_commands_count").unwrap(), &1u128); - assert!(metrics_map.contains_key("wallet_command_create_queued_commands_duration_ms")); - assert_eq!(metrics_map.get("wallet_command_create_executed_commands_count").unwrap(), &1u128); - assert!(metrics_map.contains_key("wallet_command_create_executed_commands_duration_ms")); + assert!(metrics_map.contains_key("commands_duration_ms_bucket")); + + let commands_duration_ms_bucket = metrics_map + .get("commands_duration_ms_bucket") + .unwrap() + .as_array() + .unwrap(); + + assert!(commands_duration_ms_bucket.contains(&json!({"tags":{"command": "pairwise_command_pairwise_exists", "stage": "executed"} ,"value": 0}))); + assert!(commands_duration_ms_bucket.contains(&json!({"tags":{"command": "pairwise_command_pairwise_exists", "stage": "queued"} ,"value": 0}))); + assert!(commands_duration_ms_bucket.contains(&json!({"tags":{"command": "payments_command_build_set_txn_fees_req_ack", "stage": "executed"} ,"value": 0}))); + assert!(commands_duration_ms_bucket.contains(&json!({"tags":{"command": "payments_command_build_set_txn_fees_req_ack", "stage": "queued"} ,"value": 0}))); } + fn config(name: &str) -> String { - json!({"id": name}).to_string() + json!({ "id": name }).to_string() } } diff --git a/libindy/tests/utils/ledger.rs b/libindy/tests/utils/ledger.rs index bc28b6e69d..951ff02d41 100644 --- a/libindy/tests/utils/ledger.rs +++ b/libindy/tests/utils/ledger.rs @@ -420,4 +420,11 @@ pub fn post_qualified_entities() -> (&'static str, &'static str) { (SCHEMA_ID_V2, CRED_DEF_ID_V2) } +} +pub fn build_ledgers_freeze_request(submitter_did: &str, ledgers_ids: Vec) -> Result { + ledger::build_ledgers_freeze_request(submitter_did, ledgers_ids).wait() +} + +pub fn get_frozen_ledgers_request(submitter_did: &str) -> Result { + ledger::build_get_frozen_ledgers_request(submitter_did).wait() } \ No newline at end of file diff --git a/wrappers/java/src/main/java/org/hyperledger/indy/sdk/LibIndy.java b/wrappers/java/src/main/java/org/hyperledger/indy/sdk/LibIndy.java index 50d9619f9b..1e97488446 100644 --- a/wrappers/java/src/main/java/org/hyperledger/indy/sdk/LibIndy.java +++ b/wrappers/java/src/main/java/org/hyperledger/indy/sdk/LibIndy.java @@ -1,11 +1,12 @@ package org.hyperledger.indy.sdk; +import com.sun.jna.*; +import com.sun.jna.ptr.PointerByReference; + import java.io.File; import java.util.HashMap; import java.util.Map; -import com.sun.jna.*; -import com.sun.jna.ptr.PointerByReference; import static com.sun.jna.Native.detach; public abstract class LibIndy { @@ -87,6 +88,8 @@ public interface API extends Library { public int indy_build_get_acceptance_mechanisms_request(int command_handle, String submitter_did, int timestamp, String version, Callback cb); public int indy_append_txn_author_agreement_acceptance_to_request(int command_handle, String request_json, String text, String version, String hash, String acc_mech_type, long time_of_acceptance, Callback cb); public int indy_append_request_endorser(int command_handle, String request_json, String endorser_did, Callback cb); + public int indy_build_ledgers_freeze_request(int command_handle, String submitter_did, String ledgers_ids, Callback cb); + public int indy_build_get_frozen_ledgers_request(int command_handle, String submitter_did, Callback cb); // did.rs diff --git a/wrappers/java/src/main/java/org/hyperledger/indy/sdk/ledger/Ledger.java b/wrappers/java/src/main/java/org/hyperledger/indy/sdk/ledger/Ledger.java index cb1457cc93..a951af5c30 100644 --- a/wrappers/java/src/main/java/org/hyperledger/indy/sdk/ledger/Ledger.java +++ b/wrappers/java/src/main/java/org/hyperledger/indy/sdk/ledger/Ledger.java @@ -1,18 +1,17 @@ package org.hyperledger.indy.sdk.ledger; -import java.util.concurrent.CompletableFuture; - +import com.sun.jna.Callback; import org.hyperledger.indy.sdk.IndyException; import org.hyperledger.indy.sdk.IndyJava; import org.hyperledger.indy.sdk.LibIndy; import org.hyperledger.indy.sdk.ParamGuard; +import org.hyperledger.indy.sdk.ledger.LedgerResults.ParseRegistryResponseResult; +import org.hyperledger.indy.sdk.ledger.LedgerResults.ParseResponseResult; import org.hyperledger.indy.sdk.pool.Pool; import org.hyperledger.indy.sdk.wallet.Wallet; -import org.hyperledger.indy.sdk.ledger.LedgerResults.ParseResponseResult; -import org.hyperledger.indy.sdk.ledger.LedgerResults.ParseRegistryResponseResult; - -import com.sun.jna.Callback; +import java.util.List; +import java.util.concurrent.CompletableFuture; /** * ledger.rs API @@ -1785,4 +1784,68 @@ public static CompletableFuture appendRequestEndorser( return future; } + + /** + * Request to freeze list of ledgers. + * + * @param command_handle - command handle to map callback to caller context. + * @param submitter_did - (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). + * @param ledgers_ids - List of ledgers IDs for freezing. + * @param cb - Callback that takes command result as parameter. + * + * @return A future resolving to a request result as json. + * @throws IndyException Thrown if an error occurs when calling the underlying SDK. + */ + public static CompletableFuture buildLedgersFreezeRequest(String submitterDid, List ledgersIds) throws IndyException { + ParamGuard.notNullOrWhiteSpace(submitterDid, "submitterDid"); + + CompletableFuture future = new CompletableFuture(); + int commandHandle = addFuture(future); + + int result = LibIndy.api.indy_build_ledgers_freeze_request( + commandHandle, + submitterDid, + ledgersIds.toString(), + buildRequestCb); + + checkResult(future, result); + + return future; + } + + /** + * Request to get list of frozen ledgers. + * Frozen ledgers are defined by ledgers freeze request. + * + * @param command_handle - command handle to map callback to caller context. + * @param submitter_did - (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). + * @param cb - Callback that takes command result as parameter. + * + * @return A future resolving to a request result as json. + * { + * : { + * "ledger": String - Ledger root hash, + * "state": String - State root hash, + * "seq_no": u64 - the latest transaction seqNo for particular Node, + * }, + * ... + * } + * + * @throws IndyException Thrown if an error occurs when calling the underlying SDK. + */ + public static CompletableFuture buildGetFrozenLedgersRequest(String submitterDid) throws IndyException { + ParamGuard.notNullOrWhiteSpace(submitterDid, "submitterDid"); + + CompletableFuture future = new CompletableFuture(); + int commandHandle = addFuture(future); + + int result = LibIndy.api.indy_build_get_frozen_ledgers_request( + commandHandle, + submitterDid, + buildRequestCb); + + checkResult(future, result); + + return future; + } } diff --git a/wrappers/java/src/test/java/org/hyperledger/indy/sdk/ledger/GetFrozenLedgersTest.java b/wrappers/java/src/test/java/org/hyperledger/indy/sdk/ledger/GetFrozenLedgersTest.java new file mode 100644 index 0000000000..da59c9f796 --- /dev/null +++ b/wrappers/java/src/test/java/org/hyperledger/indy/sdk/ledger/GetFrozenLedgersTest.java @@ -0,0 +1,69 @@ +package org.hyperledger.indy.sdk.ledger; + +import org.hyperledger.indy.sdk.did.Did; +import org.hyperledger.indy.sdk.did.DidResults; +import org.json.JSONObject; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.Timeout; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.TimeUnit; + +public class GetFrozenLedgersTest extends LedgerIntegrationTest { + @Rule + public Timeout globalTimeout = new Timeout(1, TimeUnit.MINUTES); + + @Test + public void TestBuildGetFrozenLedgersRequest() throws Exception { + DidResults.CreateAndStoreMyDidResult myDidResult = Did.createAndStoreMyDid(wallet, "{}").get(); + String did = myDidResult.getDid(); + + String request = Ledger.buildGetFrozenLedgersRequest(did).get(); + JSONObject expectedResult = new JSONObject() + .put("operation", new JSONObject() + .put("type", "10") + ); + + System.out.println(request); + assert (new JSONObject(request).toMap().entrySet() + .containsAll(expectedResult.toMap().entrySet())); + } + + @Test + public void TestLedgersFreezeRequest() throws Exception { + DidResults.CreateAndStoreMyDidResult myDidResult = Did.createAndStoreMyDid(wallet, "{}").get(); + String did = myDidResult.getDid(); + + List ledgersIds = Arrays.asList(0, 1, 28 ,345); + String request = Ledger.buildLedgersFreezeRequest(did, ledgersIds).get(); + + JSONObject expectedResult = new JSONObject() + .put("operation", new JSONObject() + .put("type", "9") + .put("ledgers_ids", ledgersIds) + ); + + assert (new JSONObject(request).toMap().entrySet() + .containsAll(expectedResult.toMap().entrySet())); + } + + @Test + public void TestLedgersFreezeRequestWithEmptyData() throws Exception { + DidResults.CreateAndStoreMyDidResult myDidResult = Did.createAndStoreMyDid(wallet, "{}").get(); + String did = myDidResult.getDid(); + + List ledgersIds = Arrays.asList(); + String request = Ledger.buildLedgersFreezeRequest(did, ledgersIds).get(); + + JSONObject expectedResult = new JSONObject() + .put("operation", new JSONObject() + .put("type", "9") + .put("ledgers_ids", ledgersIds) + ); + + assert (new JSONObject(request).toMap().entrySet() + .containsAll(expectedResult.toMap().entrySet())); + } +} diff --git a/wrappers/java/src/test/java/org/hyperledger/indy/sdk/metrics/CollectMetricsTest.java b/wrappers/java/src/test/java/org/hyperledger/indy/sdk/metrics/CollectMetricsTest.java index fe427939b3..2ad43809d1 100644 --- a/wrappers/java/src/test/java/org/hyperledger/indy/sdk/metrics/CollectMetricsTest.java +++ b/wrappers/java/src/test/java/org/hyperledger/indy/sdk/metrics/CollectMetricsTest.java @@ -16,8 +16,6 @@ public void testCollectMetricsMethod() throws Exception { String metricsResult = Metrics.collectMetrics().get(); assertNotNull(metricsResult); Map metricMap = (new JSONObject(metricsResult)).toMap(); - assert(metricMap.containsKey("threadpool_active_count")); - // check that vales from the result can be parsed to BigIntegers - metricMap.values().forEach(v-> new BigInteger(String.valueOf(v))); + assert(metricMap.containsKey("threadpool_threads_count")); } } diff --git a/wrappers/nodejs/src/index.js b/wrappers/nodejs/src/index.js index 5ed18fc764..09f74c94a5 100644 --- a/wrappers/nodejs/src/index.js +++ b/wrappers/nodejs/src/index.js @@ -636,6 +636,18 @@ indy.buildGetAcceptanceMechanismsRequest = function buildGetAcceptanceMechanisms return cb.promise } +indy.buildLedgersFreezeRequest = function buildLedgersFreezeRequest (submitterDid, ledgersIds, cb) { + cb = wrapIndyCallback(cb, fromJson) + capi.buildLedgersFreezeRequest(submitterDid, JSON.stringify(ledgersIds), cb) + return cb.promise +} + +indy.buildGetFrozenLedgersRequest = function buildGetFrozenLedgersRequest (submitterDid, cb) { + cb = wrapIndyCallback(cb, fromJson) + capi.buildGetFrozenLedgersRequest(submitterDid, cb) + return cb.promise +} + indy.appendTxnAuthorAgreementAcceptanceToRequest = function appendTxnAuthorAgreementAcceptanceToRequest (request, text, version, taaDigest, accMechType, timeOfAcceptance, cb) { cb = wrapIndyCallback(cb, fromJson) capi.appendTxnAuthorAgreementAcceptanceToRequest(toJson(request), text, version, taaDigest, accMechType, timeOfAcceptance, cb) diff --git a/wrappers/nodejs/src/indy.cc b/wrappers/nodejs/src/indy.cc index bb773f8562..f399f82065 100644 --- a/wrappers/nodejs/src/indy.cc +++ b/wrappers/nodejs/src/indy.cc @@ -2371,6 +2371,41 @@ NAN_METHOD(buildGetAcceptanceMechanismsRequest) { delete arg2; } +void buildLedgersFreezeRequest_cb(indy_handle_t handle, indy_error_t xerr, const char* arg0) { + IndyCallback* icb = IndyCallback::getCallback(handle); + if(icb != nullptr){ + icb->cbString(xerr, arg0); + } +} +NAN_METHOD(buildLedgersFreezeRequest) { + INDY_ASSERT_NARGS(buildLedgersFreezeRequest, 3) + INDY_ASSERT_STRING(buildLedgersFreezeRequest, 0, submitterDid) + INDY_ASSERT_STRING(buildLedgersFreezeRequest, 1, ledgersIds) + INDY_ASSERT_FUNCTION(buildLedgersFreezeRequest, 2) + const char* arg0 = argToCString(info[0]); + const char* arg1 = argToCString(info[1]); + IndyCallback* icb = argToIndyCb(info[2]); + indyCalled(icb, indy_build_ledgers_freeze_request(icb->handle, arg0, arg1, buildLedgersFreezeRequest_cb)); + delete arg0; + delete arg1; +} + +void buildGetFrozenLedgersRequest_cb(indy_handle_t handle, indy_error_t xerr, const char* arg0) { + IndyCallback* icb = IndyCallback::getCallback(handle); + if(icb != nullptr){ + icb->cbString(xerr, arg0); + } +} +NAN_METHOD(buildGetFrozenLedgersRequest) { + INDY_ASSERT_NARGS(buildGetFrozenLedgersRequest, 2) + INDY_ASSERT_STRING(buildGetFrozenLedgersRequest, 0, submitterDid) + INDY_ASSERT_FUNCTION(buildGetFrozenLedgersRequest, 1) + const char* arg0 = argToCString(info[0]); + IndyCallback* icb = argToIndyCb(info[1]); + indyCalled(icb, indy_build_get_frozen_ledgers_request(icb->handle, arg0, buildGetFrozenLedgersRequest_cb)); + delete arg0; +} + void appendTxnAuthorAgreementAcceptanceToRequest_cb(indy_handle_t handle, indy_error_t xerr, const char* arg0) { IndyCallback* icb = IndyCallback::getCallback(handle); if(icb != nullptr){ @@ -3732,6 +3767,8 @@ NAN_MODULE_INIT(InitAll) { Nan::Export(target, "buildGetTxnAuthorAgreementRequest", buildGetTxnAuthorAgreementRequest); Nan::Export(target, "buildAcceptanceMechanismsRequest", buildAcceptanceMechanismsRequest); Nan::Export(target, "buildGetAcceptanceMechanismsRequest", buildGetAcceptanceMechanismsRequest); + Nan::Export(target, "buildLedgersFreezeRequest", buildLedgersFreezeRequest); + Nan::Export(target, "buildGetFrozenLedgersRequest", buildGetFrozenLedgersRequest); Nan::Export(target, "appendTxnAuthorAgreementAcceptanceToRequest", appendTxnAuthorAgreementAcceptanceToRequest); Nan::Export(target, "appendRequestEndorser", appendRequestEndorser); Nan::Export(target, "getResponseMetadata", getResponseMetadata); diff --git a/wrappers/nodejs/test/ledger.js b/wrappers/nodejs/test/ledger.js index 59c116953f..85e9b2a43a 100644 --- a/wrappers/nodejs/test/ledger.js +++ b/wrappers/nodejs/test/ledger.js @@ -206,6 +206,25 @@ test('ledger', async function (t) { req = await indy.buildGetAcceptanceMechanismsRequest(null, 123379200, null) t.deepEqual(req['operation'], { 'type': '7', 'timestamp': 123379200 }) + // ledgers freeze + var ledgersIds = [0, 3, 76, 874] + req = await indy.buildLedgersFreezeRequest(trusteeDid, ledgersIds) + t.deepEqual(req['operation'], { 'type': '9', 'ledgers_ids': ledgersIds }) + + ledgersIds = [] + req = await indy.buildLedgersFreezeRequest(trusteeDid, ledgersIds) + t.deepEqual(req['operation'], { 'type': '9', 'ledgers_ids': ledgersIds }) + + var err = await t.throwsAsync(indy.buildLedgersFreezeRequest(trusteeDid, ['0', '3', '76', '874'])) + t.is(err.indyName, 'CommonInvalidStructure') + + err = await t.throwsAsync(indy.buildLedgersFreezeRequest(trusteeDid, '[0, 3, 76, 874]')) + t.is(err.indyName, 'CommonInvalidStructure') + + // frozen ledgers + req = await indy.buildGetFrozenLedgersRequest(trusteeDid) + t.deepEqual(req['operation'], { 'type': '10' }) + // author agreement acceptance data req = await indy.appendTxnAuthorAgreementAcceptanceToRequest(req, 'indy agreement', '1.0.0', null, 'acceptance mechanism label 1', 123379200) var expectedMeta = { diff --git a/wrappers/python/indy/ledger.py b/wrappers/python/indy/ledger.py index 721b02198b..a50dbf098e 100644 --- a/wrappers/python/indy/ledger.py +++ b/wrappers/python/indy/ledger.py @@ -1,9 +1,10 @@ from .libindy import do_call, create_cb -from typing import Optional +from typing import Optional, List from ctypes import * import logging +import json async def sign_and_submit_request(pool_handle: int, @@ -1838,3 +1839,75 @@ async def append_request_endorser(request_json: str, res = request_json.decode() logger.debug("append_request_endorser: <<< res: %r", res) return res + + +async def build_ledgers_freeze_request(submitter_did: str, ledgers_ids: List[int]) -> str: + """ + Request to freeze list of ledgers. + + :param command_handle: command handle to map callback to caller context. + :param submitter_did: (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). + :param ledgers_ids: List of ledgers IDs for freezing. + :param cb: Callback that takes command result as parameter. + + :return: Request result as json. + """ + + logger = logging.getLogger(__name__) + logger.debug("build_ledgers_freeze_request: >>> submitter_did: %r", + submitter_did) + + if not hasattr(build_ledgers_freeze_request, "cb"): + logger.debug("build_ledgers_freeze_request: Creating callback") + build_ledgers_freeze_request.cb = create_cb(CFUNCTYPE(None, c_int32, c_int32, c_char_p)) + + c_submitter_did = c_char_p(submitter_did.encode('utf-8')) + json_ledgers_ids = json.dumps(ledgers_ids) + c_ledgers_ids = c_char_p(json_ledgers_ids.encode('utf-8')) + + request_json = await do_call('indy_build_ledgers_freeze_request', + c_submitter_did, + c_ledgers_ids, + build_ledgers_freeze_request.cb) + + res = request_json.decode() + logger.debug("build_ledgers_freeze_request: <<< res: %r", res) + return res + + +async def build_get_frozen_ledgers_request(submitter_did: str) -> str: + """ + Request to get list of frozen ledgers. + Frozen ledgers are defined by ledgers freeze request. + + :param command_handle: command handle to map callback to caller context. + :param submitter_did: (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). + :param cb: Callback that takes command result as parameter. + + :return A future resolving to a request result as json. + { + : { + ledger: Ledger root hash, + state": State root hash, + seq_no: the latest transaction seqNo for particular Node, + }, + ... + } + """ + logger = logging.getLogger(__name__) + logger.debug("build_get_frozen_ledgers_request: >>> submitter_did: %r", + submitter_did) + + if not hasattr(build_get_frozen_ledgers_request, "cb"): + logger.debug("build_get_frozen_ledgers_request: Creating callback") + build_get_frozen_ledgers_request.cb = create_cb(CFUNCTYPE(None, c_int32, c_int32, c_char_p)) + + c_submitter_did = c_char_p(submitter_did.encode('utf-8')) + + request_json = await do_call('indy_build_get_frozen_ledgers_request', + c_submitter_did, + build_get_frozen_ledgers_request.cb) + + res = request_json.decode() + logger.debug("build_get_frozen_ledgers_request: <<< res: %r", res) + return res diff --git a/wrappers/python/tests/ledger/test_build_get_frozen_ledgers_request.py b/wrappers/python/tests/ledger/test_build_get_frozen_ledgers_request.py new file mode 100644 index 0000000000..47f7e037ec --- /dev/null +++ b/wrappers/python/tests/ledger/test_build_get_frozen_ledgers_request.py @@ -0,0 +1,15 @@ +from indy import ledger + +import json +import pytest + +@pytest.mark.asyncio +async def test_build_get_frozen_ledgers_request(did_trustee): + expected_response = { + "identifier": did_trustee, + "operation": { + "type": "10" + } + } + response = json.loads(await ledger.build_get_frozen_ledgers_request(did_trustee)) + assert expected_response.items() <= response.items() diff --git a/wrappers/python/tests/ledger/test_build_ledgers_freeze_request.py b/wrappers/python/tests/ledger/test_build_ledgers_freeze_request.py new file mode 100644 index 0000000000..c6c2f1e617 --- /dev/null +++ b/wrappers/python/tests/ledger/test_build_ledgers_freeze_request.py @@ -0,0 +1,47 @@ +from indy import ledger +from typing import List +from indy.error import CommonInvalidStructure + +import json +import pytest + +@pytest.mark.asyncio +async def test_build_ledgers_freeze_request(did_trustee): + ledgers_ids: List[int] = [0, 6, 78, 751] + expected_response = { + "identifier": did_trustee, + "operation": { + "type": "9", + 'ledgers_ids': ledgers_ids + } + } + response = json.loads(await ledger.build_ledgers_freeze_request(did_trustee, ledgers_ids)) + assert expected_response.items() <= response.items() + +@pytest.mark.asyncio +async def test_build_ledgers_freeze_request_with_empty_data(did_trustee): + ledgers_ids: List[int] = [] + expected_response = { + "identifier": did_trustee, + "operation": { + "type": "9", + 'ledgers_ids': ledgers_ids + } + } + + response = json.loads(await ledger.build_ledgers_freeze_request(did_trustee, ledgers_ids)) + assert expected_response.items() <= response.items() + +@pytest.mark.asyncio +async def test_build_ledgers_freeze_request_with_str_data(did_trustee): + ledgers_ids = ["0", "6", "78", "751"] + + with pytest.raises(CommonInvalidStructure): + json.loads(await ledger.build_ledgers_freeze_request(did_trustee, ledgers_ids)) + +@pytest.mark.asyncio +async def test_build_ledgers_freeze_request_with_no_data(did_trustee): + ledgers_ids = None + + with pytest.raises(CommonInvalidStructure): + json.loads(await ledger.build_ledgers_freeze_request(did_trustee, ledgers_ids)) diff --git a/wrappers/rust/indy-sys/src/ledger.rs b/wrappers/rust/indy-sys/src/ledger.rs index 2be8c99d13..f888dd5535 100644 --- a/wrappers/rust/indy-sys/src/ledger.rs +++ b/wrappers/rust/indy-sys/src/ledger.rs @@ -305,6 +305,17 @@ extern { request_json: CString, endorser_did: CString, cb: Option) -> Error; + + #[no_mangle] + pub fn indy_build_ledgers_freeze_request(command_handle: CommandHandle, + submitter_did: CString, + ledgers_ids: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_build_get_frozen_ledgers_request(command_handle: CommandHandle, + submitter_did: CString, + cb: Option) -> Error; } pub type CustomTransactionParser = extern fn(reply_from_node: CString, parsed_sp: *mut CString) -> Error; diff --git a/wrappers/rust/src/ledger.rs b/wrappers/rust/src/ledger.rs index 5551f47022..8b5871ceac 100644 --- a/wrappers/rust/src/ledger.rs +++ b/wrappers/rust/src/ledger.rs @@ -1,3 +1,4 @@ +use serde_json::json; use {ErrorCode, IndyError}; use std::ffi::CString; @@ -1510,4 +1511,65 @@ fn _append_request_endorser(command_handle: CommandHandle, endorser_did.as_ptr(), cb) }) +} +/// Request to freeze list of ledgers. +/// +/// # Arguments +/// * `command_handle`: command handle to map callback to caller context. +/// * `submitter_did`: (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). +/// * `ledgers_ids`: list of ledgers IDs for freezing. +/// * `cb`: Callback that takes command result as parameter. +/// +/// # Returns +/// Updated request result as json. +pub fn build_ledgers_freeze_request(submitter_did: &str, ledgers_ids: Vec) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + let json_ledgers_ids: &str = &json!(ledgers_ids).to_string(); + let err = _build_ledgers_freeze_request(command_handle, submitter_did, json_ledgers_ids, cb); + ResultHandler::str(command_handle, err, receiver) +} + +fn _build_ledgers_freeze_request(command_handle: CommandHandle, submitter_did: &str, ledgers_ids: &str, cb: Option) -> ErrorCode { + let submitter_did = c_str!(submitter_did); + let ledgers_ids = c_str!(ledgers_ids); + + ErrorCode::from(unsafe { + ledger::indy_build_ledgers_freeze_request(command_handle, + submitter_did.as_ptr(), + ledgers_ids.as_ptr(), + cb) + }) +} + +/// Request to get list of frozen ledgers. +/// +/// # Arguments +/// * `command_handle`: command handle to map callback to caller context. +/// * `submitter_did`: (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). +/// * `cb`: Callback that takes command result as parameter. +/// +/// # Returns +/// Request result as json. +/// { +/// : { +/// "ledger": String - Ledger root hash, +/// "state": String - State root hash, +/// "seq_no": u64 - the latest transaction seqNo for particular Node, +/// }, +/// ... +/// } +pub fn build_get_frozen_ledgers_request(submitter_did: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + let err = _build_get_frozen_ledgers_request(command_handle, submitter_did, cb); + ResultHandler::str(command_handle, err, receiver) +} + +fn _build_get_frozen_ledgers_request(command_handle: CommandHandle, submitter_did: &str, cb: Option) -> ErrorCode { + let submitter_did = c_str!(submitter_did); + + ErrorCode::from(unsafe { + ledger::indy_build_get_frozen_ledgers_request(command_handle, + submitter_did.as_ptr(), + cb) + }) } \ No newline at end of file diff --git a/wrappers/rust/tests/ledger.rs b/wrappers/rust/tests/ledger.rs index 10a871b1db..c4b4781adb 100644 --- a/wrappers/rust/tests/ledger.rs +++ b/wrappers/rust/tests/ledger.rs @@ -564,6 +564,57 @@ mod test_build_cred_def_request { } } +#[cfg(test)] +mod test_build_ledgers_freeze_request { + use super::*; + + #[test] + pub fn test_build_ledgers_freeze_request() { + let wallet = Wallet::new(); + let (did, _) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + let ledgers_ids: Vec = vec![0u64, 1u64, 10u64, 236u64]; + + match ledger::build_ledgers_freeze_request(&did, ledgers_ids).wait() { + Ok(_) => {}, + Err(ec) => { + assert!(false, "build_ledgers_freeze_request returned error_code {:?}", ec); + } + } + } + + #[test] + pub fn test_build_ledgers_freeze_request_with_empty_data() { + let wallet = Wallet::new(); + let (did, _) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + let ledgers_ids: Vec = vec![]; + + match ledger::build_ledgers_freeze_request(&did, ledgers_ids).wait() { + Ok(_) => {}, + Err(ec) => { + assert!(false, "test_build_ledgers_freeze_request_with_empty_data returned error_code {:?}", ec); + } + } + } +} + +#[cfg(test)] +mod test_build_get_frozen_ledgers_request { + use super::*; + + #[test] + pub fn test_build_get_frozen_ledgers_request() { + let wallet = Wallet::new(); + let (did, _) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + + match ledger::build_get_frozen_ledgers_request(&did).wait() { + Ok(_) => {}, + Err(ec) => { + assert!(false, "build_get_frozen_ledgers_request returned error_code {:?}", ec); + } + } + } +} + #[cfg(test)] mod test_build_get_cred_def_request {} diff --git a/wrappers/rust/tests/metrics.rs b/wrappers/rust/tests/metrics.rs index 71955d45ba..dfeff1b95a 100644 --- a/wrappers/rust/tests/metrics.rs +++ b/wrappers/rust/tests/metrics.rs @@ -13,31 +13,50 @@ mod utils; #[allow(unused_imports)] use futures::Future; -const THREADPOOL_ACTIVE_COUNT: &str = "threadpool_active_count"; -const THREADPOOL_QUEUED_COUNT: &str = "threadpool_queued_count"; -const THREADPOOL_MAX_COUNT: &str = "threadpool_max_count"; -const THREADPOOL_PANIC_COUNT: &str = "threadpool_panic_count"; -const OPENED_WALLETS_COUNT: &str = "opened_wallets_count"; -const OPENED_WALLET_IDS_COUNT: &str = "opened_wallet_ids_count"; -const PENDING_FOR_IMPORT_WALLETS_COUNT: &str = "pending_for_import_wallets_count"; -const PENDING_FOR_OPEN_WALLETS_COUNT: &str = "pending_for_open_wallets_count"; - #[cfg(test)] mod collect { use super::*; use std::collections::HashMap; + use serde_json::Value; #[test] fn collect_metrics() { let result_metrics = metrics::collect_metrics().wait().unwrap(); - let metrics_map = serde_json::from_str::>(&result_metrics).unwrap(); - assert!(metrics_map.contains_key(THREADPOOL_ACTIVE_COUNT)); - assert!(metrics_map.contains_key(THREADPOOL_QUEUED_COUNT)); - assert!(metrics_map.contains_key(THREADPOOL_MAX_COUNT)); - assert!(metrics_map.contains_key(THREADPOOL_PANIC_COUNT)); - assert!(metrics_map.contains_key(OPENED_WALLETS_COUNT)); - assert!(metrics_map.contains_key(OPENED_WALLET_IDS_COUNT)); - assert!(metrics_map.contains_key(PENDING_FOR_IMPORT_WALLETS_COUNT)); - assert!(metrics_map.contains_key(PENDING_FOR_OPEN_WALLETS_COUNT)); + let metrics_map = serde_json::from_str::>(&result_metrics).unwrap(); + + assert!(metrics_map.contains_key("threadpool_threads_count")); + assert!(metrics_map.contains_key("wallet_count")); + + let threadpool_threads_count = metrics_map + .get("threadpool_threads_count") + .unwrap() + .as_array() + .unwrap(); + let wallet_count = metrics_map + .get("wallet_count") + .unwrap() + .as_array() + .unwrap(); + + let expected_threadpool_threads_count = [ + json!({"tags":{"label":"active"},"value":0}), + json!({"tags":{"label":"queued"},"value":0}), + json!({"tags":{"label":"panic"},"value":0}), + ]; + + let expected_wallet_count = [ + json!({"tags":{"label":"opened"},"value":0}), + json!({"tags":{"label":"opened_ids"},"value":0}), + json!({"tags":{"label":"pending_for_import"},"value":0}), + json!({"tags":{"label":"pending_for_open"},"value":0}), + ]; + + for command in &expected_threadpool_threads_count { + assert!(threadpool_threads_count.contains(&command)); + } + + for command in &expected_wallet_count { + assert!(wallet_count.contains(&command)); + } } }