diff --git a/Cargo.toml b/Cargo.toml index e5a631aca0..181b4fabb0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,6 +36,7 @@ local_nodes_pool = [] [dependencies] int_traits = { version = "0.1.1", optional = true } env_logger = "0.4.2" +hex = "0.2.0" libc = "0.2.21" log = "0.3.7" openssl = { version = "0.9.11", optional = true } diff --git a/src/api/ledger.rs b/src/api/ledger.rs index 62a98026cb..83a1da7afa 100644 --- a/src/api/ledger.rs +++ b/src/api/ledger.rs @@ -76,10 +76,10 @@ pub extern fn sovrin_sign_and_submit_request(command_handle: i32, /// Ledger* #[no_mangle] pub extern fn sovrin_submit_request(command_handle: i32, - pool_handle: i32, - request_json: *const c_char, - cb: Option) -> ErrorCode { + pool_handle: i32, + request_json: *const c_char, + cb: Option) -> ErrorCode { check_useful_c_str!(request_json, ErrorCode::CommonInvalidParam3); check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); @@ -113,10 +113,10 @@ pub extern fn sovrin_submit_request(command_handle: i32, /// Common* #[no_mangle] pub extern fn sovrin_build_get_ddo_request(command_handle: i32, - submitter_did: *const c_char, - target_did: *const c_char, - cb: Option) -> ErrorCode { + submitter_did: *const c_char, + target_did: *const c_char, + cb: Option) -> ErrorCode { check_useful_c_str!(submitter_did, ErrorCode::CommonInvalidParam2); check_useful_c_str!(target_did, ErrorCode::CommonInvalidParam3); check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); @@ -155,20 +155,20 @@ pub extern fn sovrin_build_get_ddo_request(command_handle: i32, /// Common* #[no_mangle] pub extern fn sovrin_build_nym_request(command_handle: i32, - submitter_did: *const c_char, - target_did: *const c_char, - verkey: *const c_char, - xref: *const c_char, - data: *const c_char, - role: *const c_char, - cb: Option) -> ErrorCode { + submitter_did: *const c_char, + target_did: *const c_char, + verkey: *const c_char, + xref: *const c_char, + data: *const c_char, + role: *const c_char, + cb: Option) -> ErrorCode { check_useful_c_str!(submitter_did, ErrorCode::CommonInvalidParam2); check_useful_c_str!(target_did, ErrorCode::CommonInvalidParam3); - check_useful_c_str!(verkey, ErrorCode::CommonInvalidParam4); - check_useful_c_str!(xref, ErrorCode::CommonInvalidParam5); - check_useful_c_str!(data, ErrorCode::CommonInvalidParam6); - check_useful_c_str!(role, ErrorCode::CommonInvalidParam7); + check_useful_opt_c_str!(verkey, ErrorCode::CommonInvalidParam4); + check_useful_opt_c_str!(xref, ErrorCode::CommonInvalidParam5); + check_useful_opt_c_str!(data, ErrorCode::CommonInvalidParam6); + check_useful_opt_c_str!(role, ErrorCode::CommonInvalidParam7); check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam8); let result = CommandExecutor::instance() @@ -207,18 +207,18 @@ pub extern fn sovrin_build_nym_request(command_handle: i32, /// Common* #[no_mangle] pub extern fn sovrin_build_attrib_request(command_handle: i32, - submitter_did: *const c_char, - target_did: *const c_char, - hash: *const c_char, - raw: *const c_char, - enc: *const c_char, - cb: Option) -> ErrorCode { + submitter_did: *const c_char, + target_did: *const c_char, + hash: *const c_char, + raw: *const c_char, + enc: *const c_char, + cb: Option) -> ErrorCode { check_useful_c_str!(submitter_did, ErrorCode::CommonInvalidParam2); check_useful_c_str!(target_did, ErrorCode::CommonInvalidParam3); - check_useful_c_str!(hash, ErrorCode::CommonInvalidParam4); - check_useful_c_str!(raw, ErrorCode::CommonInvalidParam5); - check_useful_c_str!(enc, ErrorCode::CommonInvalidParam6); + check_useful_opt_c_str!(hash, ErrorCode::CommonInvalidParam4); + check_useful_opt_c_str!(raw, ErrorCode::CommonInvalidParam5); + check_useful_opt_c_str!(enc, ErrorCode::CommonInvalidParam6); check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam7); let result = CommandExecutor::instance() @@ -253,11 +253,11 @@ pub extern fn sovrin_build_attrib_request(command_handle: i32, /// #Errors /// Common* pub extern fn sovrin_build_get_attrib_request(command_handle: i32, - submitter_did: *const c_char, - target_did: *const c_char, - data: *const c_char, - cb: Option) -> ErrorCode { + submitter_did: *const c_char, + target_did: *const c_char, + data: *const c_char, + cb: Option) -> ErrorCode { check_useful_c_str!(submitter_did, ErrorCode::CommonInvalidParam2); check_useful_c_str!(target_did, ErrorCode::CommonInvalidParam3); check_useful_c_str!(data, ErrorCode::CommonInvalidParam4); @@ -293,10 +293,10 @@ pub extern fn sovrin_build_get_attrib_request(command_handle: i32, /// Common* #[no_mangle] pub extern fn sovrin_build_get_nym_request(command_handle: i32, - submitter_did: *const c_char, - target_did: *const c_char, - cb: Option) -> ErrorCode { + submitter_did: *const c_char, + target_did: *const c_char, + cb: Option) -> ErrorCode { check_useful_c_str!(submitter_did, ErrorCode::CommonInvalidParam2); check_useful_c_str!(target_did, ErrorCode::CommonInvalidParam3); check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); @@ -330,10 +330,10 @@ pub extern fn sovrin_build_get_nym_request(command_handle: i32, /// Common* #[no_mangle] pub extern fn sovrin_build_schema_request(command_handle: i32, - submitter_did: *const c_char, - data: *const c_char, - cb: Option) -> ErrorCode { + submitter_did: *const c_char, + data: *const c_char, + cb: Option) -> ErrorCode { check_useful_c_str!(submitter_did, ErrorCode::CommonInvalidParam2); check_useful_c_str!(data, ErrorCode::CommonInvalidParam3); check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); @@ -357,6 +357,7 @@ pub extern fn sovrin_build_schema_request(command_handle: i32, /// #Params /// command_handle: command handle to map callback to caller context. /// submitter_did: Id of Identity stored in secured Wallet. +/// dest: Id of Identity stored in secured Wallet. /// data: name, version /// cb: Callback that takes command result as parameter. /// @@ -367,17 +368,20 @@ pub extern fn sovrin_build_schema_request(command_handle: i32, /// Common* #[no_mangle] pub extern fn sovrin_build_get_schema_request(command_handle: i32, - submitter_did: *const c_char, - data: *const c_char, - cb: Option) -> ErrorCode { + submitter_did: *const c_char, + dest: *const c_char, + data: *const c_char, + cb: Option) -> ErrorCode { check_useful_c_str!(submitter_did, ErrorCode::CommonInvalidParam2); - check_useful_c_str!(data, ErrorCode::CommonInvalidParam3); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + check_useful_c_str!(dest, ErrorCode::CommonInvalidParam3); + check_useful_c_str!(data, ErrorCode::CommonInvalidParam4); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); let result = CommandExecutor::instance() .send(Command::Ledger(LedgerCommand::BuildGetSchemaRequest( submitter_did, + dest, data, Box::new(move |result| { let (err, request_json) = result_to_err_code_1!(result, String::new()); @@ -405,20 +409,22 @@ pub extern fn sovrin_build_get_schema_request(command_handle: i32, /// Common* #[no_mangle] pub extern fn sovrin_build_claim_def_txn(command_handle: i32, - submitter_did: *const c_char, - xref: *const c_char, - data: *const c_char, - cb: Option) -> ErrorCode { + submitter_did: *const c_char, + xref: i32, + signature_type: *const c_char, + data: *const c_char, + cb: Option) -> ErrorCode { check_useful_c_str!(submitter_did, ErrorCode::CommonInvalidParam2); - check_useful_c_str!(xref, ErrorCode::CommonInvalidParam3); - check_useful_c_str!(data, ErrorCode::CommonInvalidParam4); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + check_useful_c_str!(signature_type, ErrorCode::CommonInvalidParam4); + check_useful_c_str!(data, ErrorCode::CommonInvalidParam5); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); let result = CommandExecutor::instance() .send(Command::Ledger(LedgerCommand::BuildClaimDefRequest( submitter_did, xref, + signature_type, data, Box::new(move |result| { let (err, request_json) = result_to_err_code_1!(result, String::new()); @@ -436,6 +442,8 @@ pub extern fn sovrin_build_claim_def_txn(command_handle: i32, /// command_handle: command handle to map callback to caller context. /// submitter_did: Id of Identity stored in secured Wallet. /// xref: Seq. number of schema +/// signature_type: signature type (only CL supported now) +/// origin /// cb: Callback that takes command result as parameter. /// /// #Returns @@ -445,18 +453,23 @@ pub extern fn sovrin_build_claim_def_txn(command_handle: i32, /// Common* #[no_mangle] pub extern fn sovrin_build_get_claim_def_txn(command_handle: i32, - submitter_did: *const c_char, - xref: *const c_char, - cb: Option) -> ErrorCode { + submitter_did: *const c_char, + xref: i32, + signature_type: *const c_char, + origin: *const c_char, + cb: Option) -> ErrorCode { check_useful_c_str!(submitter_did, ErrorCode::CommonInvalidParam2); - check_useful_c_str!(xref, ErrorCode::CommonInvalidParam3); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + check_useful_c_str!(signature_type, ErrorCode::CommonInvalidParam4); + check_useful_c_str!(origin, ErrorCode::CommonInvalidParam4); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); let result = CommandExecutor::instance() .send(Command::Ledger(LedgerCommand::BuildGetClaimDefRequest( submitter_did, xref, + signature_type, + origin, Box::new(move |result| { let (err, request_json) = result_to_err_code_1!(result, String::new()); let request_json = CStringUtils::string_to_cstring(request_json); @@ -483,11 +496,11 @@ pub extern fn sovrin_build_get_claim_def_txn(command_handle: i32, /// Common* #[no_mangle] pub extern fn sovrin_build_node_request(command_handle: i32, - submitter_did: *const c_char, - target_did: *const c_char, - data: *const c_char, - cb: Option) -> ErrorCode { + submitter_did: *const c_char, + target_did: *const c_char, + data: *const c_char, + cb: Option) -> ErrorCode { check_useful_c_str!(submitter_did, ErrorCode::CommonInvalidParam2); check_useful_c_str!(target_did, ErrorCode::CommonInvalidParam3); check_useful_c_str!(data, ErrorCode::CommonInvalidParam4); diff --git a/src/api/signus.rs b/src/api/signus.rs index 47a45b5e94..67d24a1768 100644 --- a/src/api/signus.rs +++ b/src/api/signus.rs @@ -19,11 +19,14 @@ use self::libc::c_char; /// command_handle: command handle to map callback to user context. /// did_json: Identity information as json. Example: /// { -/// "did": string, (optional; if not provided then the first 16 bit of the verkey will be used -/// as a new DID; if provided, then keys will be replaced - key rotation use case) +/// "did": string, (optional; +/// if not provided and cid param is false then the first 16 bit of the verkey will be used as a new DID; +/// if not provided and cid is true then the full verkey will be used as a new DID; +/// if provided, then keys will be replaced - key rotation use case) /// "seed": string, (optional; if not provide then a random one will be created) /// "crypto_type": string, (optional; if not set then ed25519 curve is used; /// currently only 'ed25519' value is supported for this field) +/// "cid": string, (optional; if not set then false is used;) /// } /// cb: Callback that takes command result as parameter. /// diff --git a/src/commands/ledger.rs b/src/commands/ledger.rs index b586056abe..07c3b3978b 100644 --- a/src/commands/ledger.rs +++ b/src/commands/ledger.rs @@ -7,6 +7,7 @@ use services::pool::PoolService; use services::signus::SignusService; use services::signus::types::MyDid; use services::wallet::WalletService; +use services::ledger::LedgerService; use utils::json::JsonDecodable; @@ -38,17 +39,17 @@ pub enum LedgerCommand { BuildNymRequest( String, // submitter did String, // target did - String, // verkey - String, // xref - String, // data - String, // role + Option, // verkey + Option, // xref + Option, // data + Option, // role Box) + Send>), BuildAttribRequest( String, // submitter did String, // target did - String, // hash - String, // raw - String, // enc + Option, // hash + Option, // raw + Option, // enc Box) + Send>), BuildGetAttribRequest( String, // submitter did @@ -65,16 +66,20 @@ pub enum LedgerCommand { Box) + Send>), BuildGetSchemaRequest( String, // submitter did + String, // dest String, // data Box) + Send>), BuildClaimDefRequest( String, // submitter did - String, // xref + i32, // xref + String, // signature_type String, // data Box) + Send>), BuildGetClaimDefRequest( String, // submitter did - String, // xref + i32, // xref + String, // signature_type + String, // origin Box) + Send>), BuildNodeRequest( String, // submitter did @@ -88,6 +93,7 @@ pub struct LedgerCommandExecutor { pool_service: Rc, signus_service: Rc, wallet_service: Rc, + ledger_service: Rc, send_callbacks: RefCell)>>>, } @@ -96,12 +102,14 @@ impl LedgerCommandExecutor { pub fn new(anoncreds_service: Rc, pool_service: Rc, signus_service: Rc, - wallet_service: Rc) -> LedgerCommandExecutor { + wallet_service: Rc, + ledger_service: Rc) -> LedgerCommandExecutor { LedgerCommandExecutor { anoncreds_service: anoncreds_service, pool_service: pool_service, signus_service: signus_service, wallet_service: wallet_service, + ledger_service: ledger_service, send_callbacks: RefCell::new(HashMap::new()), } } @@ -128,11 +136,20 @@ impl LedgerCommandExecutor { } LedgerCommand::BuildNymRequest(submitter_did, target_did, verkey, xref, data, role, cb) => { info!(target: "ledger_command_executor", "BuildNymRequest command received"); - self.build_nym_request(&submitter_did, &target_did, &verkey, &xref, &data, &role, cb); + self.build_nym_request(&submitter_did, &target_did, + verkey.as_ref().map(String::as_str), + xref.as_ref().map(String::as_str), + data.as_ref().map(String::as_str), + role.as_ref().map(String::as_str), + cb); } LedgerCommand::BuildAttribRequest(submitter_did, target_did, hash, raw, enc, cb) => { info!(target: "ledger_command_executor", "BuildAttribRequest command received"); - self.build_attrib_request(&submitter_did, &target_did, &hash, &raw, &enc, cb); + self.build_attrib_request(&submitter_did, &target_did, + hash.as_ref().map(String::as_str), + raw.as_ref().map(String::as_str), + enc.as_ref().map(String::as_str), + cb); } LedgerCommand::BuildGetAttribRequest(submitter_did, target_did, data, cb) => { info!(target: "ledger_command_executor", "BuildGetAttribRequest command received"); @@ -146,17 +163,17 @@ impl LedgerCommandExecutor { info!(target: "ledger_command_executor", "BuildSchemaRequest command received"); self.build_schema_request(&submitter_did, &data, cb); } - LedgerCommand::BuildGetSchemaRequest(submitter_did, data, cb) => { + LedgerCommand::BuildGetSchemaRequest(submitter_did, dest, data, cb) => { info!(target: "ledger_command_executor", "BuildGetSchemaRequest command received"); - self.build_get_schema_request(&submitter_did, &data, cb); + self.build_get_schema_request(&submitter_did, &dest, &data, cb); } - LedgerCommand::BuildClaimDefRequest(submitter_did, xref, data, cb) => { + LedgerCommand::BuildClaimDefRequest(submitter_did, xref, signature_type, data, cb) => { info!(target: "ledger_command_executor", "BuildClaimDefRequest command received"); - self.build_issuer_key_request(&submitter_did, &xref, &data, cb); + self.build_claim_def_request(&submitter_did, xref, &signature_type, &data, cb); } - LedgerCommand::BuildGetClaimDefRequest(submitter_did, xref, cb) => { + LedgerCommand::BuildGetClaimDefRequest(submitter_did, xref, signature_type, origin, cb) => { info!(target: "ledger_command_executor", "BuildGetClaimDefRequest command received"); - self.build_get_issuer_key_request(&submitter_did, &xref, cb); + self.build_get_claim_def_request(&submitter_did, xref, &signature_type, &origin, cb); } LedgerCommand::BuildNodeRequest(submitter_did, target_did, data, cb) => { info!(target: "ledger_command_executor", "BuildNodeRequest command received"); @@ -216,28 +233,40 @@ impl LedgerCommandExecutor { submitter_did: &str, target_did: &str, cb: Box) + Send>) { - cb(Ok("".to_string())); + cb(self.ledger_service.build_get_ddo_request(submitter_did, target_did) + .map_err(|err| SovrinError::CommonError(err))) } fn build_nym_request(&self, submitter_did: &str, target_did: &str, - verkey: &str, - xref: &str, - data: &str, - role: &str, + verkey: Option<&str>, + xref: Option<&str>, + data: Option<&str>, + role: Option<&str>, cb: Box) + Send>) { - cb(Ok("".to_string())); + cb(self.ledger_service.build_nym_request(submitter_did, + target_did, + verkey, + xref, + data, + role + ).map_err(|err| SovrinError::CommonError(err))) } fn build_attrib_request(&self, submitter_did: &str, target_did: &str, - hash: &str, - raw: &str, - enc: &str, + hash: Option<&str>, + raw: Option<&str>, + enc: Option<&str>, cb: Box) + Send>) { - cb(Ok("".to_string())); + cb(self.ledger_service.build_attrib_request(submitter_did, + target_did, + hash, + raw, + enc + ).map_err(|err| SovrinError::CommonError(err))) } fn build_get_attrib_request(&self, @@ -245,43 +274,65 @@ impl LedgerCommandExecutor { target_did: &str, data: &str, cb: Box) + Send>) { - cb(Ok("".to_string())); + cb(self.ledger_service.build_get_attrib_request(submitter_did, + target_did, + data + ).map_err(|err| SovrinError::CommonError(err))) } fn build_get_nym_request(&self, submitter_did: &str, target_did: &str, cb: Box) + Send>) { - cb(Ok("".to_string())); + cb(self.ledger_service.build_get_nym_request(submitter_did, + target_did + ).map_err(|err| SovrinError::CommonError(err))) } fn build_schema_request(&self, submitter_did: &str, data: &str, cb: Box) + Send>) { - cb(Ok("".to_string())); + cb(self.ledger_service.build_schema_request(submitter_did, + data + ).map_err(|err| SovrinError::CommonError(err))) } fn build_get_schema_request(&self, submitter_did: &str, + dest: &str, data: &str, cb: Box) + Send>) { - cb(Ok("".to_string())); + cb(self.ledger_service.build_get_schema_request(submitter_did, + dest, + data + ).map_err(|err| SovrinError::CommonError(err))) } - fn build_issuer_key_request(&self, - submitter_did: &str, - xref: &str, - data: &str, - cb: Box) + Send>) { - cb(Ok("".to_string())); + fn build_claim_def_request(&self, + submitter_did: &str, + xref: i32, + signature_type: &str, + data: &str, + cb: Box) + Send>) { + cb(self.ledger_service.build_claim_def_request(submitter_did, + xref, + signature_type, + data + ).map_err(|err| SovrinError::CommonError(err))) } - fn build_get_issuer_key_request(&self, - submitter_did: &str, - xref: &str, - cb: Box) + Send>) { - cb(Ok("".to_string())); + fn build_get_claim_def_request(&self, + submitter_did: &str, + xref: i32, + signature_type: &str, + origin: &str, + cb: Box) + Send>) { + cb(self.ledger_service.build_get_claim_def_request(submitter_did, + xref, + signature_type, + origin + ).map_err(|err| SovrinError::CommonError(err))) } fn build_node_key_request(&self, @@ -289,6 +340,9 @@ impl LedgerCommandExecutor { target_did: &str, data: &str, cb: Box) + Send>) { - cb(Ok("".to_string())); + cb(self.ledger_service.build_node_request(submitter_did, + target_did, + data + ).map_err(|err| SovrinError::CommonError(err))) } } \ No newline at end of file diff --git a/src/commands/mod.rs b/src/commands/mod.rs index e64c1e3db3..e7dc187a05 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -19,6 +19,7 @@ use services::anoncreds::AnoncredsService; use services::pool::PoolService; use services::wallet::WalletService; use services::signus::SignusService; +use services::ledger::LedgerService; use std::error::Error; use std::sync::mpsc::{Sender, channel}; @@ -62,9 +63,10 @@ impl CommandExecutor { let pool_service = Rc::new(PoolService::new()); let wallet_service = Rc::new(WalletService::new()); let signus_service = Rc::new(SignusService::new()); + let ledger_service = Rc::new(LedgerService::new()); let anoncreds_command_executor = AnoncredsCommandExecutor::new(anoncreds_service.clone(), pool_service.clone(), wallet_service.clone()); - let ledger_command_executor = LedgerCommandExecutor::new(anoncreds_service.clone(), pool_service.clone(), signus_service.clone(), wallet_service.clone()); + let ledger_command_executor = LedgerCommandExecutor::new(anoncreds_service.clone(), pool_service.clone(), signus_service.clone(), wallet_service.clone(), ledger_service.clone()); let pool_command_executor = PoolCommandExecutor::new(pool_service.clone()); let signus_command_executor = SignusCommandExecutor::new(anoncreds_service.clone(), pool_service.clone(), wallet_service.clone(), signus_service.clone()); let wallet_command_executor = WalletCommandExecutor::new(wallet_service.clone()); diff --git a/src/commands/signus.rs b/src/commands/signus.rs index dc5213de7c..67ee512013 100644 --- a/src/commands/signus.rs +++ b/src/commands/signus.rs @@ -174,7 +174,7 @@ impl SignusCommandExecutor { let identity_info: MyIdentityInfo = MyIdentityInfo::from_json(identity_json) .map_err(|_| CommonError::InvalidStructure(format!("Invalid identity json")))?; - let did_info = MyDidInfo::new(Some(did.to_string()), identity_info.seed, identity_info.crypto_type); + let did_info = MyDidInfo::new(Some(did.to_string()), identity_info.seed, identity_info.crypto_type, None); let my_did = self.signus_service.create_my_did(&did_info)?; let my_did_json = my_did.to_json() diff --git a/src/errors/ledger.rs b/src/errors/ledger.rs index 3304bf9bc0..397d1542b3 100644 --- a/src/errors/ledger.rs +++ b/src/errors/ledger.rs @@ -1,3 +1,5 @@ +extern crate serde_json; + use std::error; use std::io; use std::fmt; @@ -58,6 +60,12 @@ impl ToErrorCode for LedgerError { } } +impl From for LedgerError { + fn from(err: serde_json::Error) -> LedgerError { + LedgerError::CryptoError(CryptoError::InvalidStructure(err.to_string())) + } +} + #[cfg(test)] mod tests { // use super::*; diff --git a/src/services/anoncreds/issuer.rs b/src/services/anoncreds/issuer.rs index bbfce9efa4..17022c7d78 100644 --- a/src/services/anoncreds/issuer.rs +++ b/src/services/anoncreds/issuer.rs @@ -72,7 +72,7 @@ impl Issuer { info!(target: "anoncreds_service", "Issuer generate primary keys for Schema {:?} -> start", &schema); let mut ctx = BigNumber::new_context()?; - if schema.attribute_names.len() == 0 { + if schema.keys.len() == 0 { return Err(CryptoError::InvalidStructure(format!("List of attribute names is required to setup claim definition"))) } @@ -92,7 +92,7 @@ impl Issuer { let xz = Issuer::_gen_x(&p_prime, &q_prime)?; let mut r: HashMap = HashMap::new(); - for attribute in &schema.attribute_names { + for attribute in &schema.keys { let random = Issuer::_gen_x(&p_prime, &q_prime)?; r.insert(attribute.to_string(), s.mod_exp(&random, &n, Some(&mut ctx))?); } @@ -508,7 +508,7 @@ mod tests { fn generate_claim_definition_does_not_works_with_empty_attributes() { let issuer = Issuer::new(); let mut schema = mocks::get_gvt_schema(); - schema.attribute_names = HashSet::new(); + schema.keys = HashSet::new(); let signature_type = None; let create_non_revoc = false; @@ -573,29 +573,29 @@ pub mod mocks { } pub fn get_gvt_schema() -> Schema { - let mut attr_names: HashSet = HashSet::new(); - attr_names.insert("name".to_string()); - attr_names.insert("age".to_string()); - attr_names.insert("height".to_string()); - attr_names.insert("sex".to_string()); + let mut keys: HashSet = HashSet::new(); + keys.insert("name".to_string()); + keys.insert("age".to_string()); + keys.insert("height".to_string()); + keys.insert("sex".to_string()); Schema { name: "gvt".to_string(), version: "1.0".to_string(), - attribute_names: attr_names, + keys: keys, seq_no: 1 } } pub fn get_xyz_schema() -> Schema { - let mut attr_names: HashSet = HashSet::new(); - attr_names.insert("status".to_string()); - attr_names.insert("period".to_string()); + let mut keys: HashSet = HashSet::new(); + keys.insert("status".to_string()); + keys.insert("period".to_string()); Schema { name: "xyz".to_string(), version: "1.0".to_string(), - attribute_names: attr_names, + keys: keys, seq_no: 2 } } diff --git a/src/services/anoncreds/prover.rs b/src/services/anoncreds/prover.rs index c1c75e5bd7..a0509028e0 100644 --- a/src/services/anoncreds/prover.rs +++ b/src/services/anoncreds/prover.rs @@ -512,7 +512,7 @@ impl Prover { let vtilde = BigNumber::rand(LARGE_VTILDE)?; let unrevealed_attrs: Vec = - schema.attribute_names + schema.keys .difference(&HashSet::from_iter(revealed_attrs.iter().cloned())) .map(|attr| attr.clone()) .collect::>(); diff --git a/src/services/anoncreds/types.rs b/src/services/anoncreds/types.rs index 035518a30b..63cab97633 100644 --- a/src/services/anoncreds/types.rs +++ b/src/services/anoncreds/types.rs @@ -1075,16 +1075,16 @@ impl RequestedProofJson { pub struct Schema { pub name: String, pub version: String, - pub attribute_names: HashSet, + pub keys: HashSet, pub seq_no: i32 } impl Schema { - pub fn new(name: String, version: String, attributes_names: HashSet, seq_no: i32) -> Schema { + pub fn new(name: String, version: String, keys: HashSet, seq_no: i32) -> Schema { Schema { name: name, version: version, - attribute_names: attributes_names, + keys: keys, seq_no: seq_no } } diff --git a/src/services/anoncreds/verifier.rs b/src/services/anoncreds/verifier.rs index 6be349b1d2..d581e838a3 100644 --- a/src/services/anoncreds/verifier.rs +++ b/src/services/anoncreds/verifier.rs @@ -101,7 +101,7 @@ impl Verifier { use std::iter::FromIterator; let unrevealed_attrs: Vec = - schema.attribute_names + schema.keys .difference(&HashSet::from_iter(proof.revealed_attrs.keys().cloned())) .map(|attr| attr.clone()) .collect::>(); diff --git a/src/services/ledger/constants.rs b/src/services/ledger/constants.rs new file mode 100644 index 0000000000..d436d1a237 --- /dev/null +++ b/src/services/ledger/constants.rs @@ -0,0 +1,9 @@ +pub const NODE: &'static str = "0"; +pub const NYM: &'static str = "1"; +pub const ATTRIB: &'static str = "100"; +pub const SCHEMA: &'static str = "101"; +pub const CLAIM_DEF: &'static str = "102"; +pub const GET_ATTR: &'static str = "104"; +pub const GET_NYM: &'static str = "105"; +pub const GET_SCHEMA: &'static str = "107"; +pub const GET_CLAIM_DEF: &'static str = "108"; \ No newline at end of file diff --git a/src/services/ledger/mod.rs b/src/services/ledger/mod.rs index 7b19da3951..b17d5a752c 100644 --- a/src/services/ledger/mod.rs +++ b/src/services/ledger/mod.rs @@ -1 +1,403 @@ -pub mod merkletree; \ No newline at end of file +extern crate time; + +pub mod merkletree; +pub mod types; +pub mod constants; + +use self::types::{ + AttribOperation, + GetAttribOperation, + GetNymOperation, + GetSchemaOperationData, + GetSchemaOperation, + NymOperation, + NymOperationData, + Request, + SchemaOperation, + SchemaOperationData, + ClaimDefOperation, + ClaimDefOperationData, + GetClaimDefOperation, + GetDdoOperation, + NodeOperation, + NodeOperationData +}; +use errors::common::CommonError; +use utils::json::{JsonEncodable, JsonDecodable}; + +trait LedgerSerializer { + fn serialize(&self) -> String; +} + +pub struct LedgerService {} + +impl LedgerService { + pub fn new() -> LedgerService { + LedgerService {} + } + + pub fn build_nym_request(&self, identifier: &str, dest: &str, verkey: Option<&str>, _ref: Option<&str>, + data: Option<&str>, role: Option<&str>) -> Result { + + //TODO: check identifier, dest, verkey + let req_id = LedgerService::get_req_id(); + + let data = match data { + Some(d) => Some(NymOperationData::from_json(d) + .map_err(|err| CommonError::InvalidStructure(format!("Invalid data json: {}", err.to_string())))?), + _ => None + }; + + let operation = NymOperation::new(dest.to_string(), + verkey.as_ref().map(|s| s.to_string()), + _ref.as_ref().map(|s| s.to_string()), + data, + role.as_ref().map(|s| s.to_string())); + let request = Request::new(req_id, + identifier.to_string(), + operation); + let request_json = Request::to_json(&request) + .map_err(|err| CommonError::InvalidState(format!("Invalid nym request json: {}", err.to_string())))?; + Ok(request_json) + } + + pub fn build_get_nym_request(&self, identifier: &str, dest: &str) -> Result { + let req_id = LedgerService::get_req_id(); + let operation = GetNymOperation::new(dest.to_string()); + let request = Request::new(req_id, + identifier.to_string(), + operation); + let request_json = Request::to_json(&request) + .map_err(|err| CommonError::InvalidState(format!("Invalid get_nym request json: {}", err.to_string())))?; + Ok(request_json) + } + + pub fn build_get_ddo_request(&self, identifier: &str, dest: &str) -> Result { + let req_id = LedgerService::get_req_id(); + let operation = GetDdoOperation::new(dest.to_string()); + let request = Request::new(req_id, + identifier.to_string(), + operation); + let request_json = Request::to_json(&request) + .map_err(|err| CommonError::InvalidState(format!("Invalid get_ddo request json: {}", err.to_string())))?; + Ok(request_json) + } + + pub fn build_attrib_request(&self, identifier: &str, dest: &str, hash: Option<&str>, + raw: Option<&str>, enc: Option<&str>) -> Result { + if raw.is_none() && hash.is_none() && enc.is_none() { + return Err(CommonError::InvalidStructure(format!("Either raw or hash or enc must be specified"))) + } + let req_id = LedgerService::get_req_id(); + let operation = AttribOperation::new(dest.to_string(), + hash.as_ref().map(|s| s.to_string()), + raw.as_ref().map(|s| s.to_string()), + enc.as_ref().map(|s| s.to_string())); + let request = Request::new(req_id, + identifier.to_string(), + operation); + let request_json = Request::to_json(&request) + .map_err(|err| CommonError::InvalidState(format!("Invalid attrib request json: {}", err.to_string())))?; + Ok(request_json) + } + + pub fn build_get_attrib_request(&self, identifier: &str, dest: &str, raw: &str) -> Result { + let req_id = LedgerService::get_req_id(); + let operation = GetAttribOperation::new(dest.to_string(), + raw.to_string()); + let request = Request::new(req_id, + identifier.to_string(), + operation); + let request_json = Request::to_json(&request) + .map_err(|err| CommonError::InvalidState(format!("Invalid get_attrib request json: {}", err.to_string())))?; + Ok(request_json) + } + + pub fn build_schema_request(&self, identifier: &str, data: &str) -> Result { + let req_id = LedgerService::get_req_id(); + SchemaOperationData::from_json(&data) + .map_err(|err| CommonError::InvalidStructure(format!("Invalid data json: {}", err.to_string())))?; + let operation = SchemaOperation::new(data.to_string()); + let request = Request::new(req_id, + identifier.to_string(), + operation); + let request_json = Request::to_json(&request) + .map_err(|err| CommonError::InvalidState(format!("Invalid schema request json: {}", err.to_string())))?; + Ok(request_json) + } + + pub fn build_get_schema_request(&self, identifier: &str, dest: &str, data: &str) -> Result { + let req_id = LedgerService::get_req_id(); + let data = GetSchemaOperationData::from_json(data) + .map_err(|err| CommonError::InvalidStructure(format!("Invalid data json: {}", err.to_string())))?; + let operation = GetSchemaOperation::new(dest.to_string(), data); + let request = Request::new(req_id, + identifier.to_string(), + operation); + let request_json = Request::to_json(&request) + .map_err(|err| CommonError::InvalidState(format!("Invalid get_schema request json: {}", err.to_string())))?; + Ok(request_json) + } + + pub fn build_claim_def_request(&self, identifier: &str, _ref: i32, signature_type: &str, data: &str) -> Result { + let req_id = LedgerService::get_req_id(); + println!("data {:?}", data); + ClaimDefOperationData::from_json(&data) + .map_err(|err| CommonError::InvalidStructure(format!("Invalid data json: {}", err.to_string())))?; + let operation = ClaimDefOperation::new(_ref, signature_type.to_string(), data.to_string()); + let request = Request::new(req_id, + identifier.to_string(), + operation); + let request_json = Request::to_json(&request) + .map_err(|err| CommonError::InvalidState(format!("Invalid claim_def request json: {}", err.to_string())))?; + Ok(request_json) + } + + pub fn build_get_claim_def_request(&self, identifier: &str, _ref: i32, signature_type: &str, origin: &str) -> Result { + let req_id = LedgerService::get_req_id(); + let operation = GetClaimDefOperation::new(_ref, + signature_type.to_string(), + origin.to_string()); + let request = Request::new(req_id, + identifier.to_string(), + operation); + let request_json = Request::to_json(&request) + .map_err(|err| CommonError::InvalidState(format!("Invalid get_claim_def request json: {}", err.to_string())))?; + Ok(request_json) + } + + pub fn build_node_request(&self, identifier: &str, dest: &str, data: &str) -> Result { + let req_id = LedgerService::get_req_id(); + let data = NodeOperationData::from_json(&data) + .map_err(|err| CommonError::InvalidStructure(format!("Invalid data json: {}", err.to_string())))?; + let operation = NodeOperation::new(dest.to_string(), data); + let request = Request::new(req_id, + identifier.to_string(), + operation); + let request_json = Request::to_json(&request) + .map_err(|err| CommonError::InvalidState(format!("Invalid node request json: {}", err.to_string())))?; + Ok(request_json) + } + + fn get_req_id() -> u64 { + time::get_time().sec as u64 * (1e9 as u64) + time::get_time().nsec as u64 + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn build_nym_request_works_for_only_required_fields() { + let ledger_service = LedgerService::new(); + let identifier = "some_identifier"; + let dest = "some_dest"; + + let expected_result = r#""identifier":"some_identifier","operation":{"type":"1","dest":"some_dest"}"#; + + let nym_request = ledger_service.build_nym_request(identifier, dest, None, None, None, None); + assert!(nym_request.is_ok()); + let nym_request = nym_request.unwrap(); + assert!(nym_request.contains(expected_result)); + } + + #[test] + fn build_nym_request_works_for_optional_fields() { + let ledger_service = LedgerService::new(); + let identifier = "some_identifier"; + let dest = "some_dest"; + let verkey = "some_verkey"; + + let expected_result = r#""identifier":"some_identifier","operation":{"type":"1","dest":"some_dest","verkey":"some_verkey"}"#; + + let nym_request = ledger_service.build_nym_request(identifier, dest, Some(verkey), None, None, None); + assert!(nym_request.is_ok()); + let nym_request = nym_request.unwrap(); + assert!(nym_request.contains(expected_result)); + } + + #[test] + fn build_nym_request_works_for_data_json() { + let ledger_service = LedgerService::new(); + let identifier = "some_identifier"; + let dest = "some_dest"; + let data = r#"{"alias":"some_alias"}"#; + + let expected_result = r#""identifier":"some_identifier","operation":{"type":"1","dest":"some_dest","data":{"alias":"some_alias"}}"#; + + let nym_request = ledger_service.build_nym_request(identifier, dest, None, None, Some(data), None); + assert!(nym_request.is_ok()); + let nym_request = nym_request.unwrap(); + assert!(nym_request.contains(expected_result)); + } + + #[test] + fn build_nym_request_works_for_wrong_data_json() { + let ledger_service = LedgerService::new(); + let identifier = "some_identifier"; + let dest = "some_dest"; + let data = r#"{"field": "field"}"#; + + let nym_request = ledger_service.build_nym_request(identifier, dest, None, None, Some(data), None); + assert!(nym_request.is_err()); + } + + #[test] + fn build_get_nym_request_works() { + let ledger_service = LedgerService::new(); + let identifier = "some_identifier"; + let dest = "some_dest"; + + let expected_result = r#""identifier":"some_identifier","operation":{"type":"105","dest":"some_dest"}"#; + + let get_nym_request = ledger_service.build_get_nym_request(identifier, dest); + assert!(get_nym_request.is_ok()); + let get_nym_request = get_nym_request.unwrap(); + assert!(get_nym_request.contains(expected_result)); + } + + #[test] + fn build_get_ddo_request_works() { + let ledger_service = LedgerService::new(); + let identifier = "some_identifier"; + let dest = "some_dest"; + + let expected_result = r#""identifier":"some_identifier","operation":{"type":"120","dest":"some_dest"}"#; + + let get_ddo_request = ledger_service.build_get_ddo_request(identifier, dest); + assert!(get_ddo_request.is_ok()); + let get_ddo_request = get_ddo_request.unwrap(); + assert!(get_ddo_request.contains(expected_result)); + } + + #[test] + fn build_attrib_request_works_for_miss_attrib_field() { + let ledger_service = LedgerService::new(); + let identifier = "some_identifier"; + let dest = "some_dest"; + + let attrib_request = ledger_service.build_attrib_request(identifier, dest, None, None, None); + assert!(attrib_request.is_err()); + } + + #[test] + fn build_attrib_request_works_for_hash_field() { + let ledger_service = LedgerService::new(); + let identifier = "some_identifier"; + let dest = "some_dest"; + let hash = "some_hash"; + + let expected_result = r#""identifier":"some_identifier","operation":{"type":"100","dest":"some_dest","hash":"some_hash"}"#; + + let attrib_request = ledger_service.build_attrib_request(identifier, dest, Some(hash), None, None); + assert!(attrib_request.is_ok()); + let attrib_request = attrib_request.unwrap(); + assert!(attrib_request.contains(expected_result)); + } + + #[test] + fn build_get_attrib_request_works() { + let ledger_service = LedgerService::new(); + let identifier = "some_identifier"; + let dest = "some_dest"; + let raw = "some_raw"; + + let expected_result = r#""identifier":"some_identifier","operation":{"type":"104","dest":"some_dest","raw":"some_raw"}"#; + + let get_attrib_request = ledger_service.build_get_attrib_request(identifier, dest, raw); + assert!(get_attrib_request.is_ok()); + let get_attrib_request = get_attrib_request.unwrap(); + assert!(get_attrib_request.contains(expected_result)); + } + + #[test] + fn build_schema_request_works_for_wrong_data() { + let ledger_service = LedgerService::new(); + let identifier = "some_identifier"; + let data = r#"{"name":"name"}"#; + + let get_attrib_request = ledger_service.build_schema_request(identifier, data); + assert!(get_attrib_request.is_err()); + } + + #[test] + fn build_schema_request_works_for_correct_data() { + let ledger_service = LedgerService::new(); + let identifier = "some_identifier"; + let data = r#"{"name":"name", "version":"1.0", "keys":["name","male"]}"#; + + let expected_result = "\"operation\":{\"type\":\"101\",\"data\":\"{\\\"name\\\":\\\"name\\\", \\\"version\\\":\\\"1.0\\\", \\\"keys\\\":[\\\"name\\\",\\\"male\\\"]"; + + let schema_request = ledger_service.build_schema_request(identifier, data); + assert!(schema_request.is_ok()); + let schema_request = schema_request.unwrap(); + assert!(schema_request.contains(expected_result)); + } + + #[test] + fn build_get_schema_request_works_for_wrong_data() { + let ledger_service = LedgerService::new(); + let identifier = "some_identifier"; + let data = r#"{"name":"name","keys":["name","male"]}"#; + + let get_schema_request = ledger_service.build_get_schema_request(identifier, identifier, data); + assert!(get_schema_request.is_err()); + } + + #[test] + fn build_get_schema_request_works_for_correct_data() { + let ledger_service = LedgerService::new(); + let identifier = "some_identifier"; + let data = r#"{"name":"name","version":"1.0"}"#; + + let expected_result = r#""identifier":"some_identifier","operation":{"type":"107","dest":"some_identifier","data":{"name":"name","version":"1.0"}}"#; + + let get_schema_request = ledger_service.build_get_schema_request(identifier, identifier, data); + assert!(get_schema_request.is_ok()); + let get_schema_request = get_schema_request.unwrap(); + assert!(get_schema_request.contains(expected_result)); + } + + #[test] + fn build_get_claim_def_request_works() { + let ledger_service = LedgerService::new(); + let identifier = "some_identifier"; + let _ref = 1; + let signature_type = "signature_type"; + let origin = "some_origin"; + + let expected_result = r#""identifier":"some_identifier","operation":{"type":"108","ref":1,"signature_type":"signature_type","origin":"some_origin"}"#; + + let get_claim_def_request = ledger_service.build_get_claim_def_request(identifier, _ref, signature_type, origin); + assert!(get_claim_def_request.is_ok()); + let get_claim_def_request = get_claim_def_request.unwrap(); + assert!(get_claim_def_request.contains(expected_result)); + } + + #[test] + fn build_node_request_works() { + let ledger_service = LedgerService::new(); + let identifier = "some_identifier"; + let dest = "some_dest"; + let data = r#"{"node_ip":"ip", "node_port": 1, "client_ip": "ip", "client_port": 1, "alias":"some", "services": ["VALIDATOR"]}"#; + + let expected_result = r#""identifier":"some_identifier","operation":{"type":"0","dest":"some_dest","data":{"node_ip":"ip","node_port":1,"client_ip":"ip","client_port":1,"alias":"some","services":["VALIDATOR"]}}"#; + + let node_request = ledger_service.build_node_request(identifier, dest, data); + assert!(node_request.is_ok()); + let node_request = node_request.unwrap(); + assert!(node_request.contains(expected_result)); + } + + #[test] + fn build_node_request_works_for_wrong_data() { + let ledger_service = LedgerService::new(); + let identifier = "some_identifier"; + let dest = "some_dest"; + let data = r#"{"node_ip":"ip", "node_port": 1, "client_ip": "ip", "client_port": 1}"#; + + let node_request = ledger_service.build_node_request(identifier, dest, data); + assert!(node_request.is_err()); + } +} \ No newline at end of file diff --git a/src/services/ledger/types.rs b/src/services/ledger/types.rs new file mode 100644 index 0000000000..27727ae001 --- /dev/null +++ b/src/services/ledger/types.rs @@ -0,0 +1,406 @@ +use services::anoncreds::types::{PublicKey, RevocationPublicKey}; +use utils::json::{JsonEncodable, JsonDecodable}; +use services::ledger::constants::{ + NODE, + NYM, + ATTRIB, + SCHEMA, + GET_ATTR, + GET_NYM, + GET_SCHEMA, + CLAIM_DEF, + GET_CLAIM_DEF +}; + +#[derive(Serialize, PartialEq, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Request { + pub req_id: u64, + pub identifier: String, + pub operation: T, + #[serde(skip_serializing_if = "Option::is_none")] + pub signature: Option +} + +impl Request { + pub fn new(req_id: u64, identifier: String, operation: T) -> Request { + Request { + req_id: req_id, + identifier: identifier, + operation: operation, + signature: None + } + } +} + +impl JsonEncodable for Request {} + +#[derive(Deserialize, PartialEq, Debug)] +pub struct Reply { + pub op: String, + pub result: ReplyResult, +} + +#[derive(Deserialize, PartialEq, Debug)] +#[serde(rename_all = "camelCase")] +pub struct ReplyResult { + pub txn_id: String, + pub req_id: u64, + pub data: Option +} + +#[derive(Serialize, PartialEq, Debug)] +pub struct NymOperation { + #[serde(rename = "type")] + pub _type: String, + pub dest: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub verkey: Option, + #[serde(rename = "ref")] + #[serde(skip_serializing_if = "Option::is_none")] + pub _ref: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub data: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub role: Option +} + +impl NymOperation { + pub fn new(dest: String, verkey: Option, _ref: Option, + data: Option, role: Option) -> NymOperation { + NymOperation { + _type: NYM.to_string(), + dest: dest, + verkey: verkey, + _ref: _ref, + data: data, + role: role + } + } +} + +impl JsonEncodable for NymOperation {} + + +#[derive(Serialize, Deserialize, PartialEq, Debug)] +pub struct NymOperationData { + pub alias: String +} + +impl NymOperationData { + pub fn new(alias: String) -> NymOperationData { + NymOperationData { + alias: alias + } + } +} + +impl JsonEncodable for NymOperationData {} + +impl<'a> JsonDecodable<'a> for NymOperationData {} + +#[derive(Serialize, PartialEq, Debug)] +pub struct GetNymOperation { + #[serde(rename = "type")] + pub _type: String, + pub dest: String +} + +impl GetNymOperation { + pub fn new(dest: String) -> GetNymOperation { + GetNymOperation { + _type: GET_NYM.to_string(), + dest: dest + } + } +} + +impl JsonEncodable for GetNymOperation {} + +#[derive(Deserialize, PartialEq, Debug)] +#[serde(rename_all = "camelCase")] +pub struct GetNymResultData { + pub dest: String, + pub identifier: String, + pub role: Option, + pub txn_id: String, +} + +#[derive(Serialize, PartialEq, Debug)] +pub struct AttribOperation { + #[serde(rename = "type")] + pub _type: String, + pub dest: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub hash: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub raw: Option, + // TODO raw must be {attr_name: {ha: value}} + #[serde(skip_serializing_if = "Option::is_none")] + pub enc: Option +} + +impl AttribOperation { + pub fn new(dest: String, hash: Option, raw: Option, + enc: Option) -> AttribOperation { + AttribOperation { + _type: ATTRIB.to_string(), + dest: dest, + hash: hash, + raw: raw, + // TODO Looks like currently implemented only raw in strange format raw: {"endpoint" : {"ha": "127.0.0.1:5555"}} + enc: enc, + } + } +} + +impl JsonEncodable for AttribOperation {} + + +#[derive(Serialize, PartialEq, Debug)] +pub struct GetAttribOperation { + #[serde(rename = "type")] + pub _type: String, + pub dest: String, + pub raw: String +} + +impl GetAttribOperation { + pub fn new(dest: String, raw: String) -> GetAttribOperation { + GetAttribOperation { + _type: GET_ATTR.to_string(), + dest: dest, + raw: raw + } + } +} + +impl JsonEncodable for GetAttribOperation {} + +#[derive(Serialize, PartialEq, Debug)] +pub struct SchemaOperation { + #[serde(rename = "type")] + pub _type: String, + pub data: String +} + +impl SchemaOperation { + pub fn new(data: String) -> SchemaOperation { + SchemaOperation { + data: data, + _type: SCHEMA.to_string() + } + } +} + +impl JsonEncodable for SchemaOperation {} + +#[derive(Serialize, PartialEq, Debug, Deserialize)] +pub struct SchemaOperationData { + name: String, + version: String, + keys: Vec +} + +impl SchemaOperationData { + pub fn new(name: String, version: String, keys: Vec) -> SchemaOperationData { + SchemaOperationData { + name: name, + version: version, + keys: keys + } + } +} + +impl JsonEncodable for SchemaOperationData {} + +impl<'a> JsonDecodable<'a> for SchemaOperationData {} + +#[derive(Serialize, PartialEq, Debug)] +pub struct GetSchemaOperation { + #[serde(rename = "type")] + pub _type: String, + pub dest: String, + pub data: GetSchemaOperationData +} + +impl GetSchemaOperation { + pub fn new(dest: String, data: GetSchemaOperationData) -> GetSchemaOperation { + GetSchemaOperation { + _type: GET_SCHEMA.to_string(), + dest: dest, + data: data + } + } +} + +impl JsonEncodable for GetSchemaOperation {} + +#[derive(Deserialize, PartialEq, Debug)] +#[serde(rename_all = "camelCase")] +pub struct GetSchemaResultData { + pub attr_names: Vec, + pub name: String, + pub origin: String, + pub seq_no: String, + #[serde(rename = "type")] + pub _type: Option, + pub version: String +} + +#[derive(Serialize, PartialEq, Debug, Deserialize)] +pub struct GetSchemaOperationData { + pub name: String, + pub version: String +} + +impl GetSchemaOperationData { + pub fn new(name: String, version: String) -> GetSchemaOperationData { + GetSchemaOperationData { + name: name, + version: version + } + } +} + +impl JsonEncodable for GetSchemaOperationData {} + +impl<'a> JsonDecodable<'a> for GetSchemaOperationData {} + +#[derive(Serialize, PartialEq, Debug)] +pub struct ClaimDefOperation { + #[serde(rename = "ref")] + pub _ref: i32, + pub data: String, + #[serde(rename = "type")] + pub _type: String, + pub signature_type: String +} + +impl ClaimDefOperation { + pub fn new(_ref: i32, signature_type: String, data: String) -> ClaimDefOperation { + ClaimDefOperation { + _ref: _ref, + signature_type: signature_type, + data: data, + _type: CLAIM_DEF.to_string() + } + } +} + +impl JsonEncodable for ClaimDefOperation {} + +#[derive(Serialize, PartialEq, Debug, Deserialize)] +pub struct ClaimDefOperationData { + pub primary: PublicKey, + pub revocation: Option +} + +impl ClaimDefOperationData { + pub fn new(primary: PublicKey, revocation: Option) -> ClaimDefOperationData { + ClaimDefOperationData { + primary: primary, + revocation: revocation + } + } +} + + +impl JsonEncodable for ClaimDefOperationData {} + +impl<'a> JsonDecodable<'a> for ClaimDefOperationData {} + +#[derive(Serialize, PartialEq, Debug)] +pub struct GetClaimDefOperation { + #[serde(rename = "type")] + pub _type: String, + #[serde(rename = "ref")] + pub _ref: i32, + pub signature_type: String, + pub origin: String +} + +impl GetClaimDefOperation { + pub fn new(_ref: i32, signature_type: String, origin: String) -> GetClaimDefOperation { + GetClaimDefOperation { + _type: GET_CLAIM_DEF.to_string(), + _ref: _ref, + signature_type: signature_type, + origin: origin + } + } +} + +impl JsonEncodable for GetClaimDefOperation {} + +#[derive(Serialize, PartialEq, Debug)] +pub struct NodeOperation { + #[serde(rename = "type")] + pub _type: String, + pub dest: String, + pub data: NodeOperationData +} + +impl NodeOperation { + pub fn new(dest: String, data: NodeOperationData) -> NodeOperation { + NodeOperation { + _type: NODE.to_string(), + dest: dest, + data: data + } + } +} + +impl JsonEncodable for NodeOperation {} + +#[derive(Serialize, PartialEq, Debug, Deserialize)] +pub enum Services { + VALIDATOR, + OBSERVER +} + +#[derive(Serialize, PartialEq, Debug, Deserialize)] +pub struct NodeOperationData { + pub node_ip: String, + pub node_port: i32, + pub client_ip: String, + pub client_port: i32, + pub alias: String, + pub services: Vec +} + +impl NodeOperationData { + pub fn new(node_ip: String, node_port: i32, client_ip: String, client_port: i32, alias: String, services: Vec) -> NodeOperationData { + NodeOperationData { + node_ip: node_ip, + node_port: node_port, + client_ip: client_ip, + client_port: client_port, + alias: alias, + services: services + } + } +} + +impl JsonEncodable for NodeOperationData {} + +impl<'a> JsonDecodable<'a> for NodeOperationData {} + +#[derive(Serialize, PartialEq, Debug)] +pub struct GetDdoOperation { + #[serde(rename = "type")] + pub _type: String, + pub dest: String +} + +impl GetDdoOperation { + pub fn new(dest: String) -> GetDdoOperation { + GetDdoOperation { + _type: "120".to_string(), + //TODO + dest: dest + } + } +} + +impl JsonEncodable for GetDdoOperation {} diff --git a/src/services/pool/mod.rs b/src/services/pool/mod.rs index c58770fcba..e4644ac32f 100644 --- a/src/services/pool/mod.rs +++ b/src/services/pool/mod.rs @@ -18,6 +18,7 @@ use commands::{Command, CommandExecutor}; use commands::ledger::LedgerCommand; use commands::pool::PoolCommand; use errors::pool::PoolError; +use errors::sovrin::SovrinError; use errors::crypto::CryptoError; use self::catchup::CatchupHandler; use self::types::*; @@ -94,6 +95,9 @@ impl TransactionHandler { Message::Reply(reply) => { self.process_reply(&reply, raw_msg); } + Message::Reject(response) => { + self.process_reject(&response, raw_msg); + } _ => { warn!("unhandled msg {:?}", msg); } @@ -119,6 +123,25 @@ impl TransactionHandler { } } + //TODO correct handling of Reject + fn process_reject(&mut self, response: &Response, raw_msg: &String) { + let req_id = response.req_id; + let mut remove = false; + if let Some(pend_cmd) = self.pending_commands.get_mut(&req_id) { + pend_cmd.nack_cnt += 1; + if pend_cmd.nack_cnt == self.f + 1 { + for &cmd_id in &pend_cmd.cmd_ids { + CommandExecutor::instance().send( + Command::Ledger(LedgerCommand::SubmitAck(cmd_id, Err(SovrinError::PoolError(PoolError::InvalidData(raw_msg.clone())))))).unwrap(); + } + remove = true; + } + } + if remove { + self.pending_commands.remove(&req_id); + } + } + fn try_send_request(&mut self, cmd: &String, cmd_id: i32) { info!("cmd {:?}", cmd); let tmp = SimpleRequest::from_json(cmd).unwrap(); @@ -382,6 +405,7 @@ impl RemoteNode { } let msg: String = self.zsock.as_ref().unwrap().recv_string(zmq::DONTWAIT)??; info!(target: "RemoteNode_recv_msg", "{} {}", self.name, msg); + println!("RemoteNode_recv_msg {} {}", self.name, msg); match msg.as_ref() { "pi" => Ok(None), //TODO send pong diff --git a/src/services/pool/types.rs b/src/services/pool/types.rs index 5781918230..4ac6996119 100644 --- a/src/services/pool/types.rs +++ b/src/services/pool/types.rs @@ -128,6 +128,8 @@ pub enum Message { ReqNACK(Response), #[serde(rename = "REPLY")] Reply(Reply), + #[serde(rename = "REJECT")] + Reject(Response), Ping, Pong, } diff --git a/src/services/signus/mod.rs b/src/services/signus/mod.rs index 7334cef1d9..4fc2a43c24 100644 --- a/src/services/signus/mod.rs +++ b/src/services/signus/mod.rs @@ -177,15 +177,9 @@ mod tests { #[test] fn create_my_did_with_empty_input_works() { let service = SignusService::new(); - - let did_info = MyDidInfo { - did: None, - seed: None, - crypto_type: None - }; + let did_info = MyDidInfo::new(None, None, None, None); let res = service.create_my_did(&did_info); - assert!(res.is_ok()); } @@ -194,11 +188,7 @@ mod tests { let service = SignusService::new(); let did = Some("Dbf2fjCbsiq2kfns".to_string()); - let did_info = MyDidInfo { - did: did.clone(), - seed: None, - crypto_type: None - }; + let did_info = MyDidInfo::new(did.clone(), None, None, None); let res = service.create_my_did(&did_info); assert!(res.is_ok()); @@ -212,11 +202,8 @@ mod tests { let did = Some("Dbf2fjCbsiq2kfns".to_string()); let crypto_type = Some("type".to_string()); - let did_info = MyDidInfo { - did: did.clone(), - seed: None, - crypto_type: crypto_type - }; + + let did_info = MyDidInfo::new(did.clone(), None, crypto_type, None); let res = service.create_my_did(&did_info); assert!(res.is_err()); @@ -228,16 +215,9 @@ mod tests { let did = Some("Dbf2fjCbsiq2kfns".to_string()); let seed = Some("DJASbewkdUY3265HJFDSbds278sdDSnA".to_string()); - let did_info_with_seed = MyDidInfo { - did: did.clone(), - seed: seed, - crypto_type: None - }; - let did_info_without_seed = MyDidInfo { - did: did.clone(), - seed: None, - crypto_type: None - }; + + let did_info_with_seed = MyDidInfo::new(did.clone(), seed, None, None); + let did_info_without_seed = MyDidInfo::new(did.clone(), None, None, None); let res_with_seed = service.create_my_did(&did_info_with_seed); let res_without_seed = service.create_my_did(&did_info_without_seed); @@ -252,11 +232,8 @@ mod tests { fn sign_works() { let service = SignusService::new(); - let did_info = MyDidInfo { - did: None, - seed: None, - crypto_type: None - }; + let did_info = MyDidInfo::new(None, None, None, None); + let message = r#"{ "reqId":1495034346617224651, "identifier":"GJ1SzoWzavQYfNL9XkaJdrQejfztN4XqdsiV4ct3LXKL", @@ -278,11 +255,8 @@ mod tests { fn sign_verify_works() { let service = SignusService::new(); - let did_info = MyDidInfo { - did: None, - seed: None, - crypto_type: None - }; + let did_info = MyDidInfo::new(None, None, None, None); + let message = r#"{ "reqId":1495034346617224651, "identifier":"GJ1SzoWzavQYfNL9XkaJdrQejfztN4XqdsiV4ct3LXKL", @@ -317,11 +291,8 @@ mod tests { fn try_verify_with_invalid_verkey() { let service = SignusService::new(); - let did_info = MyDidInfo { - did: None, - seed: None, - crypto_type: None - }; + let did_info = MyDidInfo::new(None, None, None, None); + let message = r#"{ "reqId":1495034346617224651, "identifier":"GJ1SzoWzavQYfNL9XkaJdrQejfztN4XqdsiV4ct3LXKL", @@ -357,11 +328,8 @@ mod tests { let msg = "some message"; - let did_info = MyDidInfo { - did: None, - seed: None, - crypto_type: None - }; + let did_info = MyDidInfo::new(None, None, None, None); + let res = service.create_my_did(&did_info); assert!(res.is_ok()); let my_did = res.unwrap(); @@ -388,11 +356,8 @@ mod tests { let msg = "some message"; - let did_info = MyDidInfo { - did: None, - seed: None, - crypto_type: None - }; + let did_info = MyDidInfo::new(None, None, None, None); + let res = service.create_my_did(&did_info); assert!(res.is_ok()); let my_did = res.unwrap(); diff --git a/src/services/signus/types.rs b/src/services/signus/types.rs index 119ccf8ed0..38c3303657 100644 --- a/src/services/signus/types.rs +++ b/src/services/signus/types.rs @@ -4,15 +4,18 @@ use utils::json::{JsonEncodable, JsonDecodable}; pub struct MyDidInfo { pub did: Option, pub seed: Option, - pub crypto_type: Option + pub crypto_type: Option, + pub cid: Option } impl MyDidInfo { - pub fn new(did: Option, seed: Option, crypto_type: Option) -> MyDidInfo { + pub fn new(did: Option, seed: Option, + crypto_type: Option, cid: Option) -> MyDidInfo { MyDidInfo { did: did, seed: seed, - crypto_type: crypto_type + crypto_type: crypto_type, + cid: cid } } } diff --git a/src/utils/crypto/signature_serializer.rs b/src/utils/crypto/signature_serializer.rs index 0485f95b83..0fa15fb95e 100644 --- a/src/utils/crypto/signature_serializer.rs +++ b/src/utils/crypto/signature_serializer.rs @@ -1,10 +1,11 @@ extern crate serde_json; +extern crate hex; +use self::hex::ToHex; use self::serde_json::Value; use errors::crypto::CryptoError; use utils::crypto::hash::Hash; -use utils::crypto::base58::Base58; pub fn serialize_signature(v: Value) -> Result { match v { @@ -30,8 +31,7 @@ pub fn serialize_signature(v: Value) -> Result { if key == "raw" { let mut ctx = Hash::new_context()?; ctx.update(&value.as_str().ok_or(CryptoError::BackendError("Cannot update hash context".to_string()))?.as_bytes())?; - let vector = Base58::encode(&ctx.finish2()?.to_vec()); - value = Value::String(vector); + value = Value::String(ctx.finish2()?.as_ref().to_hex()); } result = result + key + ":" + &serialize_signature(value)?; if index < length - 1 { @@ -90,7 +90,7 @@ mod tests { }"#; let msg: Value = serde_json::from_str(data).unwrap(); - let result = "age:43|name:John Doe|operation:dest:54|hash:cool hash|raw:31L9oDUaMfZu3t3eCWuoG6PbWigVMqHqrWuS8Ly9oH4t|phones:1234567,2345678,age:1|rust:5,3"; + let result = "age:43|name:John Doe|operation:dest:54|hash:cool hash|raw:1dcd0759ce38f57049344a6b3c5fc18144fca1724713090c2ceeffa788c02711|phones:1234567,2345678,age:1|rust:5,3"; assert_eq!(serialize_signature(msg).unwrap(), result) } diff --git a/tests/anoncreds.rs b/tests/anoncreds.rs index 79a27f158f..0d0ac54699 100644 --- a/tests/anoncreds.rs +++ b/tests/anoncreds.rs @@ -32,12 +32,12 @@ fn anoncreds_works_for_single_issuer_single_prover() { let xtype = "default"; //1. Create Issuer wallet, get wallet handle - let res = WalletUtils::create_wallet(pool_name, issuer_wallet_name, xtype); + let res = WalletUtils::create_and_open_wallet(pool_name, issuer_wallet_name, xtype); assert!(res.is_ok()); let issuer_wallet_handle = res.unwrap(); //2. Create Prover wallet, get wallet handle - let res = WalletUtils::create_wallet(pool_name, prover_wallet_name, xtype); + let res = WalletUtils::create_and_open_wallet(pool_name, prover_wallet_name, xtype); assert!(res.is_ok()); let prover_wallet_handle = res.unwrap(); @@ -162,17 +162,17 @@ fn anoncreds_works_for_multiply_issuer_single_prover() { let xtype = "default"; //1. Issuer1 create wallet, get wallet handles - let res = WalletUtils::create_wallet(pool_name, issuer1_wallet_name, xtype); + let res = WalletUtils::create_and_open_wallet(pool_name, issuer1_wallet_name, xtype); assert!(res.is_ok()); let issuer_gvt_wallet_handle = res.unwrap(); //2. Issuer2 create wallet, get wallet handles - let res = WalletUtils::create_wallet(pool_name, issuer2_wallet_name, xtype); + let res = WalletUtils::create_and_open_wallet(pool_name, issuer2_wallet_name, xtype); assert!(res.is_ok()); let issuer_xyz_wallet_handle = res.unwrap(); //3. Prover create wallet, get wallet handles - let res = WalletUtils::create_wallet(pool_name, prover_wallet_name, xtype); + let res = WalletUtils::create_and_open_wallet(pool_name, prover_wallet_name, xtype); assert!(res.is_ok()); let prover_wallet_handle = res.unwrap(); @@ -385,12 +385,12 @@ fn anoncreds_works_for_single_issuer_multiply_claims_single_prover() { let xtype = "default"; //1. Issuer create wallet, get wallet handles - let res = WalletUtils::create_wallet(pool_name, issuer_wallet_name, xtype); + let res = WalletUtils::create_and_open_wallet(pool_name, issuer_wallet_name, xtype); assert!(res.is_ok()); let issuer_wallet_handle = res.unwrap(); //2. Prover create wallet, get wallet handles - let res = WalletUtils::create_wallet(pool_name, prover_wallet_name, xtype); + let res = WalletUtils::create_and_open_wallet(pool_name, prover_wallet_name, xtype); assert!(res.is_ok()); let prover_wallet_handle = res.unwrap(); diff --git a/tests/demo.rs b/tests/demo.rs index c0a6035f83..4b17720bc2 100644 --- a/tests/demo.rs +++ b/tests/demo.rs @@ -159,7 +159,7 @@ fn anoncreds_demo_works() { let schema = format!("{{\ \"name\":\"gvt\",\ \"version\":\"1.0\",\ - \"attribute_names\":[\"age\",\"sex\",\"height\",\"name\"],\ + \"keys\":[\"age\",\"sex\",\"height\",\"name\"],\ \"seq_no\":{}\ }}", schema_seq_no); @@ -491,7 +491,7 @@ fn ledger_demo_works() { let nym_txn_req = Request { identifier: their_verkey.clone(), operation: Operation { - dest: my_verkey.clone(), + dest: my_did.clone(), type_: "1".to_string(), }, req_id: nym_req_id, @@ -522,7 +522,7 @@ fn ledger_demo_works() { identifier: my_verkey.clone(), operation: Operation { type_: "105".to_string(), - dest: my_verkey.clone(), + dest: my_did.clone(), }, }; let request = serde_json::to_string(&get_nym_txn).unwrap(); @@ -538,7 +538,7 @@ fn ledger_demo_works() { let get_nym_resp_data: ReplyResultData = serde_json::from_str(&get_nym_resp.result.data.as_ref().unwrap()).unwrap(); println!("get_nym_resp {:?}\n{:?}\n{:?}", resp, get_nym_resp, get_nym_resp_data); - assert_eq!(get_nym_resp_data.dest, my_verkey); + assert_eq!(get_nym_resp_data.dest, my_did); TestUtils::cleanup_storage(); diff --git a/tests/ledger.rs b/tests/ledger.rs new file mode 100644 index 0000000000..1e8c15939a --- /dev/null +++ b/tests/ledger.rs @@ -0,0 +1,426 @@ +#![allow(dead_code)] +#![allow(unused_variables)] + +extern crate sovrin; + +#[macro_use] +extern crate serde_derive; +extern crate serde_json; +#[macro_use] +extern crate lazy_static; + +#[macro_use] +#[path = "utils/mod.rs"] +mod utils; + +#[cfg(feature = "local_nodes_pool")] +use utils::test::TestUtils; +#[cfg(feature = "local_nodes_pool")] +use utils::pool::PoolUtils; +#[cfg(feature = "local_nodes_pool")] +use utils::wallet::WalletUtils; +#[cfg(feature = "local_nodes_pool")] +use utils::ledger::LedgerUtils; +#[cfg(feature = "local_nodes_pool")] +use utils::signus::SignusUtils; +#[cfg(feature = "local_nodes_pool")] +use utils::anoncreds::AnoncredsUtils; + +use std::collections::{HashMap, HashSet}; + + +// TODO: FIXME: create_my_did doesn't support CID creation, but this trustee has CID as DID. So it is rough workaround for this issue. +// See: https://github.com/hyperledger/indy-sdk/issues/25 +#[cfg(feature = "local_nodes_pool")] +fn get_trustee_keys(wallet_handle: i32) -> (String, String, String) { + // workaround start >>> + let res = SignusUtils::create_my_did(wallet_handle, "{\"seed\":\"000000000000000000000000Trustee1\"}"); + assert!(res.is_ok()); + let (trustee_did, trustee_verkey, trustee_pk) = res.unwrap(); + + let res = SignusUtils::create_my_did(wallet_handle, &format!("{{\"did\":\"{}\", \"seed\":\"000000000000000000000000Trustee1\"}}", trustee_verkey)); + assert!(res.is_ok()); + res.unwrap() + // workaround end <<< +} + +mod high_cases { + use super::*; + + mod nym_requests { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + #[ignore] + fn sovrin_nym_requests_works() { + TestUtils::cleanup_storage(); + + let res = PoolUtils::create_and_open_pool_ledger_config("pool1"); + assert!(res.is_ok()); + let pool_handle = res.unwrap(); + + let res = WalletUtils::create_and_open_wallet("pool1", "wallet1", "default"); + assert!(res.is_ok()); + let wallet_handle = res.unwrap(); + + let (trustee_did, trustee_verkey, trustee_pk) = get_trustee_keys(wallet_handle); + + let res = SignusUtils::create_my_did(wallet_handle, "{\"seed\":\"00000000000000000000000000000My1\"}"); + assert!(res.is_ok()); + let (my_did, my_verkey, my_pk) = res.unwrap(); + + let res = LedgerUtils::build_nym_request(&trustee_did.clone(), &my_did.clone(), Some(&my_verkey.clone()), None, None, None); + assert!(res.is_ok()); + let nym_request = res.unwrap(); + + let res = LedgerUtils::sign_and_submit_request(pool_handle, wallet_handle, &trustee_did, &nym_request); + assert!(res.is_ok()); + let nym_response = res.unwrap(); + println!("nym_response {:?}", nym_response); + + let res = LedgerUtils::build_get_nym_request(&my_did.clone(), &my_did.clone()); + assert!(res.is_ok()); + let get_nym_request = res.unwrap(); + + let res = PoolUtils::send_request(pool_handle, &get_nym_request); + assert!(res.is_ok()); + let get_nym_response = res.unwrap(); + println!("get_nym_response {:?}", get_nym_response); + + TestUtils::cleanup_storage(); + } + } + + mod attrib_requests { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + #[ignore] + fn sovrin_attrib_requests_works() { + TestUtils::cleanup_storage(); + + let res = PoolUtils::create_and_open_pool_ledger_config("pool1"); + assert!(res.is_ok()); + let pool_handle = res.unwrap(); + + let res = WalletUtils::create_and_open_wallet("pool1", "wallet1", "default"); + assert!(res.is_ok()); + let wallet_handle = res.unwrap(); + + let (trustee_did, trustee_verkey, trustee_pk) = get_trustee_keys(wallet_handle); + + let res = SignusUtils::create_my_did(wallet_handle, "{\"seed\":\"00000000000000000000000000000My1\"}"); + assert!(res.is_ok()); + let (my_did, my_verkey, my_pk) = res.unwrap(); + + let res = LedgerUtils::build_nym_request(&trustee_did.clone(), &my_did.clone(), Some(&my_verkey.clone()), None, None, None); + assert!(res.is_ok()); + let nym_request = res.unwrap(); + + let res = LedgerUtils::sign_and_submit_request(pool_handle, wallet_handle, &trustee_did, &nym_request); + assert!(res.is_ok()); + let nym_response = res.unwrap(); + + let res = LedgerUtils::build_attrib_request(&my_did.clone(), &my_did.clone(), None, Some("{\"endpoint\":{\"ha\":\"127.0.0.1:5555\"}}"), None); + assert!(res.is_ok()); + let attrib_request = res.unwrap(); + + let res = LedgerUtils::sign_and_submit_request(pool_handle, wallet_handle, &my_did, &attrib_request); + assert!(res.is_ok()); + let attrib_response = res.unwrap(); + println!("attrib_response {}", attrib_response); + + let res = LedgerUtils::build_get_attrib_request(&my_did.clone(), &my_did.clone(), "endpoint"); + assert!(res.is_ok()); + let get_attrib_request = res.unwrap(); + + println!("get_attrib_request {}", get_attrib_request); + let res = PoolUtils::send_request(pool_handle, &get_attrib_request); + assert!(res.is_ok()); + let get_attrib_response = res.unwrap(); + println!("get_attrib_response {}", get_attrib_response); + + TestUtils::cleanup_storage(); + } + } + + mod schema_requests { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + #[ignore] + fn sovrin_schema_requests_works() { + TestUtils::cleanup_storage(); + // TODO: FIXME: Understand why we use verkey insted of did as submitter id in NYM transaction + + let res = PoolUtils::create_and_open_pool_ledger_config("pool1"); + assert!(res.is_ok()); + let pool_handle = res.unwrap(); + + let res = WalletUtils::create_and_open_wallet("pool1", "wallet1", "default"); + assert!(res.is_ok()); + let wallet_handle = res.unwrap(); + + let (trustee_did, trustee_verkey, trustee_pk) = get_trustee_keys(wallet_handle); + + let res = SignusUtils::create_my_did(wallet_handle, "{}"); + assert!(res.is_ok()); + let (my_did, my_verkey, my_pk) = res.unwrap(); + + let res = LedgerUtils::build_nym_request(&trustee_did.clone(), &my_did.clone(), Some(&my_verkey.clone()), None, None, None); + assert!(res.is_ok()); + let nym_request = res.unwrap(); + + let res = LedgerUtils::sign_and_submit_request(pool_handle, wallet_handle, &trustee_did, &nym_request); + assert!(res.is_ok()); + let nym_response = res.unwrap(); + println!("nym_response {}", nym_response.clone()); + + let schema_data = "{\"name\":\"gvt2\",\ + \"version\":\"2.0\",\ + \"keys\": [\"name\", \"male\"]}"; + let res = LedgerUtils::build_schema_request(&my_did.clone(), schema_data); + assert!(res.is_ok()); + let schema_request = res.unwrap(); + + let res = LedgerUtils::sign_and_submit_request(pool_handle, wallet_handle, &my_did, &schema_request); + assert!(res.is_ok()); + let schema_response = res.unwrap(); + println!("schema_response {}", schema_response.clone()); + + let get_schema_data = "{\"name\":\"gvt2\",\"version\":\"2.0\"}"; + let res = LedgerUtils::build_get_schema_request(&my_did.clone(), &my_did, get_schema_data); + assert!(res.is_ok()); + let get_schema_request = res.unwrap(); + + let res = PoolUtils::send_request(pool_handle, &get_schema_request); + assert!(res.is_ok()); + let get_schema_response = res.unwrap(); + println!("get_schema_response {}", get_schema_response.clone()); + + TestUtils::cleanup_storage(); + } + } + + mod node_request { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + #[ignore] + fn sovrin_node_request_works() { + TestUtils::cleanup_storage(); + let res = PoolUtils::create_and_open_pool_ledger_config("pool1"); + assert!(res.is_ok()); + let pool_handle = res.unwrap(); + + let res = WalletUtils::create_and_open_wallet("pool1", "wallet1", "default"); + assert!(res.is_ok()); + let wallet_handle = res.unwrap(); + + let res = SignusUtils::create_my_did(wallet_handle, "{\"seed\":\"000000000000000000000000Trustee1\"}"); + assert!(res.is_ok()); + let (trustee_did, trustee_verkey, trustee_pk) = res.unwrap(); + + let res = SignusUtils::create_my_did(wallet_handle, "{\"seed\":\"000000000000000000000000Steward1\"}"); + assert!(res.is_ok()); + let (my_did, my_verkey, my_pk) = res.unwrap(); + + // TODO: FIXME: Understand why we use verkey insted of did as submitter id in NYM transaction + let res = LedgerUtils::build_nym_request(&trustee_verkey.clone(), &my_did.clone(), Some(&my_verkey.clone()), None, None, None); + assert!(res.is_ok()); + let nym_request = res.unwrap(); + + println!("nym_request {}", nym_request.clone()); + let res = LedgerUtils::sign_and_submit_request(pool_handle, wallet_handle, &trustee_did, &nym_request); + assert!(res.is_ok()); + let nym_response = res.unwrap(); + + let node_data = "{\"node_ip\":\"192.168.53.148\",\ + \"node_port\":9710, \ + \"client_ip\":\"192.168.53.148\",\ + \"client_port\":9709, \ + \"alias\":\"Node5\", \ + \"services\": [\"VALIDATOR\"]}"; + let res = LedgerUtils::build_node_request(&my_verkey.clone(), &my_did.clone(), node_data); + let node_request = res.unwrap(); + + + println!("node_request {}", node_request.clone()); + let res = LedgerUtils::sign_and_submit_request(pool_handle, wallet_handle, &my_did, &node_request); + //TODO correct handling of Reject + assert!(res.is_err()); + + TestUtils::cleanup_storage(); + } + } + + mod claim_def_requests { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + #[ignore] + fn sovrin_claim_def_requests_works() { + TestUtils::cleanup_storage(); + let res = PoolUtils::create_and_open_pool_ledger_config("pool1"); + assert!(res.is_ok()); + let pool_handle = res.unwrap(); + + let res = WalletUtils::create_and_open_wallet("pool1", "wallet1", "default"); + assert!(res.is_ok()); + let wallet_handle = res.unwrap(); + + let (trustee_did, trustee_verkey, trustee_pk) = get_trustee_keys(wallet_handle); + + let res = SignusUtils::create_my_did(wallet_handle, "{}"); + assert!(res.is_ok()); + let (my_did, my_verkey, my_pk) = res.unwrap(); + + let res = LedgerUtils::build_nym_request(&trustee_did.clone(), &my_did.clone(), Some(&my_verkey.clone()), None, None, None); + assert!(res.is_ok()); + let nym_request = res.unwrap(); + + let res = LedgerUtils::sign_and_submit_request(pool_handle, wallet_handle, &trustee_did, &nym_request); + assert!(res.is_ok()); + let nym_response = res.unwrap(); + println!("nym_response {}", nym_response.clone()); + + let schema_data = "{\"name\":\"gvt2\",\ + \"version\":\"2.0\",\ + \"keys\": [\"name\", \"male\"]}"; + let res = LedgerUtils::build_schema_request(&my_did.clone(), schema_data); + assert!(res.is_ok()); + let schema_request = res.unwrap(); + + let res = LedgerUtils::sign_and_submit_request(pool_handle, wallet_handle, &my_did, &schema_request); + assert!(res.is_ok()); + let schema_response = res.unwrap(); + println!("schema_response {}", schema_response.clone()); + + let get_schema_data = "{\"name\":\"gvt2\",\"version\":\"2.0\"}"; + let res = LedgerUtils::build_get_schema_request(&my_did.clone(), &my_did, get_schema_data); + assert!(res.is_ok()); + let get_schema_request = res.unwrap(); + + let res = PoolUtils::send_request(pool_handle, &get_schema_request); + assert!(res.is_ok()); + let get_schema_response = res.unwrap(); + println!("get_schema_response {}", get_schema_response); + let get_schema_response: Reply = serde_json::from_str(&get_schema_response).unwrap(); + // let schema_result_data: GetSchemaResultData = serde_json::from_str(&get_schema_response.result.data.unwrap()).unwrap(); + + let schema = Schema { + name: get_schema_response.result.data.name, + keys: get_schema_response.result.data.keys, + version: get_schema_response.result.data.version, + seq_no: get_schema_response.result.seq_no + }; + + let res = AnoncredsUtils::issuer_create_claim_definition(wallet_handle, &serde_json::to_string(&schema).unwrap()); + assert!(res.is_ok()); + let (claim_def_json, claim_def_uuid) = res.unwrap(); + println!("claim_def_json {:}", claim_def_json); + + let claim_def: ClaimDefinition = serde_json::from_str(&claim_def_json).unwrap(); + let claim_def_data = ClaimDefinitionData { + primary: claim_def.public_key, + revocation: claim_def.public_key_revocation + }; + let claim_def_data_json = serde_json::to_string(&claim_def_data).unwrap(); + + let res = LedgerUtils::build_claim_def_txn(&my_did.clone(), schema.seq_no, &claim_def.signature_type, &claim_def_data_json); + assert!(res.is_ok()); + let claim_def_request = res.unwrap(); + + let res = LedgerUtils::sign_and_submit_request(pool_handle, wallet_handle, &my_did, &claim_def_request); + assert!(res.is_ok()); + let claim_def_response = res.unwrap(); + println!("claim_def_response {}", claim_def_response); + + let res = LedgerUtils::build_get_claim_def_txn(&my_did.clone(), schema.seq_no, &claim_def.signature_type, &get_schema_response.result.data.origin); + assert!(res.is_ok()); + let get_claim_def_request = res.unwrap(); + + let res = PoolUtils::send_request(pool_handle, &get_claim_def_request); + assert!(res.is_ok()); + let get_claim_def_response = res.unwrap(); + println!("get_claim_def_response {}", get_claim_def_response); + + TestUtils::cleanup_storage(); + } + } +} + + +#[derive(Deserialize, Eq, PartialEq, Debug)] +#[serde(rename_all = "camelCase")] +struct Response { + op: String, + reason: String, + req_id: u64, + identifier: String +} + +#[derive(Deserialize, Eq, PartialEq, Debug)] +struct Reply { + op: String, + result: GetSchemaReplyResult, +} + +#[derive(Deserialize, Eq, PartialEq, Debug)] +#[serde(rename_all = "camelCase")] +struct GetSchemaReplyResult { + identifier: String, + req_id: u64, + seq_no: i32, + #[serde(rename = "type")] + _type: String, + data: GetSchemaResultData, + dest: Option +} + +#[derive(Deserialize, Debug, PartialEq, Eq)] +pub struct GetSchemaResultData { + pub keys: HashSet, + pub name: String, + pub origin: String, + pub version: String +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct Schema { + pub name: String, + pub version: String, + pub keys: HashSet, + pub seq_no: i32 +} + +#[derive(Deserialize, Debug, Serialize, PartialEq)] +pub struct ClaimDefinition { + pub public_key: PublicKey, + pub public_key_revocation: Option, + pub schema_seq_no: i32, + pub signature_type: String +} + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +pub struct PublicKey { + pub n: String, + pub s: String, + pub rms: String, + pub r: HashMap, + pub rctxt: String, + pub z: String +} + +#[derive(Deserialize, Debug, Serialize, PartialEq)] +pub struct ClaimDefinitionData { + pub primary: PublicKey, + pub revocation: Option +} + + diff --git a/tests/pool.rs b/tests/pool.rs index 18d92a3757..632594c25f 100644 --- a/tests/pool.rs +++ b/tests/pool.rs @@ -1,4 +1,4 @@ -// TODO: FIXME: It must be removed after code layout stabilization! +//// TODO: FIXME: It must be removed after code layout stabilization! #![allow(dead_code)] #![allow(unused_variables)] @@ -19,6 +19,9 @@ use sovrin::api::ErrorCode; use utils::pool::PoolUtils; use utils::test::TestUtils; +#[cfg(feature = "local_nodes_pool")] +use utils::logger::LoggerUtils; + #[test] fn create_pool_ledger_config_works() { @@ -48,6 +51,7 @@ fn open_pool_ledger_works() { #[cfg(feature = "local_nodes_pool")] fn open_pool_ledger_works_for_twice() { TestUtils::cleanup_storage(); + LoggerUtils::init(); let pool_name = "pool_open_twice"; let res = PoolUtils::create_pool_ledger_config(pool_name); @@ -110,4 +114,4 @@ struct ReplyResult { identifier: String, req_id: u64, data: Option -} +} \ No newline at end of file diff --git a/tests/utils/anoncreds.rs b/tests/utils/anoncreds.rs index 0ba070e0ca..ac723a7e88 100644 --- a/tests/utils/anoncreds.rs +++ b/tests/utils/anoncreds.rs @@ -358,7 +358,7 @@ impl AnoncredsUtils { format!("{{\ \"name\":\"gvt\",\ \"version\":\"1.0\",\ - \"attribute_names\":[\"age\",\"sex\",\"height\",\"name\"],\ + \"keys\":[\"age\",\"sex\",\"height\",\"name\"],\ \"seq_no\":{}\ }}", schema_seq_no) } @@ -367,7 +367,7 @@ impl AnoncredsUtils { format!("{{\ \"name\":\"xyz\",\ \"version\":\"1.0\",\ - \"attribute_names\":[\"status\",\"period\"],\ + \"keys\":[\"status\",\"period\"],\ \"seq_no\":{}\ }}", schema_seq_no) } diff --git a/tests/utils/callback.rs b/tests/utils/callback.rs index 741a81764a..ab1fdf529c 100644 --- a/tests/utils/callback.rs +++ b/tests/utils/callback.rs @@ -448,4 +448,70 @@ impl CallbackUtils { (command_handle, Some(prover_get_claim_offers_callback)) } + + pub fn closure_to_sign_and_submit_request_cb(closure: Box) -> (i32, + Option) { + lazy_static! { + static ref SIGN_AND_SUBMIT_REQUEST_CALLBACKS: Mutex < HashMap < i32, Box < FnMut(ErrorCode, String) + Send > >> = Default::default(); + } + + extern "C" fn closure_to_sign_and_submit_request_callback(command_handle: i32, err: ErrorCode, request_result_json: *const c_char) { + let mut callbacks = SIGN_AND_SUBMIT_REQUEST_CALLBACKS.lock().unwrap(); + let mut cb = callbacks.remove(&command_handle).unwrap(); + let request_result_json = unsafe { CStr::from_ptr(request_result_json).to_str().unwrap().to_string() }; + cb(err, request_result_json) + } + + let mut callbacks = SIGN_AND_SUBMIT_REQUEST_CALLBACKS.lock().unwrap(); + let command_handle = (COMMAND_HANDLE_COUNTER.fetch_add(1, Ordering::SeqCst) + 1) as i32; + callbacks.insert(command_handle, closure); + + (command_handle, Some(closure_to_sign_and_submit_request_callback)) + } + + pub fn closure_to_submit_request_cb(closure: Box) -> (i32, + Option) { + lazy_static! { + static ref SUBMIT_REQUEST_CALLBACKS: Mutex < HashMap < i32, Box < FnMut(ErrorCode, String) + Send > >> = Default::default(); + } + + extern "C" fn closure_to_submit_request_callback(command_handle: i32, err: ErrorCode, request_result_json: *const c_char) { + let mut callbacks = SUBMIT_REQUEST_CALLBACKS.lock().unwrap(); + let mut cb = callbacks.remove(&command_handle).unwrap(); + let request_result_json = unsafe { CStr::from_ptr(request_result_json).to_str().unwrap().to_string() }; + cb(err, request_result_json) + } + + let mut callbacks = SUBMIT_REQUEST_CALLBACKS.lock().unwrap(); + let command_handle = (COMMAND_HANDLE_COUNTER.fetch_add(1, Ordering::SeqCst) + 1) as i32; + callbacks.insert(command_handle, closure); + + (command_handle, Some(closure_to_submit_request_callback)) + } + + pub fn closure_to_build_request_cb(closure: Box) -> (i32, + Option) { + lazy_static! { + static ref BUILD_REQUEST_CALLBACKS: Mutex < HashMap < i32, Box < FnMut(ErrorCode, String) + Send > >> = Default::default(); + } + + extern "C" fn closure_to_build_request_callback(command_handle: i32, err: ErrorCode, request_json: *const c_char) { + let mut callbacks = BUILD_REQUEST_CALLBACKS.lock().unwrap(); + let mut cb = callbacks.remove(&command_handle).unwrap(); + let request_json = unsafe { CStr::from_ptr(request_json).to_str().unwrap().to_string() }; + cb(err, request_json) + } + + let mut callbacks = BUILD_REQUEST_CALLBACKS.lock().unwrap(); + let command_handle = (COMMAND_HANDLE_COUNTER.fetch_add(1, Ordering::SeqCst) + 1) as i32; + callbacks.insert(command_handle, closure); + + (command_handle, Some(closure_to_build_request_callback)) + } } diff --git a/tests/utils/ledger.rs b/tests/utils/ledger.rs new file mode 100644 index 0000000000..0a957317bb --- /dev/null +++ b/tests/utils/ledger.rs @@ -0,0 +1,430 @@ +extern crate time; + +use sovrin::api::ErrorCode; +use sovrin::api::ledger::{ + sovrin_sign_and_submit_request, + sovrin_submit_request, + sovrin_build_get_ddo_request, + sovrin_build_attrib_request, + sovrin_build_get_attrib_request, + sovrin_build_get_nym_request, + sovrin_build_schema_request, + sovrin_build_get_schema_request, + sovrin_build_claim_def_txn, + sovrin_build_get_claim_def_txn, + sovrin_build_node_request, + sovrin_build_nym_request +}; + +use utils::callback::CallbackUtils; +use utils::timeout::TimeoutUtils; + +use std::ffi::CString; +use std::ptr::null; +use std::sync::mpsc::channel; + +pub struct LedgerUtils {} + +impl LedgerUtils { + pub fn sign_and_submit_request(pool_handle: i32, wallet_handle: i32, submitter_did: &str, request_json: &str) -> Result { + let (sender, receiver) = channel(); + + let cb = Box::new(move |err, request_result_json| { + sender.send((err, request_result_json)).unwrap(); + }); + + let (command_handle, cb) = CallbackUtils::closure_to_sign_and_submit_request_cb(cb); + + let submitter_did = CString::new(submitter_did).unwrap(); + let request_json = CString::new(request_json).unwrap(); + + let err = + sovrin_sign_and_submit_request(command_handle, + pool_handle, + wallet_handle, + submitter_did.as_ptr(), + request_json.as_ptr(), + cb); + + if err != ErrorCode::Success { + return Err(err); + } + + let (err, request_result_json) = receiver.recv_timeout(TimeoutUtils::long_timeout()).unwrap(); + + if err != ErrorCode::Success { + return Err(err); + } + + Ok(request_result_json) + } + + pub fn submit_request(pool_handle: i32, request_json: &str) -> Result { + let (sender, receiver) = channel(); + + let cb = Box::new(move |err, request_result_json| { + sender.send((err, request_result_json)).unwrap(); + }); + + let (command_handle, cb) = CallbackUtils::closure_to_submit_request_cb(cb); + + let request_json = CString::new(request_json).unwrap(); + + let err = + sovrin_submit_request(command_handle, + pool_handle, + request_json.as_ptr(), + cb); + + if err != ErrorCode::Success { + return Err(err); + } + + let (err, request_result_json) = receiver.recv_timeout(TimeoutUtils::long_timeout()).unwrap(); + + if err != ErrorCode::Success { + return Err(err); + } + + Ok(request_result_json) + } + + pub fn build_get_ddo_request(submitter_did: &str, target_did: &str) -> Result { + let (sender, receiver) = channel(); + + let cb = Box::new(move |err, request_json| { + sender.send((err, request_json)).unwrap(); + }); + + let (command_handle, cb) = CallbackUtils::closure_to_build_request_cb(cb); + + let submitter_did = CString::new(submitter_did).unwrap(); + let target_did = CString::new(target_did).unwrap(); + + let err = + sovrin_build_get_ddo_request(command_handle, + submitter_did.as_ptr(), + target_did.as_ptr(), + cb); + + if err != ErrorCode::Success { + return Err(err); + } + + let (err, request_json) = receiver.recv_timeout(TimeoutUtils::long_timeout()).unwrap(); + + if err != ErrorCode::Success { + return Err(err); + } + + Ok(request_json) + } + + pub fn build_nym_request(submitter_did: &str, target_did: &str, verkey: Option<&str>, xref: Option<&str>, + data: Option<&str>, role: Option<&str>) -> Result { + let (sender, receiver) = channel(); + + let cb = Box::new(move |err, request_json| { + sender.send((err, request_json)).unwrap(); + }); + + let (command_handle, cb) = CallbackUtils::closure_to_build_request_cb(cb); + + let submitter_did = CString::new(submitter_did).unwrap(); + let target_did = CString::new(target_did).unwrap(); + + let verkey_str = verkey.map(|s| CString::new(s).unwrap()).unwrap_or(CString::new("").unwrap());; + let xref_str = xref.map(|s| CString::new(s).unwrap()).unwrap_or(CString::new("").unwrap());; + let data_str = data.map(|s| CString::new(s).unwrap()).unwrap_or(CString::new("").unwrap());; + let role_str = role.map(|s| CString::new(s).unwrap()).unwrap_or(CString::new("").unwrap());; + let err = + sovrin_build_nym_request(command_handle, + submitter_did.as_ptr(), + target_did.as_ptr(), + if verkey.is_some() { verkey_str.as_ptr() } else { null() }, + if xref.is_some() { xref_str.as_ptr() } else { null() }, + if data.is_some() { data_str.as_ptr() } else { null() }, + if role.is_some() { role_str.as_ptr() } else { null() }, + cb); + + if err != ErrorCode::Success { + return Err(err); + } + + let (err, request_json) = receiver.recv_timeout(TimeoutUtils::long_timeout()).unwrap(); + + if err != ErrorCode::Success { + return Err(err); + } + + Ok(request_json) + } + + pub fn build_attrib_request(submitter_did: &str, target_did: &str, hash: Option<&str>, raw: Option<&str>, enc: Option<&str>) -> Result { + let (sender, receiver) = channel(); + + let cb = Box::new(move |err, request_json| { + sender.send((err, request_json)).unwrap(); + }); + + let (command_handle, cb) = CallbackUtils::closure_to_build_request_cb(cb); + + let submitter_did = CString::new(submitter_did).unwrap(); + let target_did = CString::new(target_did).unwrap(); + + let hash_str = hash.map(|s| CString::new(s).unwrap()).unwrap_or(CString::new("").unwrap()); + let raw_str = raw.map(|s| CString::new(s).unwrap()).unwrap_or(CString::new("").unwrap()); + let enc_str = enc.map(|s| CString::new(s).unwrap()).unwrap_or(CString::new("").unwrap()); + + + let err = + sovrin_build_attrib_request(command_handle, + submitter_did.as_ptr(), + target_did.as_ptr(), + if hash.is_some() { hash_str.as_ptr() } else { null() }, + if raw.is_some() { raw_str.as_ptr() } else { null() }, + if enc.is_some() { enc_str.as_ptr() } else { null() }, + cb); + + if err != ErrorCode::Success { + return Err(err); + } + + let (err, request_json) = receiver.recv_timeout(TimeoutUtils::long_timeout()).unwrap(); + + if err != ErrorCode::Success { + return Err(err); + } + + Ok(request_json) + } + + pub fn build_get_attrib_request(submitter_did: &str, target_did: &str, data: &str) -> Result { + let (sender, receiver) = channel(); + + let cb = Box::new(move |err, request_json| { + sender.send((err, request_json)).unwrap(); + }); + + let (command_handle, cb) = CallbackUtils::closure_to_build_request_cb(cb); + + let submitter_did = CString::new(submitter_did).unwrap(); + let target_did = CString::new(target_did).unwrap(); + let data = CString::new(data).unwrap(); + + let err = + sovrin_build_get_attrib_request(command_handle, + submitter_did.as_ptr(), + target_did.as_ptr(), + data.as_ptr(), + cb); + + if err != ErrorCode::Success { + return Err(err); + } + + let (err, request_json) = receiver.recv_timeout(TimeoutUtils::long_timeout()).unwrap(); + + if err != ErrorCode::Success { + return Err(err); + } + + Ok(request_json) + } + + pub fn build_get_nym_request(submitter_did: &str, target_did: &str) -> Result { + let (sender, receiver) = channel(); + + let cb = Box::new(move |err, request_json| { + sender.send((err, request_json)).unwrap(); + }); + + let (command_handle, cb) = CallbackUtils::closure_to_build_request_cb(cb); + + let submitter_did = CString::new(submitter_did).unwrap(); + let target_did = CString::new(target_did).unwrap(); + + let err = + sovrin_build_get_nym_request(command_handle, + submitter_did.as_ptr(), + target_did.as_ptr(), + cb); + + if err != ErrorCode::Success { + return Err(err); + } + + let (err, request_json) = receiver.recv_timeout(TimeoutUtils::long_timeout()).unwrap(); + + if err != ErrorCode::Success { + return Err(err); + } + + Ok(request_json) + } + + pub fn build_schema_request(submitter_did: &str, data: &str) -> Result { + let (sender, receiver) = channel(); + + let cb = Box::new(move |err, request_json| { + sender.send((err, request_json)).unwrap(); + }); + + let (command_handle, cb) = CallbackUtils::closure_to_build_request_cb(cb); + + let submitter_did = CString::new(submitter_did).unwrap(); + let data = CString::new(data).unwrap(); + + let err = + sovrin_build_schema_request(command_handle, + submitter_did.as_ptr(), + data.as_ptr(), + cb); + + if err != ErrorCode::Success { + return Err(err); + } + + let (err, request_json) = receiver.recv_timeout(TimeoutUtils::long_timeout()).unwrap(); + + if err != ErrorCode::Success { + return Err(err); + } + + Ok(request_json) + } + + pub fn build_get_schema_request(submitter_did: &str, dest: &str, data: &str) -> Result { + let (sender, receiver) = channel(); + + let cb = Box::new(move |err, request_json| { + sender.send((err, request_json)).unwrap(); + }); + + let (command_handle, cb) = CallbackUtils::closure_to_build_request_cb(cb); + + let submitter_did = CString::new(submitter_did).unwrap(); + let dest = CString::new(dest).unwrap(); + let data = CString::new(data).unwrap(); + + let err = + sovrin_build_get_schema_request(command_handle, + submitter_did.as_ptr(), + dest.as_ptr(), + data.as_ptr(), + cb); + + if err != ErrorCode::Success { + return Err(err); + } + + let (err, request_json) = receiver.recv_timeout(TimeoutUtils::long_timeout()).unwrap(); + + if err != ErrorCode::Success { + return Err(err); + } + + Ok(request_json) + } + + pub fn build_claim_def_txn(submitter_did: &str, xref: i32, signature_type: &str, data: &str) -> Result { + let (sender, receiver) = channel(); + + let cb = Box::new(move |err, request_json| { + sender.send((err, request_json)).unwrap(); + }); + + let (command_handle, cb) = CallbackUtils::closure_to_build_request_cb(cb); + + let submitter_did = CString::new(submitter_did).unwrap(); + let signature_type = CString::new(signature_type).unwrap(); + let data = CString::new(data).unwrap(); + + let err = + sovrin_build_claim_def_txn(command_handle, + submitter_did.as_ptr(), + xref, + signature_type.as_ptr(), + data.as_ptr(), + cb); + + if err != ErrorCode::Success { + return Err(err); + } + + let (err, request_json) = receiver.recv_timeout(TimeoutUtils::long_timeout()).unwrap(); + + if err != ErrorCode::Success { + return Err(err); + } + + Ok(request_json) + } + + pub fn build_get_claim_def_txn(submitter_did: &str, xref: i32, signature_type: &str, origin: &str) -> Result { + let (sender, receiver) = channel(); + + let cb = Box::new(move |err, request_json| { + sender.send((err, request_json)).unwrap(); + }); + + let (command_handle, cb) = CallbackUtils::closure_to_build_request_cb(cb); + + let submitter_did = CString::new(submitter_did).unwrap(); + let signature_type = CString::new(signature_type).unwrap(); + let origin = CString::new(origin).unwrap(); + + let err = + sovrin_build_get_claim_def_txn(command_handle, + submitter_did.as_ptr(), + xref, + signature_type.as_ptr(), + origin.as_ptr(), + cb); + + if err != ErrorCode::Success { + return Err(err); + } + + let (err, request_json) = receiver.recv_timeout(TimeoutUtils::long_timeout()).unwrap(); + + if err != ErrorCode::Success { + return Err(err); + } + + Ok(request_json) + } + + pub fn build_node_request(submitter_did: &str, target_did: &str, data: &str) -> Result { + let (sender, receiver) = channel(); + + let cb = Box::new(move |err, request_json| { + sender.send((err, request_json)).unwrap(); + }); + + let (command_handle, cb) = CallbackUtils::closure_to_build_request_cb(cb); + + let submitter_did = CString::new(submitter_did).unwrap(); + let target_did = CString::new(target_did).unwrap(); + let data = CString::new(data).unwrap(); + + let err = + sovrin_build_node_request(command_handle, + submitter_did.as_ptr(), + target_did.as_ptr(), + data.as_ptr(), + cb); + + if err != ErrorCode::Success { + return Err(err); + } + + let (err, request_json) = receiver.recv_timeout(TimeoutUtils::long_timeout()).unwrap(); + + if err != ErrorCode::Success { + return Err(err); + } + + Ok(request_json) + } +} \ No newline at end of file diff --git a/tests/utils/mod.rs b/tests/utils/mod.rs index 47a35546d9..274b726af1 100644 --- a/tests/utils/mod.rs +++ b/tests/utils/mod.rs @@ -4,7 +4,9 @@ pub mod callback; pub mod environment; pub mod pool; +pub mod signus; pub mod wallet; +pub mod ledger; pub mod anoncreds; #[macro_use] diff --git a/tests/utils/pool.rs b/tests/utils/pool.rs index ada8bcbdd5..fb4e8f58d1 100644 --- a/tests/utils/pool.rs +++ b/tests/utils/pool.rs @@ -84,6 +84,62 @@ impl PoolUtils { Ok(pool_handle) } + pub fn create_and_open_pool_ledger_config(pool_name: &str) -> Result { + let (sender, receiver) = channel(); + + let cb = Box::new(move |err| { + sender.send(err).unwrap(); + }); + + let (command_handle, cb) = CallbackUtils::closure_to_create_pool_ledger_cb(cb); + + PoolUtils::create_genesis_txn_file(pool_name); + let pool_config = CString::new(PoolUtils::create_pool_config(pool_name)).unwrap(); + let pool_name = CString::new(pool_name).unwrap(); + + let err = sovrin_create_pool_ledger_config(command_handle, + pool_name.as_ptr(), + pool_config.as_ptr(), + cb); + + if err != ErrorCode::Success { + return Err(err); + } + + let err = receiver.recv_timeout(TimeoutUtils::short_timeout()).unwrap(); + + if err != ErrorCode::Success { + return Err(err); + } + + let (open_sender, open_receiver) = channel(); + + let open_cb = Box::new(move |err, pool_handle| { + open_sender.send((err, pool_handle)).unwrap(); + }); + + let (open_command_handle, open_cb) = CallbackUtils::closure_to_open_pool_ledger_cb(open_cb); + + let pool_name = CString::new(pool_name).unwrap(); + + let err = sovrin_open_pool_ledger(open_command_handle, + pool_name.as_ptr(), + null(), + open_cb); + + if err != ErrorCode::Success { + return Err(err); + } + + let (err, pool_handle) = open_receiver.recv_timeout(TimeoutUtils::short_timeout()).unwrap(); + + if err != ErrorCode::Success { + return Err(err); + } + + Ok(pool_handle) + } + pub fn send_request(pool_handle: i32, request: &str) -> Result { let (sender, receiver) = channel(); let cb_send = Box::new(move |err, resp| { @@ -101,7 +157,7 @@ impl PoolUtils { return Err(err); } - let (err, resp) = receiver.recv_timeout(TimeoutUtils::short_timeout()).unwrap(); + let (err, resp) = receiver.recv_timeout(TimeoutUtils::medium_timeout()).unwrap(); if err != ErrorCode::Success { return Err(err); diff --git a/tests/utils/signus.rs b/tests/utils/signus.rs new file mode 100644 index 0000000000..401304e9d4 --- /dev/null +++ b/tests/utils/signus.rs @@ -0,0 +1,111 @@ +extern crate time; + +use sovrin::api::ErrorCode; +use sovrin::api::signus::{ + sovrin_sign, + sovrin_create_and_store_my_did, + sovrin_store_their_did +}; + +use utils::callback::CallbackUtils; +use utils::timeout::TimeoutUtils; + +use std::ffi::CString; +use std::sync::mpsc::channel; + +pub struct SignusUtils {} + +impl SignusUtils { + pub fn sign(wallet_handle: i32, their_did: &str, msg: &str) -> Result { + let (sender, receiver) = channel(); + + let cb = Box::new(move |err, signature| { + sender.send((err, signature)).unwrap(); + }); + + let (command_handle, cb) = CallbackUtils::closure_to_sign_cb(cb); + + let their_did = CString::new(their_did).unwrap(); + let msg = CString::new(msg).unwrap(); + + let err = + sovrin_sign(command_handle, + wallet_handle, + their_did.as_ptr(), + msg.as_ptr(), + cb); + + if err != ErrorCode::Success { + return Err(err); + } + + let (err, signature) = receiver.recv_timeout(TimeoutUtils::long_timeout()).unwrap(); + + if err != ErrorCode::Success { + return Err(err); + } + + Ok(signature) + } + + pub fn create_my_did(wallet_handle: i32, my_did_json: &str) -> Result<(String, String, String), ErrorCode> { + let (sender, receiver) = channel(); + + let cb = Box::new(move |err, did, verkey, public_key| { + sender.send((err, did, verkey, public_key)).unwrap(); + }); + + let (command_handle, cb) = CallbackUtils::closure_to_create_and_store_my_did_cb(cb); + + let my_did_json = CString::new(my_did_json).unwrap(); + + let err = + sovrin_create_and_store_my_did(command_handle, + wallet_handle, + my_did_json.as_ptr(), + cb); + + if err != ErrorCode::Success { + return Err(err); + } + + let (err, my_did, my_verkey, my_pk) = receiver.recv_timeout(TimeoutUtils::long_timeout()).unwrap(); + + if err != ErrorCode::Success { + return Err(err); + } + + Ok((my_did, my_verkey, my_pk)) + } + + pub fn store_their_did(wallet_handle: i32, identity_json: &str) -> Result<(), ErrorCode> { + let (sender, receiver) = channel(); + + let cb = Box::new(move |err| { + sender.send((err)).unwrap(); + }); + + let (command_handle, cb) = CallbackUtils::closure_to_store_their_did_cb(cb); + + let identity_json = CString::new(identity_json).unwrap(); + + + let err = + sovrin_store_their_did(command_handle, + wallet_handle, + identity_json.as_ptr(), + cb); + + if err != ErrorCode::Success { + return Err(err); + } + + let err = receiver.recv_timeout(TimeoutUtils::long_timeout()).unwrap(); + + if err != ErrorCode::Success { + return Err(err); + } + + Ok(()) + } +} \ No newline at end of file diff --git a/tests/utils/wallet.rs b/tests/utils/wallet.rs index 75ba3a9877..50e299c3d7 100644 --- a/tests/utils/wallet.rs +++ b/tests/utils/wallet.rs @@ -15,7 +15,7 @@ use std::sync::mpsc::channel; pub struct WalletUtils {} impl WalletUtils { - pub fn create_wallet(pool_name: &str, wallet_name: &str, xtype: &str) -> Result { + pub fn create_and_open_wallet(pool_name: &str, wallet_name: &str, xtype: &str) -> Result { let (sender, receiver) = channel(); let (open_sender, open_receiver) = channel();