diff --git a/doc/libsovrin-agent-2-agent.puml b/doc/libsovrin-agent-2-agent.puml new file mode 100644 index 0000000..5e0fb97 --- /dev/null +++ b/doc/libsovrin-agent-2-agent.puml @@ -0,0 +1,93 @@ +@startuml +skinparam ParticipantPadding 20 +skinparam BoxPadding 20 + +title Libsovrin Agent to Agent communucation API +scale 0.9 + +box "Sender Agent" #LightBlue +actor "Sender Agent" as SA +participant "Sender Libsovrin" as SL +participant "Sender Wallet" as SW +participant "Sender Socket" as SS +endbox + +box "Receiver Agent" #LightBlue +actor "Receiver Agent" as RA +participant "Receiver Libsovrin" as RL +participant "Receiver Wallet" as RW +participant "Receiver Socket" as RS +endbox + +participant "Ledger" as L + +=== Start listening == + +RA -> RL: 1. sovrin_create_and_store_my_did +RL -> RW: Store receiver keys + +RA -> RL: 2. sovrin_agent_listen +RL -> RS: Start listening +RL -> RA: Listener handle (cb) + +=== Establish connection == + +SA -> SL: 3. sovrin_create_and_store_my_did +SL -> SW: Store sender keys + +SA -> SL: 4. sovrin_agent_connect +SL -> SW: Get sender keys +SW -> SL: Sender keys +SL -> L: GET_NYM/GET_DDO +L -> SL: Receiver keys and endpoint +SL -> SW: Store receiver keys and endpoint + +SL -> SS: Receiver did, keys and endpoint. Sender did, keys + +SS -> RS: PairwiseCurveCP Hello message +RS -> RL: Keys lookup request +RL -> RW: Get keys and did for request +RW -> RL: Receiver keys and did +RL -> RS: Receiver keys +RS -> SS: PairwiseCurveCP Welcome message + +SS -> RS: Next PairwiseCurveCP handshake messages +RS -> SS: PairwiseCurveCP handshake messages answers + +SS -> SL: PairwiseCurveCP connection established + +SL -> SS: DID message +SS -> RS: DID message +RS -> RL: Sender did and public key +RL -> L: GET_NYM/GET_DDO +L -> RL: Sender keys and did (from Ledger) +RL -> RL: Connection verification +RL -> RS: DID message answer +RS -> SS: DID message answer +SS -> SL: DID message answer +SL -> SA: Connection handle (cb) +RL -> RA: Connection handle (cb) + +=== Exchange messages == + +SA -> SL: 4. sovrin_agent_send +SL -> SS: Message +SS -> RS: Message +RS -> RL: Message +RL -> RA: Message (cb) + +RA -> RL: 5. sovrin_agent_send +RL -> RS: Message +RS -> SS: Message +SS -> SL: Message +SL -> SA: Message (cb) + +=== Clean up == + +SA -> SL: 5. sovrin_agent_close_connection +SL -> SS: Close socket + +RA -> RL: 5. sovrin_agent_close_listener +RL -> RS: Close socket + +@enduml diff --git a/include/sovrin_anoncreds.h b/include/sovrin_anoncreds.h index 69f3bef..f3674aa 100644 --- a/include/sovrin_anoncreds.h +++ b/include/sovrin_anoncreds.h @@ -138,7 +138,6 @@ extern "C" { extern sovrin_error_t sovrin_verifier_verify_proof(sovrin_handle_t command_handle, - sovrin_handle_t wallet_handle, const char * proof_request_json, const char * proof_json, const char * schemas_json, diff --git a/include/sovrin_mod.h b/include/sovrin_mod.h index 82cfe80..5702ec6 100644 --- a/include/sovrin_mod.h +++ b/include/sovrin_mod.h @@ -83,7 +83,10 @@ typedef enum // IO error during access pool ledger files PoolLedgerIOError, - + + // Pool ledger terminated + PoolLedgerTerminated, + // No concensus during ledger operation LedgerNoConsensusError, diff --git a/src/api/agent.rs b/src/api/agent.rs new file mode 100644 index 0000000..24162b3 --- /dev/null +++ b/src/api/agent.rs @@ -0,0 +1,179 @@ +extern crate libc; + +use api::ErrorCode; +use errors::ToErrorCode; +use commands::{Command, CommandExecutor}; +use utils::cstring::CStringUtils; + +use self::libc::c_char; + +/// Establishes agent to agent connection. +/// +/// Information about sender Identity must be saved in the wallet with sovrin_create_and_store_my_did +/// call before establishing of connection. +/// +/// Information about receiver Identity can be saved in the wallet with sovrin_store_their_did +/// call before establishing of connection. If there is no corresponded wallet record for receiver Identity +/// than this call will lookup Identity Ledger and cache this information in the wallet. +/// +/// Note that messages encryption/decryption will be performed automatically. +/// +/// #Params +/// command_handle: Command handle to map callback to caller context. +/// wallet_handle: Wallet handle (created by open_wallet). +/// sender_did: Id of sender Identity stored in secured Wallet. +/// receiver_did: Id of receiver Identity. +/// connection_cb: Callback that will be called after establishing of connection or on error. +/// message_cb: Callback that will be called on receiving of an incomming message. +/// +/// #Returns +/// Error code +/// connection_cb: +/// - xcommand_handle: command handle to map callback to caller context. +/// - err: Error code. +/// - connection_handle: Connection handle to use for messages sending and mapping of incomming messages to this connection. +/// message_cb: +/// - xconnection_handle: Connection handle. Indetnifies connection. +/// - err: Error code. +/// - message: Received message. +#[no_mangle] +pub extern fn sovrin_agent_connect(command_handle: i32, + wallet_handle: i32, + sender_did: *const c_char, + receiver_did: *const c_char, + connection_cb: Option, + message_cb: Option) -> ErrorCode { + unimplemented!() +} + +/// Starts listening of agent connections. +/// +/// On incomming connection listener performs wallet lookup to find corresponded receiver Identity +/// information. Information about receiver Identity must be saved in the wallet with +/// sovrin_create_and_store_my_did call before establishing of connection. +/// +/// Information about sender Identity for incomming connection validation can be saved in the wallet +/// with sovrin_store_their_did call before establishing of connection. If there is no corresponded +/// wallet record for sender Identity than listener will lookup Identity Ledger and cache this +/// information in the wallet. +/// +/// Note that messages encryption/decryption will be performed automatically. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// wallet_handle: wallet handle (created by open_wallet). +/// listener_cb: Callback that will be called after listening started or on error. +/// connection_cb: Callback that will be called after establishing of incomming connection. +/// message_cb: Callback that will be called on receiving of an incomming message. +/// +/// #Returns +/// Error code +/// listener_cb: +/// - xcommand_handle: command handle to map callback to caller context. +/// - err: Error code +/// - listener_handle: Listener handle to use for mapping of incomming connections to this listener. +/// connection_cb: +/// - xlistener_handle: Listener handle. Identifies listener. +/// - err: Error code +/// - connection_handle: Connection handle to use for messages sending and mapping of incomming messages to to this connection. +/// - sender_did: Id of sender Identity stored in secured Wallet. +/// - receiver_did: Id of receiver Identity. +/// message_cb: +/// - xconnection_handle: Connection handle. Indetnifies connection. +/// - err: Error code. +/// - message: Received message. +#[no_mangle] +pub extern fn sovrin_agent_listen(command_handle: i32, + wallet_handle: i32, + listener_cb: Option, + connection_cb: Option, + message_cb: Option) -> ErrorCode { + unimplemented!() +} + +/// Sends message to connected agent. +/// +/// Note that this call works for both incoming and outgoing connections. +/// Note that messages encryption/decryption will be performed automatically. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// connection_handle: Connection handle returned by sovrin_agent_connect or sovrin_agent_listen calls. +/// message: Message to send. +/// cb: Callback that will be called after message sent or on error. +/// +/// #Returns +/// err: Error code +/// cb: +/// - xcommand_handle: Command handle to map callback to caller context. +/// - err: Error code +/// +/// #Errors +#[no_mangle] +pub extern fn sovrin_agent_send(command_handle: i32, + connection_handle: i32, + message: *const c_char, + cb: Option) -> ErrorCode { + unimplemented!() +} + +/// Closes agent connection. +/// +/// Note that this call works for both incoming and outgoing connections. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// connection_handle: Connection handle returned by sovrin_agent_connect or sovrin_agent_listen calls. +/// cb: Callback that will be called after connection closed or on error. +/// +/// #Returns +/// Error code +/// cb: +/// - xcommand_handle: command handle to map callback to caller context. +/// - err: Error code +/// +/// #Errors +#[no_mangle] +pub extern fn sovrin_agent_close_connection(command_handle: i32, + connection_handle: i32, + cb: Option) -> ErrorCode { + unimplemented!() +} + +/// Closes listener and stops listening for agent connections. +/// +/// Note that all opened incomming connections will be closed automatically. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// listener_handle: Listener handle returned by sovrin_agent_listen call. +/// cb: Callback that will be called after listener closed or on error. +/// +/// #Returns +/// Error code +/// cb: +/// - xcommand_handle: command handle to map callback to caller context. +/// - err: Error code +/// +/// #Errors +#[no_mangle] +pub extern fn sovrin_agent_close_listener(command_handle: i32, + listener_handle: i32, + cb: Option) -> ErrorCode { + unimplemented!() +} \ No newline at end of file diff --git a/src/api/ledger.rs b/src/api/ledger.rs index 62a9802..d03a7d8 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); @@ -367,10 +367,10 @@ 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, + 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); @@ -405,20 +405,23 @@ 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: *const c_char, + 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 +439,7 @@ 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) /// cb: Callback that takes command result as parameter. /// /// #Returns @@ -445,18 +449,21 @@ 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: *const c_char, + signature_type: *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_callback!(cb, ErrorCode::CommonInvalidParam5); let result = CommandExecutor::instance() .send(Command::Ledger(LedgerCommand::BuildGetClaimDefRequest( submitter_did, xref, + signature_type, 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 +490,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/mod.rs b/src/api/mod.rs index 831f376..d73aa57 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1,5 +1,6 @@ extern crate libc; +pub mod agent; pub mod anoncreds; pub mod signus; pub mod ledger; @@ -92,6 +93,9 @@ pub enum ErrorCode { // IO error during access pool ledger files PoolLedgerIOError, + // Pool ledger terminated + PoolLedgerTerminated, + // No concensus during ledger operation LedgerNoConsensusError, diff --git a/src/commands/ledger.rs b/src/commands/ledger.rs index b586056..144eb24 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; @@ -29,7 +30,7 @@ pub enum LedgerCommand { Box) + Send>), SubmitAck( i32, // cmd_id - Result, // result json or error + Result, // result json or error ), BuildGetDdoRequest( String, // submitter did @@ -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 @@ -70,11 +71,13 @@ pub enum LedgerCommand { BuildClaimDefRequest( String, // submitter did String, // xref + String, // signature_type String, // data Box) + Send>), BuildGetClaimDefRequest( String, // submitter did String, // xref + String, // signature_type Box) + Send>), BuildNodeRequest( String, // submitter did @@ -88,6 +91,7 @@ pub struct LedgerCommandExecutor { pool_service: Rc, signus_service: Rc, wallet_service: Rc, + ledger_service: Rc, send_callbacks: RefCell)>>>, } @@ -96,12 +100,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()), } } @@ -120,7 +126,7 @@ impl LedgerCommandExecutor { info!(target: "ledger_command_executor", "SubmitAck command received"); self.send_callbacks.borrow_mut().remove(&handle) .expect("Expect callback to process ack command") - (result); + (result.map_err(SovrinError::from)); } LedgerCommand::BuildGetDdoRequest(submitter_did, target_did, cb) => { info!(target: "ledger_command_executor", "BuildGetDdoRequest command received"); @@ -128,11 +134,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"); @@ -150,13 +165,13 @@ impl LedgerCommandExecutor { info!(target: "ledger_command_executor", "BuildGetSchemaRequest command received"); self.build_get_schema_request(&submitter_did, &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, 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, cb); } LedgerCommand::BuildNodeRequest(submitter_did, target_did, data, cb) => { info!(target: "ledger_command_executor", "BuildNodeRequest command received"); @@ -171,17 +186,8 @@ impl LedgerCommandExecutor { submitter_did: &str, request_json: &str, cb: Box) + Send>) { - { - // FIXME REMOVE - // FIXME just remove with block after errors refactoring - let cb = |se: Result<(), SovrinError>| { - cb(Err(se.err().unwrap())) - }; - //FIXME REMOVE code above and extract next line from the block - check_wallet_and_pool_handles_consistency!(self.wallet_service, self.pool_service, - wallet_handle, pool_handle, cb - ); - } + check_wallet_and_pool_handles_consistency!(self.wallet_service, self.pool_service, + wallet_handle, pool_handle, cb); match self._sign_request(wallet_handle, submitter_did, request_json) { Ok(signed_request) => self.submit_request(pool_handle, signed_request.as_str(), cb), Err(err) => cb(Err(err)) @@ -216,28 +222,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 +263,61 @@ 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, data: &str, cb: Box) + Send>) { - cb(Ok("".to_string())); + cb(self.ledger_service.build_get_schema_request(submitter_did, + 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: &str, + 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: &str, + signature_type: &str, + cb: Box) + Send>) { + cb(self.ledger_service.build_get_claim_def_request(submitter_did, + xref, + signature_type + ).map_err(|err| SovrinError::CommonError(err))) } fn build_node_key_request(&self, @@ -289,6 +325,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 e64c1e3..e7dc187 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/pool.rs b/src/commands/pool.rs index 5c54a55..939c921 100644 --- a/src/commands/pool.rs +++ b/src/commands/pool.rs @@ -18,15 +18,15 @@ pub enum PoolCommand { Option, // config Box) + Send>), OpenAck(i32, // cmd id - Result), + Result), Close(i32, // pool handle Box) + Send>), CloseAck(i32, - Result<(), SovrinError>), + Result<(), PoolError>), Refresh(i32, // pool handle Box) + Send>), RefreshAck(i32, - Result<(), SovrinError>), + Result<(), PoolError>), } pub struct PoolCommandExecutor { @@ -58,6 +58,7 @@ impl PoolCommandExecutor { } PoolCommand::OpenAck(handle, result) => { info!("OpenAck handle {:?}, result {:?}", handle, result); + let result = result.map_err(SovrinError::from); match self.open_callbacks.try_borrow_mut() { Ok(mut cbs) => { match cbs.remove(&handle) { diff --git a/src/errors/ledger.rs b/src/errors/ledger.rs index 3304bf9..397d154 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/errors/pool.rs b/src/errors/pool.rs index 393fd03..b96e878 100644 --- a/src/errors/pool.rs +++ b/src/errors/pool.rs @@ -1,11 +1,9 @@ extern crate zmq; extern crate serde_json; -use std::error; -use std::io; -use std::fmt; -use std::error::Error; use std::cell::{BorrowError, BorrowMutError}; +use std::{error, fmt, io}; +use std::error::Error; use api::ErrorCode; use errors::ToErrorCode; @@ -17,7 +15,8 @@ pub enum PoolError { InvalidData(String), InvalidConfiguration(String), InvalidHandle(String), - Io(io::Error) + Io(io::Error), + Terminate, } impl fmt::Display for PoolError { @@ -28,7 +27,8 @@ impl fmt::Display for PoolError { PoolError::InvalidHandle(ref description) => write!(f, "Invalid Handle: {}", description), PoolError::InvalidConfiguration(ref description) => write!(f, "Invalid configuration: {}", description), PoolError::InvalidData(ref description) => write!(f, "Invalid data: {}", description), - PoolError::Io(ref err) => err.fmt(f) + PoolError::Io(ref err) => err.fmt(f), + PoolError::Terminate => write!(f, "Pool work terminated"), } } } @@ -41,22 +41,34 @@ impl error::Error for PoolError { PoolError::InvalidHandle(ref description) | PoolError::InvalidData(ref description) | PoolError::InvalidConfiguration(ref description) => description, - PoolError::Io(ref err) => err.description() + PoolError::Io(ref err) => err.description(), + PoolError::Terminate => "Pool work terminated", } } fn cause(&self) -> Option<&error::Error> { match *self { - PoolError::NotCreated(ref description) | - PoolError::InvalidState(ref description) | - PoolError::InvalidHandle(ref description) | - PoolError::InvalidData(ref description) | - PoolError::InvalidConfiguration(ref description) => None, + PoolError::NotCreated(_) | + PoolError::InvalidState(_) | + PoolError::InvalidHandle(_) | + PoolError::InvalidData(_) | + PoolError::InvalidConfiguration(_) | + PoolError::Terminate => None, PoolError::Io(ref err) => Some(err) } } } +impl PoolError { + pub fn from_displayable_as_invalid_config(err: D) -> PoolError where D: fmt::Display { + PoolError::InvalidConfiguration(format!("{}", err)) + } + + pub fn from_displayable_as_invalid_data(err: D) -> PoolError where D: fmt::Display { + PoolError::InvalidData(format!("{}", err)) + } +} + impl From for PoolError { fn from(err: io::Error) -> PoolError { PoolError::Io(err) @@ -69,12 +81,6 @@ impl From for PoolError { } } -impl From for PoolError { - fn from(err: serde_json::Error) -> PoolError { - PoolError::InvalidConfiguration(err.description().to_string()) - } -} - impl From for PoolError { fn from(err: BorrowError) -> Self { PoolError::InvalidState(err.description().to_string()) @@ -95,7 +101,8 @@ impl ToErrorCode for PoolError { PoolError::InvalidConfiguration(ref description) => ErrorCode::PoolLedgerInvalidConfiguration, PoolError::InvalidHandle(ref description) => ErrorCode::PoolLedgerInvalidPoolHandle, PoolError::InvalidData(ref description) => ErrorCode::PoolLedgerInvalidDataFormat, - PoolError::Io(ref err) => ErrorCode::PoolLedgerIOError + PoolError::Io(ref err) => ErrorCode::PoolLedgerIOError, + PoolError::Terminate => ErrorCode::PoolLedgerTerminated, } } } diff --git a/src/services/anoncreds/issuer.rs b/src/services/anoncreds/issuer.rs index bbfce9e..b96d032 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.attr_names.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.attr_names { 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.attr_names = HashSet::new(); let signature_type = None; let create_non_revoc = false; @@ -582,7 +582,7 @@ pub mod mocks { Schema { name: "gvt".to_string(), version: "1.0".to_string(), - attribute_names: attr_names, + attr_names: attr_names, seq_no: 1 } } @@ -595,7 +595,7 @@ pub mod mocks { Schema { name: "xyz".to_string(), version: "1.0".to_string(), - attribute_names: attr_names, + attr_names: attr_names, seq_no: 2 } } diff --git a/src/services/anoncreds/prover.rs b/src/services/anoncreds/prover.rs index c1c75e5..9f0d89c 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.attr_names .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 035518a..bc86587 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 attr_names: 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, attr_names: HashSet, seq_no: i32) -> Schema { Schema { name: name, version: version, - attribute_names: attributes_names, + attr_names: attr_names, seq_no: seq_no } } diff --git a/src/services/anoncreds/verifier.rs b/src/services/anoncreds/verifier.rs index 6be349b..c20e69b 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.attr_names .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 0000000..d436d1a --- /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 7b19da3..cf620b6 100644 --- a/src/services/ledger/mod.rs +++ b/src/services/ledger/mod.rs @@ -1 +1,400 @@ -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(); + let data = SchemaOperationData::from_json(&data) + .map_err(|err| CommonError::InvalidStructure(format!("Invalid data json: {}", err.to_string())))?; + let operation = SchemaOperation::new(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 schema request json: {}", err.to_string())))?; + Ok(request_json) + } + + pub fn build_get_schema_request(&self, identifier: &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(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: &str, signature_type: &str, data: &str) -> Result { + let req_id = LedgerService::get_req_id(); + let data = ClaimDefOperationData::from_json(&data) + .map_err(|err| CommonError::InvalidStructure(format!("Invalid data json: {}", err.to_string())))?; + let operation = ClaimDefOperation::new(_ref.to_string(), signature_type.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 claim_def request json: {}", err.to_string())))?; + Ok(request_json) + } + + pub fn build_get_claim_def_request(&self, identifier: &str, _ref: &str, signature_type: &str) -> Result { + let req_id = LedgerService::get_req_id(); + let operation = GetClaimDefOperation::new(_ref.to_string(), + signature_type.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 = r#""identifier":"some_identifier","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, 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","data":{"name":"name","version":"1.0"}}"#; + + let get_schema_request = ledger_service.build_get_schema_request(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 = "some_ref"; + let signature_type = "signature_type"; + + let expected_result = r#""identifier":"some_identifier","operation":{"type":"108","ref":"some_ref","signature_type":"signature_type"}"#; + + let get_claim_def_request = ledger_service.build_get_claim_def_request(identifier, _ref, signature_type); + 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 0000000..f8f694d --- /dev/null +++ b/src/services/ledger/types.rs @@ -0,0 +1,397 @@ +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: SchemaOperationData +} + +impl SchemaOperation { + pub fn new(data: SchemaOperationData) -> 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 data: GetSchemaOperationData +} + +impl GetSchemaOperation { + pub fn new(data: GetSchemaOperationData) -> GetSchemaOperation { + GetSchemaOperation { + _type: GET_SCHEMA.to_string(), + 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: String, + pub data: ClaimDefOperationData, + #[serde(rename = "type")] + pub _type: String, + pub signature_type: String +} + +impl ClaimDefOperation { + pub fn new(_ref: String, signature_type: String, data: ClaimDefOperationData) -> 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: RevocationPublicKey, + pub signature_type: String +} + +impl ClaimDefOperationData { + pub fn new(primary: PublicKey, revocation: RevocationPublicKey, signature_type: String, ) -> ClaimDefOperationData { + ClaimDefOperationData { + primary: primary, + revocation: revocation, + signature_type: signature_type + } + } +} + +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: String, + pub signature_type: String//TODO In Python there is Origin field, {ORIGIN: id.schemaKey.issuerId}, but there is not in table. We can get it field form GET_SCHEMA response +} + +impl GetClaimDefOperation { + pub fn new(_ref: String, signature_type: String) -> GetClaimDefOperation { + GetClaimDefOperation { + _type: GET_CLAIM_DEF.to_string(), + _ref: _ref, + signature_type: signature_type + } + } +} + +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 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/catchup.rs b/src/services/pool/catchup.rs index e5f32cb..1d256e3 100644 --- a/src/services/pool/catchup.rs +++ b/src/services/pool/catchup.rs @@ -1,6 +1,8 @@ use std::cmp; use std::collections::{BinaryHeap}; +use commands::{Command, CommandExecutor}; +use commands::pool::PoolCommand; use errors::pool::PoolError; use super::{ MerkleTree, @@ -17,7 +19,25 @@ pub struct CatchupHandler { pub new_mt_size: usize, pub new_mt_vote: usize, pub nodes: Vec, + pub open_cmd_id: i32, pub pending_catchup: Option, + pub pool_id: i32, +} + +impl Default for CatchupHandler { + fn default() -> Self { + CatchupHandler { + f: 0, + ledger_status_same: 0, + merkle_tree: MerkleTree::from_vec(Vec::new()).unwrap(), + nodes: Vec::new(), + new_mt_size: 0, + new_mt_vote: 0, + pending_catchup: None, + open_cmd_id: 0, + pool_id: 0, + } + } } impl CatchupHandler { @@ -32,10 +52,13 @@ impl CatchupHandler { ledgerId: 0, }; let resp_msg: Message = Message::LedgerStatus(ls); - self.nodes[src_ind].send_msg(&resp_msg); + self.nodes[src_ind].send_msg(&resp_msg)?; } Message::LedgerStatus(ledger_status) => { - assert_eq!(ledger_status.merkleRoot, self.merkle_tree.root_hash().as_slice().to_base58()); + if self.merkle_tree.root_hash().as_slice().to_base58().ne(ledger_status.merkleRoot.as_str()) { + return Err(PoolError::InvalidState( + "Ledger merkle tree doesn't acceptable for current tree.".to_string())); + } self.ledger_status_same += 1; if self.ledger_status_same == self.f + 1 { return Ok(Some(self.merkle_tree.clone())); @@ -50,7 +73,7 @@ impl CatchupHandler { debug!("merkle tree expected size now {}", self.new_mt_size); } if self.new_mt_vote == self.f + 1 { - self.start_catchup(); + self.start_catchup()?; } } Message::CatchupRep(catchup) => { @@ -65,18 +88,31 @@ impl CatchupHandler { Ok(None) } - pub fn start_catchup(&mut self) { + pub fn start_catchup(&mut self) -> Result<(), PoolError> { trace!("start_catchup"); - assert!(self.pending_catchup.is_none()); + if self.pending_catchup.is_some() { + return Err(PoolError::InvalidState( + "CatchUp already started for the pool".to_string() + )); + } + let node_cnt = self.nodes.len(); + if self.merkle_tree.count() != node_cnt { + return Err(PoolError::InvalidState( + "Merkle tree doesn't equal nodes count".to_string() + )); + } + let cnt_to_catchup = self.new_mt_size - self.merkle_tree.count(); + if cnt_to_catchup <= 0 { + return Err(PoolError::InvalidState( + "Nothing to CatchUp, but started".to_string() + )); + } + self.pending_catchup = Some(CatchUpProcess { merkle_tree: self.merkle_tree.clone(), pending_reps: BinaryHeap::new(), }); - let node_cnt = self.nodes.len(); - assert!(self.merkle_tree.count() == node_cnt); - let cnt_to_catchup = self.new_mt_size - self.merkle_tree.count(); - assert!(cnt_to_catchup > 0); let portion = (cnt_to_catchup + node_cnt - 1) / node_cnt; //TODO check standard round up div let mut catchup_req = CatchupReq { ledgerId: 0, @@ -85,24 +121,27 @@ impl CatchupHandler { catchupTill: self.new_mt_size, }; for node in &self.nodes { - node.send_msg(&Message::CatchupReq(catchup_req.clone())); + node.send_msg(&Message::CatchupReq(catchup_req.clone()))?; catchup_req.seqNoStart += portion; catchup_req.seqNoEnd = cmp::min(catchup_req.seqNoStart + portion - 1, catchup_req.catchupTill); } + Ok(()) } pub fn process_catchup_rep(&mut self, catchup: CatchupRep) -> Result, PoolError> { trace!("append {:?}", catchup); let catchup_finished = { - let mut process = self.pending_catchup.as_mut().unwrap(); + let mut process = self.pending_catchup.as_mut() + .ok_or(PoolError::InvalidState("Process non-existing CatchUp".to_string()))?; process.pending_reps.push(catchup); while !process.pending_reps.is_empty() && process.pending_reps.peek().unwrap().min_tx() - 1 == process.merkle_tree.count() { let mut first_resp = process.pending_reps.pop().unwrap(); while !first_resp.txns.is_empty() { let key = first_resp.min_tx().to_string(); - let new_gen_tx = first_resp.txns.remove(&key).unwrap().to_json().unwrap(); + let new_gen_tx = first_resp.txns.remove(&key).unwrap().to_json() + .map_err(PoolError::from_displayable_as_invalid_data)?; trace!("append to tree {}", new_gen_tx); process.merkle_tree.append( new_gen_tx @@ -124,6 +163,14 @@ impl CatchupHandler { } pub fn finish_catchup(&mut self) -> Result { - Ok(self.pending_catchup.take().unwrap().merkle_tree) + Ok(self.pending_catchup.take(). + ok_or(PoolError::InvalidState("Try to finish non-existing CatchUp".to_string()))? + .merkle_tree) + } + + pub fn flush_requests(&mut self, status: Result<(), PoolError>) -> Result<(), PoolError> { + CommandExecutor::instance().send(Command::Pool( + PoolCommand::OpenAck(self.open_cmd_id, Ok(self.pool_id)))) + .map_err(|err| { PoolError::InvalidState("Can't send ACK cmd".to_string()) }) } } diff --git a/src/services/pool/mod.rs b/src/services/pool/mod.rs index c58770f..b3ae83c 100644 --- a/src/services/pool/mod.rs +++ b/src/services/pool/mod.rs @@ -3,10 +3,12 @@ mod catchup; extern crate byteorder; extern crate rust_base58; +extern crate serde_json; extern crate zmq; use self::byteorder::{ByteOrder, LittleEndian}; use self::rust_base58::FromBase58; +use self::serde_json::Value; use std::cell::RefCell; use std::collections::{HashMap}; use std::{fmt, fs, io, thread}; @@ -16,7 +18,6 @@ use std::error::Error; use commands::{Command, CommandExecutor}; use commands::ledger::LedgerCommand; -use commands::pool::PoolCommand; use errors::pool::PoolError; use errors::crypto::CryptoError; use self::catchup::CatchupHandler; @@ -35,7 +36,7 @@ struct Pool { name: String, id: i32, cmd_sock: zmq::Socket, - worker: Option>>, + worker: Option>, } struct PoolWorker { @@ -47,6 +48,7 @@ struct PoolWorker { } enum PoolWorkerHandler { + //TODO trait ? CatchupHandler(CatchupHandler), TransactionHandler(TransactionHandler), } @@ -59,13 +61,32 @@ struct TransactionHandler { impl PoolWorkerHandler { fn process_msg(&mut self, raw_msg: &String, src_ind: usize) -> Result, PoolError> { - let msg = Message::from_raw_str(raw_msg).unwrap(); + let msg = Message::from_raw_str(raw_msg) + .map_err(PoolError::from_displayable_as_invalid_data)?; match self { &mut PoolWorkerHandler::CatchupHandler(ref mut ch) => ch.process_msg(msg, raw_msg, src_ind), &mut PoolWorkerHandler::TransactionHandler(ref mut ch) => ch.process_msg(msg, raw_msg, src_ind), } } + fn send_request(&mut self, cmd: &str, cmd_id: i32) -> Result<(), PoolError> { + match self { + &mut PoolWorkerHandler::CatchupHandler(ref mut ch) => { + Err(PoolError::InvalidState("Try send request while CatchUp.".to_string())) + } + &mut PoolWorkerHandler::TransactionHandler(ref mut ch) => { + ch.try_send_request(cmd, cmd_id) + } + } + } + + fn flush_requests(&mut self, status: Result<(), PoolError>) -> Result<(), PoolError> { + match self { + &mut PoolWorkerHandler::CatchupHandler(ref mut ch) => ch.flush_requests(status), + &mut PoolWorkerHandler::TransactionHandler(ref mut ch) => ch.flush_requests(status), + } + } + fn nodes(&self) -> &Vec { match self { &PoolWorkerHandler::CatchupHandler(ref ch) => &ch.nodes, @@ -119,45 +140,84 @@ impl TransactionHandler { } } - fn try_send_request(&mut self, cmd: &String, cmd_id: i32) { + fn try_send_request(&mut self, cmd: &str, cmd_id: i32) -> Result<(), PoolError> { info!("cmd {:?}", cmd); - let tmp = SimpleRequest::from_json(cmd).unwrap(); - if self.pending_commands.contains_key(&tmp.req_id) { - self.pending_commands.get_mut(&tmp.req_id).unwrap().cmd_ids.push(cmd_id); + let request: Value = serde_json::from_str(cmd) + .map_err(PoolError::from_displayable_as_invalid_data)?; + let request_id: u64 = request["reqId"] + .as_u64() + .ok_or(PoolError::InvalidData("Invalid request: missed requestId field".to_string()))?; + if self.pending_commands.contains_key(&request_id) { + self.pending_commands.get_mut(&request_id).unwrap().cmd_ids.push(cmd_id); } else { let pc = CommandProcess { cmd_ids: vec!(cmd_id), nack_cnt: 0, reply_cnt: 0, }; - self.pending_commands.insert(tmp.req_id, pc); + self.pending_commands.insert(request_id, pc); for node in &self.nodes { let node: &RemoteNode = node; - node.send_str(cmd); + node.send_str(cmd)?; + } + } + Ok(()) + } + + fn flush_requests(&mut self, status: Result<(), PoolError>) -> Result<(), PoolError> { + match status { + Ok(()) => { + return Err(PoolError::InvalidState( + "Can't flash all transaction requests with common success status".to_string())); + } + Err(err) => { + for (_, pending_cmd) in &self.pending_commands { + let pending_cmd: &CommandProcess = pending_cmd; + for cmd_id in &pending_cmd.cmd_ids { + CommandExecutor::instance() + .send(Command::Ledger(LedgerCommand::SubmitAck( + cmd_id.clone(), Err(PoolError::Terminate)))) + .map_err(|err| { + PoolError::InvalidState("Can't send ACK cmd".to_string()) + })?; + } + } + Ok(()) } } } } +impl Default for TransactionHandler { + fn default() -> Self { + TransactionHandler { + pending_commands: HashMap::new(), + f: 0, + nodes: Vec::new(), + } + } +} + impl PoolWorker { fn connect_to_known_nodes(&mut self, merkle_tree: Option<&MerkleTree>) -> Result<(), PoolError> { - let merkle_tree: MerkleTree = match merkle_tree { - Some(mt) => { - let mt: MerkleTree = mt.clone(); - mt - } - None => { + let merkle_tree: MerkleTree = merkle_tree.map(|x| { x.clone() }) + .or_else(|| { match self.handler { - PoolWorkerHandler::CatchupHandler(ref ch) => ch.merkle_tree.clone(), - PoolWorkerHandler::TransactionHandler(_) => return Err(PoolError::InvalidState("Expect catchup state".to_string())), + //TODO default self.handler.get_default_mt() -> Result + PoolWorkerHandler::CatchupHandler(ref ch) => Some(ch.merkle_tree.clone()), + PoolWorkerHandler::TransactionHandler(_) => None } - } - }; + }) + .ok_or(PoolError::InvalidState("Expect catchup state".to_string()))?; let ctx: zmq::Context = zmq::Context::new(); for gen_txn in &merkle_tree { - let mut rn: RemoteNode = RemoteNode::new(gen_txn.as_str()); - rn.connect(&ctx); - rn.zsock.as_ref().unwrap().send("pi".as_bytes(), 0).expect("send ping"); + let gen_txn: GenTransaction = GenTransaction::from_json(gen_txn) + .map_err(|e| { + PoolError::InvalidState(format!("MerkleTree contains invalid data {}", e)) + })?; + let mut rn: RemoteNode = RemoteNode::new(&gen_txn)?; + rn.connect(&ctx)?; + rn.send_str("pi")?; self.handler.nodes_mut().push(rn); } self.handler.set_f(PoolWorker::get_f(merkle_tree.count())); //TODO set cnt to connect @@ -166,13 +226,10 @@ impl PoolWorker { fn init_catchup(&mut self) -> Result<(), PoolError> { let catchup_handler = CatchupHandler { - f: 0, - ledger_status_same: 0, - nodes: Vec::new(), - new_mt_size: 0, - new_mt_vote: 0, merkle_tree: PoolWorker::_restore_merkle_tree(self.name.as_str())?, - pending_catchup: None, + open_cmd_id: self.open_cmd_id, + pool_id: self.pool_id, + ..Default::default() }; self.handler = PoolWorkerHandler::CatchupHandler(catchup_handler); self.connect_to_known_nodes(None)?; @@ -180,56 +237,66 @@ impl PoolWorker { } pub fn run(&mut self) -> Result<(), PoolError> { + self._run().or_else(|err: PoolError| { + self.handler.flush_requests(Err(PoolError::Terminate))?; + match err { + PoolError::Terminate => Ok(()), + _ => Err(err), + } + }) + } + + fn _run(&mut self) -> Result<(), PoolError> { self.init_catchup()?; //TODO consider error as PoolOpen error - 'zmq_poll_loop: loop { + loop { trace!("zmq poll loop >>"); - let actions = self.poll_zmq(); + let actions = self.poll_zmq()?; - for action in &actions { - match action { - &ZMQLoopAction::Terminate => { - //TODO terminate all pending commands? - break 'zmq_poll_loop; - } - &ZMQLoopAction::MessageToProcess(ref msg) => { - if let Some(new_mt) = self.handler.process_msg(&msg.message, msg.node_idx)? { - self.handler = PoolWorkerHandler::TransactionHandler(TransactionHandler { - nodes: Vec::new(), - pending_commands: HashMap::new(), - f: 0, - }); - self.connect_to_known_nodes(Some(&new_mt))?; - CommandExecutor::instance().send(Command::Pool( - PoolCommand::OpenAck(self.open_cmd_id, Ok(self.pool_id)))).expect("send ack cmd"); //TODO send only once? - } - } - &ZMQLoopAction::RequestToSend(ref req) => { - match self.handler { - PoolWorkerHandler::CatchupHandler(_) => panic!("incorrect state"), //FIXME - PoolWorkerHandler::TransactionHandler(ref mut handler) => handler.try_send_request(&req.request, req.id), - } + self.process_actions(actions)?; + + trace!("zmq poll loop <<"); + } + } + + fn process_actions(&mut self, actions: Vec) -> Result<(), PoolError> { + for action in &actions { + match action { + &ZMQLoopAction::Terminate => { + return Err(PoolError::Terminate); + } + &ZMQLoopAction::MessageToProcess(ref msg) => { + if let Some(new_mt) = self.handler.process_msg(&msg.message, msg.node_idx)? { + self.handler.flush_requests(Ok(()))?; + self.handler = PoolWorkerHandler::TransactionHandler(Default::default()); + self.connect_to_known_nodes(Some(&new_mt))?; } } + &ZMQLoopAction::RequestToSend(ref req) => { + self.handler.send_request(req.request.as_str(), req.id).or_else(|err| { + CommandExecutor::instance() + .send(Command::Ledger(LedgerCommand::SubmitAck(req.id, Err(err)))) + .map_err(|err| { + PoolError::InvalidState("Can't send ACK cmd".to_string()) + }) + })?; + } } - - trace!("zmq poll loop <<"); } - info!("zmq poll loop finished"); Ok(()) } - fn poll_zmq(&mut self) -> Vec { + fn poll_zmq(&mut self) -> Result, PoolError> { let mut actions: Vec = Vec::new(); - let mut poll_items = self.get_zmq_poll_items(); - let r = zmq::poll(poll_items.as_mut_slice(), -1).expect("poll"); + let mut poll_items = self.get_zmq_poll_items()?; + let r = zmq::poll(poll_items.as_mut_slice(), -1)?; trace!("zmq poll {:?}", r); for i in 0..self.handler.nodes().len() { if poll_items[1 + i].is_readable() { - if let Some(msg) = self.handler.nodes()[i].recv_msg().expect("recv msg") { + if let Some(msg) = self.handler.nodes()[i].recv_msg()? { actions.push(ZMQLoopAction::MessageToProcess(MessageToProcess { node_idx: i, message: msg, @@ -238,9 +305,10 @@ impl PoolWorker { } } if poll_items[0].is_readable() { - let cmd = self.cmd_sock.recv_multipart(zmq::DONTWAIT).unwrap(); + let cmd = self.cmd_sock.recv_multipart(zmq::DONTWAIT)?; trace!("cmd {:?}", cmd); - let cmd_s = String::from_utf8(cmd[0].clone()).expect("non-string command"); + let cmd_s = String::from_utf8(cmd[0].clone()) + .map_err(PoolError::from_displayable_as_invalid_data)?; if "exit".eq(cmd_s.as_str()) { actions.push(ZMQLoopAction::Terminate); } else { @@ -250,17 +318,19 @@ impl PoolWorker { })); } } - actions + Ok(actions) } - fn get_zmq_poll_items(&self) -> Vec { + fn get_zmq_poll_items(&self) -> Result, PoolError> { let mut poll_items: Vec = Vec::new(); poll_items.push(self.cmd_sock.as_poll_item(zmq::POLLIN)); for ref node in self.handler.nodes() { - let s: &zmq::Socket = node.zsock.as_ref().unwrap(); + let s: &zmq::Socket = node.zsock.as_ref() + .ok_or(PoolError::InvalidState( + "Try to poll from ZMQ socket for unconnected RemoteNode".to_string()))?; poll_items.push(s.as_poll_item(zmq::POLLIN)); } - poll_items + Ok(poll_items) } @@ -304,13 +374,9 @@ impl Pool { pool_id: pool_id, name: name.to_string(), handler: PoolWorkerHandler::CatchupHandler(CatchupHandler { - f: 0, - ledger_status_same: 0, - nodes: Vec::new(), - new_mt_size: 0, - new_mt_vote: 0, - merkle_tree: MerkleTree::from_vec(Vec::new())?, - pending_catchup: None, + open_cmd_id: cmd_id, + pool_id: pool_id, + ..Default::default() }), }; @@ -319,15 +385,17 @@ impl Pool { id: pool_id, cmd_sock: send_cmd_sock, worker: Some(thread::spawn(move || { - pool_worker.run() + pool_worker.run().unwrap_or_else(|err| { + error!("Pool worker thread finished with error {:?}", err); + }) })), }) } - pub fn send_tx(&self, cmd_id: i32, json: &str) { + pub fn send_tx(&self, cmd_id: i32, json: &str) -> Result<(), PoolError> { let mut buf = [0u8; 4]; LittleEndian::write_i32(&mut buf, cmd_id); - self.cmd_sock.send_multipart(&[json.as_bytes(), &buf], zmq::DONTWAIT).expect("send to cmd sock"); + Ok(self.cmd_sock.send_multipart(&[json.as_bytes(), &buf], zmq::DONTWAIT)?) } } @@ -338,7 +406,9 @@ impl Drop for Pool { self.cmd_sock.send("exit".as_bytes(), 0).expect("send exit command"); //TODO info!(target: target.as_str(), "Drop wait worker"); // Option worker type and this kludge is workaround for rust - self.worker.take().unwrap().join().unwrap().unwrap(); + if let Some(worker) = self.worker.take() { + worker.join().unwrap(); + } info!(target: target.as_str(), "Drop finished"); } } @@ -357,21 +427,32 @@ impl Debug for RemoteNode { } impl RemoteNode { - fn new(txn: &str) -> RemoteNode { - let gen_tx = GenTransaction::from_json(txn).expect("RemoteNode parsing"); - RemoteNode::from(gen_tx) - } - - fn connect(&mut self, ctx: &zmq::Context) { - let key_pair = zmq::CurveKeyPair::new().expect("create key pair"); - let s = ctx.socket(zmq::SocketType::DEALER).expect("socket for Node"); - s.set_identity(key_pair.public_key.as_bytes()).expect("set identity"); - s.set_curve_secretkey(key_pair.secret_key.as_str()).expect("set secret key"); - s.set_curve_publickey(key_pair.public_key.as_str()).expect("set public key"); - s.set_curve_serverkey(zmq::z85_encode(self.verify_key.as_slice()).unwrap().as_str()).expect("set verify key"); - s.set_linger(0).expect("set linger"); //TODO set correct timeout - s.connect(self.zaddr.as_str()).expect("connect to Node"); + fn new(txn: &GenTransaction) -> Result { + let public_key = txn.dest.as_str().from_base58() + .map_err(|e| { PoolError::InvalidData("Invalid field dest in genesis transaction".to_string()) })?; + Ok(RemoteNode { + verify_key: ED25519::pk_to_curve25519(&public_key), + public_key: public_key, + zaddr: format!("tcp://{}:{}", txn.data.client_ip, txn.data.client_port), + zsock: None, + name: txn.data.alias.clone(), + }) + } + + fn connect(&mut self, ctx: &zmq::Context) -> Result<(), PoolError> { + let key_pair = zmq::CurveKeyPair::new()?; + let s = ctx.socket(zmq::SocketType::DEALER)?; + s.set_identity(key_pair.public_key.as_bytes())?; + s.set_curve_secretkey(key_pair.secret_key.as_str())?; + s.set_curve_publickey(key_pair.public_key.as_str())?; + s.set_curve_serverkey( + zmq::z85_encode(self.verify_key.as_slice()) + .map_err(|err| { PoolError::InvalidData("Can't encode server key as z85".to_string()) })? + .as_str())?; + s.set_linger(0)?; //TODO set correct timeout + s.connect(self.zaddr.as_str())?; self.zsock = Some(s); + Ok(()) } fn recv_msg(&self) -> Result, PoolError> { @@ -380,37 +461,25 @@ impl RemoteNode { PoolError::Io(io::Error::from(io::ErrorKind::InvalidData)) } } - let msg: String = self.zsock.as_ref().unwrap().recv_string(zmq::DONTWAIT)??; + let msg: String = self.zsock.as_ref() + .ok_or(PoolError::InvalidState("Try to receive msg for unconnected RemoteNode".to_string()))? + .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 - _ => Ok(Some(msg)) - } + Ok(Some(msg)) } - fn send_str(&self, str: &str) { + fn send_str(&self, str: &str) -> Result<(), PoolError> { info!("Sending {:?}", str); - self.zsock.as_ref().unwrap() - .send_str(str, zmq::DONTWAIT) - .unwrap(); - } - - fn send_msg(&self, msg: &Message) { - self.send_str(msg.to_json().unwrap().as_str()); + self.zsock.as_ref() + .ok_or(PoolError::InvalidState("Try to send str for unconnected RemoteNode".to_string()))? + .send_str(str, zmq::DONTWAIT)?; + Ok(()) } -} -impl From for RemoteNode { - fn from(tx: GenTransaction) -> RemoteNode { - let public_key = tx.dest.as_str().from_base58().expect("dest field in GenTransaction isn't valid"); - RemoteNode { - verify_key: ED25519::pk_to_curve25519(&public_key), - public_key: public_key, - zaddr: format!("tcp://{}:{}", tx.data.client_ip, tx.data.client_port), - zsock: None, - name: tx.data.alias, - } + fn send_msg(&self, msg: &Message) -> Result<(), PoolError> { + self.send_str(msg.to_json().map_err(PoolError::from_displayable_as_invalid_data)?.as_str()) } } @@ -424,7 +493,8 @@ impl PoolService { pub fn create(&self, name: &str, config: Option<&str>) -> Result<(), PoolError> { let mut path = EnvironmentUtils::pool_path(name); let pool_config = match config { - Some(config) => PoolConfig::from_json(config)?, + Some(config) => PoolConfig::from_json(config) + .map_err(PoolError::from_displayable_as_invalid_config)?, None => PoolConfig::default_for_name(name) }; @@ -442,7 +512,8 @@ impl PoolService { path.push("config"); path.set_extension("json"); let mut f: fs::File = fs::File::create(path.as_path())?; - f.write(pool_config.to_json()?.as_bytes())?; + f.write(pool_config.to_json() + .map_err(PoolError::from_displayable_as_invalid_config)?.as_bytes())?; f.flush()?; // TODO probably create another one file pool.json with pool description, @@ -475,7 +546,7 @@ impl PoolService { let cmd_id: i32 = SequenceUtils::get_next_id(); self.pools.try_borrow()? .get(&handle).ok_or(PoolError::InvalidHandle("No pool with requested handle".to_string()))? - .send_tx(cmd_id, json); + .send_tx(cmd_id, json)?; Ok(cmd_id) } @@ -576,13 +647,13 @@ mod tests { recv_cmd_sock.bind(inproc_sock_name.as_str()).unwrap(); send_cmd_sock.connect(inproc_sock_name.as_str()).unwrap(); let pool = Pool { - worker: Some(thread::spawn(|| { Ok(()) })), + worker: None, name: name.to_string(), id: 0, cmd_sock: send_cmd_sock, }; let test_data = "str_instead_of_tx_json"; - pool.send_tx(0, test_data); + pool.send_tx(0, test_data).unwrap(); assert_eq!(recv_cmd_sock.recv_string(zmq::DONTWAIT).unwrap().unwrap(), test_data); } @@ -598,30 +669,6 @@ mod tests { } } - impl Default for CatchupHandler { - fn default() -> Self { - CatchupHandler { - f: 0, - ledger_status_same: 0, - merkle_tree: MerkleTree::from_vec(Vec::new()).unwrap(), - nodes: Vec::new(), - new_mt_size: 0, - new_mt_vote: 0, - pending_catchup: None, - } - } - } - - impl Default for TransactionHandler { - fn default() -> Self { - TransactionHandler { - pending_commands: HashMap::new(), - f: 0, - nodes: Vec::new(), - } - } - } - #[test] fn pool_worker_restore_merkle_tree_works_from_genesis_txns() { let txns_src = format!("{}\n{}\n{}\n{}\n", @@ -672,7 +719,7 @@ mod tests { send_cmd_sock.connect(pair_socket_addr).expect("connect"); let handle: thread::JoinHandle> = thread::spawn(move || { - pw.poll_zmq() + pw.poll_zmq().unwrap() }); send_cmd_sock.send_str("exit", zmq::DONTWAIT).expect("send"); let actions: Vec = handle.join().unwrap(); @@ -685,7 +732,7 @@ mod tests { fn pool_worker_get_zmq_poll_items_works() { let pw: PoolWorker = Default::default(); - let poll_items = pw.get_zmq_poll_items(); + let poll_items = pw.get_zmq_poll_items().unwrap(); assert_eq!(poll_items.len(), pw.handler.nodes().len() + 1 ); //TODO compare poll items @@ -729,12 +776,9 @@ mod tests { let req_id = 2; let cmd_id = 1; - let req = SimpleRequest { - req_id: req_id, - }; - let cmd = req.to_json().unwrap(); + let cmd = format!("{{\"reqId\": {}}}", req_id); - th.try_send_request(&cmd, cmd_id); + th.try_send_request(&cmd, cmd_id).unwrap(); assert_eq!(th.pending_commands.len(), 1); let pending_cmd = th.pending_commands.get(&req_id).unwrap(); @@ -751,12 +795,12 @@ mod tests { let mut ch: CatchupHandler = Default::default(); let (gt, handle) = nodes_emulator::start(); ch.merkle_tree.append(gt.to_json().unwrap()).unwrap(); - let mut rn: RemoteNode = RemoteNode::from(gt); - rn.connect(&zmq::Context::new()); + let mut rn: RemoteNode = RemoteNode::new(>).unwrap(); + rn.connect(&zmq::Context::new()).unwrap(); ch.nodes.push(rn); ch.new_mt_size = 2; - ch.start_catchup(); + ch.start_catchup().unwrap(); let emulator_msgs: Vec = handle.join().unwrap(); assert_eq!(1, emulator_msgs.len()); @@ -773,10 +817,10 @@ mod tests { #[test] fn remote_node_connect_works_and_can_ping_pong() { let (gt, handle) = nodes_emulator::start(); - let mut rn: RemoteNode = RemoteNode::from(gt); + let mut rn: RemoteNode = RemoteNode::new(>).unwrap(); let ctx = zmq::Context::new(); - rn.connect(&ctx); - rn.zsock.as_ref().expect("sock").send_str("pi", zmq::DONTWAIT).expect("send"); + rn.connect(&ctx).unwrap(); + rn.send_str("pi").expect("send"); rn.zsock.as_ref().expect("sock").poll(zmq::POLLIN, nodes_emulator::POLL_TIMEOUT).expect("poll"); assert_eq!("po", rn.zsock.as_ref().expect("sock").recv_string(zmq::DONTWAIT).expect("recv").expect("string").as_str()); handle.join().expect("join"); diff --git a/tests/demo.rs b/tests/demo.rs index c0a6035..5fffd69 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\"],\ + \"attr_names\":[\"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 0000000..cef8524 --- /dev/null +++ b/tests/ledger.rs @@ -0,0 +1,408 @@ +#![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::logger::LoggerUtils; +#[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; + + +#[test] +#[cfg(feature = "local_nodes_pool")] +fn sovrin_nym_requests_works() { + TestUtils::cleanup_storage(); + LoggerUtils::init(); + + let pool_name = "test_submit_tx"; + let my_wallet_name = "my_wallet"; + let their_wallet_name = "their_wallet"; + let wallet_type = "default"; + + let res = PoolUtils::create_pool_ledger_config(pool_name); + assert!(res.is_ok()); + let res = PoolUtils::open_pool_ledger(pool_name); + assert!(res.is_ok()); + let pool_handle = res.unwrap(); + + let res = WalletUtils::create_wallet(pool_name, my_wallet_name, wallet_type); + assert!(res.is_ok()); + let my_wallet_handle = res.unwrap(); + + let res = WalletUtils::create_wallet(pool_name, their_wallet_name, wallet_type); + assert!(res.is_ok()); + let their_wallet_handle = res.unwrap(); + + let my_did_json = "{}"; + let res = SignusUtils::create_my_did(my_wallet_handle, my_did_json); + assert!(res.is_ok()); + let (my_did, my_verkey, my_pk) = res.unwrap(); + + let their_did_json = "{\"seed\":\"000000000000000000000000Trustee1\"}"; + let res = SignusUtils::create_my_did(their_wallet_handle, their_did_json); + assert!(res.is_ok()); + let (their_did, their_verkey, their_pk) = res.unwrap(); + + let res = LedgerUtils::build_nym_request(&their_verkey.clone(), &my_verkey.clone(), None, None, None, None); + assert!(res.is_ok()); + let nym_request = res.unwrap(); + + let res = SignusUtils::sign(their_wallet_handle, &their_did, &nym_request); + assert!(res.is_ok()); + let nym_request = res.unwrap(); + + println!("{}", nym_request.clone()); + let res = PoolUtils::send_request(pool_handle, &nym_request); + assert!(res.is_ok()); + let nym_response = res.unwrap(); + + let res = LedgerUtils::build_get_nym_request(&my_verkey.clone(), &my_did.clone()); + assert!(res.is_ok()); + let get_nym_request = res.unwrap(); + + println!("{}", get_nym_request.clone()); + let res = PoolUtils::send_request(pool_handle, &get_nym_request); + assert!(res.is_ok()); + let nym_response = res.unwrap(); + + TestUtils::cleanup_storage(); +} + +#[test] +#[cfg(feature = "local_nodes_pool")] +#[ignore] +fn sovrin_attrib_requests_works() { + TestUtils::cleanup_storage(); + let pool_name = "test_submit_tx"; + let my_wallet_name = "my_wallet"; + let their_wallet_name = "their_wallet"; + let wallet_type = "default"; + + let res = PoolUtils::create_pool_ledger_config(pool_name); + assert!(res.is_ok()); + let res = PoolUtils::open_pool_ledger(pool_name); + assert!(res.is_ok()); + let pool_handle = res.unwrap(); + + let res = WalletUtils::create_wallet(pool_name, my_wallet_name, wallet_type); + assert!(res.is_ok()); + let my_wallet_handle = res.unwrap(); + + let res = WalletUtils::create_wallet(pool_name, their_wallet_name, wallet_type); + assert!(res.is_ok()); + let their_wallet_handle = res.unwrap(); + + let my_did_json = "{}"; + let res = SignusUtils::create_my_did(my_wallet_handle, my_did_json); + assert!(res.is_ok()); + let (my_did, my_verkey, my_pk) = res.unwrap(); + + let their_did_json = "{\"seed\":\"000000000000000000000000Trustee1\"}"; + let res = SignusUtils::create_my_did(their_wallet_handle, their_did_json); + assert!(res.is_ok()); + let (their_did, their_verkey, their_pk) = res.unwrap(); + + let res = LedgerUtils::build_nym_request(&their_verkey.clone(), &my_did.clone(), None, None, None, None); + assert!(res.is_ok()); + let nym_request = res.unwrap(); + + let res = SignusUtils::sign(their_wallet_handle, &their_did, &nym_request); + assert!(res.is_ok()); + let nym_request = res.unwrap(); + + println!("nym_request {}", nym_request.clone()); + let res = PoolUtils::send_request(pool_handle, &nym_request); + assert!(res.is_ok()); + let nym_response = res.unwrap(); + + let res = LedgerUtils::build_attrib_request(&their_verkey.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 = SignusUtils::sign(their_wallet_handle, &their_did, &attrib_request); + assert!(res.is_ok()); + let attrib_request = res.unwrap(); + + println!("attrib_request {}", attrib_request.clone()); + let res = PoolUtils::send_request(pool_handle, &attrib_request); + assert!(res.is_ok()); + let attrib_response = res.unwrap(); + + let res = LedgerUtils::build_get_attrib_request(&their_verkey.clone(), &my_did.clone(), "endpoint"); + assert!(res.is_ok()); + let get_attrib_request = res.unwrap(); + + println!("get_attrib_request {}", get_attrib_request.clone()); + let res = PoolUtils::send_request(pool_handle, &get_attrib_request); + assert!(res.is_ok()); + let get_attrib_response = res.unwrap(); + + TestUtils::cleanup_storage(); +} + +#[test] +#[cfg(feature = "local_nodes_pool")] +#[ignore] +fn sovrin_schema_requests_works() { + TestUtils::cleanup_storage(); + let pool_name = "test_submit_tx"; + let my_wallet_name = "my_wallet"; + let their_wallet_name = "their_wallet"; + let wallet_type = "default"; + + let res = PoolUtils::create_pool_ledger_config(pool_name); + assert!(res.is_ok()); + let res = PoolUtils::open_pool_ledger(pool_name); + assert!(res.is_ok()); + let pool_handle = res.unwrap(); + + let res = WalletUtils::create_wallet(pool_name, my_wallet_name, wallet_type); + assert!(res.is_ok()); + let my_wallet_handle = res.unwrap(); + + let res = WalletUtils::create_wallet(pool_name, their_wallet_name, wallet_type); + assert!(res.is_ok()); + let their_wallet_handle = res.unwrap(); + + let my_did_json = "{}"; + let res = SignusUtils::create_my_did(my_wallet_handle, my_did_json); + assert!(res.is_ok()); + let (my_did, my_verkey, my_pk) = res.unwrap(); + + let their_did_json = "{\"seed\":\"000000000000000000000000Trustee1\"}"; + let res = SignusUtils::create_my_did(their_wallet_handle, their_did_json); + assert!(res.is_ok()); + let (their_did, their_verkey, their_pk) = res.unwrap(); + + let res = LedgerUtils::build_nym_request(&their_verkey.clone(), &my_did.clone(), None, None, None, None); + assert!(res.is_ok()); + let nym_request = res.unwrap(); + + let res = SignusUtils::sign(their_wallet_handle, &their_did, &nym_request); + assert!(res.is_ok()); + let nym_request = res.unwrap(); + + println!("nym_request {}", nym_request.clone()); + let res = PoolUtils::send_request(pool_handle, &nym_request); + assert!(res.is_ok()); + let nym_response = res.unwrap(); + + let schema_data = "{\"name\":\"gvt\",\ + \"version\":\"1.0\",\ + \"keys\": [\"name\", \"male\"]}"; + let res = LedgerUtils::build_schema_request(&my_verkey.clone(), schema_data); + assert!(res.is_ok()); + let schema_request = res.unwrap(); + + let res = SignusUtils::sign(their_wallet_handle, &their_did, &schema_request); + assert!(res.is_ok()); + let schema_request = res.unwrap(); + + println!("schema_request {}", schema_request.clone()); + let res = PoolUtils::send_request(pool_handle, &schema_request); + assert!(res.is_ok()); + let schema_response = res.unwrap(); + + let get_schema_data = "{\"name\":\"gvt\",\"version\":\"1.0\"}"; + let res = LedgerUtils::build_get_schema_request(&my_verkey.clone(), get_schema_data); + assert!(res.is_ok()); + let get_schema_request = res.unwrap(); + + println!("get_schema_request {}", get_schema_request.clone()); + let res = PoolUtils::send_request(pool_handle, &get_schema_request); + assert!(res.is_ok()); + let get_schema_response = res.unwrap(); + + TestUtils::cleanup_storage(); +} + +#[test] +#[cfg(feature = "local_nodes_pool")] +#[ignore] +fn sovrin_node_request_works() { + TestUtils::cleanup_storage(); + let pool_name = "test_submit_tx"; + let my_wallet_name = "my_wallet"; + let their_wallet_name = "their_wallet"; + let wallet_type = "default"; + + let res = PoolUtils::create_pool_ledger_config(pool_name); + assert!(res.is_ok()); + let res = PoolUtils::open_pool_ledger(pool_name); + assert!(res.is_ok()); + let pool_handle = res.unwrap(); + + let res = WalletUtils::create_wallet(pool_name, my_wallet_name, wallet_type); + assert!(res.is_ok()); + let my_wallet_handle = res.unwrap(); + + let res = WalletUtils::create_wallet(pool_name, their_wallet_name, wallet_type); + assert!(res.is_ok()); + let their_wallet_handle = res.unwrap(); + + let my_did_json = "{\"seed\":\"000000000000000000000000Steward1\"}"; + let res = SignusUtils::create_my_did(my_wallet_handle, my_did_json); + assert!(res.is_ok()); + let (my_did, my_verkey, my_pk) = res.unwrap(); + + let their_did_json = "{\"seed\":\"000000000000000000000000Trustee1\"}"; + let res = SignusUtils::create_my_did(their_wallet_handle, their_did_json); + assert!(res.is_ok()); + let (their_did, their_verkey, their_pk) = res.unwrap(); + + let res = LedgerUtils::build_nym_request(&their_verkey.clone(), &my_did.clone(), None, None, None, None); + assert!(res.is_ok()); + let nym_request = res.unwrap(); + + let res = SignusUtils::sign(my_wallet_handle, &their_did, &nym_request); + assert!(res.is_ok()); + let nym_request = res.unwrap(); + + println!("nym_request {}", nym_request.clone()); + let res = PoolUtils::send_request(pool_handle, &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(&their_verkey.clone(), &my_did.clone(), node_data); + assert!(res.is_ok()); + let node_request = res.unwrap(); + + let res = SignusUtils::sign(my_wallet_handle, &their_did, &node_request); + assert!(res.is_ok()); + let node_request = res.unwrap(); + + println!("node_request {}", node_request.clone()); + let res = PoolUtils::send_request(pool_handle, &node_request); + assert!(res.is_ok()); + let node_response = res.unwrap(); + + TestUtils::cleanup_storage(); +} + +//#[test] +//#[cfg(feature = "local_nodes_pool")] +//#[ignore] +//fn sovrin_claim_def_requests_works() { +// TestUtils::cleanup_storage(); +// let pool_name = "test_submit_tx"; +// let my_wallet_name = "my_wallet"; +// let their_wallet_name = "their_wallet"; +// let wallet_type = "default"; +// +// let res = PoolUtils::create_pool_ledger_config(pool_name); +// assert!(res.is_ok()); +// let res = PoolUtils::open_pool_ledger(pool_name); +// assert!(res.is_ok()); +// let pool_handle = res.unwrap(); +// +// let res = WalletUtils::create_wallet(pool_name, my_wallet_name, wallet_type); +// assert!(res.is_ok()); +// let my_wallet_handle = res.unwrap(); +// +// let res = WalletUtils::create_wallet(pool_name, their_wallet_name, wallet_type); +// assert!(res.is_ok()); +// let their_wallet_handle = res.unwrap(); +// +// let my_did_json = "{}"; +// let res = SignusUtils::create_my_did(my_wallet_handle, my_did_json); +// assert!(res.is_ok()); +// let (my_did, my_verkey, my_pk) = res.unwrap(); +// +// let their_did_json = "{\"seed\":\"000000000000000000000000Trustee1\"}"; +// let res = SignusUtils::create_my_did(their_wallet_handle, their_did_json); +// assert!(res.is_ok()); +// let (their_did, their_verkey, their_pk) = res.unwrap(); +// +// let schema_data = "{\"name\":\"gvt\",\ +// \"version\":\"1.0\",\ +// \"keys\": [\"name\", \"male\"]}"; +// let res = LedgerUtils::build_schema_request(&my_verkey.clone(), schema_data); +// assert!(res.is_ok()); +// let schema_request = res.unwrap(); +// +// let res = SignusUtils::sign(my_wallet_handle, &their_did, &schema_request); +// assert!(res.is_ok()); +// let schema_request = res.unwrap(); +// +// println!("schema_request {}", schema_request.clone()); +// let res = PoolUtils::send_request(pool_handle, &schema_request); +// assert!(res.is_ok()); +// let schema_response = res.unwrap(); +// let schema_response: Reply = serde_json::from_str(&schema_response).unwrap(); +// let schema = schema_response.result.data; +// +// let schema: Schema = serde_json::from_str(&schema).unwrap(); +// +// let res = AnoncredsUtils::issuer_create_claim_definition(my_wallet_handle, &schema); +// assert!(res.is_ok()); +// let (claim_def_json, claim_def_uuid) = res.unwrap(); +// +// //TODO Claim_def_json cast and change json +// let signature_type = "CL".to_string(); +// let res = LedgerUtils::build_claim_def_txn(&my_verkey.clone(), schema.seq_no, signature_type, claim_def_json); +// assert!(res.is_ok()); +// let claim_def_request = res.unwrap(); +// +// let res = SignusUtils::sign(my_wallet_handle, &their_did, &claim_def_request); +// assert!(res.is_ok()); +// let claim_def_request = res.unwrap(); +// +// println!("claim_def_request {}", claim_def_request.clone()); +// let res = PoolUtils::send_request(pool_handle, &claim_def_request); +// assert!(res.is_ok()); +// let claim_def_response = res.unwrap(); +// +// TestUtils::cleanup_storage(); +//} + +#[derive(Deserialize, Eq, PartialEq, Debug)] +struct Reply { + op: String, + result: ReplyResult, +} + +#[derive(Deserialize, Eq, PartialEq, Debug)] +#[serde(rename_all = "camelCase")] +struct ReplyResult { + identifier: String, + req_id: u64, + data: Option +} + +#[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 +} \ No newline at end of file diff --git a/tests/pool.rs b/tests/pool.rs index 18d92a3..632594c 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 0ba070e..64c25e1 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\"],\ + \"attr_names\":[\"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\"],\ + \"attr_names\":[\"status\",\"period\"],\ \"seq_no\":{}\ }}", schema_seq_no) } diff --git a/tests/utils/callback.rs b/tests/utils/callback.rs index 741a817..ab1fdf5 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 0000000..3bc355f --- /dev/null +++ b/tests/utils/ledger.rs @@ -0,0 +1,429 @@ +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(pool_handle, + command_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 = verkey.map(|s| CString::new(s).unwrap()); + let xref = xref.map(|s| CString::new(s).unwrap()); + let data = data.map(|s| CString::new(s).unwrap()); + let role = role.map(|s| CString::new(s).unwrap()); + + let err = + sovrin_build_nym_request(command_handle, + submitter_did.as_ptr(), + target_did.as_ptr(), + if verkey.is_some() { verkey.unwrap().as_ptr() } else { null() }, + if xref.is_some() { xref.unwrap().as_ptr() } else { null() }, + if data.is_some() { data.unwrap().as_ptr() } else { null() }, + if role.is_some() { role.unwrap().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 = hash.map(|s| CString::new(s).unwrap()); + let raw = raw.map(|s| CString::new(s).unwrap()); + let enc = enc.map(|s| CString::new(s).unwrap()); + + + let err = + sovrin_build_attrib_request(command_handle, + submitter_did.as_ptr(), + target_did.as_ptr(), + if hash.is_some() { hash.unwrap().as_ptr() } else { null() }, + if raw.is_some() { raw.unwrap().as_ptr() } else { null() }, + if enc.is_some() { enc.unwrap().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, 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_get_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_claim_def_txn(submitter_did: &str, xref: &str, 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 xref = CString::new(xref).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.as_ptr(), + 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: &str, signature_type: &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 xref = CString::new(xref).unwrap(); + let signature_type = CString::new(signature_type).unwrap(); + + let err = + sovrin_build_get_claim_def_txn(command_handle, + submitter_did.as_ptr(), + xref.as_ptr(), + signature_type.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 47a3554..274b726 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/signus.rs b/tests/utils/signus.rs new file mode 100644 index 0000000..401304e --- /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/wrappers/ios/libsovrin-pod/libsovrin-demo.xcodeproj/project.pbxproj b/wrappers/ios/libsovrin-pod/libsovrin-demo.xcodeproj/project.pbxproj index 776edbd..909eae6 100644 --- a/wrappers/ios/libsovrin-pod/libsovrin-demo.xcodeproj/project.pbxproj +++ b/wrappers/ios/libsovrin-pod/libsovrin-demo.xcodeproj/project.pbxproj @@ -14,19 +14,18 @@ 3E2A7F951EC36186006194EC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3E2A7F941EC36186006194EC /* Assets.xcassets */; }; 3E2A7F981EC36187006194EC /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3E2A7F961EC36187006194EC /* LaunchScreen.storyboard */; }; 3E2A7FA31EC36187006194EC /* AnoncredsDemo.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3E2A7FA21EC36187006194EC /* AnoncredsDemo.mm */; }; + 3E2FFA3F1ED5C06E00536EAD /* Anoncreds.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E2FFA3E1ED5C06E00536EAD /* Anoncreds.m */; }; + 3E2FFA441ED5C37100536EAD /* WalletUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E2FFA431ED5C37100536EAD /* WalletUtils.m */; }; + 3E2FFA471ED5CC5E00536EAD /* AnoncredsUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E2FFA461ED5CC5E00536EAD /* AnoncredsUtils.m */; }; 3E9CDB9A1ECC841700B1980D /* SignusDemo.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3E9CDB991ECC841700B1980D /* SignusDemo.mm */; }; - 3ED5BE4C1EC4967C00881380 /* libsovrin.framework in Resources */ = {isa = PBXBuildFile; fileRef = 3EF020DC1EC45A9B00CF985C /* libsovrin.framework */; }; - 3ED5BE4F1EC4984900881380 /* libsovrin.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3EF020DC1EC45A9B00CF985C /* libsovrin.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 3ED5BE511EC4986100881380 /* libsovrin.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3EF020DC1EC45A9B00CF985C /* libsovrin.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 3EC6BCF51EDC0A4500A290DE /* libsovrin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3EC6BCF41EDC0A4500A290DE /* libsovrin.framework */; }; + 3EC6BCF61EDC0A5600A290DE /* libsovrin.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3EC6BCF41EDC0A4500A290DE /* libsovrin.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 3ED5BE521EC98D6600881380 /* TestUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 3EF020D71EC4593900CF985C /* TestUtils.m */; }; 3ED5BE541EC9D8F200881380 /* LedgerDemo.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3ED5BE531EC9D8F200881380 /* LedgerDemo.mm */; }; 3ED5BE571EC9DA9700881380 /* PoolUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 3ED5BE561EC9DA9700881380 /* PoolUtils.m */; }; 3EF020D81EC4593900CF985C /* TestUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 3EF020D71EC4593900CF985C /* TestUtils.m */; }; 3EF020DB1EC4595500CF985C /* Environment.m in Sources */ = {isa = PBXBuildFile; fileRef = 3EF020DA1EC4595500CF985C /* Environment.m */; }; - 3EF020DD1EC45A9B00CF985C /* libsovrin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3EF020DC1EC45A9B00CF985C /* libsovrin.framework */; }; - 3EF020DE1EC45AA300CF985C /* libsovrin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3EF020DC1EC45A9B00CF985C /* libsovrin.framework */; }; 4E342A88B72D9633DC35144B /* libPods-libsovrin-demo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 920EA9D52354D5FE353162A1 /* libPods-libsovrin-demo.a */; }; - C417EEF3998DF20C9FE62376 /* libPods-libsovrin-demo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 920EA9D52354D5FE353162A1 /* libPods-libsovrin-demo.a */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -46,7 +45,7 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 3ED5BE4F1EC4984900881380 /* libsovrin.framework in CopyFiles */, + 3EC6BCF61EDC0A5600A290DE /* libsovrin.framework in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -56,7 +55,6 @@ dstPath = ""; dstSubfolderSpec = 6; files = ( - 3ED5BE511EC4986100881380 /* libsovrin.framework in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -77,7 +75,13 @@ 3E2A7F9E1EC36187006194EC /* libsovrin-demoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "libsovrin-demoTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 3E2A7FA21EC36187006194EC /* AnoncredsDemo.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = AnoncredsDemo.mm; sourceTree = ""; }; 3E2A7FA41EC36187006194EC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 3E2FFA3E1ED5C06E00536EAD /* Anoncreds.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Anoncreds.m; sourceTree = ""; }; + 3E2FFA421ED5C37100536EAD /* WalletUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WalletUtils.h; sourceTree = ""; }; + 3E2FFA431ED5C37100536EAD /* WalletUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WalletUtils.m; sourceTree = ""; }; + 3E2FFA451ED5CC5E00536EAD /* AnoncredsUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AnoncredsUtils.h; sourceTree = ""; }; + 3E2FFA461ED5CC5E00536EAD /* AnoncredsUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AnoncredsUtils.m; sourceTree = ""; }; 3E9CDB991ECC841700B1980D /* SignusDemo.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SignusDemo.mm; sourceTree = ""; }; + 3EC6BCF41EDC0A4500A290DE /* libsovrin.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = libsovrin.framework; path = "../../../../../../Library/Developer/Xcode/DerivedData/libsovrin-fpqoyzkovibgszalhhmmnlcetkfp/Build/Products/Debug-iphoneos/libsovrin.framework"; sourceTree = ""; }; 3ED5BE531EC9D8F200881380 /* LedgerDemo.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = LedgerDemo.mm; sourceTree = ""; }; 3ED5BE551EC9DA9700881380 /* PoolUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PoolUtils.h; sourceTree = ""; }; 3ED5BE561EC9DA9700881380 /* PoolUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PoolUtils.m; sourceTree = ""; }; @@ -85,7 +89,6 @@ 3EF020D71EC4593900CF985C /* TestUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TestUtils.m; sourceTree = ""; }; 3EF020D91EC4595500CF985C /* Environment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Environment.h; sourceTree = ""; }; 3EF020DA1EC4595500CF985C /* Environment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Environment.m; sourceTree = ""; }; - 3EF020DC1EC45A9B00CF985C /* libsovrin.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = libsovrin.framework; path = "../../../../../../Library/Developer/Xcode/DerivedData/libsovrin-dlmogskbrwrmnoceaqqsbyhvursy/Build/Products/Debug-iphoneos/libsovrin.framework"; sourceTree = ""; }; 920EA9D52354D5FE353162A1 /* libPods-libsovrin-demo.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-libsovrin-demo.a"; sourceTree = BUILT_PRODUCTS_DIR; }; A49C6DA8781C6A9455450851 /* Pods-libsovrin-demo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-libsovrin-demo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-libsovrin-demo/Pods-libsovrin-demo.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -95,8 +98,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 3EF020DD1EC45A9B00CF985C /* libsovrin.framework in Frameworks */, - C417EEF3998DF20C9FE62376 /* libPods-libsovrin-demo.a in Frameworks */, + 3EC6BCF51EDC0A4500A290DE /* libsovrin.framework in Frameworks */, 4E342A88B72D9633DC35144B /* libPods-libsovrin-demo.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -105,7 +107,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 3EF020DE1EC45AA300CF985C /* libsovrin.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -159,6 +160,7 @@ 3E2A7FA21EC36187006194EC /* AnoncredsDemo.mm */, 3E9CDB991ECC841700B1980D /* SignusDemo.mm */, 3ED5BE531EC9D8F200881380 /* LedgerDemo.mm */, + 3E2FFA3E1ED5C06E00536EAD /* Anoncreds.m */, 3E2A7FA41EC36187006194EC /* Info.plist */, ); path = "libsovrin-demoTests"; @@ -185,6 +187,10 @@ 3EF020DA1EC4595500CF985C /* Environment.m */, 3ED5BE551EC9DA9700881380 /* PoolUtils.h */, 3ED5BE561EC9DA9700881380 /* PoolUtils.m */, + 3E2FFA421ED5C37100536EAD /* WalletUtils.h */, + 3E2FFA431ED5C37100536EAD /* WalletUtils.m */, + 3E2FFA451ED5CC5E00536EAD /* AnoncredsUtils.h */, + 3E2FFA461ED5CC5E00536EAD /* AnoncredsUtils.m */, ); name = TestUtils; sourceTree = ""; @@ -192,7 +198,7 @@ 84DF55ECAD03C4B4CEE16BD1 /* Frameworks */ = { isa = PBXGroup; children = ( - 3EF020DC1EC45A9B00CF985C /* libsovrin.framework */, + 3EC6BCF41EDC0A4500A290DE /* libsovrin.framework */, 920EA9D52354D5FE353162A1 /* libPods-libsovrin-demo.a */, ); name = Frameworks; @@ -306,7 +312,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 3ED5BE4C1EC4967C00881380 /* libsovrin.framework in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -378,10 +383,13 @@ files = ( 3E2A7FA31EC36187006194EC /* AnoncredsDemo.mm in Sources */, 3EF020DB1EC4595500CF985C /* Environment.m in Sources */, + 3E2FFA441ED5C37100536EAD /* WalletUtils.m in Sources */, 3ED5BE571EC9DA9700881380 /* PoolUtils.m in Sources */, 3E9CDB9A1ECC841700B1980D /* SignusDemo.mm in Sources */, + 3E2FFA471ED5CC5E00536EAD /* AnoncredsUtils.m in Sources */, 3EF020D81EC4593900CF985C /* TestUtils.m in Sources */, 3ED5BE541EC9D8F200881380 /* LedgerDemo.mm in Sources */, + 3E2FFA3F1ED5C06E00536EAD /* Anoncreds.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/wrappers/ios/libsovrin-pod/libsovrin-demoTests/Anoncreds.m b/wrappers/ios/libsovrin-pod/libsovrin-demoTests/Anoncreds.m new file mode 100644 index 0000000..694ea40 --- /dev/null +++ b/wrappers/ios/libsovrin-pod/libsovrin-demoTests/Anoncreds.m @@ -0,0 +1,216 @@ +// +// Anoncreds.m +// libsovrin-demo +// + + +#import +#import +#import +#import "TestUtils.h" +#import "WalletUtils.h" +#import "AnoncredsUtils.h" + +@interface Anoncreds : XCTestCase + +@end + +@implementation Anoncreds + +- (void)setUp +{ + [super setUp]; + // Put setup code here. This method is called before the invocation of each test method in the class. +} + +- (void)tearDown +{ + // Put teardown code here. This method is called after the invocation of each test method in the class. + [super tearDown]; +} + +-(void) anoncredsWorksForSingleIssuerSingleProverTest +{ + NSLog(@"anoncredsWorksForSingleIssuerSingleProverTest() started..."); + [TestUtils cleanupStorage]; + + NSString* poolName = @"pool1"; + NSString* issuerWalletName = @"issuer_wallet"; + NSString* proverWalletName = @"prover_wallet"; + NSString* xtype = @"default"; + SovrinHandle issuerWalletHandle = 0; + SovrinHandle proverWalletHandle = 0; + NSError *res = nil; + + //1. Create Issuer wallet, get wallet handle + + res = [[WalletUtils sharedInstance] createWallet:poolName walletName:issuerWalletName xtype:xtype handle:&issuerWalletHandle]; + NSAssert(res.code == Success, @"WalletUtils::createWallet() failed"); + + //2. Create Prover wallet, get wallet handle + res = [[WalletUtils sharedInstance] createWallet:poolName walletName:proverWalletName xtype:xtype handle:&proverWalletHandle]; + NSAssert(res.code == Success, @"WalletUtils::createWallet() failed"); + + //3. Issuer create claim definition + NSString* issuerDid = @"some_issuer_did"; + NSNumber* schemaSeqNo = @1; + NSNumber* claimDefSeqNo = @1; + NSString* claimDefJSON = nil; + NSString* schema = [[AnoncredsUtils sharedInstance] getGvtSchemaJson: schemaSeqNo]; + + res = [[AnoncredsUtils sharedInstance] createClaimDefinitionAndSetLink: issuerWalletHandle + schema: schema + seqNo: schemaSeqNo + outJson:&claimDefJSON]; + + NSAssert(res.code == Success, @"AnoncredsUtils::createClaimDefinitionAndSetLink() failed"); + + //4. Prover create Master Secret + + NSString *masterSecretName = @"prover_master_secret"; + + res = [[AnoncredsUtils sharedInstance] proverCreateMasterSecret:proverWalletHandle + masterSecretName:masterSecretName]; + + NSAssert(res.code == Success, @"AnoncredsUtils::proverCreateMasterSecret() failed"); + + //5. Prover store Claim Offer received from Issuer + + NSString *claimOfferJson = [[ AnoncredsUtils sharedInstance] getClaimOfferJson: issuerDid seqNo: claimDefSeqNo ]; + + res = [[AnoncredsUtils sharedInstance] proverStoreClaimOffer: proverWalletHandle + claimOfferJson: claimOfferJson ]; + + NSAssert(res.code == Success, @"AnoncredsUtils::proverStoreClaimOffer() failed"); + + //6. Prover get Claim Offers + + NSString *filterJson = [NSString stringWithFormat: @"{ \"issuer_did\":\"%@\"}", issuerDid]; + NSString *claimOffersJson = nil; + + res = [[AnoncredsUtils sharedInstance] proverGetClaimOffers: proverWalletHandle + filterJson: filterJson + outClaimOffersJSON: &claimOffersJson]; + + NSAssert(res.code == Success, @"AnoncredsUtils::proverGetClaimOffers() failed"); + + // TODO: add more asserts here + + //7. Prover create Claim Request + NSString* proverDid = @"some_prover_did"; + NSString* claimReq = nil; + + res = [[ AnoncredsUtils sharedInstance] proverCreateAndStoreClaimReq: proverWalletHandle + proverDid: proverDid + claimOfferJson: claimOfferJson + claimDefJson: claimDefJSON + masterSecretName: masterSecretName + outClaimReqJson:&claimReq ]; + + NSAssert(res.code == Success, @"AnoncredsUtils::proverCreateAndStoreClaimReq() failed"); + + //8. Issuer create Claim + NSString *revocRegUpdateJson = nil; + NSString *xclaimJson = nil; + + NSString *claimJson = [[ AnoncredsUtils sharedInstance] getGvtClaimJson]; + + res = [[AnoncredsUtils sharedInstance] issuerCreateClaim: issuerWalletHandle + claimReqJson: claimReq + claimJson: claimJson + outRevocRegUpdateJSON:&revocRegUpdateJson + outClaimJson:&xclaimJson ]; + + NSAssert(res.code == Success, @"AnoncredsUtils::issuerCreateClaim() failed"); + + // 9. Prover store received Claim + + res = [[AnoncredsUtils sharedInstance] proverStoreClaim: proverWalletHandle + claimsJson: xclaimJson]; + + NSAssert(res.code == Success, @"AnoncredsUtils::proverStoreClaim() failed"); + + + // 10. Prover gets Claims for Proof Request + NSString *proofReqJson =[ NSString stringWithFormat:@"{"\ + " \"nonce\":\"123432421212\","\ + " \"requested_attrs\":"\ + " {\"attr1_uuid\":"\ + " {"\ + " \"schema_seq_no\":%d,\"name\":\"name\""\ + " }"\ + " },"\ + " \"requested_predicates\":"\ + " {"\ + " \"predicate1_uuid\":"\ + " {\"attr_name\":\"age\",\"p_type\":\"GE\",\"value\":18}"\ + " }"\ + "}", [schemaSeqNo integerValue] ]; + NSString *claimsJson = nil; + + res = [[AnoncredsUtils sharedInstance] proverGetClaimsForProofReq:proverWalletHandle + proofRequestJson:proofReqJson + outClaimsJson:&claimsJson]; + + NSAssert(res.code == Success, @"AnoncredsUtils::proverGetClaimsForProofReq() failed"); + + NSDictionary *claims = [NSJSONSerialization JSONObjectWithData:[NSData dataWithBytes:[claimsJson UTF8String] + length:[claimsJson length]] + options:kNilOptions + error: &res]; + NSAssert( claims, @"serialization failed"); + + NSDictionary *claims_for_attr_1 = [[ [claims objectForKey: @"attrs" ] objectForKey: @"attr1_uuid"] objectAtIndex: 0 ]; + + NSAssert( claims_for_attr_1, @"no object for key \"attr1_uuid\""); + + NSString *claimUUID = [claims_for_attr_1 objectForKey:@"claim_uuid"]; + + //TODO: add assert here + + // 11. Prover create Proof + NSString* requestedClaimsJson = [ NSString stringWithFormat:@"{"\ + " \"self_attested_attributes\":{},"\ + " \"requested_attrs\":{\"attr1_uuid\":[\"%@\",true]},"\ + " \"requested_predicates\":{\"predicate1_uuid\":\"%@\"}"\ + "}", claimUUID,claimUUID]; + + NSString* schemasJson = [NSString stringWithFormat: @"{\"%@\":%@}", claimUUID, schema]; + + NSString* claimDefsJson = [NSString stringWithFormat:@"{\"%@\":%@}", claimUUID, claimDefJSON]; + NSString* revocRegsJsons = @"{}"; + + NSString* proofJson = nil; + + res = [[AnoncredsUtils sharedInstance] proverCreateProof: proverWalletHandle + proofReqJson: proofReqJson + requestedClaimsJson: requestedClaimsJson + schemasJson: schemasJson + masterSecretName: masterSecretName + claimDefsJson: claimDefsJson + revocRegsJson: revocRegsJsons + outProofJson:&proofJson]; + + NSAssert(res.code == Success, @"AnoncredsUtils::proverCreateProof() failed"); + + BOOL isValid = NO; + + res = [[AnoncredsUtils sharedInstance ] verifierVerifyProof:proofReqJson + proofJson:proofJson + schemasJson:schemasJson + claimDefsJson:claimDefsJson + revocRegsJson:revocRegsJsons + outValid:&isValid ]; + + NSAssert(res.code == Success, @"AnoncredsUtils::verifierVerifyProof() failed"); + NSAssert( isValid == YES, @"isValid == NO"); + NSLog(@"anoncredsWorksForSingleIssuerSingleProverTest() ended..."); + [TestUtils cleanupStorage]; +} + +- (void)testAnoncreds +{ + [self anoncredsWorksForSingleIssuerSingleProverTest]; +} + +@end diff --git a/wrappers/ios/libsovrin-pod/libsovrin-demoTests/AnoncredsDemo.mm b/wrappers/ios/libsovrin-pod/libsovrin-demoTests/AnoncredsDemo.mm index 631b048..941ea84 100644 --- a/wrappers/ios/libsovrin-pod/libsovrin-demoTests/AnoncredsDemo.mm +++ b/wrappers/ios/libsovrin-pod/libsovrin-demoTests/AnoncredsDemo.mm @@ -7,6 +7,7 @@ #import #import #import "TestUtils.h" +#import "WalletUtils.h" @interface AnoncredsDemo : XCTestCase @@ -34,41 +35,18 @@ - (void)testAnoncredsDemo NSString *xType = @"default"; XCTestExpectation* completionExpectation = [[ XCTestExpectation alloc] initWithDescription: @"completion finished"]; - // 1. Create wallet + SovrinHandle walletHandle = 0; - NSError *ret = [[SovrinWallet sharedInstance] createWallet: poolName - name: walletName - xType: xType - config: nil - credentials: nil - completion: ^(NSError* error) - { - XCTAssertEqual(error.code, Success, "createWallet got error in completion"); - [completionExpectation fulfill]; - }]; - - NSAssert( ret.code == Success, @"createWallet() failed!"); - [self waitForExpectations: @[completionExpectation] timeout:[TestUtils defaultTimeout]]; - - // 2. Open Issuer Wallet. Gets Issuer wallet handle - completionExpectation = [[ XCTestExpectation alloc] initWithDescription: @"completion finished"]; + // 1. Create and open the wallet - __block SovrinHandle walletHandle = 0; + NSError *ret = [[WalletUtils sharedInstance] createWallet: poolName + walletName: walletName + xtype: xType + handle: &walletHandle]; - ret = [[SovrinWallet sharedInstance] openWallet: walletName - runtimeConfig: nil - credentials: nil - completion: ^(NSError* error, SovrinHandle handle) - { - XCTAssertEqual(error.code, Success, "openWallet got error in completion"); - walletHandle = handle; - [completionExpectation fulfill]; - }]; + NSAssert( ret.code == Success, @"WalletUtils::createWallet() failed!"); - NSAssert( ret.code == Success, @"openWallet() failed!"); - [self waitForExpectations: @[completionExpectation] timeout:[TestUtils defaultTimeout]]; - - // 3. Issuer create Claim Definition for Schema + // 2. Issuer create Claim Definition for Schema completionExpectation = [[ XCTestExpectation alloc] initWithDescription: @"completion finished"]; NSUInteger seqNo = 1; @@ -76,8 +54,8 @@ - (void)testAnoncredsDemo \"name\":\"gvt\",\ \"version\":\"1.0\",\ \"attribute_names\":[\"age\",\"sex\",\"height\",\"name\"],\ - \"seq_no\":%d\ - }", seqNo ]; + \"seq_no\":%lu\ + }", (unsigned long)seqNo ]; __block NSString *claimJSON = nil; __block NSString *claimDefUUID = nil; @@ -97,7 +75,7 @@ - (void)testAnoncredsDemo NSAssert( ret.code == Success, @"issuerCreateAndStoreClaimDef() failed!"); [self waitForExpectations: @[completionExpectation] timeout:[TestUtils defaultTimeout]]; - // 4. Create relationship between claim_def_seq_no and claim_def_uuid in wallet + // 3. Create relationship between claim_def_seq_no and claim_def_uuid in wallet completionExpectation = [[ XCTestExpectation alloc] initWithDescription: @"completion finished"]; ret = [[SovrinWallet sharedInstance] walletSetSeqNo: [NSNumber numberWithInteger: seqNo] @@ -112,7 +90,7 @@ - (void)testAnoncredsDemo NSAssert( ret.code == Success, @"walletSetSeqNo() failed!"); [self waitForExpectations: @[completionExpectation] timeout:[TestUtils defaultTimeout]]; - // 5. Prover create Master Secret + // 4. Prover create Master Secret completionExpectation = [[ XCTestExpectation alloc] initWithDescription: @"completion finished"]; NSString *masterSecretName = @"master_secret"; @@ -129,12 +107,12 @@ - (void)testAnoncredsDemo NSAssert( ret.code == Success, @"proverCreateMasterSecret() failed!"); [self waitForExpectations: @[completionExpectation] timeout:[TestUtils defaultTimeout]]; - // 6. Prover create Claim Request + // 5. Prover create Claim Request completionExpectation = [[ XCTestExpectation alloc] initWithDescription: @"completion finished"]; NSString *proverDiD = @"some_prover_did"; - NSString *claimOfferJSON = [NSString stringWithFormat: @"{\"issuer_did\":\"some_issuer_did\",\"claim_def_seq_no\":%d}", seqNo]; + NSString *claimOfferJSON = [NSString stringWithFormat: @"{\"issuer_did\":\"some_issuer_did\",\"claim_def_seq_no\":%lu}", (unsigned long)seqNo]; __block NSString *claimReqJSON = nil; ret = [SovrinAnoncreds proverCreateAndStoreClaimReq: walletHandle @@ -153,7 +131,7 @@ - (void)testAnoncredsDemo NSAssert( ret.code == Success, @"proverCreateAndStoreClaimReq() failed!"); [self waitForExpectations: @[completionExpectation] timeout:[TestUtils defaultTimeout]]; - // 7. Issuer create Claim for Claim Request + // 6. Issuer create Claim for Claim Request completionExpectation = [[ XCTestExpectation alloc] initWithDescription: @"completion finished"]; NSString* testClaimJson = @"{\ @@ -179,7 +157,7 @@ - (void)testAnoncredsDemo NSAssert( ret.code == Success, @"issuerCreateClaim() failed!"); [self waitForExpectations: @[completionExpectation] timeout:[TestUtils defaultTimeout]]; - // 8. Prover process and store Claim + // 7. Prover process and store Claim completionExpectation = [[ XCTestExpectation alloc] initWithDescription: @"completion finished"]; ret = [SovrinAnoncreds proverStoreClaim: walletHandle @@ -193,7 +171,7 @@ - (void)testAnoncredsDemo NSAssert( ret.code == Success, @"proverStoreClaim() failed!"); [self waitForExpectations: @[completionExpectation] timeout:[TestUtils defaultTimeout]]; - // 9. Prover gets Claims for Proof Request + // 8. Prover gets Claims for Proof Request completionExpectation = [[ XCTestExpectation alloc] initWithDescription: @"completion finished"]; NSString* proofReqJSON = [NSString stringWithFormat: @"\ @@ -201,18 +179,18 @@ - (void)testAnoncredsDemo \"nonce\":\"123432421212\",\ \"requested_attrs\":{\ \"attr1_uuid\":{\ - \"schema_seq_no\":%d,\ - \"name\":\"name\"\ - }\ - },\ - \"requested_predicates\":{\ - \"predicate1_uuid\":{\ - \"attr_name\":\"age\",\ - \"p_type\":\"GE\",\ - \"value\":18\ - }\ - }\ - }", seqNo ]; + \"schema_seq_no\":%lu,\ + \"name\":\"name\"\ + }\ + },\ + \"requested_predicates\":{\ + \"predicate1_uuid\":{\ + \"attr_name\":\"age\",\ + \"p_type\":\"GE\",\ + \"value\":18\ + }\ + }\ + }", (unsigned long)seqNo ]; ret = [SovrinAnoncreds proverGetClaimsForProofReq: walletHandle proofReqJSON: proofReqJSON @@ -226,18 +204,18 @@ - (void)testAnoncredsDemo NSAssert( ret.code == Success, @"proverGetClaimsForProofReq() failed!"); [self waitForExpectations: @[completionExpectation] timeout:[TestUtils defaultTimeout]]; - // 10. Prover create Proof for Proof Request + // 9. Prover create Proof for Proof Request completionExpectation = [[ XCTestExpectation alloc] initWithDescription: @"completion finished"]; NSString* requestedClaimsJSON = [ NSString stringWithFormat: @"{\ \"self_attested_attributes\":{},\ - \"requested_attrs\":{\"attr1_uuid\":[\"%d\",true]},\ - \"requested_predicates\":{\"predicate1_uuid\":\"%d\"}\ - }", seqNo, seqNo ]; + \"requested_attrs\":{\"attr1_uuid\":[\"%lu\",true]},\ + \"requested_predicates\":{\"predicate1_uuid\":\"%lu\"}\ + }", (unsigned long)seqNo, (unsigned long)seqNo ]; - NSString *schemas = [NSString stringWithFormat: @"{\"%d\":%@}", seqNo, schema]; + NSString *schemas = [NSString stringWithFormat: @"{\"%lu\":%@}", (unsigned long)seqNo, schema]; - NSString *claimDefsJSON = [NSString stringWithFormat: @"{\"%d\":%@}", seqNo, claimJSON]; + NSString *claimDefsJSON = [NSString stringWithFormat: @"{\"%lu\":%@}", (unsigned long)seqNo, claimJSON]; NSString *revocRegsJsons = @"{}"; @@ -260,11 +238,10 @@ - (void)testAnoncredsDemo NSAssert( ret.code == Success, @"proverCreateProof() failed!"); [self waitForExpectations: @[completionExpectation] timeout:[TestUtils defaultTimeout]]; - // 11. Verifier verify proof + // 10. Verifier verify proof completionExpectation = [[ XCTestExpectation alloc] initWithDescription: @"completion finished"]; - ret = [SovrinAnoncreds verifierVerifyProof: walletHandle - proofReqJSON: proofReqJSON + ret = [SovrinAnoncreds verifierVerifyProof: proofReqJSON proofJSON: proofJSON schemasJSON: schemas claimDefsJSON: claimDefsJSON @@ -280,7 +257,7 @@ - (void)testAnoncredsDemo NSAssert( ret.code == Success, @"verifierVerifyProof() failed!"); [self waitForExpectations: @[completionExpectation] timeout:[TestUtils defaultTimeout]]; - // 12. close wallet + // 11. close wallet completionExpectation = [[ XCTestExpectation alloc] initWithDescription: @"completion finished"]; ret = [[SovrinWallet sharedInstance] closeWallet: walletHandle diff --git a/wrappers/ios/libsovrin-pod/libsovrin-demoTests/AnoncredsUtils.h b/wrappers/ios/libsovrin-pod/libsovrin-demoTests/AnoncredsUtils.h new file mode 100644 index 0000000..b88f987 --- /dev/null +++ b/wrappers/ios/libsovrin-pod/libsovrin-demoTests/AnoncredsUtils.h @@ -0,0 +1,72 @@ +// +// AnoncredsUtils.h +// libsovrin-demo +// + +#import +#import +#import + +@interface AnoncredsUtils : XCTestCase + ++ (AnoncredsUtils *)sharedInstance; + +-(NSString*) getGvtSchemaJson:(NSNumber*) seqNo; + +-(NSString*) getClaimOfferJson:(NSString*) issuerDid + seqNo:(NSNumber*) claimDefSeqNo; + +-(NSString*) getGvtClaimJson; + +-(NSError*) createClaimDefinitionAndSetLink:(SovrinHandle) walletHandle + schema:(NSString*) schema + seqNo:(NSNumber*) claimDefSeqNo + outJson:(NSString**) outJson; + +-(NSError*) proverCreateMasterSecret:(SovrinHandle) walletHandle + masterSecretName:(NSString*) name; + +-(NSError*) proverStoreClaimOffer:(SovrinHandle) walletHandle + claimOfferJson:(NSString*) str; + +-(NSError*) proverGetClaimOffers:(SovrinHandle) walletHandle + filterJson:(NSString*) filterJson + outClaimOffersJSON:(NSString**) outJson; + +-(NSError*) proverCreateAndStoreClaimReq:(SovrinHandle) walletHandle + proverDid:(NSString*) pd + claimOfferJson:(NSString*) coj + claimDefJson:(NSString*) cdj + masterSecretName:(NSString*) name + outClaimReqJson:(NSString**) outJson; + +-(NSError*) issuerCreateClaim:(SovrinHandle) walletHandle + claimReqJson:(NSString*) claimReqJson + claimJson:(NSString*) claimJson + outRevocRegUpdateJSON:(NSString**) outRevocRegUpdateJson + outClaimJson:(NSString**) outClaimJson; + +-(NSError*) proverStoreClaim:(SovrinHandle) walletHandle + claimsJson:(NSString*) str; + +-(NSError*) proverGetClaimsForProofReq:(SovrinHandle) walletHandle + proofRequestJson:(NSString*) str + outClaimsJson:(NSString**) outClaimsJson; + +-(NSError*) proverCreateProof:(SovrinHandle) walletHandle + proofReqJson:(NSString*) proofReqJson + requestedClaimsJson:(NSString*) requestedClaimsJson + schemasJson:(NSString*) schemasJson + masterSecretName:(NSString*) masterSecreteName + claimDefsJson:(NSString*) claimDefsJson + revocRegsJson:(NSString*) revocRegsJson + outProofJson:(NSString**) outProofJson; + +-(NSError*) verifierVerifyProof:(NSString*) proofRequestJson + proofJson:(NSString*) proofJson + schemasJson:(NSString*) schemasJson + claimDefsJson:(NSString*) claimDefsJson + revocRegsJson:(NSString*) revocRegsJson + outValid:(BOOL*) isValid; + +@end diff --git a/wrappers/ios/libsovrin-pod/libsovrin-demoTests/AnoncredsUtils.m b/wrappers/ios/libsovrin-pod/libsovrin-demoTests/AnoncredsUtils.m new file mode 100644 index 0000000..1cf021f --- /dev/null +++ b/wrappers/ios/libsovrin-pod/libsovrin-demoTests/AnoncredsUtils.m @@ -0,0 +1,403 @@ +// +// AnoncredsUtils.m +// libsovrin-demo +// +// Created by Kirill Neznamov on 24/05/2017. +// Copyright © 2017 Kirill Neznamov. All rights reserved. +// + +#import "AnoncredsUtils.h" +#import +#import "TestUtils.h" +#import "WalletUtils.h" + +@implementation AnoncredsUtils + ++ (AnoncredsUtils *)sharedInstance +{ + static AnoncredsUtils *instance = nil; + static dispatch_once_t dispatch_once_block; + + dispatch_once(&dispatch_once_block, ^{ + instance = [AnoncredsUtils new]; + }); + + return instance; +} + +-(NSString*) getGvtSchemaJson:(NSNumber*) seqNo +{ + return [NSString stringWithFormat:@"{"\ + "\"name\":\"gvt\"," \ + "\"version\":\"1.0\"," \ + "\"attribute_names\":[\"age\",\"sex\",\"height\",\"name\"]," \ + "\"seq_no\":%d" \ + "}", [seqNo integerValue] + ]; +} + +-(NSString*) getClaimOfferJson:(NSString*) issuerDid seqNo:(NSNumber*) claimDefSeqNo +{ + return [NSString stringWithFormat:@"{"\ + "\"issuer_did\":\"%@\"," \ + "\"claim_def_seq_no\":%d" \ + "}", issuerDid, [claimDefSeqNo integerValue] + ]; +} + +-(NSString*) getGvtClaimJson +{ + return [NSString stringWithFormat:@"{"\ + "\"sex\":[\"male\",\"5944657099558967239210949258394887428692050081607692519917050011144233115103\"],"\ + "\"name\":[\"Alex\",\"1139481716457488690172217916278103335\"],"\ + "\"height\":[\"175\",\"175\"],"\ + "\"age\":[\"28\",\"28\"]"\ + "}"]; +} + +-(NSError*) issuerCreateClaimDefinition:(SovrinHandle) walletHandle + schema:(NSString*) schema + outClaimDefJson:(NSString**) outClaimDefJson + outClaimDefUUID:(NSString**) outClaimDefUUID +{ + __block NSError *err = nil; + XCTestExpectation* completionExpectation = nil; + + completionExpectation = [[ XCTestExpectation alloc] initWithDescription: @"completion finished"]; + + NSError *ret = [SovrinAnoncreds issuerCreateAndStoreClaimDef:walletHandle + schemaJSON:schema + signatureType:nil + createNonRevoc:NO + completion:^(NSError *error, NSString *claimDefJSON, NSString *claimDefUUID) + { + err = error; + if(claimDefJSON && outClaimDefJson) + { + *outClaimDefJson = claimDefJSON; + } + if(claimDefUUID && outClaimDefUUID) + { + *outClaimDefUUID = claimDefUUID; + } + [completionExpectation fulfill]; + }]; + + if( ret.code != Success) + { + return ret; + } + + [self waitForExpectations: @[completionExpectation] timeout:[TestUtils defaultTimeout]]; + + return err; +} + +-(NSError*) createClaimDefinitionAndSetLink:(SovrinHandle) walletHandle + schema:(NSString*) schema + seqNo:(NSNumber*) claimDefSeqNo + outJson:(NSString**) outJson +{ + NSString* uuid = nil; + + NSError *ret = [ self issuerCreateClaimDefinition:walletHandle + schema:schema + outClaimDefJson:outJson + outClaimDefUUID:&uuid ]; + if( ret.code != Success ) + { + return ret; + } + + ret = [[WalletUtils sharedInstance] walletSetSeqNoForValue:walletHandle + claimDefUUID:uuid + claimDefSeqNo:claimDefSeqNo]; + return ret; +} + +-(NSError*) proverCreateMasterSecret:(SovrinHandle) walletHandle + masterSecretName:(NSString*) name +{ + __block NSError *err = nil; + XCTestExpectation* completionExpectation = nil; + + completionExpectation = [[ XCTestExpectation alloc] initWithDescription: @"completion finished"]; + + NSError *ret = [SovrinAnoncreds proverCreateMasterSecret: walletHandle + masterSecretName: name + completion: ^(NSError *error) + { + err = error; + [completionExpectation fulfill]; + }]; + + if( ret.code != Success) + { + return ret; + } + + [self waitForExpectations: @[completionExpectation] timeout:[TestUtils defaultTimeout]]; + return err; +} + +-(NSError*) proverStoreClaimOffer:(SovrinHandle) walletHandle + claimOfferJson:(NSString*) str +{ + __block NSError *err = nil; + XCTestExpectation* completionExpectation = nil; + + completionExpectation = [[ XCTestExpectation alloc] initWithDescription: @"completion finished"]; + + NSError *ret = [SovrinAnoncreds proverStoreClaimOffer: walletHandle + claimOfferJSON: str + completion: ^(NSError *error) + { + err = error; + [completionExpectation fulfill]; + }]; + + if( ret.code != Success) + { + return ret; + } + + [self waitForExpectations: @[completionExpectation] timeout:[TestUtils defaultTimeout]]; + return err; + +} + +-(NSError*) proverGetClaimOffers:(SovrinHandle) walletHandle + filterJson:(NSString*) filterJson + outClaimOffersJSON:(NSString**) outJson +{ + __block NSError *err = nil; + XCTestExpectation* completionExpectation = nil; + + completionExpectation = [[ XCTestExpectation alloc] initWithDescription: @"completion finished"]; + + NSError *ret = [ SovrinAnoncreds proverGetClaimOffers: walletHandle + filterJSON: filterJson + completion:^(NSError *error, NSString *claimOffersJSON) + { + err = error; + if(outJson) + { + *outJson = claimOffersJSON; + } + [completionExpectation fulfill]; + }]; + + if( ret.code != Success) + { + return ret; + } + + [self waitForExpectations: @[completionExpectation] timeout:[TestUtils defaultTimeout]]; + return err; +} + +-(NSError*) proverCreateAndStoreClaimReq:(SovrinHandle) walletHandle + proverDid:(NSString*) pd + claimOfferJson:(NSString*) coj + claimDefJson:(NSString*) cdj + masterSecretName:(NSString*) name + outClaimReqJson:(NSString**) outJson +{ + __block NSError *err = nil; + XCTestExpectation* completionExpectation = nil; + + completionExpectation = [[ XCTestExpectation alloc] initWithDescription: @"completion finished"]; + + NSError *ret = [ SovrinAnoncreds proverCreateAndStoreClaimReq: walletHandle + proverDid: pd + claimOfferJSON: coj + masterSecretName: name + claimDefJSON: cdj + completion:^(NSError* error, NSString* claimReqJSON) + { + err = error; + if(outJson) + { + *outJson = claimReqJSON; + } + [completionExpectation fulfill]; + }]; + + if( ret.code != Success) + { + return ret; + } + + [self waitForExpectations: @[completionExpectation] timeout:[TestUtils defaultTimeout]]; + return err; +} + +-(NSError*) issuerCreateClaim:(SovrinHandle) walletHandle + claimReqJson:(NSString*) claimReqJson + claimJson:(NSString*) claimJson + outRevocRegUpdateJSON:(NSString**) outRevocRegUpdateJson + outClaimJson:(NSString**) outClaimJson +{ + __block NSError *err = nil; + XCTestExpectation* completionExpectation = nil; + + completionExpectation = [[ XCTestExpectation alloc] initWithDescription: @"completion finished"]; + + NSError *ret = [SovrinAnoncreds issuerCreateClaim:walletHandle + claimReqJSON:claimReqJson + claimJSON:claimJson + revocRegSeqNo:nil + userRevocIndex:nil completion:^(NSError *error, NSString *revocRegUpdateJSON, NSString *claimJSON) + { + err = error; + if(outRevocRegUpdateJson) + { + *outRevocRegUpdateJson = revocRegUpdateJSON; + } + if(claimJson) + { + *outClaimJson = claimJSON; + } + [completionExpectation fulfill]; + }]; + + if( ret.code != Success) + { + return ret; + } + + [self waitForExpectations: @[completionExpectation] timeout:[TestUtils defaultTimeout]]; + return err; +} + +-(NSError*) proverStoreClaim:(SovrinHandle) walletHandle + claimsJson:(NSString*) str +{ + __block NSError *err = nil; + XCTestExpectation* completionExpectation = nil; + + completionExpectation = [[ XCTestExpectation alloc] initWithDescription: @"completion finished"]; + + NSError *ret = [SovrinAnoncreds proverStoreClaim: walletHandle claimsJSON:str completion:^(NSError *error) + { + err = error; + [completionExpectation fulfill]; + }]; + + if( ret.code != Success) + { + return ret; + } + + [self waitForExpectations: @[completionExpectation] timeout:[TestUtils defaultTimeout]]; + return err; +} + +-(NSError*) proverGetClaimsForProofReq:(SovrinHandle) walletHandle + proofRequestJson:(NSString*) str + outClaimsJson:(NSString**) outClaimsJson +{ + __block NSError *err = nil; + XCTestExpectation* completionExpectation = nil; + + completionExpectation = [[ XCTestExpectation alloc] initWithDescription: @"completion finished"]; + + NSError *ret = [SovrinAnoncreds proverGetClaimsForProofReq: walletHandle + proofReqJSON: str + completion:^(NSError *error, NSString *claimsJSON) + { + err = error; + if(outClaimsJson) + { + *outClaimsJson = claimsJSON; + } + [completionExpectation fulfill]; + }]; + + if( ret.code != Success) + { + return ret; + } + + [self waitForExpectations: @[completionExpectation] timeout:[TestUtils defaultTimeout]]; + return err; +} + +-(NSError*) proverCreateProof:(SovrinHandle) walletHandle + proofReqJson:(NSString*) proofReqJson + requestedClaimsJson:(NSString*) requestedClaimsJson + schemasJson:(NSString*) schemasJson + masterSecretName:(NSString*) masterSecreteName + claimDefsJson:(NSString*) claimDefsJson + revocRegsJson:(NSString*) revocRegsJson + outProofJson:(NSString**) outProofJson +{ + __block NSError *err = nil; + XCTestExpectation* completionExpectation = nil; + + completionExpectation = [[ XCTestExpectation alloc] initWithDescription: @"completion finished"]; + + NSError *ret = [SovrinAnoncreds proverCreateProof:walletHandle + proofReqJSON:proofReqJson + requestedClaimsJSON:requestedClaimsJson + schemasJSON:schemasJson + masterSecretName:masterSecreteName + claimDefsJSON:claimDefsJson + revocRegsJSON:revocRegsJson + completion:^(NSError *error, NSString *proofJSON) + { + err = error; + if (outProofJson) + { + *outProofJson = proofJSON; + } + [completionExpectation fulfill]; + }]; + + if( ret.code != Success) + { + return ret; + } + + [self waitForExpectations: @[completionExpectation] timeout:[TestUtils defaultTimeout]]; + return err; +} + +-(NSError*) verifierVerifyProof:(NSString*) proofRequestJson + proofJson:(NSString*) proofJson + schemasJson:(NSString*) schemasJson + claimDefsJson:(NSString*) claimDefsJson + revocRegsJson:(NSString*) revocRegsJson + outValid:(BOOL*) isValid +{ + __block NSError *err = nil; + XCTestExpectation* completionExpectation = nil; + + completionExpectation = [[ XCTestExpectation alloc] initWithDescription: @"completion finished"]; + + NSError* ret = [SovrinAnoncreds verifierVerifyProof:proofRequestJson + proofJSON:proofJson + schemasJSON:schemasJson + claimDefsJSON:claimDefsJson + revocRegsJSON:revocRegsJson + completion:^(NSError *error, BOOL valid) + { + err = error; + if(isValid) + { + *isValid = valid; + } + [completionExpectation fulfill]; + }]; + + if( ret.code != Success) + { + return ret; + } + + [self waitForExpectations: @[completionExpectation] timeout:[TestUtils defaultTimeout]]; + return err; + +} + +@end diff --git a/wrappers/ios/libsovrin-pod/libsovrin-demoTests/LedgerDemo.mm b/wrappers/ios/libsovrin-pod/libsovrin-demoTests/LedgerDemo.mm index a1e0edd..9ca5d60 100644 --- a/wrappers/ios/libsovrin-pod/libsovrin-demoTests/LedgerDemo.mm +++ b/wrappers/ios/libsovrin-pod/libsovrin-demoTests/LedgerDemo.mm @@ -2,9 +2,7 @@ // LedgerDemo.m // libsovrin-demo // -// Created by Kirill Neznamov on 15/05/2017. -// Copyright © 2017 Kirill Neznamov. All rights reserved. -// + #import #import "PoolUtils.h" @@ -91,8 +89,7 @@ - (void)testLedger NSString *str = @"{"\ @" \"op\": \"REPLY\","\ @" \"result\": {"\ - @" \"req_id\": 1491566332010860,"\ - @" \"txn_id\": \"5511e5493c1d37dfa67b73269a392a7aca5b71e9d10ac106adc7f9e552aee560\""\ + @" \"reqId\": 1491566332010860"\ @" }"\ @"}"; @@ -101,8 +98,18 @@ - (void)testLedger options: kNilOptions error: &error]; - NSAssert( [dictionary1 isEqualToDictionary: dictionary2 ] == YES, @"got unexpected result"); + NSAssert( [self validate:@"op" d1: dictionary1 d2: dictionary2] == YES, @"unexpected result"); + NSDictionary *r1 = [ dictionary1 objectForKey: @"result"]; + NSDictionary *r2 = [ dictionary2 objectForKey: @"result"]; + NSAssert( [self validate:@"reqId" d1: r1 d2: r2] == YES, @"unexpected result"); + NSLog(@"test ended"); +} +-(BOOL) validate:(NSString*) key d1: (NSDictionary*) d1 d2: (NSDictionary*) d2 +{ + id obj1 = [ d1 objectForKey: key]; + id obj2 = [ d2 objectForKey: key]; + return [ obj1 isEqual: obj2]; } @end diff --git a/wrappers/ios/libsovrin-pod/libsovrin-demoTests/PoolUtils.m b/wrappers/ios/libsovrin-pod/libsovrin-demoTests/PoolUtils.m index cca8259..5767ddf 100644 --- a/wrappers/ios/libsovrin-pod/libsovrin-demoTests/PoolUtils.m +++ b/wrappers/ios/libsovrin-pod/libsovrin-demoTests/PoolUtils.m @@ -28,22 +28,22 @@ + (PoolUtils *)sharedInstance - (void)createGenesisTXNFile:(NSString *)poolName { NSString *genesisTXNs = - @"{\"data\":{\"alias\":\"Node1\",\"client_ip\":\"10.0.0.2\",\"client_port\":9702,\"node_ip\":\"10.0.0.2\",\"node_" - "port\":9701,\"services\":[\"VALIDATOR\"]},\"dest\":\"Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv\"," - "\"identifier\":\"FYmoFw55GeQH7SRFa37dkx1d2dZ3zUF8ckg7wmL7ofN4\",\"txnId\":" - "\"fea82e10e894419fe2bea7d96296a6d46f50f93f9eeda954ec461b2ed2950b62\",\"type\":\"0\"}" - "{\"data\":{\"alias\":\"Node2\",\"client_ip\":\"10.0.0.3\",\"client_port\":9704,\"node_ip\":\"10.0.0.3\",\"node_" - "port\":9703,\"services\":[\"VALIDATOR\"]},\"dest\":\"8ECVSk179mjsjKRLWiQtssMLgp6EPhWXtaYyStWPSGAb\"," - "\"identifier\":\"8QhFxKxyaFsJy4CyxeYX34dFH8oWqyBv1P4HLQCsoeLy\",\"txnId\":" - "\"1ac8aece2a18ced660fef8694b61aac3af08ba875ce3026a160acbc3a3af35fc\",\"type\":\"0\"}" - "{\"data\":{\"alias\":\"Node3\",\"client_ip\":\"10.0.0.4\",\"client_port\":9706,\"node_ip\":\"10.0.0.4\",\"node_" - "port\":9705,\"services\":[\"VALIDATOR\"]},\"dest\":\"DKVxG2fXXTU8yT5N7hGEbXB3dfdAnYv1JczDUHpmDxya\"," - "\"identifier\":\"2yAeV5ftuasWNgQwVYzeHeTuM7LwwNtPR3Zg9N4JiDgF\",\"txnId\":" - "\"7e9f355dffa78ed24668f0e0e369fd8c224076571c51e2ea8be5f26479edebe4\",\"type\":\"0\"}" - "{\"data\":{\"alias\":\"Node4\",\"client_ip\":\"10.0.0.5\",\"client_port\":9708,\"node_ip\":\"10.0.0.5\",\"node_" - "port\":9707,\"services\":[\"VALIDATOR\"]},\"dest\":\"4PS3EDQ3dW1tci1Bp6543CfuuebjFrg36kLAUcskGfaA\"," - "\"identifier\":\"FTE95CVthRtrBnK2PYCBbC9LghTcGwi9Zfi1Gz2dnyNx\",\"txnId\":" - "\"aa5e817d7cc626170eca175822029339a444eb0ee8f0bd20d3b0b76e566fb008\",\"type\":\"0\"}"; + @"{\"data\":{\"alias\":\"Node1\",\"client_ip\":\"192.168.53.148\",\"client_port\":9702,\"node_ip\":\"192.168.53.148\",\"node_" + "port\":9701,\"services\":[\"VALIDATOR\"]},\"dest\":\"Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv\"," + "\"identifier\":\"FYmoFw55GeQH7SRFa37dkx1d2dZ3zUF8ckg7wmL7ofN4\",\"txnId\":" + "\"fea82e10e894419fe2bea7d96296a6d46f50f93f9eeda954ec461b2ed2950b62\",\"type\":\"0\"}\n" + "{\"data\":{\"alias\":\"Node2\",\"client_ip\":\"192.168.53.148\",\"client_port\":9704,\"node_ip\":\"192.168.53.148\",\"node_" + "port\":9703,\"services\":[\"VALIDATOR\"]},\"dest\":\"8ECVSk179mjsjKRLWiQtssMLgp6EPhWXtaYyStWPSGAb\"," + "\"identifier\":\"8QhFxKxyaFsJy4CyxeYX34dFH8oWqyBv1P4HLQCsoeLy\",\"txnId\":" + "\"1ac8aece2a18ced660fef8694b61aac3af08ba875ce3026a160acbc3a3af35fc\",\"type\":\"0\"}\n" + "{\"data\":{\"alias\":\"Node3\",\"client_ip\":\"192.168.53.148\",\"client_port\":9706,\"node_ip\":\"192.168.53.148\",\"node_" + "port\":9705,\"services\":[\"VALIDATOR\"]},\"dest\":\"DKVxG2fXXTU8yT5N7hGEbXB3dfdAnYv1JczDUHpmDxya\"," + "\"identifier\":\"2yAeV5ftuasWNgQwVYzeHeTuM7LwwNtPR3Zg9N4JiDgF\",\"txnId\":" + "\"7e9f355dffa78ed24668f0e0e369fd8c224076571c51e2ea8be5f26479edebe4\",\"type\":\"0\"}\n" + "{\"data\":{\"alias\":\"Node4\",\"client_ip\":\"192.168.53.148\",\"client_port\":9708,\"node_ip\":\"192.168.53.148\",\"node_" + "port\":9707,\"services\":[\"VALIDATOR\"]},\"dest\":\"4PS3EDQ3dW1tci1Bp6543CfuuebjFrg36kLAUcskGfaA\"," + "\"identifier\":\"FTE95CVthRtrBnK2PYCBbC9LghTcGwi9Zfi1Gz2dnyNx\",\"txnId\":" + "\"aa5e817d7cc626170eca175822029339a444eb0ee8f0bd20d3b0b76e566fb008\",\"type\":\"0\"}\n"; [[NSFileManager defaultManager] createFileAtPath:[NSString stringWithFormat:@"%@/%@.txn", [TestUtils getUserTmpDir], poolName] contents:[NSData dataWithBytes:[genesisTXNs UTF8String] length:[genesisTXNs length]] @@ -52,7 +52,7 @@ - (void)createGenesisTXNFile:(NSString *)poolName - (NSString *)createPoolConfig:(NSString *)poolName { - NSString *filePath = [NSString stringWithFormat:@"%@/%@.txn", [TestUtils getUserTmpDir], poolName]; + NSString *filePath = [NSString stringWithFormat:@"%@%@.txn", [TestUtils getUserTmpDir], poolName]; return [NSString stringWithFormat:@"{\"genesis_txn\":\"%@\"}", filePath]; } diff --git a/wrappers/ios/libsovrin-pod/libsovrin-demoTests/SignusDemo.mm b/wrappers/ios/libsovrin-pod/libsovrin-demoTests/SignusDemo.mm index 692f33c..cd4afac 100644 --- a/wrappers/ios/libsovrin-pod/libsovrin-demoTests/SignusDemo.mm +++ b/wrappers/ios/libsovrin-pod/libsovrin-demoTests/SignusDemo.mm @@ -7,6 +7,7 @@ #import "PoolUtils.h" #import "TestUtils.h" #import +#import "WalletUtils.h" @interface SignusDemo : XCTestCase @@ -35,84 +36,31 @@ - (void)testSignus NSString *theirWalletName = @"their_wallet"; NSString *xtype = @"default"; NSError *ret = nil; - - __block SovrinHandle myWalletHandle; - __block SovrinHandle theirWalletHandle; + XCTestExpectation* completionExpectation = nil; + SovrinHandle myWalletHandle = 0; + SovrinHandle theirWalletHandle = 0; //TODO CREATE ISSUER, PROVER, VERIFIER WALLETS - //1. Create My Wallet - - XCTestExpectation* completionExpectation = [[ XCTestExpectation alloc] initWithDescription: @"completion finished"]; - - ret = [[SovrinWallet sharedInstance] createWallet: poolName - name: myWalletName - xType: xtype - config: nil - credentials: nil - completion: ^(NSError* error) - { - XCTAssertEqual(error.code, Success, "createWallet got error in completion"); - [completionExpectation fulfill]; - }]; - - NSAssert( ret.code == Success, @"createWallet() failed!"); - [self waitForExpectations: @[completionExpectation] timeout:[TestUtils defaultTimeout]]; - - //2. Create Their Wallet + //1. Create and open my wallet - completionExpectation = [[ XCTestExpectation alloc] initWithDescription: @"completion finished"]; - - ret = [[SovrinWallet sharedInstance] createWallet: poolName - name: theirWalletName - xType: xtype - config: nil - credentials: nil - completion: ^(NSError* error) - { - XCTAssertEqual(error.code, Success, "createWallet got error in completion"); - [completionExpectation fulfill]; - }]; - - NSAssert( ret.code == Success, @"createWallet() failed!"); - [self waitForExpectations: @[completionExpectation] timeout:[TestUtils defaultTimeout]]; + ret = [[WalletUtils sharedInstance] createWallet: poolName + walletName: myWalletName + xtype: xtype + handle: &myWalletHandle]; - //3. Open My Wallet. Gets My wallet handle - completionExpectation = [[ XCTestExpectation alloc] initWithDescription: @"completion finished"]; - - ret = [[SovrinWallet sharedInstance] openWallet: myWalletName - runtimeConfig: nil - credentials: nil - completion: ^(NSError* error, SovrinHandle walletHandle) + NSAssert( ret.code == Success, @"WalletUtils::createWallet() failed!"); - { - XCTAssertEqual(error.code, Success, "openWallet got error in completion"); - myWalletHandle = walletHandle; - [completionExpectation fulfill]; - }]; - - NSAssert( ret.code == Success, @"openWallet() failed!"); - [self waitForExpectations: @[completionExpectation] timeout:[TestUtils defaultTimeout]]; + //2. Create and open Their Wallet - //4. Open Their Wallet. Gets Their wallet handle - - completionExpectation = [[ XCTestExpectation alloc] initWithDescription: @"completion finished"]; + ret = [[WalletUtils sharedInstance] createWallet: poolName + walletName: theirWalletName + xtype: xtype + handle: &theirWalletHandle]; - ret = [[SovrinWallet sharedInstance] openWallet: theirWalletName - runtimeConfig: nil - credentials: nil - completion: ^(NSError* error, SovrinHandle walletHandle) - - { - XCTAssertEqual(error.code, Success, "openWallet got error in completion"); - theirWalletHandle = walletHandle; - [completionExpectation fulfill]; - }]; - - NSAssert( ret.code == Success, @"openWallet() failed!"); - [self waitForExpectations: @[completionExpectation] timeout:[TestUtils defaultTimeout]]; - - // 5. Create My DID + NSAssert( ret.code == Success, @"WalletUtils::createWallet() failed!"); + + // 3. Create My DID NSString *myDidJson = @"{}"; completionExpectation = [[ XCTestExpectation alloc] initWithDescription: @"completion finished"]; @@ -132,7 +80,7 @@ - (void)testSignus NSAssert( ret.code == Success, @"createAndStoreMyDid() failed!"); [self waitForExpectations: @[completionExpectation] timeout:[TestUtils defaultTimeout]]; - // 6. Create Their DID + // 4. Create Their DID NSString *theirDidJson = @"{}"; completionExpectation = [[ XCTestExpectation alloc] initWithDescription: @"completion finished"]; @@ -159,7 +107,7 @@ - (void)testSignus NSAssert( ret.code == Success, @"createAndStoreMyDid() failed!"); [self waitForExpectations: @[completionExpectation] timeout:[TestUtils defaultTimeout]]; - // 7. Store Their DID + // 5. Store Their DID NSString* theirIdentityJson = [NSString stringWithFormat: @"{\"did\":\"%@\",\ \"pk\":\"%@\",\ @@ -177,7 +125,7 @@ - (void)testSignus NSAssert( ret.code == Success, @"createAndStoreMyDid() failed!"); [self waitForExpectations: @[completionExpectation] timeout:[TestUtils defaultTimeout]]; - // 8. Their Sign message + // 6. Their Sign message NSString* message = @"test message"; @@ -198,7 +146,7 @@ - (void)testSignus NSAssert( ret.code == Success, @"sign() failed!"); [self waitForExpectations: @[completionExpectation] timeout:[TestUtils defaultTimeout]]; - // 9. I Verify message + // 7. I Verify message SovrinHandle poolHandle = 1; completionExpectation = [[ XCTestExpectation alloc] initWithDescription: @"completion finished"]; diff --git a/wrappers/ios/libsovrin-pod/libsovrin-demoTests/WalletUtils.h b/wrappers/ios/libsovrin-pod/libsovrin-demoTests/WalletUtils.h new file mode 100644 index 0000000..5ad1c5e --- /dev/null +++ b/wrappers/ios/libsovrin-pod/libsovrin-demoTests/WalletUtils.h @@ -0,0 +1,23 @@ +// +// WalletUtils.h +// libsovrin-demo +// + +#import +#import +#import + +@interface WalletUtils : XCTestCase + ++ (WalletUtils *)sharedInstance; + +-(NSError*) createWallet:(NSString*) poolName + walletName:(NSString*) walletName + xtype:(NSString*) xtype + handle:(SovrinHandle*) handle; + +-(NSError*) walletSetSeqNoForValue:(SovrinHandle) walletHandle + claimDefUUID:(NSString*) uuid + claimDefSeqNo:(NSNumber*) seqNo; + +@end diff --git a/wrappers/ios/libsovrin-pod/libsovrin-demoTests/WalletUtils.m b/wrappers/ios/libsovrin-pod/libsovrin-demoTests/WalletUtils.m new file mode 100644 index 0000000..3f15568 --- /dev/null +++ b/wrappers/ios/libsovrin-pod/libsovrin-demoTests/WalletUtils.m @@ -0,0 +1,108 @@ +// +// WalletUtils.m +// libsovrin-demo +// + +#import "WalletUtils.h" +#import +#import "TestUtils.h" + +@implementation WalletUtils + ++ (WalletUtils *)sharedInstance +{ + static WalletUtils *instance = nil; + static dispatch_once_t dispatch_once_block; + + dispatch_once(&dispatch_once_block, ^ { + instance = [WalletUtils new]; + }); + + return instance; +} + +-(NSError*) createWallet:(NSString*) poolName + walletName:(NSString*) walletName + xtype:(NSString*) xtype + handle:(SovrinHandle*) handle +{ + __block NSError *err = nil; + NSError *ret = nil; + + XCTestExpectation* completionExpectation = [[ XCTestExpectation alloc] initWithDescription: @"completion finished"]; + + ret = [[SovrinWallet sharedInstance] createWallet: poolName + name: walletName + xType: xtype + config: nil + credentials: nil + completion: ^(NSError* error) + { + err = error; + [completionExpectation fulfill]; + }]; + + if( ret.code != Success ) + { + return ret; + } + + [self waitForExpectations: @[completionExpectation] timeout:[TestUtils defaultTimeout]]; + + if( err.code != Success) + { + return err; + } + + completionExpectation = [[ XCTestExpectation alloc] initWithDescription: @"completion finished"]; + __block SovrinHandle walletHandle = 0; + + ret = [[SovrinWallet sharedInstance] openWallet: walletName + runtimeConfig: nil + credentials: nil + completion: ^(NSError* error, SovrinHandle h) + { + err = error; + walletHandle = h; + [completionExpectation fulfill]; + }]; + + if( ret.code != Success ) + { + return ret; + } + + [self waitForExpectations: @[completionExpectation] timeout:[TestUtils defaultTimeout]]; + + *handle = walletHandle; + return err; +} + +-(NSError*) walletSetSeqNoForValue:(SovrinHandle) walletHandle + claimDefUUID:(NSString*) uuid + claimDefSeqNo:(NSNumber*) seqNo +{ + __block NSError *err = nil; + NSError *ret = nil; + + XCTestExpectation* completionExpectation = [[ XCTestExpectation alloc] initWithDescription: @"completion finished"]; + + ret = [[SovrinWallet sharedInstance] walletSetSeqNo: seqNo + forHandle: walletHandle + andKey: uuid + completion: ^(NSError *error) + { + err = error; + [completionExpectation fulfill]; + }]; + + if( ret.code != Success ) + { + return ret; + } + + [self waitForExpectations: @[completionExpectation] timeout:[TestUtils defaultTimeout]]; + return err; +} + +@end diff --git a/wrappers/ios/libsovrin-pod/libsovrin/SovrinAnoncreds.h b/wrappers/ios/libsovrin-pod/libsovrin/SovrinAnoncreds.h index bc8e97e..035cb51 100644 --- a/wrappers/ios/libsovrin-pod/libsovrin/SovrinAnoncreds.h +++ b/wrappers/ios/libsovrin-pod/libsovrin/SovrinAnoncreds.h @@ -73,12 +73,12 @@ revocRegsJSON:(NSString*) revocJson completion:(void (^)(NSError* error, NSString* proofJSON)) handler; -+ (NSError*) verifierVerifyProof:(SovrinHandle) walletHandle - proofReqJSON:(NSString*) reqJSON + ++ (NSError*) verifierVerifyProof:(NSString*) proofReqJSON proofJSON:(NSString*) proofJSON schemasJSON:(NSString*) schemasJSON - claimDefsJSON:(NSString*) claimDefsJson - revocRegsJSON:(NSString*) revocJson + claimDefsJSON:(NSString*) claimDefsJSON + revocRegsJSON:(NSString*) revocJSON completion:(void (^)(NSError* error, BOOL valid)) handler; @end diff --git a/wrappers/ios/libsovrin-pod/libsovrin/SovrinAnoncreds.mm b/wrappers/ios/libsovrin-pod/libsovrin/SovrinAnoncreds.mm index ee643c4..707b432 100644 --- a/wrappers/ios/libsovrin-pod/libsovrin/SovrinAnoncreds.mm +++ b/wrappers/ios/libsovrin-pod/libsovrin/SovrinAnoncreds.mm @@ -301,8 +301,7 @@ + (NSError*) proverCreateProof:(SovrinHandle) walletHandle return [NSError errorFromSovrinError: ret]; } -+ (NSError*) verifierVerifyProof:(SovrinHandle) walletHandle - proofReqJSON:(NSString*) reqJSON ++ (NSError*) verifierVerifyProof:(NSString*) proofReqJSON proofJSON:(NSString*) proofJSON schemasJSON:(NSString*) schemasJSON claimDefsJSON:(NSString*) claimDefsJSON @@ -314,8 +313,7 @@ + (NSError*) verifierVerifyProof:(SovrinHandle) walletHandle sovrin_handle_t handle = [[SovrinCallbacks sharedInstance] add: (void*) handler]; ret = sovrin_verifier_verify_proof(handle, - walletHandle, - [reqJSON UTF8String], + [proofReqJSON UTF8String], [proofJSON UTF8String], [schemasJSON UTF8String], [claimDefsJSON UTF8String], diff --git a/wrappers/ios/libsovrin-pod/libsovrin/SovrinErrors.h b/wrappers/ios/libsovrin-pod/libsovrin/SovrinErrors.h index 4b2e621..e5a49cb 100644 --- a/wrappers/ios/libsovrin-pod/libsovrin/SovrinErrors.h +++ b/wrappers/ios/libsovrin-pod/libsovrin/SovrinErrors.h @@ -34,6 +34,8 @@ typedef NS_ENUM(NSInteger, SovrinErrorCode) // Invalid library state was detected in runtime. It signals library bug CommonInvalidState, + CommonInvalidStructure, + // Wallet errors // Caller passed invalid wallet handle WalletInvalidHandle = 200,