diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 97d456b777..e6ae50b4cf 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -481,7 +481,7 @@ jobs: with: skip-docker-setup: true - name: "Run workspace tests: general_test" - run: RUST_TEST_THREADS=1 cargo test --workspace --lib --exclude aries-vcx-agent --exclude libvdrtools + run: RUST_TEST_THREADS=1 cargo test --workspace --lib --exclude aries-vcx-agent --exclude libvdrtools --exclude wallet_migrator test-integration-aries-vcx: needs: workflow-setup @@ -544,6 +544,20 @@ jobs: - name: "Run aries-vcx tests: pool_tests agency_pool_tests" run: RUST_TEST_THREADS=1 cargo test --manifest-path="aries_vcx/Cargo.toml" -F mixed_breed -- --include-ignored; + test-integration-aries-vcx-migration: + needs: workflow-setup + runs-on: ubuntu-20.04 + steps: + - name: "Git checkout" + uses: actions/checkout@v3 + - name: "Setup rust testing environment" + uses: ./.github/actions/setup-testing-rust + - name: "Run aries-vcx tests: pool_tests agency_pool_tests" + run: | + cargo test --manifest-path="wallet_migrator/Cargo.toml"; + RUST_TEST_THREADS=1 CARGO_INCREMENTAL=0 TEST_POOL_IP=127.0.0.1 cargo test --manifest-path="aries_vcx/Cargo.toml" -F migration --test test_creds_proofs -- --include-ignored; + RUST_TEST_THREADS=1 CARGO_INCREMENTAL=0 TEST_POOL_IP=127.0.0.1 cargo test --manifest-path="aries_vcx/Cargo.toml" -F migration --test test_creds_proofs_revocations -- --include-ignored; + test-integration-libvcx: needs: workflow-setup if: ${{ needs.workflow-setup.outputs.SKIP_CI != 'true' }} diff --git a/Cargo.lock b/Cargo.lock index 11a54df27b..28a20f7e65 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -218,7 +218,6 @@ dependencies = [ "serde_derive", "serde_json", "shared_vcx", - "sqlx 0.5.11", "strum 0.16.0", "strum_macros 0.16.0", "thiserror", @@ -226,6 +225,7 @@ dependencies = [ "tokio", "url", "uuid 0.8.2", + "wallet_migrator", ] [[package]] @@ -554,12 +554,6 @@ version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" -[[package]] -name = "base64ct" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6b4d9b1225d28d360ec6a231d65af1fd99a2a095154c8040689617290569c5c" - [[package]] name = "bincode" version = "1.3.3" @@ -1052,16 +1046,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "ctor" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" -dependencies = [ - "quote", - "syn 1.0.109", -] - [[package]] name = "ctor" version = "0.2.0" @@ -1267,7 +1251,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79b71cca7d95d7681a4b3b9cdf63c8dbc3730d0584c2c74e31416d64a90493f4" dependencies = [ "const-oid", - "crypto-bigint", ] [[package]] @@ -2297,7 +2280,6 @@ version = "0.1.0" dependencies = [ "aes 0.7.5", "bs58 0.4.0", - "failure", "futures", "libc", "log", @@ -2305,7 +2287,8 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "sqlx 0.5.8", + "sqlx", + "thiserror", "ursa", "zeroize", "zmq", @@ -2492,7 +2475,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "sqlx 0.5.8", + "sqlx", "zeroize", ] @@ -2779,11 +2762,10 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" dependencies = [ - "cfg-if 1.0.0", "value-bag", ] @@ -2969,7 +2951,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49ac8112fe5998579b22e29903c7b277fc7f91c7860c0236f35792caf8156e18" dependencies = [ "bitflags 2.3.1", - "ctor 0.2.0", + "ctor", "napi-derive", "napi-sys", "once_cell", @@ -3281,15 +3263,6 @@ dependencies = [ "serde", ] -[[package]] -name = "pem-rfc7468" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84e93a3b1cc0510b03020f33f21e62acdde3dcaef432edc95bea377fbd4c2cd4" -dependencies = [ - "base64ct", -] - [[package]] name = "percent-encoding" version = "2.2.0" @@ -3326,17 +3299,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "pkcs1" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "116bee8279d783c0cf370efa1a94632f2108e5ef0bb32df31f051647810a4e2c" -dependencies = [ - "der", - "pem-rfc7468", - "zeroize", -] - [[package]] name = "pkcs8" version = "0.7.6" @@ -3344,10 +3306,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee3ef9b64d26bad0536099c816c6734379e45bbd5f14798def6809e5cc350447" dependencies = [ "der", - "pem-rfc7468", - "pkcs1", "spki", - "zeroize", ] [[package]] @@ -3842,26 +3801,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "rsa" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e05c2603e2823634ab331437001b411b9ed11660fbc4066f3908c84a9439260d" -dependencies = [ - "byteorder", - "digest 0.9.0", - "lazy_static", - "num-bigint-dig", - "num-integer", - "num-iter", - "num-traits", - "pkcs1", - "pkcs8", - "rand 0.8.5", - "subtle", - "zeroize", -] - [[package]] name = "rustc-demangle" version = "0.1.23" @@ -4254,18 +4193,8 @@ name = "sqlx" version = "0.5.8" source = "git+https://github.com/jovfer/sqlx?branch=feature/json_no_preserve_order_v5#7b9b4b371071e7d29d3b10da5a205460b3fc2de4" dependencies = [ - "sqlx-core 0.5.8", - "sqlx-macros 0.5.8", -] - -[[package]] -name = "sqlx" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc15591eb44ffb5816a4a70a7efd5dd87bfd3aa84c4c200401c4396140525826" -dependencies = [ - "sqlx-core 0.5.11", - "sqlx-macros 0.5.11", + "sqlx-core", + "sqlx-macros", ] [[package]] @@ -4303,7 +4232,7 @@ dependencies = [ "parking_lot", "percent-encoding", "rand 0.8.5", - "rsa 0.4.1", + "rsa", "rustls", "serde", "serde_json", @@ -4311,7 +4240,7 @@ dependencies = [ "sha2 0.9.9", "smallvec", "sqlformat", - "sqlx-rt 0.5.8", + "sqlx-rt", "stringprep", "thiserror", "tokio-stream", @@ -4321,53 +4250,6 @@ dependencies = [ "whoami", ] -[[package]] -name = "sqlx-core" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "195183bf6ff8328bb82c0511a83faf60aacf75840103388851db61d7a9854ae3" -dependencies = [ - "ahash 0.7.6", - "atoi", - "bitflags 1.3.2", - "byteorder", - "bytes", - "crc", - "crossbeam-queue", - "digest 0.9.0", - "either", - "futures-channel", - "futures-core", - "futures-intrusive", - "futures-util", - "generic-array 0.14.7", - "hashlink", - "hex", - "indexmap", - "itoa 1.0.6", - "libc", - "log", - "memchr", - "num-bigint 0.3.3", - "once_cell", - "paste", - "percent-encoding", - "rand 0.8.5", - "rsa 0.5.0", - "rustls", - "sha-1", - "sha2 0.9.9", - "smallvec", - "sqlformat", - "sqlx-rt 0.5.13", - "stringprep", - "thiserror", - "tokio-stream", - "url", - "webpki", - "webpki-roots", -] - [[package]] name = "sqlx-macros" version = "0.5.8" @@ -4381,27 +4263,8 @@ dependencies = [ "quote", "serde_json", "sha2 0.9.9", - "sqlx-core 0.5.8", - "sqlx-rt 0.5.8", - "syn 1.0.109", - "url", -] - -[[package]] -name = "sqlx-macros" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eee35713129561f5e55c554bba1c378e2a7e67f81257b7311183de98c50e6f94" -dependencies = [ - "dotenv", - "either", - "heck 0.3.3", - "once_cell", - "proc-macro2", - "quote", - "sha2 0.9.9", - "sqlx-core 0.5.11", - "sqlx-rt 0.5.13", + "sqlx-core", + "sqlx-rt", "syn 1.0.109", "url", ] @@ -4416,17 +4279,6 @@ dependencies = [ "tokio-rustls", ] -[[package]] -name = "sqlx-rt" -version = "0.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4db708cd3e459078f85f39f96a00960bd841f66ee2a669e90bf36907f5a79aae" -dependencies = [ - "once_cell", - "tokio", - "tokio-rustls", -] - [[package]] name = "static_assertions" version = "1.1.0" @@ -4639,9 +4491,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.28.1" +version = "1.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aa32867d44e6f2ce3385e89dceb990188b8bb0fb25b0cf576647a6f98ac5105" +checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" dependencies = [ "autocfg 1.1.0", "bytes", @@ -5085,13 +4937,9 @@ dependencies = [ [[package]] name = "value-bag" -version = "1.0.0-alpha.9" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2209b78d1249f7e6f3293657c9779fe31ced465df091bbd433a1cf88e916ec55" -dependencies = [ - "ctor 0.1.26", - "version_check", -] +checksum = "a4d330786735ea358f3bc09eea4caa098569c1c93f342d9aca0514915022fe7e" [[package]] name = "vcpkg" @@ -5124,6 +4972,19 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" +[[package]] +name = "wallet_migrator" +version = "0.1.0" +dependencies = [ + "aries_vcx_core", + "indy-credx", + "libvdrtools", + "log", + "serde_json", + "thiserror", + "tokio", +] + [[package]] name = "want" version = "0.3.0" diff --git a/Cargo.toml b/Cargo.toml index 9c81c2e147..74109d99ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,8 @@ members = [ "did_resolver_registry", "did_resolver_sov", "did_resolver_web", - "indy_ledger_response_parser" + "indy_ledger_response_parser", + "wallet_migrator" ] [workspace.package] diff --git a/agency_client/src/agency_client.rs b/agency_client/src/agency_client.rs index 8f21ccb354..6d4b2a5abe 100644 --- a/agency_client/src/agency_client.rs +++ b/agency_client/src/agency_client.rs @@ -11,7 +11,7 @@ use crate::wallet::base_agency_client_wallet::{BaseAgencyClientWallet, StubAgenc #[derive(Clone, Debug)] pub struct AgencyClient { - wallet: Arc, + pub wallet: Arc, pub agency_url: Url, pub agency_did: String, pub agency_vk: String, diff --git a/aries_vcx/Cargo.toml b/aries_vcx/Cargo.toml index 0b6d57069b..535e9dc29e 100644 --- a/aries_vcx/Cargo.toml +++ b/aries_vcx/Cargo.toml @@ -21,6 +21,8 @@ vdr_proxy_ledger = ["aries_vcx_core/vdr_proxy_ledger", "vdrtools"] # Temporary feature used for testing the full credx anoncreds impl # using vdrtools ledger and wallet. mixed_breed = ["vdrtools", "modular_libs"] +# Used for testing the migrator +migration = ["vdrtools", "modular_libs"] [dependencies] agency_client = { path = "../agency_client" } @@ -55,10 +57,6 @@ url = { version = "2.3", features = ["serde"] } android_logger = "0.5" [dev-dependencies] +wallet_migrator = { path = "../wallet_migrator" } async-channel = "1.7.1" tokio = { version = "1.20", features = ["rt", "macros", "rt-multi-thread"] } -sqlx = { version = "0.5", features = [ - "migrate", - "mysql", - "runtime-tokio-rustls", -] } diff --git a/aries_vcx/migrations/20210903123945_migration0.sql b/aries_vcx/migrations/20210903123945_migration0.sql deleted file mode 100644 index 1349eb5a5e..0000000000 --- a/aries_vcx/migrations/20210903123945_migration0.sql +++ /dev/null @@ -1,14 +0,0 @@ -CREATE TABLE `items` ( - `wallet_id` int NOT NULL, - `type` varchar(256) NOT NULL, - `name` varchar(256) NOT NULL, - `value` blob NOT NULL, - `tags` varchar(256) DEFAULT NULL, - PRIMARY KEY (wallet_id, type, name) -); -CREATE TABLE `wallets` ( - `id` int NOT NULL AUTO_INCREMENT, - `name` varchar(64) NOT NULL, - `metadata` varchar(4096) DEFAULT NULL, - PRIMARY KEY (`id`) -); diff --git a/aries_vcx/src/core/profile/modular_libs_profile.rs b/aries_vcx/src/core/profile/modular_libs_profile.rs index cd05136e84..0ffe02b0bd 100644 --- a/aries_vcx/src/core/profile/modular_libs_profile.rs +++ b/aries_vcx/src/core/profile/modular_libs_profile.rs @@ -1,10 +1,8 @@ -use std::ops::Deref; use std::sync::Arc; use std::time::Duration; use aries_vcx_core::anoncreds::base_anoncreds::BaseAnonCreds; use aries_vcx_core::anoncreds::credx_anoncreds::IndyCredxAnonCreds; -use aries_vcx_core::errors::error::VcxCoreResult; use aries_vcx_core::ledger::base_ledger::{ AnoncredsLedgerRead, AnoncredsLedgerWrite, IndyLedgerRead, IndyLedgerWrite, TaaConfigurator, TxnAuthrAgrmtOptions, }; @@ -50,7 +48,7 @@ impl ModularLibsProfile { let response_cacher = Arc::new(InMemoryResponseCacher::new(cacher_config)); let config_read = IndyVdrLedgerReadConfig { - request_submitter: request_submitter.clone(), + request_submitter, response_parser, response_cacher, protocol_version: ProtocolVersion::node_1_4(), diff --git a/aries_vcx/src/core/profile/profile.rs b/aries_vcx/src/core/profile/profile.rs index bf5ecb566e..edd826f015 100644 --- a/aries_vcx/src/core/profile/profile.rs +++ b/aries_vcx/src/core/profile/profile.rs @@ -1,14 +1,18 @@ -use std::sync::{Arc, RwLock}; +use std::sync::Arc; use crate::errors::error::VcxResult; -use aries_vcx_core::ledger::base_ledger::{TaaConfigurator, TxnAuthrAgrmtOptions}; +use aries_vcx_core::ledger::base_ledger::TxnAuthrAgrmtOptions; use aries_vcx_core::{ anoncreds::base_anoncreds::BaseAnonCreds, ledger::base_ledger::{AnoncredsLedgerRead, AnoncredsLedgerWrite, IndyLedgerRead, IndyLedgerWrite}, wallet::base_wallet::BaseWallet, }; + use async_trait::async_trait; +#[cfg(feature = "migration")] +use aries_vcx_core::WalletHandle; + #[async_trait] pub trait Profile: std::fmt::Debug + Send + Sync { fn inject_indy_ledger_read(&self) -> Arc; @@ -23,5 +27,10 @@ pub trait Profile: std::fmt::Debug + Send + Sync { fn inject_wallet(&self) -> Arc; + #[cfg(feature = "migration")] + fn wallet_handle(&self) -> Option { + None + } + fn update_taa_configuration(&self, taa_options: TxnAuthrAgrmtOptions) -> VcxResult<()>; } diff --git a/aries_vcx/src/core/profile/vdrtools_profile.rs b/aries_vcx/src/core/profile/vdrtools_profile.rs index d0c9430272..d3c379dc9a 100644 --- a/aries_vcx/src/core/profile/vdrtools_profile.rs +++ b/aries_vcx/src/core/profile/vdrtools_profile.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use super::profile::Profile; use crate::errors::error::{AriesVcxError, AriesVcxErrorKind, VcxResult}; -use aries_vcx_core::ledger::base_ledger::{TaaConfigurator, TxnAuthrAgrmtOptions}; +use aries_vcx_core::ledger::base_ledger::TxnAuthrAgrmtOptions; use aries_vcx_core::{ anoncreds::{base_anoncreds::BaseAnonCreds, indy_anoncreds::IndySdkAnonCreds}, ledger::{ @@ -16,7 +16,7 @@ use async_trait::async_trait; #[derive(Debug)] pub struct VdrtoolsProfile { - wallet: Arc, + wallet: Arc, anoncreds: Arc, anoncreds_ledger_read: Arc, anoncreds_ledger_write: Arc, @@ -64,7 +64,12 @@ impl Profile for VdrtoolsProfile { } fn inject_wallet(&self) -> Arc { - Arc::clone(&self.wallet) + self.wallet.clone() + } + + #[cfg(feature = "migration")] + fn wallet_handle(&self) -> Option { + Some(self.wallet.wallet_handle) } fn update_taa_configuration(&self, _taa_options: TxnAuthrAgrmtOptions) -> VcxResult<()> { diff --git a/aries_vcx/src/utils/devsetup.rs b/aries_vcx/src/utils/devsetup.rs index 5ed1baf183..9005b33017 100644 --- a/aries_vcx/src/utils/devsetup.rs +++ b/aries_vcx/src/utils/devsetup.rs @@ -89,7 +89,7 @@ pub struct SetupWalletPool { pub struct SetupProfile { pub institution_did: String, pub profile: Arc, - pub(self) teardown: Arc BoxFuture<'static, ()>>, + pub(self) teardown: Arc BoxFuture<'static, ()> + Send + Sync>, } pub struct SetupInstitutionWallet { @@ -373,6 +373,14 @@ impl SetupProfile { init_test_logging(); set_test_configs(); + // We have to start with the vdrtools profile + // in order to perform the migration + #[cfg(feature = "migration")] + return { + info!("SetupProfile >> using indy profile"); + SetupProfile::init_indy().await + }; + #[cfg(feature = "mixed_breed")] return { info!("SetupProfile >> using mixed breed profile"); @@ -398,8 +406,6 @@ impl SetupProfile { }; } - // FUTURE - ideally no tests should be using this method, they should be using the generic init - // after modular profile Anoncreds/Ledger methods have all been implemented, all tests should use init() #[cfg(feature = "vdrtools")] async fn init_indy() -> SetupProfile { let (institution_did, wallet_handle) = setup_issuer_wallet().await; diff --git a/aries_vcx/tests/test_creds_proofs.rs b/aries_vcx/tests/test_creds_proofs.rs index 32e5e08fd4..87a04cf23c 100644 --- a/aries_vcx/tests/test_creds_proofs.rs +++ b/aries_vcx/tests/test_creds_proofs.rs @@ -28,10 +28,13 @@ mod integration_tests { }; use messages::AriesMessage; + #[cfg(feature = "migration")] + use crate::utils::migration::Migratable; + #[tokio::test] #[ignore] async fn test_agency_pool_retrieve_credentials() { - SetupProfile::run(|setup| async move { + SetupProfile::run(|mut setup: SetupProfile| async move { create_and_store_nonrevocable_credential( &setup.profile.inject_anoncreds(), &setup.profile.inject_anoncreds(), @@ -41,6 +44,10 @@ mod integration_tests { DEFAULT_SCHEMA_ATTRS, ) .await; + + #[cfg(feature = "migration")] + setup.migrate().await; + let (_, _, req, _) = create_indy_proof( &setup.profile.inject_anoncreds(), &setup.profile.inject_anoncreds(), @@ -82,7 +89,7 @@ mod integration_tests { #[tokio::test] #[ignore] async fn test_agency_pool_get_credential_def() { - SetupProfile::run(|setup| async move { + SetupProfile::run(|mut setup| async move { let (_, _, cred_def_id, cred_def_json, _) = create_and_store_nonrevocable_credential_def( &setup.profile.inject_anoncreds(), &setup.profile.inject_anoncreds_ledger_read(), @@ -92,6 +99,9 @@ mod integration_tests { ) .await; + #[cfg(feature = "migration")] + setup.migrate().await; + let ledger = Arc::clone(&setup.profile).inject_anoncreds_ledger_read(); let r_cred_def_json = ledger.get_cred_def(&cred_def_id, None).await.unwrap(); @@ -105,7 +115,7 @@ mod integration_tests { #[tokio::test] #[ignore] async fn test_agency_pool_retrieve_credentials_empty() { - SetupProfile::run(|setup| async move { + SetupProfile::run(|mut setup| async move { // create skeleton proof request attachment data let mut req = json!({ "nonce":"123432421212", @@ -133,6 +143,9 @@ mod integration_tests { let proof_req = RequestPresentation::with_decorators(id, content, decorators); let proof: Prover = Prover::create_from_request("1", proof_req).unwrap(); + #[cfg(feature = "migration")] + setup.migrate().await; + let retrieved_creds = proof .retrieve_credentials(&setup.profile.inject_anoncreds()) .await @@ -181,7 +194,7 @@ mod integration_tests { #[tokio::test] #[ignore] async fn test_agency_pool_case_for_proof_req_doesnt_matter_for_retrieve_creds() { - SetupProfile::run(|setup| async move { + SetupProfile::run(|mut setup| async move { create_and_store_nonrevocable_credential( &setup.profile.inject_anoncreds(), &setup.profile.inject_anoncreds(), @@ -248,6 +261,9 @@ mod integration_tests { let content = RequestPresentationContent::new(vec![attach]); let decorators = RequestPresentationDecorators::default(); + #[cfg(feature = "migration")] + setup.migrate().await; + let proof_req = RequestPresentation::with_decorators(id, content, decorators); let proof: Prover = Prover::create_from_request("2", proof_req).unwrap(); let retrieved_creds2 = proof @@ -296,7 +312,7 @@ mod integration_tests { #[tokio::test] #[ignore] async fn test_agency_pool_generate_proof() { - SetupProfile::run(|setup| async move { + SetupProfile::run(|mut setup| async move { create_and_store_credential( &setup.profile.inject_anoncreds(), &setup.profile.inject_anoncreds(), @@ -323,10 +339,13 @@ mod integration_tests { "name":"self_attested_attr", }), "requested_predicates": {}, - "non_revoked": {"from": 098, "to": to} + "non_revoked": {"from": 98, "to": to} }) .to_string(); + #[cfg(feature = "migration")] + setup.migrate().await; + let pres_req_data: PresentationRequestData = serde_json::from_str(&indy_proof_req).unwrap(); let id = "test_id".to_owned(); @@ -382,7 +401,7 @@ mod integration_tests { #[tokio::test] #[ignore] async fn test_agency_pool_generate_proof_with_predicates() { - SetupProfile::run(|setup| async move { + SetupProfile::run(|mut setup| async move { create_and_store_credential( &setup.profile.inject_anoncreds(), &setup.profile.inject_anoncreds(), @@ -411,7 +430,7 @@ mod integration_tests { "requested_predicates": json!({ "zip_3": {"name":"zip", "p_type":">=", "p_value":18} }), - "non_revoked": {"from": 098, "to": to} + "non_revoked": {"from": 98, "to": to} }) .to_string(); @@ -432,6 +451,9 @@ mod integration_tests { let proof_req = RequestPresentation::with_decorators(id, content, decorators); let mut proof: Prover = Prover::create_from_request("1", proof_req).unwrap(); + #[cfg(feature = "migration")] + setup.migrate().await; + let all_creds = proof .retrieve_credentials(&setup.profile.inject_anoncreds()) .await @@ -473,7 +495,7 @@ mod integration_tests { #[tokio::test] #[ignore] async fn test_agency_pool_generate_self_attested_proof() { - SetupProfile::run(|setup| async move { + SetupProfile::run(|mut setup| async move { let indy_proof_req = json!({ "nonce":"123432421212", "name":"proof_req_1", @@ -494,6 +516,9 @@ mod integration_tests { let presentation_request = verifier.get_presentation_request_msg().unwrap(); verifier.mark_presentation_request_msg_sent().unwrap(); + #[cfg(feature = "migration")] + setup.migrate().await; + // prover receives request and generates presentation let mut proof: Prover = Prover::create_from_request("1", presentation_request).unwrap(); @@ -533,7 +558,6 @@ mod integration_tests { } } -#[cfg(test)] mod tests { use std::collections::HashMap; use std::time::Duration; @@ -564,7 +588,8 @@ mod tests { send_proof_proposal_1, send_proof_request, verifier_create_proof_and_send_request, verify_proof, }; - use super::*; + #[cfg(feature = "migration")] + use crate::utils::migration::Migratable; #[tokio::test] #[ignore] @@ -583,6 +608,10 @@ mod tests { &institution_to_consumer, ) .await; + + #[cfg(feature = "migration")] + institution.migrate().await; + let requested_attrs_string = serde_json::to_string(&json!([ { "name": "address1", @@ -608,6 +637,9 @@ mod tests { ) .await; + #[cfg(feature = "migration")] + consumer.migrate().await; + prover_select_credentials_and_send_proof(&mut consumer, &consumer_to_institution, None, None).await; info!("test_proof_should_be_validated :: verifier :: going to verify proof"); @@ -645,6 +677,10 @@ mod tests { &institution_to_consumer, ) .await; + + #[cfg(feature = "migration")] + institution.migrate().await; + let requested_preds_string = serde_json::to_string(&json!([ { "name": "zip", @@ -667,6 +703,9 @@ mod tests { ) .await; + #[cfg(feature = "migration")] + consumer.migrate().await; + prover_select_credentials_and_send_proof(&mut consumer, &consumer_to_institution, None, None).await; info!("test_proof_with_predicates_should_be_validated :: verifier :: going to verify proof"); @@ -708,6 +747,10 @@ mod tests { &institution_to_consumer, ) .await; + + #[cfg(feature = "migration")] + institution.migrate().await; + let requested_preds_string = serde_json::to_string(&json!([ { "name": "zip", @@ -720,6 +763,7 @@ mod tests { "test_basic_proof :: Going to seng proof request with attributes {}", &requested_preds_string ); + send_proof_request( &mut institution, &institution_to_consumer, @@ -730,6 +774,9 @@ mod tests { ) .await; + #[cfg(feature = "migration")] + consumer.migrate().await; + prover_select_credentials_and_fail_to_generate_proof(&mut consumer, &consumer_to_institution, None, None) .await; }) @@ -754,6 +801,9 @@ mod tests { let (consumer2_to_issuer, issuer_to_consumer2) = create_connected_connections(&mut consumer2, &mut issuer).await; + #[cfg(feature = "migration")] + issuer.migrate().await; + let (schema_id, _schema_json, cred_def_id, _cred_def_json, cred_def, rev_reg, _rev_reg_id) = _create_address_schema(&issuer.profile, &issuer.config_issuer.institution_did).await; let (address1, address2, city, state, zip) = attr_names(); @@ -769,6 +819,10 @@ mod tests { None, ) .await; + + #[cfg(feature = "migration")] + verifier.migrate().await; + let credential_data2 = json!({address1.clone(): "101 Tela Lane", address2.clone(): "Suite 1", city.clone(): "SLC", state.clone(): "WA", zip.clone(): "8721"}).to_string(); let _credential_handle2 = _exchange_credential( &mut consumer2, @@ -791,6 +845,10 @@ mod tests { request_name1, ) .await; + + #[cfg(feature = "migration")] + consumer1.migrate().await; + prover_select_credentials_and_send_proof(&mut consumer1, &consumer1_to_verifier, None, None).await; proof_verifier .update_state( @@ -811,6 +869,10 @@ mod tests { request_name2, ) .await; + + #[cfg(feature = "migration")] + consumer2.migrate().await; + prover_select_credentials_and_send_proof(&mut consumer2, &consumer2_to_verifier, None, None).await; proof_verifier .update_state( @@ -844,6 +906,10 @@ mod tests { let (schema_id, cred_def_id, _rev_reg_id, _cred_def, _rev_reg, _credential_handle) = issue_address_credential(&mut consumer, &mut issuer, &consumer_to_issuer, &issuer_to_consumer).await; + + #[cfg(feature = "migration")] + issuer.migrate().await; + let request_name1 = Some("request1"); let mut proof_verifier = verifier_create_proof_and_send_request( &mut verifier, @@ -853,6 +919,10 @@ mod tests { request_name1, ) .await; + + #[cfg(feature = "migration")] + verifier.migrate().await; + prover_select_credentials_and_send_proof(&mut consumer, &consumer_to_verifier, request_name1, None).await; proof_verifier .update_state( @@ -878,6 +948,10 @@ mod tests { request_name2, ) .await; + + #[cfg(feature = "migration")] + consumer.migrate().await; + prover_select_credentials_and_send_proof(&mut consumer, &consumer_to_verifier, request_name2, None).await; proof_verifier .update_state( @@ -932,6 +1006,10 @@ mod tests { request_name1, ) .await; + + #[cfg(feature = "migration")] + institution.migrate().await; + prover_select_credentials_and_send_proof(&mut consumer, &consumer_to_institution, request_name1, None).await; verifier .update_state( @@ -957,6 +1035,10 @@ mod tests { request_name2, ) .await; + + #[cfg(feature = "migration")] + consumer.migrate().await; + prover_select_credentials_and_send_proof(&mut consumer, &consumer_to_institution, request_name2, None).await; verifier .update_state( @@ -1007,6 +1089,10 @@ mod tests { for i in 1..number_of_attributes { credential_data[format!("key{}", i)] = Value::String(format!("value{}", i)); } + + #[cfg(feature = "migration")] + institution.migrate().await; + info!("test_real_proof :: sending credential offer"); let credential_data = credential_data.to_string(); info!("test_real_proof :: generated credential data: {}", credential_data); @@ -1023,6 +1109,9 @@ mod tests { info!("test_real_proof :: AS CONSUMER SEND CREDENTIAL REQUEST"); let mut holder_credential = send_cred_req(&mut consumer, &consumer_to_issuer, None).await; + #[cfg(feature = "migration")] + consumer.migrate().await; + info!("test_real_proof :: AS INSTITUTION SEND CREDENTIAL"); send_credential( &mut consumer, @@ -1129,6 +1218,10 @@ mod tests { req1, ) .await; + + #[cfg(feature = "migration")] + issuer.migrate().await; + let credential_data2 = json!({address1.clone(): "101 Tela Lane", address2.clone(): "Suite 1", city.clone(): "SLC", state.clone(): "WA", zip.clone(): "8721"}).to_string(); let _credential_handle2 = _exchange_credential( &mut consumer, @@ -1142,6 +1235,9 @@ mod tests { ) .await; + #[cfg(feature = "migration")] + verifier.migrate().await; + let mut proof_verifier = verifier_create_proof_and_send_request( &mut verifier, &verifier_to_consumer, @@ -1170,6 +1266,11 @@ mod tests { req2, ) .await; + + + #[cfg(feature = "migration")] + consumer.migrate().await; + prover_select_credentials_and_send_proof(&mut consumer, &consumer_to_verifier, req2, Some(&credential_data2)) .await; proof_verifier @@ -1186,7 +1287,7 @@ mod tests { #[tokio::test] #[ignore] - pub async fn test_agency_pool_credential_exchange_via_proposal() { + async fn test_agency_pool_credential_exchange_via_proposal() { SetupPool::run(|setup| async move { let mut institution = Faber::setup(setup.pool_handle).await; let mut consumer = create_test_alice_instance(&setup).await; @@ -1197,6 +1298,9 @@ mod tests { _create_address_schema(&institution.profile, &institution.config_issuer.institution_did).await; let tails_file = rev_reg.get_tails_dir(); + #[cfg(feature = "migration")] + institution.migrate().await; + _exchange_credential_with_proposal( &mut consumer, &mut institution, @@ -1215,7 +1319,7 @@ mod tests { #[tokio::test] #[ignore] - pub async fn test_agency_pool_credential_exchange_via_proposal_failed() { + async fn test_agency_pool_credential_exchange_via_proposal_failed() { SetupPool::run(|setup| async move { let mut institution = Faber::setup(setup.pool_handle).await; let mut consumer = create_test_alice_instance(&setup).await; @@ -1234,6 +1338,10 @@ mod tests { "comment", ) .await; + + #[cfg(feature = "migration")] + institution.migrate().await; + let mut issuer = accept_cred_proposal(&mut institution, &institution_to_consumer, rev_reg_id, Some(tails_file)).await; decline_offer(&mut consumer, &consumer_to_institution, &mut holder).await; @@ -1255,7 +1363,7 @@ mod tests { #[tokio::test] #[ignore] - pub async fn test_agency_pool_credential_exchange_via_proposal_with_negotiation() { + async fn test_agency_pool_credential_exchange_via_proposal_with_negotiation() { SetupPool::run(|setup| async move { let mut institution = Faber::setup(setup.pool_handle).await; let mut consumer = create_test_alice_instance(&setup).await; @@ -1266,6 +1374,9 @@ mod tests { _create_address_schema(&institution.profile, &institution.config_issuer.institution_did).await; let tails_file = rev_reg.get_tails_dir(); + #[cfg(feature = "migration")] + institution.migrate().await; + let mut holder = send_cred_proposal( &mut consumer, &consumer_to_institution, @@ -1281,6 +1392,10 @@ mod tests { Some(tails_file.clone()), ) .await; + + #[cfg(feature = "migration")] + consumer.migrate().await; + send_cred_proposal_1( &mut holder, &mut consumer, @@ -1316,7 +1431,7 @@ mod tests { #[tokio::test] #[ignore] - pub async fn test_agency_pool_presentation_via_proposal() { + async fn test_agency_pool_presentation_via_proposal() { SetupPool::run(|setup| async move { let mut institution = Faber::setup(setup.pool_handle).await; let mut consumer = create_test_alice_instance(&setup).await; @@ -1327,6 +1442,9 @@ mod tests { _create_address_schema(&institution.profile, &institution.config_issuer.institution_did).await; let tails_file = rev_reg.get_tails_dir(); + #[cfg(feature = "migration")] + institution.migrate().await; + _exchange_credential_with_proposal( &mut consumer, &mut institution, @@ -1342,6 +1460,10 @@ mod tests { let mut prover = send_proof_proposal(&mut consumer, &consumer_to_institution, &cred_def_id).await; let mut verifier = Verifier::create("1").unwrap(); accept_proof_proposal(&mut institution, &mut verifier, &institution_to_consumer).await; + + #[cfg(feature = "migration")] + consumer.migrate().await; + let selected_credentials = prover_select_credentials(&mut prover, &mut consumer, &consumer_to_institution, None).await; generate_and_send_proof( @@ -1358,7 +1480,7 @@ mod tests { #[tokio::test] #[ignore] - pub async fn test_agency_pool_presentation_via_proposal_with_rejection() { + async fn test_agency_pool_presentation_via_proposal_with_rejection() { SetupPool::run(|setup| async move { let mut institution = Faber::setup(setup.pool_handle).await; let mut consumer = create_test_alice_instance(&setup).await; @@ -1369,6 +1491,9 @@ mod tests { _create_address_schema(&institution.profile, &institution.config_issuer.institution_did).await; let tails_file = rev_reg.get_tails_dir(); + #[cfg(feature = "migration")] + institution.migrate().await; + _exchange_credential_with_proposal( &mut consumer, &mut institution, @@ -1390,7 +1515,7 @@ mod tests { #[tokio::test] #[ignore] - pub async fn test_agency_pool_presentation_via_proposal_with_negotiation() { + async fn test_agency_pool_presentation_via_proposal_with_negotiation() { SetupPool::run(|setup| async move { let mut institution = Faber::setup(setup.pool_handle).await; let mut consumer = create_test_alice_instance(&setup).await; @@ -1401,6 +1526,9 @@ mod tests { _create_address_schema(&institution.profile, &institution.config_issuer.institution_did).await; let tails_file = rev_reg.get_tails_dir(); + #[cfg(feature = "migration")] + institution.migrate().await; + _exchange_credential_with_proposal( &mut consumer, &mut institution, @@ -1415,6 +1543,10 @@ mod tests { .await; let mut prover = send_proof_proposal(&mut consumer, &consumer_to_institution, &cred_def_id).await; let mut verifier = Verifier::create("1").unwrap(); + + #[cfg(feature = "migration")] + consumer.migrate().await; + accept_proof_proposal(&mut institution, &mut verifier, &institution_to_consumer).await; send_proof_proposal_1(&mut consumer, &mut prover, &consumer_to_institution, &cred_def_id).await; accept_proof_proposal(&mut institution, &mut verifier, &institution_to_consumer).await; @@ -1447,6 +1579,9 @@ mod tests { faber.create_nonrevocable_credential_definition().await; + #[cfg(feature = "migration")] + faber.migrate().await; + // Connection let invite = faber.create_invite().await; alice.accept_invite(&invite).await; @@ -1455,6 +1590,9 @@ mod tests { alice.update_state(4).await; faber.update_state(4).await; + #[cfg(feature = "migration")] + alice.migrate().await; + // Credential issuance faber.offer_non_revocable_credential().await; alice.accept_offer().await; @@ -1485,6 +1623,9 @@ mod tests { faber.create_nonrevocable_credential_definition().await; + #[cfg(feature = "migration")] + faber.migrate().await; + // Connection let invite = faber.create_invite().await; alice.accept_invite(&invite).await; @@ -1524,6 +1665,9 @@ mod tests { assert_eq!(HolderState::RequestSent, alice.credential.get_state()); } + #[cfg(feature = "migration")] + alice.migrate().await; + faber.send_credential().await; alice.accept_credential().await; @@ -1584,6 +1728,9 @@ mod tests { faber.create_nonrevocable_credential_definition().await; + #[cfg(feature = "migration")] + faber.migrate().await; + // Connection let invite = faber.create_invite().await; alice.accept_invite(&invite).await; @@ -1633,6 +1780,9 @@ mod tests { faber.send_credential().await; alice.accept_credential().await; + #[cfg(feature = "migration")] + alice.migrate().await; + // Credential Presentation faber.request_presentation().await; diff --git a/aries_vcx/tests/test_creds_proofs_revocations.rs b/aries_vcx/tests/test_creds_proofs_revocations.rs index 22651df766..dc42677673 100644 --- a/aries_vcx/tests/test_creds_proofs_revocations.rs +++ b/aries_vcx/tests/test_creds_proofs_revocations.rs @@ -5,7 +5,6 @@ extern crate serde_json; pub mod utils; -#[cfg(test)] mod integration_tests { use std::time::Duration; @@ -23,6 +22,9 @@ mod integration_tests { verifier_create_proof_and_send_request, }; + #[cfg(feature = "migration")] + use crate::utils::migration::Migratable; + use super::*; #[tokio::test] @@ -42,6 +44,9 @@ mod integration_tests { ) .await; + #[cfg(feature = "migration")] + institution.migrate().await; + assert!(!issuer_credential .is_revoked(&institution.profile.inject_anoncreds_ledger_read()) .await @@ -51,6 +56,9 @@ mod integration_tests { info!("test_basic_revocation :: verifier :: Going to revoke credential"); revoke_credential_and_publish_accumulator(&mut institution, &issuer_credential, &rev_reg).await; + #[cfg(feature = "migration")] + consumer.migrate().await; + tokio::time::sleep(Duration::from_millis(1000)).await; let time_after_revocation = time::OffsetDateTime::now_utc().unix_timestamp() as u64; @@ -124,6 +132,9 @@ mod integration_tests { ) .await; + #[cfg(feature = "migration")] + institution.migrate().await; + assert!(!issuer_credential .is_revoked(&institution.profile.inject_anoncreds_ledger_read()) .await @@ -133,6 +144,9 @@ mod integration_tests { revoke_credential_and_publish_accumulator(&mut institution, &issuer_credential, &rev_reg).await; tokio::time::sleep(Duration::from_millis(1000)).await; + #[cfg(feature = "migration")] + consumer.migrate().await; + assert!(issuer_credential .is_revoked(&institution.profile.inject_anoncreds_ledger_read()) .await @@ -188,6 +202,9 @@ mod integration_tests { ) .await; + #[cfg(feature = "migration")] + institution.migrate().await; + revoke_credential_local(&mut institution, &issuer_credential, &rev_reg.rev_reg_id).await; assert!(!issuer_credential .is_revoked(&institution.profile.inject_anoncreds_ledger_read()) @@ -202,6 +219,10 @@ mod integration_tests { request_name1, ) .await; + + #[cfg(feature = "migration")] + consumer.migrate().await; + prover_select_credentials_and_send_proof(&mut consumer, &consumer_to_institution, request_name1, None) .await; @@ -267,223 +288,175 @@ mod integration_tests { #[ignore] async fn test_agency_batch_revocation() { SetupPool::run(|setup| async move { - let mut institution = Faber::setup(setup.pool_handle).await; - let mut consumer1 = create_test_alice_instance(&setup).await; - let mut consumer2 = create_test_alice_instance(&setup).await; - let mut consumer3 = create_test_alice_instance(&setup).await; - - let (consumer_to_institution1, institution_to_consumer1) = - create_connected_connections(&mut consumer1, &mut institution).await; - let (consumer_to_institution2, institution_to_consumer2) = - create_connected_connections(&mut consumer2, &mut institution).await; - let (consumer_to_institution3, institution_to_consumer3) = - create_connected_connections(&mut consumer3, &mut institution).await; - - // Issue and send three credentials of the same schema - let (schema_id, _schema_json, cred_def_id, _cred_def_json, cred_def, rev_reg, _rev_reg_id) = - _create_address_schema(&institution.profile, &institution.config_issuer.institution_did).await; - let (address1, address2, city, state, zip) = attr_names(); - let credential_data1 = json!({address1.clone(): "123 Main St", address2.clone(): "Suite 3", city.clone(): "Draper", state.clone(): "UT", zip.clone(): "84000"}).to_string(); - let issuer_credential1 = _exchange_credential( - &mut consumer1, - &mut institution, - credential_data1, - &cred_def, - &rev_reg, - &consumer_to_institution1, - &institution_to_consumer1, - None, - ) - .await; - let credential_data2 = json!({address1.clone(): "101 Tela Lane", address2.clone(): "Suite 1", city.clone(): "SLC", state.clone(): "WA", zip.clone(): "8721"}).to_string(); - let issuer_credential2 = _exchange_credential( - &mut consumer2, - &mut institution, - credential_data2, - &cred_def, - &rev_reg, - &consumer_to_institution2, - &institution_to_consumer2, - None, - ) - .await; - let credential_data3 = json!({address1.clone(): "5th Avenue", address2.clone(): "Suite 1234", city.clone(): "NYC", state.clone(): "NYS", zip.clone(): "84712"}).to_string(); - let issuer_credential3 = _exchange_credential( - &mut consumer3, - &mut institution, - credential_data3, - &cred_def, - &rev_reg, - &consumer_to_institution3, - &institution_to_consumer3, - None, - ) - .await; - - revoke_credential_local(&mut institution, &issuer_credential1, &rev_reg.rev_reg_id).await; - revoke_credential_local(&mut institution, &issuer_credential2, &rev_reg.rev_reg_id).await; - assert!(!issuer_credential1.is_revoked(&institution.profile.inject_anoncreds_ledger_read()).await.unwrap()); - assert!(!issuer_credential2.is_revoked(&institution.profile.inject_anoncreds_ledger_read()).await.unwrap()); - assert!(!issuer_credential3.is_revoked(&institution.profile.inject_anoncreds_ledger_read()).await.unwrap()); - - // Revoke two locally and verify their are all still valid - let request_name1 = Some("request1"); - let mut verifier1 = verifier_create_proof_and_send_request( - &mut institution, - &institution_to_consumer1, - &schema_id, - &cred_def_id, - request_name1, - ) - .await; - prover_select_credentials_and_send_proof(&mut consumer1, &consumer_to_institution1, request_name1, None).await; - let mut verifier2 = verifier_create_proof_and_send_request( - &mut institution, - &institution_to_consumer2, - &schema_id, - &cred_def_id, - request_name1, - ) - .await; - prover_select_credentials_and_send_proof(&mut consumer2, &consumer_to_institution2, request_name1, None).await; - let mut verifier3 = verifier_create_proof_and_send_request( - &mut institution, - &institution_to_consumer3, - &schema_id, - &cred_def_id, - request_name1, - ) - .await; - prover_select_credentials_and_send_proof(&mut consumer3, &consumer_to_institution3, request_name1, None).await; - - verifier1 - .update_state( - &institution.profile.inject_wallet(), - &institution.profile.inject_anoncreds_ledger_read(), - &institution.profile.inject_anoncreds(), - &institution.agency_client, + let mut institution = Faber::setup(setup.pool_handle).await; + let mut consumer1 = create_test_alice_instance(&setup).await; + let mut consumer2 = create_test_alice_instance(&setup).await; + let mut consumer3 = create_test_alice_instance(&setup).await; + + let (consumer_to_institution1, institution_to_consumer1) = create_connected_connections(&mut consumer1, &mut institution).await; + let (consumer_to_institution2, institution_to_consumer2) = create_connected_connections(&mut consumer2, &mut institution).await; + let (consumer_to_institution3, institution_to_consumer3) = create_connected_connections(&mut consumer3, &mut institution).await; + + // Issue and send three credentials of the same schema + let (schema_id, _schema_json, cred_def_id, _cred_def_json, cred_def, rev_reg, _rev_reg_id) = _create_address_schema(&institution.profile, &institution.config_issuer.institution_did).await; + let (address1, address2, city, state, zip) = attr_names(); + let credential_data1 = json!({address1.clone(): "123 Main St", address2.clone(): "Suite 3", city.clone(): "Draper", state.clone(): "UT", zip.clone(): "84000"}).to_string(); + let issuer_credential1 = _exchange_credential( + &mut consumer1, + &mut institution, + credential_data1, + &cred_def, + &rev_reg, + &consumer_to_institution1, &institution_to_consumer1, + None, ) - .await - .unwrap(); - verifier2 - .update_state( - &institution.profile.inject_wallet(), - &institution.profile.inject_anoncreds_ledger_read(), - &institution.profile.inject_anoncreds(), - &institution.agency_client, + .await; + + #[cfg(feature = "migration")] + institution.migrate().await; + + let credential_data2 = json!({address1.clone(): "101 Tela Lane", address2.clone(): "Suite 1", city.clone(): "SLC", state.clone(): "WA", zip.clone(): "8721"}).to_string(); + let issuer_credential2 = _exchange_credential( + &mut consumer2, + &mut institution, + credential_data2, + &cred_def, + &rev_reg, + &consumer_to_institution2, &institution_to_consumer2, + None, ) - .await - .unwrap(); - verifier3 - .update_state( - &institution.profile.inject_wallet(), - &institution.profile.inject_anoncreds_ledger_read(), - &institution.profile.inject_anoncreds(), - &institution.agency_client, + .await; + + #[cfg(feature = "migration")] + consumer1.migrate().await; + + let credential_data3 = json!({address1.clone(): "5th Avenue", address2.clone(): "Suite 1234", city.clone(): "NYC", state.clone(): "NYS", zip.clone(): "84712"}).to_string(); + let issuer_credential3 = _exchange_credential( + &mut consumer3, + &mut institution, + credential_data3, + &cred_def, + &rev_reg, + &consumer_to_institution3, &institution_to_consumer3, + None, ) - .await - .unwrap(); - assert_eq!( - verifier1.get_verification_status(), - PresentationVerificationStatus::Valid - ); - assert_eq!( - verifier2.get_verification_status(), - PresentationVerificationStatus::Valid - ); - assert_eq!( - verifier3.get_verification_status(), - PresentationVerificationStatus::Valid - ); + .await; - // Publish revocations and verify the two are invalid, third still valid - publish_revocation(&mut institution, &rev_reg).await; - tokio::time::sleep(Duration::from_millis(1000)).await; - - assert!(issuer_credential1.is_revoked(&institution.profile.inject_anoncreds_ledger_read()).await.unwrap()); - assert!(issuer_credential2.is_revoked(&institution.profile.inject_anoncreds_ledger_read()).await.unwrap()); - assert!(!issuer_credential3.is_revoked(&institution.profile.inject_anoncreds_ledger_read()).await.unwrap()); - - let request_name2 = Some("request2"); - let mut verifier1 = verifier_create_proof_and_send_request( - &mut institution, - &institution_to_consumer1, - &schema_id, - &cred_def_id, - request_name2, - ) - .await; - prover_select_credentials_and_send_proof(&mut consumer1, &consumer_to_institution1, request_name2, None).await; - let mut verifier2 = verifier_create_proof_and_send_request( - &mut institution, - &institution_to_consumer2, - &schema_id, - &cred_def_id, - request_name2, - ) - .await; - prover_select_credentials_and_send_proof(&mut consumer2, &consumer_to_institution2, request_name2, None).await; - let mut verifier3 = verifier_create_proof_and_send_request( - &mut institution, - &institution_to_consumer3, - &schema_id, - &cred_def_id, - request_name2, - ) + revoke_credential_local(&mut institution, &issuer_credential1, &rev_reg.rev_reg_id).await; + revoke_credential_local(&mut institution, &issuer_credential2, &rev_reg.rev_reg_id).await; + assert!(!issuer_credential1.is_revoked(&institution.profile.inject_anoncreds_ledger_read()).await.unwrap()); + assert!(!issuer_credential2.is_revoked(&institution.profile.inject_anoncreds_ledger_read()).await.unwrap()); + assert!(!issuer_credential3.is_revoked(&institution.profile.inject_anoncreds_ledger_read()).await.unwrap()); + + // Revoke two locally and verify their are all still valid + let request_name1 = Some("request1"); + let mut verifier1 = verifier_create_proof_and_send_request(&mut institution, &institution_to_consumer1, &schema_id, &cred_def_id, request_name1).await; + + #[cfg(feature = "migration")] + consumer2.migrate().await; + + #[cfg(feature = "migration")] + consumer3.migrate().await; + + prover_select_credentials_and_send_proof(&mut consumer1, &consumer_to_institution1, request_name1, None).await; + let mut verifier2 = verifier_create_proof_and_send_request(&mut institution, &institution_to_consumer2, &schema_id, &cred_def_id, request_name1).await; + prover_select_credentials_and_send_proof(&mut consumer2, &consumer_to_institution2, request_name1, None).await; + let mut verifier3 = verifier_create_proof_and_send_request(&mut institution, &institution_to_consumer3, &schema_id, &cred_def_id, request_name1).await; + prover_select_credentials_and_send_proof(&mut consumer3, &consumer_to_institution3, request_name1, None).await; + + verifier1 + .update_state( + &institution.profile.inject_wallet(), + &institution.profile.inject_anoncreds_ledger_read(), + &institution.profile.inject_anoncreds(), + &institution.agency_client, + &institution_to_consumer1, + ) + .await + .unwrap(); + verifier2 + .update_state( + &institution.profile.inject_wallet(), + &institution.profile.inject_anoncreds_ledger_read(), + &institution.profile.inject_anoncreds(), + &institution.agency_client, + &institution_to_consumer2, + ) + .await + .unwrap(); + verifier3 + .update_state( + &institution.profile.inject_wallet(), + &institution.profile.inject_anoncreds_ledger_read(), + &institution.profile.inject_anoncreds(), + &institution.agency_client, + &institution_to_consumer3, + ) + .await + .unwrap(); + assert_eq!(verifier1.get_verification_status(), PresentationVerificationStatus::Valid); + assert_eq!(verifier2.get_verification_status(), PresentationVerificationStatus::Valid); + assert_eq!(verifier3.get_verification_status(), PresentationVerificationStatus::Valid); + + // Publish revocations and verify the two are invalid, third still valid + publish_revocation(&mut institution, &rev_reg).await; + tokio::time::sleep(Duration::from_millis(1000)).await; + + assert!(issuer_credential1.is_revoked(&institution.profile.inject_anoncreds_ledger_read()).await.unwrap()); + assert!(issuer_credential2.is_revoked(&institution.profile.inject_anoncreds_ledger_read()).await.unwrap()); + assert!(!issuer_credential3.is_revoked(&institution.profile.inject_anoncreds_ledger_read()).await.unwrap()); + + let request_name2 = Some("request2"); + let mut verifier1 = verifier_create_proof_and_send_request(&mut institution, &institution_to_consumer1, &schema_id, &cred_def_id, request_name2).await; + prover_select_credentials_and_send_proof(&mut consumer1, &consumer_to_institution1, request_name2, None).await; + let mut verifier2 = verifier_create_proof_and_send_request(&mut institution, &institution_to_consumer2, &schema_id, &cred_def_id, request_name2).await; + prover_select_credentials_and_send_proof(&mut consumer2, &consumer_to_institution2, request_name2, None).await; + let mut verifier3 = verifier_create_proof_and_send_request(&mut institution, &institution_to_consumer3, &schema_id, &cred_def_id, request_name2).await; + prover_select_credentials_and_send_proof(&mut consumer3, &consumer_to_institution3, request_name2, None).await; + assert_ne!(verifier1, verifier2); + assert_ne!(verifier1, verifier3); + assert_ne!(verifier2, verifier3); + + verifier1 + .update_state( + &institution.profile.inject_wallet(), + &institution.profile.inject_anoncreds_ledger_read(), + &institution.profile.inject_anoncreds(), + &institution.agency_client, + &institution_to_consumer1, + ) + .await + .unwrap(); + verifier2 + .update_state( + &institution.profile.inject_wallet(), + &institution.profile.inject_anoncreds_ledger_read(), + &institution.profile.inject_anoncreds(), + &institution.agency_client, + &institution_to_consumer2, + ) + .await + .unwrap(); + verifier3 + .update_state( + &institution.profile.inject_wallet(), + &institution.profile.inject_anoncreds_ledger_read(), + &institution.profile.inject_anoncreds(), + &institution.agency_client, + &institution_to_consumer3, + ) + .await + .unwrap(); + assert_eq!(verifier1.get_verification_status(), PresentationVerificationStatus::Invalid); + + assert_eq!(verifier2.get_verification_status(), PresentationVerificationStatus::Invalid); + + assert_eq!(verifier3.get_verification_status(), PresentationVerificationStatus::Valid); + }) .await; - prover_select_credentials_and_send_proof(&mut consumer3, &consumer_to_institution3, request_name2, None).await; - assert_ne!(verifier1, verifier2); - assert_ne!(verifier1, verifier3); - assert_ne!(verifier2, verifier3); - - verifier1 - .update_state( - &institution.profile.inject_wallet(), - &institution.profile.inject_anoncreds_ledger_read(), - &institution.profile.inject_anoncreds(), - &institution.agency_client, - &institution_to_consumer1, - ) - .await - .unwrap(); - verifier2 - .update_state( - &institution.profile.inject_wallet(), - &institution.profile.inject_anoncreds_ledger_read(), - &institution.profile.inject_anoncreds(), - &institution.agency_client, - &institution_to_consumer2, - ) - .await - .unwrap(); - verifier3 - .update_state( - &institution.profile.inject_wallet(), - &institution.profile.inject_anoncreds_ledger_read(), - &institution.profile.inject_anoncreds(), - &institution.agency_client, - &institution_to_consumer3, - ) - .await - .unwrap(); - assert_eq!( - verifier1.get_verification_status(), - PresentationVerificationStatus::Invalid - ); - - assert_eq!( - verifier2.get_verification_status(), - PresentationVerificationStatus::Invalid - ); - - assert_eq!( - verifier3.get_verification_status(), - PresentationVerificationStatus::Valid - ); - }).await; } #[tokio::test] @@ -493,18 +466,15 @@ mod integration_tests { let mut institution = Faber::setup(setup.pool_handle).await; let mut consumer = create_test_alice_instance(&setup).await; - let (consumer_to_institution, institution_to_consumer) = - create_connected_connections(&mut consumer, &mut institution).await; - let (schema_id, cred_def_id, _, _cred_def, rev_reg, issuer_credential) = issue_address_credential( - &mut consumer, - &mut institution, - &consumer_to_institution, - &institution_to_consumer, - ) - .await; + let (consumer_to_institution, institution_to_consumer) = create_connected_connections(&mut consumer, &mut institution).await; + let (schema_id, cred_def_id, _, _cred_def, rev_reg, issuer_credential) = + issue_address_credential(&mut consumer, &mut institution, &consumer_to_institution, &institution_to_consumer).await; assert!(!issuer_credential.is_revoked(&institution.profile.inject_anoncreds_ledger_read()).await.unwrap()); + #[cfg(feature = "migration")] + institution.migrate().await; + tokio::time::sleep(Duration::from_millis(1000)).await; let time_before_revocation = time::OffsetDateTime::now_utc().unix_timestamp() as u64; tokio::time::sleep(Duration::from_millis(1000)).await; @@ -512,31 +482,17 @@ mod integration_tests { revoke_credential_and_publish_accumulator(&mut institution, &issuer_credential, &rev_reg).await; tokio::time::sleep(Duration::from_millis(1000)).await; + #[cfg(feature = "migration")] + consumer.migrate().await; + let from = time_before_revocation - 100; let to = time_before_revocation; - let _requested_attrs = requested_attrs( - &institution.config_issuer.institution_did, - &schema_id, - &cred_def_id, - Some(from), - Some(to), - ); + let _requested_attrs = requested_attrs(&institution.config_issuer.institution_did, &schema_id, &cred_def_id, Some(from), Some(to)); let interval = json!({"from": from, "to": to}).to_string(); let requested_attrs_string = serde_json::to_string(&_requested_attrs).unwrap(); - info!( - "test_revoked_credential_might_still_work :: Going to seng proof request with attributes {}", - &requested_attrs_string - ); - let mut verifier = send_proof_request( - &mut institution, - &institution_to_consumer, - &requested_attrs_string, - "[]", - &interval, - None, - ) - .await; + info!("test_revoked_credential_might_still_work :: Going to seng proof request with attributes {}", &requested_attrs_string); + let mut verifier = send_proof_request(&mut institution, &institution_to_consumer, &requested_attrs_string, "[]", &interval, None).await; info!("test_revoked_credential_might_still_work :: Going to create proof"); let mut prover = create_proof(&mut consumer, &consumer_to_institution, None).await; @@ -553,13 +509,7 @@ mod integration_tests { "test_revoked_credential_might_still_work :: prover :: retrieved credential converted to selected: {:?}", &selected_credentials ); - generate_and_send_proof( - &mut consumer, - &mut prover, - &consumer_to_institution, - selected_credentials, - ) - .await; + generate_and_send_proof(&mut consumer, &mut prover, &consumer_to_institution, selected_credentials).await; assert_eq!(ProverState::PresentationSent, prover.get_state()); info!("test_revoked_credential_might_still_work :: verifier :: going to verify proof"); @@ -574,10 +524,7 @@ mod integration_tests { .await .unwrap(); assert_eq!(verifier.get_state(), VerifierState::Finished); - assert_eq!( - verifier.get_verification_status(), - PresentationVerificationStatus::Valid - ); + assert_eq!(verifier.get_verification_status(), PresentationVerificationStatus::Valid); }) .await; } @@ -586,504 +533,537 @@ mod integration_tests { #[ignore] async fn test_agency_pool_two_creds_one_rev_reg_revoke_first() { SetupPool::run(|setup| async move { - let mut issuer = Faber::setup(setup.pool_handle).await; - let mut verifier = Faber::setup(setup.pool_handle).await; - let mut consumer = create_test_alice_instance(&setup).await; - - let (consumer_to_verifier, verifier_to_consumer) = - create_connected_connections(&mut consumer, &mut verifier).await; - let (consumer_to_issuer, issuer_to_consumer) = create_connected_connections(&mut consumer, &mut issuer).await; - - let (schema_id, _schema_json, cred_def_id, _cred_def_json, cred_def, rev_reg, _rev_reg_id) = - _create_address_schema(&issuer.profile, &issuer.config_issuer.institution_did).await; - let (address1, address2, city, state, zip) = attr_names(); - let (req1, req2) = (Some("request1"), Some("request2")); - let credential_data1 = json!({address1.clone(): "123 Main St", address2.clone(): "Suite 3", city.clone(): "Draper", state.clone(): "UT", zip.clone(): "84000"}).to_string(); - let issuer_credential1 = _exchange_credential( - &mut consumer, - &mut issuer, - credential_data1.clone(), - &cred_def, - &rev_reg, - &consumer_to_issuer, - &issuer_to_consumer, - req1, - ) - .await; - let credential_data2 = json!({address1.clone(): "101 Tela Lane", address2.clone(): "Suite 1", city.clone(): "SLC", state.clone(): "WA", zip.clone(): "8721"}).to_string(); - let issuer_credential2 = _exchange_credential( - &mut consumer, - &mut issuer, - credential_data2.clone(), - &cred_def, - &rev_reg, - &consumer_to_issuer, - &issuer_to_consumer, - req2, - ) - .await; + let mut issuer = Faber::setup(setup.pool_handle).await; + let mut verifier = Faber::setup(setup.pool_handle).await; + let mut consumer = create_test_alice_instance(&setup).await; + + let (consumer_to_verifier, verifier_to_consumer) = create_connected_connections(&mut consumer, &mut verifier).await; + let (consumer_to_issuer, issuer_to_consumer) = create_connected_connections(&mut consumer, &mut issuer).await; + + let (schema_id, _schema_json, cred_def_id, _cred_def_json, cred_def, rev_reg, _rev_reg_id) = _create_address_schema(&issuer.profile, &issuer.config_issuer.institution_did).await; + let (address1, address2, city, state, zip) = attr_names(); + let (req1, req2) = (Some("request1"), Some("request2")); + let credential_data1 = json!({address1.clone(): "123 Main St", address2.clone(): "Suite 3", city.clone(): "Draper", state.clone(): "UT", zip.clone(): "84000"}).to_string(); + let issuer_credential1 = _exchange_credential( + &mut consumer, + &mut issuer, + credential_data1.clone(), + &cred_def, + &rev_reg, + &consumer_to_issuer, + &issuer_to_consumer, + req1, + ) + .await; - assert!(!issuer_credential1.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); - assert!(!issuer_credential2.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); + #[cfg(feature = "migration")] + issuer.migrate().await; - revoke_credential_and_publish_accumulator(&mut issuer, &issuer_credential1, &rev_reg).await; + let credential_data2 = json!({address1.clone(): "101 Tela Lane", address2.clone(): "Suite 1", city.clone(): "SLC", state.clone(): "WA", zip.clone(): "8721"}).to_string(); - let mut proof_verifier = verifier_create_proof_and_send_request( - &mut verifier, - &verifier_to_consumer, - &schema_id, - &cred_def_id, - req1, - ) - .await; - prover_select_credentials_and_send_proof(&mut consumer, &consumer_to_verifier, req1, Some(&credential_data1)) + let issuer_credential2 = _exchange_credential( + &mut consumer, + &mut issuer, + credential_data2.clone(), + &cred_def, + &rev_reg, + &consumer_to_issuer, + &issuer_to_consumer, + req2, + ) .await; - proof_verifier - .update_state( - &verifier.profile.inject_wallet(), - &verifier.profile.inject_anoncreds_ledger_read(), - &verifier.profile.inject_anoncreds(), - &verifier.agency_client, - &verifier_to_consumer) - .await - .unwrap(); - assert_eq!( - proof_verifier.get_state(), - VerifierState::Finished - ); - assert_eq!( - proof_verifier.get_verification_status(), - PresentationVerificationStatus::Invalid - ); - let mut proof_verifier = verifier_create_proof_and_send_request( - &mut verifier, - &verifier_to_consumer, - &schema_id, - &cred_def_id, - req2, - ) + assert!(!issuer_credential1.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); + assert!(!issuer_credential2.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); + + #[cfg(feature = "migration")] + verifier.migrate().await; + + revoke_credential_and_publish_accumulator(&mut issuer, &issuer_credential1, &rev_reg).await; + + let mut proof_verifier = verifier_create_proof_and_send_request(&mut verifier, &verifier_to_consumer, &schema_id, &cred_def_id, req1).await; + prover_select_credentials_and_send_proof(&mut consumer, &consumer_to_verifier, req1, Some(&credential_data1)).await; + proof_verifier + .update_state( + &verifier.profile.inject_wallet(), + &verifier.profile.inject_anoncreds_ledger_read(), + &verifier.profile.inject_anoncreds(), + &verifier.agency_client, + &verifier_to_consumer, + ) + .await + .unwrap(); + assert_eq!(proof_verifier.get_state(), VerifierState::Finished); + assert_eq!(proof_verifier.get_verification_status(), PresentationVerificationStatus::Invalid); + + let mut proof_verifier = verifier_create_proof_and_send_request(&mut verifier, &verifier_to_consumer, &schema_id, &cred_def_id, req2).await; + prover_select_credentials_and_send_proof(&mut consumer, &consumer_to_verifier, req2, Some(&credential_data2)).await; + + #[cfg(feature = "migration")] + consumer.migrate().await; + + proof_verifier + .update_state( + &verifier.profile.inject_wallet(), + &verifier.profile.inject_anoncreds_ledger_read(), + &verifier.profile.inject_anoncreds(), + &verifier.agency_client, + &verifier_to_consumer, + ) + .await + .unwrap(); + assert_eq!(proof_verifier.get_verification_status(), PresentationVerificationStatus::Valid); + + assert!(issuer_credential1.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); + assert!(!issuer_credential2.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); + }) .await; - prover_select_credentials_and_send_proof(&mut consumer, &consumer_to_verifier, req2, Some(&credential_data2)) - .await; - proof_verifier - .update_state( - &verifier.profile.inject_wallet(), - &verifier.profile.inject_anoncreds_ledger_read(), - &verifier.profile.inject_anoncreds(), - &verifier.agency_client, - &verifier_to_consumer - ) - .await - .unwrap(); - assert_eq!( - proof_verifier.get_verification_status(), - PresentationVerificationStatus::Valid - ); - - assert!(issuer_credential1.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); - assert!(!issuer_credential2.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); - }).await; } #[tokio::test] #[ignore] async fn test_agency_pool_two_creds_one_rev_reg_revoke_second() { SetupPool::run(|setup| async move { - let mut issuer = Faber::setup(setup.pool_handle).await; - let mut verifier = Faber::setup(setup.pool_handle).await; - let mut consumer = create_test_alice_instance(&setup).await; - - let (consumer_to_verifier, verifier_to_consumer) = - create_connected_connections(&mut consumer, &mut verifier).await; - let (consumer_to_issuer, issuer_to_consumer) = create_connected_connections(&mut consumer, &mut issuer).await; - - let (schema_id, _schema_json, cred_def_id, _cred_def_json, cred_def, rev_reg, _rev_reg_id) = - _create_address_schema(&issuer.profile, &issuer.config_issuer.institution_did).await; - let (address1, address2, city, state, zip) = attr_names(); - let (req1, req2) = (Some("request1"), Some("request2")); - let credential_data1 = json!({address1.clone(): "123 Main St", address2.clone(): "Suite 3", city.clone(): "Draper", state.clone(): "UT", zip.clone(): "84000"}).to_string(); - let issuer_credential1 = _exchange_credential( - &mut consumer, - &mut issuer, - credential_data1.clone(), - &cred_def, - &rev_reg, - &consumer_to_issuer, - &issuer_to_consumer, - req1, - ) - .await; - let credential_data2 = json!({address1.clone(): "101 Tela Lane", address2.clone(): "Suite 1", city.clone(): "SLC", state.clone(): "WA", zip.clone(): "8721"}).to_string(); - let issuer_credential2 = _exchange_credential( - &mut consumer, - &mut issuer, - credential_data2.clone(), - &cred_def, - &rev_reg, - &consumer_to_issuer, - &issuer_to_consumer, - req2, - ) - .await; - - assert!(!issuer_credential1.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); - assert!(!issuer_credential2.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); + let mut issuer = Faber::setup(setup.pool_handle).await; + let mut verifier = Faber::setup(setup.pool_handle).await; + let mut consumer = create_test_alice_instance(&setup).await; - revoke_credential_and_publish_accumulator(&mut issuer, &issuer_credential2, &rev_reg).await; + let (consumer_to_verifier, verifier_to_consumer) = create_connected_connections(&mut consumer, &mut verifier).await; + let (consumer_to_issuer, issuer_to_consumer) = create_connected_connections(&mut consumer, &mut issuer).await; - let mut proof_verifier = verifier_create_proof_and_send_request( - &mut verifier, - &verifier_to_consumer, - &schema_id, - &cred_def_id, - req1, - ) - .await; - prover_select_credentials_and_send_proof(&mut consumer, &consumer_to_verifier, req1, Some(&credential_data1)) - .await; - proof_verifier - .update_state( - &verifier.profile.inject_wallet(), - &verifier.profile.inject_anoncreds_ledger_read(), - &verifier.profile.inject_anoncreds(), - &verifier.agency_client, - &verifier_to_consumer + let (schema_id, _schema_json, cred_def_id, _cred_def_json, cred_def, rev_reg, _rev_reg_id) = _create_address_schema(&issuer.profile, &issuer.config_issuer.institution_did).await; + let (address1, address2, city, state, zip) = attr_names(); + let (req1, req2) = (Some("request1"), Some("request2")); + let credential_data1 = json!({address1.clone(): "123 Main St", address2.clone(): "Suite 3", city.clone(): "Draper", state.clone(): "UT", zip.clone(): "84000"}).to_string(); + let issuer_credential1 = _exchange_credential( + &mut consumer, + &mut issuer, + credential_data1.clone(), + &cred_def, + &rev_reg, + &consumer_to_issuer, + &issuer_to_consumer, + req1, ) - .await - .unwrap(); - assert_eq!( - proof_verifier.get_verification_status(), - PresentationVerificationStatus::Valid - ); - - let mut proof_verifier = verifier_create_proof_and_send_request( - &mut verifier, - &verifier_to_consumer, - &schema_id, - &cred_def_id, - req2, - ) - .await; - prover_select_credentials_and_send_proof(&mut consumer, &consumer_to_verifier, req2, Some(&credential_data2)) .await; - proof_verifier - .update_state( - &verifier.profile.inject_wallet(), - &verifier.profile.inject_anoncreds_ledger_read(), - &verifier.profile.inject_anoncreds(), - &verifier.agency_client, - &verifier_to_consumer + + #[cfg(feature = "migration")] + issuer.migrate().await; + + let credential_data2 = json!({address1.clone(): "101 Tela Lane", address2.clone(): "Suite 1", city.clone(): "SLC", state.clone(): "WA", zip.clone(): "8721"}).to_string(); + let issuer_credential2 = _exchange_credential( + &mut consumer, + &mut issuer, + credential_data2.clone(), + &cred_def, + &rev_reg, + &consumer_to_issuer, + &issuer_to_consumer, + req2, ) - .await - .unwrap(); - assert_eq!( - proof_verifier.get_verification_status(), - PresentationVerificationStatus::Invalid - ); - - assert!(!issuer_credential1.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); - assert!(issuer_credential2.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); - }).await; + .await; + + assert!(!issuer_credential1.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); + assert!(!issuer_credential2.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); + + revoke_credential_and_publish_accumulator(&mut issuer, &issuer_credential2, &rev_reg).await; + + #[cfg(feature = "migration")] + verifier.migrate().await; + + let mut proof_verifier = verifier_create_proof_and_send_request(&mut verifier, &verifier_to_consumer, &schema_id, &cred_def_id, req1).await; + prover_select_credentials_and_send_proof(&mut consumer, &consumer_to_verifier, req1, Some(&credential_data1)).await; + proof_verifier + .update_state( + &verifier.profile.inject_wallet(), + &verifier.profile.inject_anoncreds_ledger_read(), + &verifier.profile.inject_anoncreds(), + &verifier.agency_client, + &verifier_to_consumer, + ) + .await + .unwrap(); + assert_eq!(proof_verifier.get_verification_status(), PresentationVerificationStatus::Valid); + + let mut proof_verifier = verifier_create_proof_and_send_request(&mut verifier, &verifier_to_consumer, &schema_id, &cred_def_id, req2).await; + + #[cfg(feature = "migration")] + consumer.migrate().await; + + prover_select_credentials_and_send_proof(&mut consumer, &consumer_to_verifier, req2, Some(&credential_data2)).await; + proof_verifier + .update_state( + &verifier.profile.inject_wallet(), + &verifier.profile.inject_anoncreds_ledger_read(), + &verifier.profile.inject_anoncreds(), + &verifier.agency_client, + &verifier_to_consumer, + ) + .await + .unwrap(); + assert_eq!(proof_verifier.get_verification_status(), PresentationVerificationStatus::Invalid); + + assert!(!issuer_credential1.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); + assert!(issuer_credential2.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); + }) + .await; } #[tokio::test] #[ignore] async fn test_agency_pool_two_creds_two_rev_reg_id() { SetupPool::run(|setup| async move { - let mut issuer = Faber::setup(setup.pool_handle).await; - let mut verifier = Faber::setup(setup.pool_handle).await; - let mut consumer = create_test_alice_instance(&setup).await; - - let (consumer_to_verifier, verifier_to_consumer) = - create_connected_connections(&mut consumer, &mut verifier).await; - let (consumer_to_issuer, issuer_to_consumer) = create_connected_connections(&mut consumer, &mut issuer).await; - - let (schema_id, _schema_json, cred_def_id, _cred_def_json, cred_def, rev_reg, _) = - _create_address_schema(&issuer.profile, &issuer.config_issuer.institution_did).await; - let (address1, address2, city, state, zip) = attr_names(); - let (req1, req2) = (Some("request1"), Some("request2")); - let credential_data1 = json!({address1.clone(): "123 Main St", address2.clone(): "Suite 3", city.clone(): "Draper", state.clone(): "UT", zip.clone(): "84000"}).to_string(); - let issuer_credential1 = _exchange_credential( - &mut consumer, - &mut issuer, - credential_data1.clone(), - &cred_def, - &rev_reg, - &consumer_to_issuer, - &issuer_to_consumer, - req1, - ) - .await; - let rev_reg_2 = rotate_rev_reg(&mut issuer, &cred_def, &rev_reg).await; - let credential_data2 = json!({address1.clone(): "101 Tela Lane", address2.clone(): "Suite 1", city.clone(): "SLC", state.clone(): "WA", zip.clone(): "8721"}).to_string(); - let issuer_credential2 = _exchange_credential( - &mut consumer, - &mut issuer, - credential_data2.clone(), - &cred_def, - &rev_reg_2, - &consumer_to_issuer, - &issuer_to_consumer, - req2, - ) - .await; + let mut issuer = Faber::setup(setup.pool_handle).await; + let mut verifier = Faber::setup(setup.pool_handle).await; + let mut consumer = create_test_alice_instance(&setup).await; - let mut proof_verifier = verifier_create_proof_and_send_request( - &mut verifier, - &verifier_to_consumer, - &schema_id, - &cred_def_id, - req1, - ) - .await; - prover_select_credentials_and_send_proof(&mut consumer, &consumer_to_verifier, req1, Some(&credential_data1)) + let (consumer_to_verifier, verifier_to_consumer) = create_connected_connections(&mut consumer, &mut verifier).await; + let (consumer_to_issuer, issuer_to_consumer) = create_connected_connections(&mut consumer, &mut issuer).await; + + let (schema_id, _schema_json, cred_def_id, _cred_def_json, cred_def, rev_reg, _) = _create_address_schema(&issuer.profile, &issuer.config_issuer.institution_did).await; + let (address1, address2, city, state, zip) = attr_names(); + let (req1, req2) = (Some("request1"), Some("request2")); + let credential_data1 = json!({address1.clone(): "123 Main St", address2.clone(): "Suite 3", city.clone(): "Draper", state.clone(): "UT", zip.clone(): "84000"}).to_string(); + let issuer_credential1 = _exchange_credential( + &mut consumer, + &mut issuer, + credential_data1.clone(), + &cred_def, + &rev_reg, + &consumer_to_issuer, + &issuer_to_consumer, + req1, + ) .await; - proof_verifier - .update_state( - &verifier.profile.inject_wallet(), - &verifier.profile.inject_anoncreds_ledger_read(), - &verifier.profile.inject_anoncreds(), - &verifier.agency_client, - &verifier_to_consumer + + #[cfg(feature = "migration")] + issuer.migrate().await; + + let rev_reg_2 = rotate_rev_reg(&mut issuer, &cred_def, &rev_reg).await; + let credential_data2 = json!({address1.clone(): "101 Tela Lane", address2.clone(): "Suite 1", city.clone(): "SLC", state.clone(): "WA", zip.clone(): "8721"}).to_string(); + let issuer_credential2 = _exchange_credential( + &mut consumer, + &mut issuer, + credential_data2.clone(), + &cred_def, + &rev_reg_2, + &consumer_to_issuer, + &issuer_to_consumer, + req2, ) - .await - .unwrap(); - assert_eq!( - proof_verifier.get_verification_status(), - PresentationVerificationStatus::Valid - ); - - - let mut proof_verifier = verifier_create_proof_and_send_request( - &mut verifier, - &verifier_to_consumer, - &schema_id, - &cred_def_id, - req2, - ) - .await; - prover_select_credentials_and_send_proof(&mut consumer, &consumer_to_verifier, req2, Some(&credential_data2)) .await; - proof_verifier - .update_state( - &verifier.profile.inject_wallet(), - &verifier.profile.inject_anoncreds_ledger_read(), - &verifier.profile.inject_anoncreds(), - &verifier.agency_client, - &verifier_to_consumer) - .await - .unwrap(); - assert_eq!( - proof_verifier.get_verification_status(), - PresentationVerificationStatus::Valid - ); - - assert!(!issuer_credential1.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); - assert!(!issuer_credential2.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); - }).await; + + let mut proof_verifier = verifier_create_proof_and_send_request(&mut verifier, &verifier_to_consumer, &schema_id, &cred_def_id, req1).await; + prover_select_credentials_and_send_proof(&mut consumer, &consumer_to_verifier, req1, Some(&credential_data1)).await; + proof_verifier + .update_state( + &verifier.profile.inject_wallet(), + &verifier.profile.inject_anoncreds_ledger_read(), + &verifier.profile.inject_anoncreds(), + &verifier.agency_client, + &verifier_to_consumer, + ) + .await + .unwrap(); + assert_eq!(proof_verifier.get_verification_status(), PresentationVerificationStatus::Valid); + + #[cfg(feature = "migration")] + verifier.migrate().await; + + let mut proof_verifier = verifier_create_proof_and_send_request(&mut verifier, &verifier_to_consumer, &schema_id, &cred_def_id, req2).await; + + #[cfg(feature = "migration")] + consumer.migrate().await; + + prover_select_credentials_and_send_proof(&mut consumer, &consumer_to_verifier, req2, Some(&credential_data2)).await; + proof_verifier + .update_state( + &verifier.profile.inject_wallet(), + &verifier.profile.inject_anoncreds_ledger_read(), + &verifier.profile.inject_anoncreds(), + &verifier.agency_client, + &verifier_to_consumer, + ) + .await + .unwrap(); + assert_eq!(proof_verifier.get_verification_status(), PresentationVerificationStatus::Valid); + + assert!(!issuer_credential1.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); + assert!(!issuer_credential2.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); + }) + .await; } #[tokio::test] #[ignore] async fn test_agency_pool_two_creds_two_rev_reg_id_revoke_first() { SetupPool::run(|setup| async move { - let mut issuer = Faber::setup(setup.pool_handle).await; - let mut verifier = Faber::setup(setup.pool_handle).await; - let mut consumer = create_test_alice_instance(&setup).await; - - let (consumer_to_verifier, verifier_to_consumer) = - create_connected_connections(&mut consumer, &mut verifier).await; - let (consumer_to_issuer, issuer_to_consumer) = create_connected_connections(&mut consumer, &mut issuer).await; - - let (schema_id, _schema_json, cred_def_id, _cred_def_json, cred_def, rev_reg, _) = - _create_address_schema(&issuer.profile, &issuer.config_issuer.institution_did).await; - let (address1, address2, city, state, zip) = attr_names(); - let (req1, req2) = (Some("request1"), Some("request2")); - let credential_data1 = json!({address1.clone(): "123 Main St", address2.clone(): "Suite 3", city.clone(): "Draper", state.clone(): "UT", zip.clone(): "84000"}).to_string(); - let issuer_credential1 = _exchange_credential( - &mut consumer, - &mut issuer, - credential_data1.clone(), - &cred_def, - &rev_reg, - &consumer_to_issuer, - &issuer_to_consumer, - req1, - ) - .await; - let rev_reg_2 = rotate_rev_reg(&mut issuer, &cred_def, &rev_reg).await; - let credential_data2 = json!({address1.clone(): "101 Tela Lane", address2.clone(): "Suite 1", city.clone(): "SLC", state.clone(): "WA", zip.clone(): "8721"}).to_string(); - let issuer_credential2 = _exchange_credential( - &mut consumer, - &mut issuer, - credential_data2.clone(), - &cred_def, - &rev_reg_2, - &consumer_to_issuer, - &issuer_to_consumer, - req2, - ) - .await; + let mut issuer = Faber::setup(setup.pool_handle).await; + let mut verifier = Faber::setup(setup.pool_handle).await; + let mut consumer = create_test_alice_instance(&setup).await; + + let (consumer_to_verifier, verifier_to_consumer) = create_connected_connections(&mut consumer, &mut verifier).await; + let (consumer_to_issuer, issuer_to_consumer) = create_connected_connections(&mut consumer, &mut issuer).await; - assert!(!issuer_credential1.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); - assert!(!issuer_credential2.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); + let (schema_id, _schema_json, cred_def_id, _cred_def_json, cred_def, rev_reg, _) = _create_address_schema(&issuer.profile, &issuer.config_issuer.institution_did).await; + let (address1, address2, city, state, zip) = attr_names(); + let (req1, req2) = (Some("request1"), Some("request2")); + let credential_data1 = json!({address1.clone(): "123 Main St", address2.clone(): "Suite 3", city.clone(): "Draper", state.clone(): "UT", zip.clone(): "84000"}).to_string(); + let issuer_credential1 = _exchange_credential( + &mut consumer, + &mut issuer, + credential_data1.clone(), + &cred_def, + &rev_reg, + &consumer_to_issuer, + &issuer_to_consumer, + req1, + ) + .await; - revoke_credential_and_publish_accumulator(&mut issuer, &issuer_credential1, &rev_reg).await; + #[cfg(feature = "migration")] + issuer.migrate().await; - let mut proof_verifier = verifier_create_proof_and_send_request( - &mut verifier, - &verifier_to_consumer, - &schema_id, - &cred_def_id, - req1, - ) - .await; - prover_select_credentials_and_send_proof(&mut consumer, &consumer_to_verifier, req1, Some(&credential_data1)) + let rev_reg_2 = rotate_rev_reg(&mut issuer, &cred_def, &rev_reg).await; + let credential_data2 = json!({address1.clone(): "101 Tela Lane", address2.clone(): "Suite 1", city.clone(): "SLC", state.clone(): "WA", zip.clone(): "8721"}).to_string(); + let issuer_credential2 = _exchange_credential( + &mut consumer, + &mut issuer, + credential_data2.clone(), + &cred_def, + &rev_reg_2, + &consumer_to_issuer, + &issuer_to_consumer, + req2, + ) .await; - proof_verifier - .update_state( - &verifier.profile.inject_wallet(), - &verifier.profile.inject_anoncreds_ledger_read(), - &verifier.profile.inject_anoncreds(), - &verifier.agency_client, - &verifier_to_consumer) - .await - .unwrap(); - assert_eq!( - proof_verifier.get_verification_status(), - PresentationVerificationStatus::Invalid - ); - - let mut proof_verifier = verifier_create_proof_and_send_request( - &mut verifier, - &verifier_to_consumer, - &schema_id, - &cred_def_id, - req2, - ) + + assert!(!issuer_credential1.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); + assert!(!issuer_credential2.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); + + revoke_credential_and_publish_accumulator(&mut issuer, &issuer_credential1, &rev_reg).await; + + #[cfg(feature = "migration")] + verifier.migrate().await; + + let mut proof_verifier = verifier_create_proof_and_send_request(&mut verifier, &verifier_to_consumer, &schema_id, &cred_def_id, req1).await; + prover_select_credentials_and_send_proof(&mut consumer, &consumer_to_verifier, req1, Some(&credential_data1)).await; + proof_verifier + .update_state( + &verifier.profile.inject_wallet(), + &verifier.profile.inject_anoncreds_ledger_read(), + &verifier.profile.inject_anoncreds(), + &verifier.agency_client, + &verifier_to_consumer, + ) + .await + .unwrap(); + assert_eq!(proof_verifier.get_verification_status(), PresentationVerificationStatus::Invalid); + + #[cfg(feature = "migration")] + consumer.migrate().await; + + let mut proof_verifier = verifier_create_proof_and_send_request(&mut verifier, &verifier_to_consumer, &schema_id, &cred_def_id, req2).await; + prover_select_credentials_and_send_proof(&mut consumer, &consumer_to_verifier, req2, Some(&credential_data2)).await; + proof_verifier + .update_state( + &verifier.profile.inject_wallet(), + &verifier.profile.inject_anoncreds_ledger_read(), + &verifier.profile.inject_anoncreds(), + &verifier.agency_client, + &verifier_to_consumer, + ) + .await + .unwrap(); + assert_eq!(proof_verifier.get_verification_status(), PresentationVerificationStatus::Valid); + + assert!(issuer_credential1.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); + assert!(!issuer_credential2.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); + }) .await; - prover_select_credentials_and_send_proof(&mut consumer, &consumer_to_verifier, req2, Some(&credential_data2)) - .await; - proof_verifier - .update_state( - &verifier.profile.inject_wallet(), - &verifier.profile.inject_anoncreds_ledger_read(), - &verifier.profile.inject_anoncreds(), - &verifier.agency_client, - &verifier_to_consumer - ) - .await - .unwrap(); - assert_eq!( - proof_verifier.get_verification_status(), - PresentationVerificationStatus::Valid - ); - - assert!(issuer_credential1.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); - assert!(!issuer_credential2.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); - }).await; } #[tokio::test] #[ignore] async fn test_agency_pool_two_creds_two_rev_reg_id_revoke_second() { SetupPool::run(|setup| async move { - let mut issuer = Faber::setup(setup.pool_handle).await; - let mut verifier = Faber::setup(setup.pool_handle).await; - let mut consumer = create_test_alice_instance(&setup).await; - - let (consumer_to_verifier, verifier_to_consumer) = - create_connected_connections(&mut consumer, &mut verifier).await; - let (consumer_to_issuer, issuer_to_consumer) = create_connected_connections(&mut consumer, &mut issuer).await; - - let (schema_id, _schema_json, cred_def_id, _cred_def_json, cred_def, rev_reg, _) = - _create_address_schema(&issuer.profile, &issuer.config_issuer.institution_did).await; - let (address1, address2, city, state, zip) = attr_names(); - let (req1, req2) = (Some("request1"), Some("request2")); - let credential_data1 = json!({address1.clone(): "123 Main St", address2.clone(): "Suite 3", city.clone(): "Draper", state.clone(): "UT", zip.clone(): "84000"}).to_string(); - let issuer_credential1 = _exchange_credential( - &mut consumer, - &mut issuer, - credential_data1.clone(), - &cred_def, - &rev_reg, - &consumer_to_issuer, - &issuer_to_consumer, - req1, - ) - .await; - let rev_reg_2 = rotate_rev_reg(&mut issuer, &cred_def, &rev_reg).await; - let credential_data2 = json!({address1.clone(): "101 Tela Lane", address2.clone(): "Suite 1", city.clone(): "SLC", state.clone(): "WA", zip.clone(): "8721"}).to_string(); - let issuer_credential2 = _exchange_credential( - &mut consumer, - &mut issuer, - credential_data2.clone(), - &cred_def, - &rev_reg_2, - &consumer_to_issuer, - &issuer_to_consumer, - req2, - ) - .await; + let mut issuer = Faber::setup(setup.pool_handle).await; + let mut verifier = Faber::setup(setup.pool_handle).await; + let mut consumer = create_test_alice_instance(&setup).await; - assert!(!issuer_credential1.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); - assert!(!issuer_credential2.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); + let (consumer_to_verifier, verifier_to_consumer) = create_connected_connections(&mut consumer, &mut verifier).await; + let (consumer_to_issuer, issuer_to_consumer) = create_connected_connections(&mut consumer, &mut issuer).await; - revoke_credential_and_publish_accumulator(&mut issuer, &issuer_credential2, &rev_reg_2).await; + let (schema_id, _schema_json, cred_def_id, _cred_def_json, cred_def, rev_reg, _) = _create_address_schema(&issuer.profile, &issuer.config_issuer.institution_did).await; + let (address1, address2, city, state, zip) = attr_names(); + let (req1, req2) = (Some("request1"), Some("request2")); + let credential_data1 = json!({address1.clone(): "123 Main St", address2.clone(): "Suite 3", city.clone(): "Draper", state.clone(): "UT", zip.clone(): "84000"}).to_string(); + let issuer_credential1 = _exchange_credential( + &mut consumer, + &mut issuer, + credential_data1.clone(), + &cred_def, + &rev_reg, + &consumer_to_issuer, + &issuer_to_consumer, + req1, + ) + .await; + + #[cfg(feature = "migration")] + issuer.migrate().await; + + let rev_reg_2 = rotate_rev_reg(&mut issuer, &cred_def, &rev_reg).await; + let credential_data2 = json!({address1.clone(): "101 Tela Lane", address2.clone(): "Suite 1", city.clone(): "SLC", state.clone(): "WA", zip.clone(): "8721"}).to_string(); + let issuer_credential2 = _exchange_credential( + &mut consumer, + &mut issuer, + credential_data2.clone(), + &cred_def, + &rev_reg_2, + &consumer_to_issuer, + &issuer_to_consumer, + req2, + ) + .await; + + assert!(!issuer_credential1.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); + assert!(!issuer_credential2.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); + + revoke_credential_and_publish_accumulator(&mut issuer, &issuer_credential2, &rev_reg_2).await; + + let mut proof_verifier = verifier_create_proof_and_send_request(&mut verifier, &verifier_to_consumer, &schema_id, &cred_def_id, req1).await; + prover_select_credentials_and_send_proof(&mut consumer, &consumer_to_verifier, req1, Some(&credential_data1)).await; - let mut proof_verifier = verifier_create_proof_and_send_request( - &mut verifier, - &verifier_to_consumer, - &schema_id, - &cred_def_id, - req1, - ) + #[cfg(feature = "migration")] + verifier.migrate().await; + + proof_verifier + .update_state( + &verifier.profile.inject_wallet(), + &verifier.profile.inject_anoncreds_ledger_read(), + &verifier.profile.inject_anoncreds(), + &verifier.agency_client, + &verifier_to_consumer, + ) + .await + .unwrap(); + assert_eq!(proof_verifier.get_verification_status(), PresentationVerificationStatus::Valid); + + let mut proof_verifier = verifier_create_proof_and_send_request(&mut verifier, &verifier_to_consumer, &schema_id, &cred_def_id, req2).await; + + #[cfg(feature = "migration")] + consumer.migrate().await; + + prover_select_credentials_and_send_proof(&mut consumer, &consumer_to_verifier, req2, Some(&credential_data2)).await; + proof_verifier + .update_state( + &verifier.profile.inject_wallet(), + &verifier.profile.inject_anoncreds_ledger_read(), + &verifier.profile.inject_anoncreds(), + &verifier.agency_client, + &verifier_to_consumer, + ) + .await + .unwrap(); + assert_eq!(proof_verifier.get_verification_status(), PresentationVerificationStatus::Invalid); + + assert!(!issuer_credential1.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); + assert!(issuer_credential2.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); + }) .await; - prover_select_credentials_and_send_proof(&mut consumer, &consumer_to_verifier, req1, Some(&credential_data1)) + } + + #[tokio::test] + #[ignore] + async fn test_agency_pool_three_creds_one_rev_reg_revoke_all() { + SetupPool::run(|setup| async move { + let mut issuer = Faber::setup(setup.pool_handle).await; + let mut consumer = create_test_alice_instance(&setup).await; + + let (consumer_to_issuer, issuer_to_consumer) = + create_connected_connections(&mut consumer, &mut issuer).await; + + let (_schema_id, _schema_json, _cred_def_id, _cred_def_json, cred_def, rev_reg, _rev_reg_id) = + _create_address_schema(&issuer.profile, &issuer.config_issuer.institution_did).await; + + let (address1, address2, city, state, zip) = attr_names(); + let (req1, req2, req3) = (Some("request1"), Some("request2"), Some("request3")); + + let credential_data1 = json!({address1.clone(): "123 Main St", address2.clone(): "Suite 3", city.clone(): "Draper", state.clone(): "UT", zip.clone(): "84000"}).to_string(); + let issuer_credential1 = _exchange_credential( + &mut consumer, + &mut issuer, + credential_data1.clone(), + &cred_def, + &rev_reg, + &consumer_to_issuer, + &issuer_to_consumer, + req1, + ) .await; - proof_verifier - .update_state( - &verifier.profile.inject_wallet(), - &verifier.profile.inject_anoncreds_ledger_read(), - &verifier.profile.inject_anoncreds(), - &verifier.agency_client, - &verifier_to_consumer + + assert!(!issuer_credential1 + .is_revoked(&issuer.profile.inject_anoncreds_ledger_read()) + .await + .unwrap()); + revoke_credential_local(&mut issuer, &issuer_credential1, &rev_reg.rev_reg_id).await; + + let credential_data2 = json!({address1.clone(): "101 Tela Lane", address2.clone(): "Suite 1", city.clone(): "SLC", state.clone(): "WA", zip.clone(): "8721"}).to_string(); + + let issuer_credential2 = _exchange_credential( + &mut consumer, + &mut issuer, + credential_data2.clone(), + &cred_def, + &rev_reg, + &consumer_to_issuer, + &issuer_to_consumer, + req2, ) - .await - .unwrap(); - assert_eq!( - proof_verifier.get_verification_status(), - PresentationVerificationStatus::Valid - ); - - let mut proof_verifier = verifier_create_proof_and_send_request( - &mut verifier, - &verifier_to_consumer, - &schema_id, - &cred_def_id, - req2, - ) - .await; - prover_select_credentials_and_send_proof(&mut consumer, &consumer_to_verifier, req2, Some(&credential_data2)) .await; - proof_verifier - .update_state( - &verifier.profile.inject_wallet(), - &verifier.profile.inject_anoncreds_ledger_read(), - &verifier.profile.inject_anoncreds(), - &verifier.agency_client, - &verifier_to_consumer + + assert!(!issuer_credential2 + .is_revoked(&issuer.profile.inject_anoncreds_ledger_read()) + .await + .unwrap()); + + #[cfg(feature = "migration")] + issuer.migrate().await; + + #[cfg(feature = "migration")] + consumer.migrate().await; + + revoke_credential_local(&mut issuer, &issuer_credential2, &rev_reg.rev_reg_id).await; + + let credential_data3 = json!({address1.clone(): "221 Baker Street", address2.clone(): "Apt. B", city.clone(): "London", state.clone(): "N/A", zip.clone(): "NW1 6XE."}).to_string(); + + let issuer_credential3 = _exchange_credential( + &mut consumer, + &mut issuer, + credential_data3.clone(), + &cred_def, + &rev_reg, + &consumer_to_issuer, + &issuer_to_consumer, + req3, ) - .await - .unwrap(); - assert_eq!( - proof_verifier.get_verification_status(), - PresentationVerificationStatus::Invalid - ); - - assert!(!issuer_credential1.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); - assert!(issuer_credential2.is_revoked(&issuer.profile.inject_anoncreds_ledger_read()).await.unwrap()); + .await; + + revoke_credential_and_publish_accumulator(&mut issuer, &issuer_credential3, &rev_reg).await; + + assert!(issuer_credential1 + .is_revoked(&issuer.profile.inject_anoncreds_ledger_read()) + .await + .unwrap()); + assert!(issuer_credential2 + .is_revoked(&issuer.profile.inject_anoncreds_ledger_read()) + .await + .unwrap()); + assert!(issuer_credential3 + .is_revoked(&issuer.profile.inject_anoncreds_ledger_read()) + .await + .unwrap()); }).await; } } diff --git a/aries_vcx/tests/test_mysql_wallet.rs b/aries_vcx/tests/test_mysql_wallet.rs index 0342796a51..2a456ad111 100644 --- a/aries_vcx/tests/test_mysql_wallet.rs +++ b/aries_vcx/tests/test_mysql_wallet.rs @@ -1,33 +1,6 @@ -#[macro_use] -extern crate log; - #[macro_use] extern crate serde_json; -extern crate sqlx; - -mod test_utils { - use sqlx::{Connection, MySqlConnection}; - - pub async fn setup_mysql_walletdb() -> Result { - debug!("Running query."); - let db_name = format!("mysqltest_{}", uuid::Uuid::new_v4().to_string()).replace("-", "_"); - let url = "mysql://root:mysecretpassword@localhost:3306"; - let mut connection = MySqlConnection::connect(url).await?; - let query = format!("CREATE DATABASE {};", db_name); - let query = sqlx::query(&query); - let res = query.execute(&mut connection).await; - debug!("Create database result: {:?}", res); - connection.close().await.unwrap(); - - let url = format!("mysql://root:mysecretpassword@localhost:3306/{}", db_name); - let mut connection = MySqlConnection::connect(&url).await?; - let res = sqlx::migrate!("./migrations").run(&mut connection).await; - debug!("Create tables result: {:?}", res); - Ok(db_name) - } -} - #[cfg(test)] mod dbtests { use std::sync::Arc; @@ -45,19 +18,17 @@ mod dbtests { }; use aries_vcx_core::wallet::indy_wallet::IndySdkWallet; - use crate::test_utils::setup_mysql_walletdb; - #[tokio::test] #[ignore] async fn test_mysql_provision_cloud_agent_with_mysql_wallet() { LibvcxDefaultLogger::init_testing_logger(); - let db_name = setup_mysql_walletdb().await.unwrap(); + let db_name = format!("mysqltest_{}", uuid::Uuid::new_v4()).replace('-', "_"); let storage_config = json!({ "read_host": "localhost", "write_host": "localhost", - "port": 3306 as u32, + "port": 3306, "db_name": db_name, - "default_connection_limit": 50 as u32 + "default_connection_limit": 50 }) .to_string(); let storage_credentials = json!({ @@ -81,7 +52,7 @@ mod dbtests { agency_endpoint: AGENCY_ENDPOINT.parse().unwrap(), agent_seed: None, }; - // create_main_wallet(&config_wallet).await.unwrap(); + create_wallet_with_master_secret(&config_wallet).await.unwrap(); let wallet_handle = open_wallet(&config_wallet).await.unwrap(); let profile = Arc::new(IndySdkWallet::new(wallet_handle)); diff --git a/aries_vcx/tests/utils/devsetup_agent.rs b/aries_vcx/tests/utils/devsetup_agent.rs index 7ea8457c37..acf191ff20 100644 --- a/aries_vcx/tests/utils/devsetup_agent.rs +++ b/aries_vcx/tests/utils/devsetup_agent.rs @@ -138,7 +138,7 @@ pub mod test_utils { pub verifier: Verifier, pub pairwise_info: PairwiseInfo, pub agency_client: AgencyClient, - pub(self) teardown: Arc BoxFuture<'static, ()>>, + pub(self) teardown: Arc BoxFuture<'static, ()> + Send + Sync>, } impl Faber { @@ -505,17 +505,17 @@ pub mod test_utils { pub rev_not_receiver: Option, pub prover: Prover, pub agency_client: AgencyClient, - pub(self) teardown: Arc BoxFuture<'static, ()>>, + pub(self) teardown: Arc BoxFuture<'static, ()> + Send + Sync>, } pub async fn create_test_alice_instance(setup: &SetupPool) -> Alice { - #[cfg(not(feature = "modular_libs"))] + #[cfg(any(not(feature = "modular_libs"), feature = "migration"))] let (alice_profile, teardown) = { info!("create_test_alice_instance >> using indy profile"); Alice::setup_indy_profile(setup.pool_handle).await }; - #[cfg(feature = "modular_libs")] + #[cfg(all(feature = "modular_libs", not(feature = "migration")))] let (alice_profile, teardown) = { let genesis_file_path = setup.genesis_file_path.clone(); let config = LedgerPoolConfig { genesis_file_path }; @@ -548,7 +548,7 @@ pub mod test_utils { #[cfg(feature = "modular_libs")] pub async fn setup_modular_profile( ledger_pool_config: LedgerPoolConfig, - ) -> (Arc, Arc BoxFuture<'static, ()>>) { + ) -> (Arc, Arc BoxFuture<'static, ()> + Send + Sync>) { let (wallet_handle, config_wallet) = Alice::setup_indy_wallet().await; let wallet: Arc = Arc::new(IndySdkWallet::new(wallet_handle)); @@ -570,7 +570,7 @@ pub mod test_utils { pub async fn setup_indy_profile( pool_handle: PoolHandle, - ) -> (Arc, Arc BoxFuture<'static, ()>>) { + ) -> (Arc, Arc BoxFuture<'static, ()> + Send + Sync>) { let (wallet_handle, config_wallet) = Alice::setup_indy_wallet().await; let indy_profile = VdrtoolsProfile::init(wallet_handle, pool_handle); @@ -581,7 +581,10 @@ pub mod test_utils { ) } - pub async fn setup(profile: Arc, teardown: Arc BoxFuture<'static, ()>>) -> Alice { + pub async fn setup( + profile: Arc, + teardown: Arc BoxFuture<'static, ()> + Send + Sync>, + ) -> Alice { let config_provision_agent = AgentProvisionConfig { agency_did: AGENCY_DID.to_string(), agency_verkey: AGENCY_VERKEY.to_string(), diff --git a/aries_vcx/tests/utils/migration.rs b/aries_vcx/tests/utils/migration.rs new file mode 100644 index 0000000000..d9192cac37 --- /dev/null +++ b/aries_vcx/tests/utils/migration.rs @@ -0,0 +1,87 @@ +use std::sync::Arc; + +use aries_vcx::{ + core::profile::modular_libs_profile::ModularLibsProfile, + global::settings::WALLET_KDF_RAW, + utils::{constants::GENESIS_PATH, devsetup::SetupProfile, get_temp_dir_path}, +}; +use aries_vcx_core::{ + indy::wallet::{create_and_open_wallet, WalletConfig}, + ledger::request_submitter::vdr_ledger::LedgerPoolConfig, + wallet::{agency_client_wallet::ToBaseAgencyClientWallet, base_wallet::BaseWallet, indy_wallet::IndySdkWallet}, + WalletHandle, +}; +use async_trait::async_trait; +use uuid::Uuid; + +use super::devsetup_agent::test_utils::{Alice, Faber}; + +#[async_trait] +pub trait Migratable { + async fn migrate(&mut self); +} + +#[async_trait] +impl Migratable for SetupProfile { + async fn migrate(&mut self) { + let old_wh = self.profile.wallet_handle().unwrap(); + let new_wh = migrate_and_replace_profile(old_wh).await; + self.profile = make_modular_profile(new_wh); + } +} + +#[async_trait] +impl Migratable for Alice { + async fn migrate(&mut self) { + let old_wh = self.profile.wallet_handle().unwrap(); + let new_wh = migrate_and_replace_profile(old_wh).await; + self.profile = make_modular_profile(new_wh); + let new_wallet: Arc = Arc::new(IndySdkWallet::new(new_wh)); + self.agency_client.wallet = new_wallet.to_base_agency_client_wallet(); + } +} + +#[async_trait] +impl Migratable for Faber { + async fn migrate(&mut self) { + let old_wh = self.profile.wallet_handle().unwrap(); + let new_wh = migrate_and_replace_profile(old_wh).await; + self.profile = make_modular_profile(new_wh); + let new_wallet: Arc = Arc::new(IndySdkWallet::new(new_wh)); + self.agency_client.wallet = new_wallet.to_base_agency_client_wallet(); + } +} + +async fn migrate_and_replace_profile(src_wallet_handle: WalletHandle) -> WalletHandle { + let wallet_config = make_wallet_config(); + let dest_wallet_handle = create_and_open_wallet(&wallet_config).await.unwrap(); + + wallet_migrator::migrate_wallet( + src_wallet_handle, + dest_wallet_handle, + wallet_migrator::vdrtools2credx::migrate_any_record, + ) + .await + .unwrap(); + + dest_wallet_handle +} + +pub fn make_modular_profile(wallet_handle: WalletHandle) -> Arc { + let genesis_file_path = String::from(get_temp_dir_path(GENESIS_PATH).to_str().unwrap()); + let wallet = IndySdkWallet::new(wallet_handle); + + Arc::new(ModularLibsProfile::init(Arc::new(wallet), LedgerPoolConfig { genesis_file_path }).unwrap()) +} + +fn make_wallet_config() -> WalletConfig { + let wallet_key = "8dvfYSt5d1taSd6yJdpjq4emkwsPDDLYxkNFysFD2cZY".to_owned(); + let wallet_name = format!("wallet_{}", Uuid::new_v4()); + + WalletConfig { + wallet_name, + wallet_key, + wallet_key_derivation: WALLET_KDF_RAW.to_string(), + ..Default::default() + } +} diff --git a/aries_vcx/tests/utils/mod.rs b/aries_vcx/tests/utils/mod.rs index 8359ed31f0..1db6f6bb26 100644 --- a/aries_vcx/tests/utils/mod.rs +++ b/aries_vcx/tests/utils/mod.rs @@ -1,3 +1,5 @@ pub mod devsetup_agent; +#[cfg(feature = "migration")] +pub mod migration; pub mod scenarios; pub mod test_macros; diff --git a/aries_vcx/tests/utils/scenarios.rs b/aries_vcx/tests/utils/scenarios.rs index 5221df6279..4edeb3df59 100644 --- a/aries_vcx/tests/utils/scenarios.rs +++ b/aries_vcx/tests/utils/scenarios.rs @@ -561,7 +561,7 @@ pub mod test_utils { info!("send_credential >>> getting offers"); let thread_id = issuer_credential.get_thread_id().unwrap(); assert_eq!(IssuerState::OfferSent, issuer_credential.get_state()); - assert_eq!(issuer_credential.is_revokable(), false); + assert!(!issuer_credential.is_revokable()); issuer_credential .update_state( @@ -573,7 +573,7 @@ pub mod test_utils { .await .unwrap(); assert_eq!(IssuerState::RequestReceived, issuer_credential.get_state()); - assert_eq!(issuer_credential.is_revokable(), false); + assert!(!issuer_credential.is_revokable()); assert_eq!(thread_id, issuer_credential.get_thread_id().unwrap()); info!("send_credential >>> sending credential"); @@ -705,7 +705,7 @@ pub mod test_utils { .attributes .into_iter() .map(|attr| AttrInfo { - name: Some(attr.name.clone()), + name: Some(attr.name), ..AttrInfo::default() }) .collect(); @@ -918,6 +918,7 @@ pub mod test_utils { rev_reg: &RevocationRegistry, ) { revoke_credential_local(faber, issuer_credential, &rev_reg.rev_reg_id).await; + rev_reg .publish_local_revocations( &faber.profile.inject_anoncreds(), @@ -930,16 +931,19 @@ pub mod test_utils { pub async fn revoke_credential_local(faber: &mut Faber, issuer_credential: &Issuer, rev_reg_id: &str) { let ledger = Arc::clone(&faber.profile).inject_anoncreds_ledger_read(); - let (_, delta, timestamp) = ledger.get_rev_reg_delta_json(&rev_reg_id, None, None).await.unwrap(); + let (_, delta, timestamp) = ledger.get_rev_reg_delta_json(rev_reg_id, None, None).await.unwrap(); info!("revoking credential locally"); + issuer_credential .revoke_credential_local(&faber.profile.inject_anoncreds()) .await .unwrap(); + let (_, delta_after_revoke, _) = ledger .get_rev_reg_delta_json(rev_reg_id, Some(timestamp + 1), None) .await .unwrap(); + assert_ne!(delta, delta_after_revoke); // They will not equal as we have saved the delta in cache } diff --git a/aries_vcx_core/src/anoncreds/credx_anoncreds.rs b/aries_vcx_core/src/anoncreds/credx_anoncreds.rs index 49c3dc0151..58a2c37cff 100644 --- a/aries_vcx_core/src/anoncreds/credx_anoncreds.rs +++ b/aries_vcx_core/src/anoncreds/credx_anoncreds.rs @@ -36,22 +36,22 @@ use uuid::Uuid; use super::base_anoncreds::BaseAnonCreds; -const CATEGORY_LINK_SECRET: &str = "VCX_LINK_SECRET"; +pub const CATEGORY_LINK_SECRET: &str = "VCX_LINK_SECRET"; -const CATEGORY_CREDENTIAL: &str = "VCX_CREDENTIAL"; -const CATEGORY_CRED_DEF: &str = "VCX_CRED_DEF"; -const CATEGORY_CRED_KEY_CORRECTNESS_PROOF: &str = "VCX_CRED_KEY_CORRECTNESS_PROOF"; -const CATEGORY_CRED_DEF_PRIV: &str = "VCX_CRED_DEF_PRIV"; -const CATEGORY_CRED_SCHEMA: &str = "VCX_CRED_SCHEMA"; +pub const CATEGORY_CREDENTIAL: &str = "VCX_CREDENTIAL"; +pub const CATEGORY_CRED_DEF: &str = "VCX_CRED_DEF"; +pub const CATEGORY_CRED_KEY_CORRECTNESS_PROOF: &str = "VCX_CRED_KEY_CORRECTNESS_PROOF"; +pub const CATEGORY_CRED_DEF_PRIV: &str = "VCX_CRED_DEF_PRIV"; +pub const CATEGORY_CRED_SCHEMA: &str = "VCX_CRED_SCHEMA"; // Category used for mapping a cred_def_id to a schema_id -const CATEGORY_CRED_MAP_SCHEMA_ID: &str = "VCX_CRED_MAP_SCHEMA_ID"; +pub const CATEGORY_CRED_MAP_SCHEMA_ID: &str = "VCX_CRED_MAP_SCHEMA_ID"; -const CATEGORY_REV_REG: &str = "VCX_REV_REG"; -const CATEGORY_REV_REG_DELTA: &str = "VCX_REV_REG_DELTA"; -const CATEGORY_REV_REG_INFO: &str = "VCX_REV_REG_INFO"; -const CATEGORY_REV_REG_DEF: &str = "VCX_REV_REG_DEF"; -const CATEGORY_REV_REG_DEF_PRIV: &str = "VCX_REV_REG_DEF_PRIV"; +pub const CATEGORY_REV_REG: &str = "VCX_REV_REG"; +pub const CATEGORY_REV_REG_DELTA: &str = "VCX_REV_REG_DELTA"; +pub const CATEGORY_REV_REG_INFO: &str = "VCX_REV_REG_INFO"; +pub const CATEGORY_REV_REG_DEF: &str = "VCX_REV_REG_DEF"; +pub const CATEGORY_REV_REG_DEF_PRIV: &str = "VCX_REV_REG_DEF_PRIV"; #[derive(Debug, Deserialize, Serialize, Clone)] pub struct RevocationRegistryInfo { @@ -209,7 +209,7 @@ impl BaseAnonCreds for IndyCredxAnonCreds { &pres_req, &hashmap_as_ref(&schemas), &hashmap_as_ref(&cred_defs), - rev_reg_defs.as_ref().map(|regs| hashmap_as_ref(regs)).as_ref(), + rev_reg_defs.as_ref().map(hashmap_as_ref).as_ref(), rev_regs.as_ref(), )?) } @@ -344,10 +344,8 @@ impl BaseAnonCreds for IndyCredxAnonCreds { warn!("Storing schema {schema_json} failed - {e}. It's possible it is already stored.") } - let str_schema_id = serde_json::to_string(schema.id())?; - self.wallet - .add_wallet_record(CATEGORY_CRED_MAP_SCHEMA_ID, &cred_def_id.0, &str_schema_id, None) + .add_wallet_record(CATEGORY_CRED_MAP_SCHEMA_ID, &cred_def_id.0, &schema.id().0, None) .await?; // Return the ID and the cred def @@ -362,9 +360,12 @@ impl BaseAnonCreds for IndyCredxAnonCreds { .await?; let schema_id = self + .wallet .get_wallet_record_value(CATEGORY_CRED_MAP_SCHEMA_ID, cred_def_id) .await?; + let schema_id = SchemaId(schema_id); + // If cred_def contains schema ID, why take it as an argument here...? let offer = credx::issuer::create_credential_offer(&schema_id, &cred_def, &correctness_proof)?; @@ -383,6 +384,7 @@ impl BaseAnonCreds for IndyCredxAnonCreds { let cred_request = serde_json::from_str(cred_req_json)?; let cred_values = serde_json::from_str(cred_values_json)?; + // TODO: Might need to qualify with offer method or something - look into how vdrtools does it let cred_def_id = &cred_offer.cred_def_id.0; let cred_def = self.get_wallet_record_value(CATEGORY_CRED_DEF, cred_def_id).await?; @@ -968,6 +970,34 @@ impl BaseAnonCreds for IndyCredxAnonCreds { let rev_reg_def = self.get_wallet_record_value(CATEGORY_REV_REG_DEF, rev_reg_id).await?; + let mut rev_reg_info: RevocationRegistryInfo = + self.get_wallet_record_value(CATEGORY_REV_REG_INFO, rev_reg_id).await?; + + let issuance_type = match &rev_reg_def { + RevocationRegistryDefinition::RevocationRegistryDefinitionV1(r) => r.value.issuance_type, + }; + + match issuance_type { + IssuanceType::ISSUANCE_ON_DEMAND => { + if !rev_reg_info.used_ids.remove(&cred_rev_id) { + return Err(AriesVcxCoreError::from_msg( + AriesVcxCoreErrorKind::InvalidInput, + format!("Revocation id: {:?} not found in RevocationRegistry", cred_rev_id), + )); + }; + } + IssuanceType::ISSUANCE_BY_DEFAULT => { + if !rev_reg_info.used_ids.insert(cred_rev_id) { + return Err(AriesVcxCoreError::from_msg( + AriesVcxCoreErrorKind::InvalidInput, + format!("Revocation id: {:?} not found in RevocationRegistry", cred_rev_id), + )); + } + } + }; + + let str_rev_reg_info = serde_json::to_string(&rev_reg_info)?; + let tails_file_hash = match &rev_reg_def { RevocationRegistryDefinition::RevocationRegistryDefinitionV1(r) => &r.value.tails_hash, }; @@ -997,6 +1027,10 @@ impl BaseAnonCreds for IndyCredxAnonCreds { .update_wallet_record_value(CATEGORY_REV_REG, rev_reg_id, &str_rev_reg) .await?; + self.wallet + .update_wallet_record_value(CATEGORY_REV_REG_INFO, rev_reg_id, &str_rev_reg_info) + .await?; + match old_str_rev_reg_delta { Some(_) => { self.wallet diff --git a/aries_vcx_core/src/wallet/indy_wallet.rs b/aries_vcx_core/src/wallet/indy_wallet.rs index cc01f78d24..8175e696f6 100644 --- a/aries_vcx_core/src/wallet/indy_wallet.rs +++ b/aries_vcx_core/src/wallet/indy_wallet.rs @@ -17,7 +17,7 @@ use super::base_wallet::BaseWallet; #[derive(Debug)] pub struct IndySdkWallet { - wallet_handle: WalletHandle, + pub wallet_handle: WalletHandle, } impl IndySdkWallet { @@ -66,11 +66,7 @@ impl BaseWallet for IndySdkWallet { } async fn get_wallet_record_value(&self, xtype: &str, id: &str) -> VcxCoreResult { - let options = r#"{ - "retrieve_type": false, - "retrieve_value": true, - "retrieve_tags": false - }"#; + let options = r#"{"retrieveType": false, "retrieveValue": true, "retrieveTags": false}"#; let str_record = self.get_wallet_record(xtype, id, options).await?; let wallet_record: WalletRecord = serde_json::from_str(&str_record)?; diff --git a/libvdrtools/indy-api-types/Cargo.toml b/libvdrtools/indy-api-types/Cargo.toml index 8747718dd4..ce79f74df8 100644 --- a/libvdrtools/indy-api-types/Cargo.toml +++ b/libvdrtools/indy-api-types/Cargo.toml @@ -12,7 +12,7 @@ casting_errors = [ "openssl", "rust-base58", "zmq", "ursa", "sqlx"] rust-base58 = ["bs58"] [dependencies] -failure = "0.1.8" +thiserror = "1.0.40" futures = { version = "0.3", default-features = false, features = ["std"] } log = { version = "0.4.17", features = ["std"] } libc = "0.2.114" diff --git a/libvdrtools/indy-api-types/src/errors.rs b/libvdrtools/indy-api-types/src/errors.rs index 34774e28d2..a2f4f91888 100644 --- a/libvdrtools/indy-api-types/src/errors.rs +++ b/libvdrtools/indy-api-types/src/errors.rs @@ -6,8 +6,9 @@ use std::{ sync::Arc, }; -use failure::{Backtrace, Context, Fail}; use log; +use std::error::Error; +use thiserror::Error as ThisError; #[cfg(feature = "casting_errors")] use sqlx; @@ -26,136 +27,124 @@ pub mod prelude { }; } -#[derive(Copy, Clone, Eq, PartialEq, Debug, Fail)] +#[derive(Copy, Clone, Eq, PartialEq, Debug, ThisError)] pub enum IndyErrorKind { // Common errors - #[fail(display = "Invalid library state")] + #[error("Invalid library state")] InvalidState, - #[fail(display = "Invalid structure")] + #[error("Invalid structure")] InvalidStructure, - #[fail(display = "Invalid parameter {}", 0)] + #[error("Invalid parameter {0}")] InvalidParam(u32), - #[fail(display = "IO error")] + #[error("IO error")] IOError, // Anoncreds errors - #[fail(display = "Duplicated master secret")] + #[error("Duplicated master secret")] MasterSecretDuplicateName, - #[fail(display = "Proof rejected")] + #[error("Proof rejected")] ProofRejected, - #[fail(display = "Revocation registry is full")] + #[error("Revocation registry is full")] RevocationRegistryFull, - #[fail(display = "Invalid revocation id")] + #[error("Invalid revocation id")] InvalidUserRevocId, - #[fail(display = "Credential revoked")] + #[error("Credential revoked")] CredentialRevoked, - #[fail(display = "Credential definition already exists")] + #[error("Credential definition already exists")] CredDefAlreadyExists, // Ledger errors - #[fail(display = "No consensus")] + #[error("No consensus")] NoConsensus, - #[fail(display = "Invalid transaction")] + #[error("Invalid transaction")] InvalidTransaction, - #[fail(display = "Item not found on ledger")] + #[error("Item not found on ledger")] LedgerItemNotFound, // Pool errors - #[fail(display = "Pool not created")] + #[error("Pool not created")] PoolNotCreated, - #[fail(display = "Invalid pool handle")] + #[error("Invalid pool handle")] InvalidPoolHandle, - #[fail(display = "Pool work terminated")] + #[error("Pool work terminated")] PoolTerminated, - #[fail(display = "Pool timeout")] + #[error("Pool timeout")] PoolTimeout, - #[fail(display = "Pool ledger config already exists")] + #[error("Pool ledger config already exists")] PoolConfigAlreadyExists, - #[fail(display = "Pool Genesis Transactions are not compatible with Protocol version")] + #[error("Pool Genesis Transactions are not compatible with Protocol version")] PoolIncompatibleProtocolVersion, // Crypto errors - #[fail(display = "Unknown crypto")] + #[error("Unknown crypto")] UnknownCrypto, // Wallet errors - #[fail(display = "Invalid wallet handle was passed")] + #[error("Invalid wallet handle was passed")] InvalidWalletHandle, - #[fail(display = "Unknown wallet storage type")] + #[error("Unknown wallet storage type")] UnknownWalletStorageType, - #[fail(display = "Wallet storage type already registered")] + #[error("Wallet storage type already registered")] WalletStorageTypeAlreadyRegistered, - #[fail(display = "Wallet with this name already exists")] + #[error("Wallet with this name already exists")] WalletAlreadyExists, - #[fail(display = "Wallet not found")] + #[error("Wallet not found")] WalletNotFound, - #[fail(display = "Wallet already opened")] + #[error("Wallet already opened")] WalletAlreadyOpened, - #[fail(display = "Wallet security error")] + #[error("Wallet security error")] WalletAccessFailed, - #[fail(display = "Wallet encoding error")] + #[error("Wallet encoding error")] WalletEncodingError, - #[fail(display = "Wallet storage error occurred")] + #[error("Wallet storage error occurred")] WalletStorageError, - #[fail(display = "Wallet encryption error")] + #[error("Wallet encryption error")] WalletEncryptionError, - #[fail(display = "Wallet item not found")] + #[error("Wallet item not found")] WalletItemNotFound, - #[fail(display = "Wallet item already exists")] + #[error("Wallet item already exists")] WalletItemAlreadyExists, - #[fail(display = "Wallet query error")] + #[error("Wallet query error")] WalletQueryError, // DID errors - #[fail(display = "DID already exists")] + #[error("DID already exists")] DIDAlreadyExists, // Payments errors - #[fail(display = "Unknown payment method type")] + #[error("Unknown payment method type")] UnknownPaymentMethodType, - #[fail(display = "No method were scraped from inputs/outputs or more than one were scraped")] + #[error("No method were scraped from inputs/outputs or more than one were scraped")] IncompatiblePaymentMethods, - #[fail(display = "Payment insufficient funds on inputs")] + #[error("Payment insufficient funds on inputs")] PaymentInsufficientFunds, - #[fail(display = "Payment Source does not exist")] + #[error("Payment Source does not exist")] PaymentSourceDoesNotExist, - #[fail(display = "Payment operation not supported")] + #[error("Payment operation not supported")] PaymentOperationNotSupported, - #[fail(display = "Payment extra funds")] + #[error("Payment extra funds")] PaymentExtraFunds, - #[fail(display = "The transaction is not allowed to a requester")] + #[error("The transaction is not allowed to a requester")] TransactionNotAllowed, - #[fail(display = "Query account does not exist")] + #[error("Query account does not exist")] QueryAccountDoesNotExist, - #[fail(display = "Invalid VDR handle")] + #[error("Invalid VDR handle")] InvalidVDRHandle, - #[fail(display = "Failed to get ledger for VDR Namespace")] + #[error("Failed to get ledger for VDR Namespace")] InvalidVDRNamespace, - #[fail(display = "Registered Ledger type does not match to the network of id")] + #[error("Registered Ledger type does not match to the network of id")] IncompatibleLedger, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, ThisError)] pub struct IndyError { // FIXME: We have to use Arc as for now we clone messages in pool service // FIXME: In theory we can avoid sync by refactoring of pool service - inner: Arc>, -} - -impl Fail for IndyError { - fn cause(&self) -> Option<&dyn Fail> { - self.inner.cause() - } - - fn backtrace(&self) -> Option<&Backtrace> { - self.inner.backtrace() - } + #[source] + kind: IndyErrorKind, + msg: Arc, } impl fmt::Display for IndyError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut causes = ::iter_chain(self.inner.as_ref()); - - if let Some(cause) = causes.next() { - writeln!(f, "Error: {}", cause)?; - } + writeln!(f, "Error: {}", self.kind())?; - for cause in causes { - writeln!(f, " Caused by: {}", cause)?; + if let Some(src) = self.kind.source() { + writeln!(f, " Caused by: {}", src)?; } Ok(()) @@ -165,35 +154,35 @@ impl fmt::Display for IndyError { impl IndyError { pub fn from_msg(kind: IndyErrorKind, msg: D) -> IndyError where - D: fmt::Display + fmt::Debug + Send + Sync + 'static, + D: fmt::Display + Send + Sync + 'static, { IndyError { - inner: Arc::new(Context::new(msg).context(kind)), + kind, + msg: Arc::new(msg.to_string()), } } pub fn kind(&self) -> IndyErrorKind { - *self.inner.get_context() + self.kind } pub fn extend(self, msg: D) -> IndyError where D: fmt::Display + fmt::Debug + Send + Sync + 'static, { - let kind = self.kind(); - let inner = Arc::try_unwrap(self.inner).unwrap(); IndyError { - inner: Arc::new(inner.map(|_| msg).context(kind)), + kind: self.kind, + msg: Arc::new(format!("{}\n Caused by: {msg}", self.msg)), } } pub fn map(self, kind: IndyErrorKind, msg: D) -> IndyError where - D: fmt::Display + fmt::Debug + Send + Sync + 'static, + D: fmt::Display + Send + Sync + 'static, { - let inner = Arc::try_unwrap(self.inner).unwrap(); IndyError { - inner: Arc::new(inner.map(|_| msg).context(kind)), + kind, + msg: Arc::new(format!("{}\n Caused by: {msg}", self.msg)), } } } @@ -208,88 +197,92 @@ where impl From for IndyError { fn from(kind: IndyErrorKind) -> IndyError { IndyError { - inner: Arc::new(Context::new(kind)), - } - } -} - -impl From> for IndyError { - fn from(inner: Context) -> IndyError { - IndyError { - inner: Arc::new(inner), + kind, + msg: Arc::new(String::new()), } } } impl From for IndyError { fn from(err: io::Error) -> Self { - err.context(IndyErrorKind::IOError).into() + IndyError { + kind: IndyErrorKind::IOError, + msg: Arc::new(err.to_string()), + } } } #[cfg(feature = "casting_errors")] impl From for IndyError { fn from(err: zmq::Error) -> Self { - err.context(IndyErrorKind::IOError).into() + IndyError { + kind: IndyErrorKind::IOError, + msg: Arc::new(err.to_string()), + } } } impl From for IndyError { fn from(err: cell::BorrowError) -> Self { - err.context(IndyErrorKind::InvalidState).into() + IndyError { + kind: IndyErrorKind::InvalidState, + msg: Arc::new(err.to_string()), + } } } impl From for IndyError { fn from(err: cell::BorrowMutError) -> Self { - err.context(IndyErrorKind::InvalidState).into() + IndyError { + kind: IndyErrorKind::InvalidState, + msg: Arc::new(err.to_string()), + } } } impl From for IndyError { fn from(err: futures::channel::oneshot::Canceled) -> Self { - err.context(IndyErrorKind::InvalidState).into() + IndyError { + kind: IndyErrorKind::InvalidState, + msg: Arc::new(err.to_string()), + } } } impl From for IndyError { fn from(err: log::SetLoggerError) -> IndyError { - err.context(IndyErrorKind::InvalidState).into() + IndyError { + kind: IndyErrorKind::InvalidState, + msg: Arc::new(err.to_string()), + } } } #[cfg(feature = "casting_errors")] impl From for IndyError { fn from(err: UrsaCryptoError) -> Self { - let message = format!( - "UrsaCryptoError: {}", - ::iter_causes(&err) - .map(|e| e.to_string()) - .collect::() - ); - match err.kind() { UrsaCryptoErrorKind::InvalidState => { - IndyError::from_msg(IndyErrorKind::InvalidState, message) + IndyError::from_msg(IndyErrorKind::InvalidState, err) } UrsaCryptoErrorKind::InvalidStructure => { - IndyError::from_msg(IndyErrorKind::InvalidStructure, message) + IndyError::from_msg(IndyErrorKind::InvalidStructure, err) } - UrsaCryptoErrorKind::IOError => IndyError::from_msg(IndyErrorKind::IOError, message), + UrsaCryptoErrorKind::IOError => IndyError::from_msg(IndyErrorKind::IOError, err), UrsaCryptoErrorKind::InvalidRevocationAccumulatorIndex => { - IndyError::from_msg(IndyErrorKind::InvalidUserRevocId, message) + IndyError::from_msg(IndyErrorKind::InvalidUserRevocId, err) } UrsaCryptoErrorKind::RevocationAccumulatorIsFull => { - IndyError::from_msg(IndyErrorKind::RevocationRegistryFull, message) + IndyError::from_msg(IndyErrorKind::RevocationRegistryFull, err) } UrsaCryptoErrorKind::ProofRejected => { - IndyError::from_msg(IndyErrorKind::ProofRejected, message) + IndyError::from_msg(IndyErrorKind::ProofRejected, err) } UrsaCryptoErrorKind::CredentialRevoked => { - IndyError::from_msg(IndyErrorKind::CredentialRevoked, message) + IndyError::from_msg(IndyErrorKind::CredentialRevoked, err) } UrsaCryptoErrorKind::InvalidParam(_) => { - IndyError::from_msg(IndyErrorKind::InvalidStructure, message) + IndyError::from_msg(IndyErrorKind::InvalidStructure, err) } } } @@ -580,13 +573,13 @@ pub trait IndyResultExt { impl IndyResultExt for Result where - E: Fail, + E: fmt::Display, { fn to_indy(self, kind: IndyErrorKind, msg: D) -> IndyResult where D: fmt::Display + Send + Sync + 'static, { - self.map_err(|err| err.context(msg).context(kind).into()) + self.map_err(|err| err.to_indy(kind, msg)) } } @@ -599,13 +592,13 @@ pub trait IndyErrorExt { impl IndyErrorExt for E where - E: Fail, + E: fmt::Display, { fn to_indy(self, kind: IndyErrorKind, msg: D) -> IndyError where D: fmt::Display + Send + Sync + 'static, { - self.context(msg).context(kind).into() + IndyError::from_msg(kind, format!("{msg}\n Caused by: {self}")) } } @@ -618,7 +611,7 @@ pub fn set_current_error(err: &IndyError) { .try_with(|error| { let error_json = json!({ "message": err.to_string(), - "backtrace": err.backtrace().map(|bt| bt.to_string()) + "backtrace": err.source().map(|bt| bt.to_string()) }) .to_string(); error.replace(Some(string_to_cstring(error_json))); diff --git a/libvdrtools/indy-utils/src/crypto/base64/rust_base64.rs b/libvdrtools/indy-utils/src/crypto/base64/rust_base64.rs index b79359448a..cac198ae91 100644 --- a/libvdrtools/indy-utils/src/crypto/base64/rust_base64.rs +++ b/libvdrtools/indy-utils/src/crypto/base64/rust_base64.rs @@ -1,4 +1,3 @@ -use failure::ResultExt; use indy_api_types::errors::prelude::*; pub fn encode(doc: &[u8]) -> String { @@ -7,9 +6,7 @@ pub fn encode(doc: &[u8]) -> String { pub fn decode(doc: &str) -> Result, IndyError> { base64::decode(doc) - .context("Invalid base64 sequence") - .context(IndyErrorKind::InvalidStructure) - .map_err(|err| err.into()) + .map_err(|e| e.to_indy(IndyErrorKind::InvalidStructure, "Invalid base64 sequence")) } pub fn encode_urlsafe(doc: &[u8]) -> String { @@ -17,10 +14,12 @@ pub fn encode_urlsafe(doc: &[u8]) -> String { } pub fn decode_urlsafe(doc: &str) -> Result, IndyError> { - base64::decode_config(doc, base64::URL_SAFE_NO_PAD) - .context("Invalid base64URL_SAFE sequence") - .context(IndyErrorKind::InvalidStructure) - .map_err(|err| err.into()) + base64::decode_config(doc, base64::URL_SAFE_NO_PAD).map_err(|e| { + e.to_indy( + IndyErrorKind::InvalidStructure, + "Invalid base64URL_SAFE sequence", + ) + }) } #[cfg(test)] diff --git a/libvdrtools/indy-utils/src/crypto/xsalsa20/sodium.rs b/libvdrtools/indy-utils/src/crypto/xsalsa20/sodium.rs index 7278c6966c..913aba2456 100644 --- a/libvdrtools/indy-utils/src/crypto/xsalsa20/sodium.rs +++ b/libvdrtools/indy-utils/src/crypto/xsalsa20/sodium.rs @@ -1,7 +1,6 @@ extern crate sodiumoxide; use self::sodiumoxide::crypto::{secretbox, secretbox::xsalsa20poly1305}; -use failure::{err_msg, ResultExt}; use indy_api_types::errors::prelude::*; pub const KEYBYTES: usize = xsalsa20poly1305::KEYBYTES; @@ -25,10 +24,12 @@ pub fn encrypt(key: &Key, nonce: &Nonce, doc: &[u8]) -> Vec { } pub fn decrypt(key: &Key, nonce: &Nonce, doc: &[u8]) -> Result, IndyError> { - secretbox::open(doc, &nonce.0, &key.0) - .map_err(|_| err_msg("Unable to open sodium secretbox")) - .context(IndyErrorKind::InvalidStructure) - .map_err(|err| err.into()) + secretbox::open(doc, &nonce.0, &key.0).map_err(|_| { + IndyError::from_msg( + IndyErrorKind::InvalidStructure, + "Unable to open sodium secretbox", + ) + }) } pub fn encrypt_detached(key: &Key, nonce: &Nonce, doc: &[u8]) -> (Vec, Tag) { @@ -46,10 +47,8 @@ pub fn decrypt_detached( ) -> Result, IndyError> { let mut plain = doc.to_vec(); secretbox::open_detached(plain.as_mut_slice(), &tag.0, &nonce.0, &key.0) - .map_err(|_| err_msg("Unable to decrypt data")) - .context(IndyErrorKind::InvalidStructure) - .map_err(|err| err.into()) - .map(|()| plain) + .map_err(|_| IndyError::from_msg(IndyErrorKind::InvalidStructure, "Unable to decrypt data")) + .map(|_| plain) } #[cfg(test)] diff --git a/libvdrtools/indy-utils/src/lib.rs b/libvdrtools/indy-utils/src/lib.rs index a45af9d3c1..4aa04545cb 100644 --- a/libvdrtools/indy-utils/src/lib.rs +++ b/libvdrtools/indy-utils/src/lib.rs @@ -27,8 +27,6 @@ pub mod sequence; pub mod test; pub mod wql; -pub(crate) use indy_api_types::ErrorCode; - use indy_api_types::{CommandHandle, PoolHandle, SearchHandle, VdrHandle, WalletHandle}; pub fn next_wallet_handle() -> WalletHandle { diff --git a/libvdrtools/indy-utils/src/test.rs b/libvdrtools/indy-utils/src/test.rs index d12c84e0c4..dbaf50da56 100644 --- a/libvdrtools/indy-utils/src/test.rs +++ b/libvdrtools/indy-utils/src/test.rs @@ -1,9 +1,9 @@ use super::environment; -use std::{fs, fs::File, path::PathBuf}; +use std::{fs, fs::File, path::Path}; -pub fn cleanup_files(dir: &PathBuf, name: &str) { - let mut path = dir.clone(); +pub fn cleanup_files(dir: &Path, name: &str) { + let mut path = dir.to_path_buf(); path.push(name); if path.exists() { if path.is_dir() { diff --git a/libvdrtools/indy-utils/src/wql.rs b/libvdrtools/indy-utils/src/wql.rs index 8ad57f63cc..6af8897b5f 100644 --- a/libvdrtools/indy-utils/src/wql.rs +++ b/libvdrtools/indy-utils/src/wql.rs @@ -49,7 +49,7 @@ impl<'de> Deserialize<'de> for Query { .ok_or_else(|| de::Error::custom("Restriction is invalid"))? .clone() .into_iter() - .filter(|&(_, ref v)| !v.is_null()) + .filter(|(_, v)| !v.is_null()) .collect(); if !sub_query.is_empty() { diff --git a/libvdrtools/indy-wallet/src/encryption.rs b/libvdrtools/indy-wallet/src/encryption.rs index 0d1717cae9..28c94a14fc 100644 --- a/libvdrtools/indy-wallet/src/encryption.rs +++ b/libvdrtools/indy-wallet/src/encryption.rs @@ -9,11 +9,6 @@ use crate::{ Keys, Metadata, WalletRecord, }; -#[cfg(test)] -pub(super) fn gen_master_key_salt() -> IndyResult { - Ok(pwhash_argon2i13::gen_salt()) -} - pub(super) fn master_key_salt_from_slice(slice: &[u8]) -> IndyResult { let salt = pwhash_argon2i13::Salt::from_slice(slice) .to_indy(IndyErrorKind::WalletAccessFailed, "Invalid master key salt")?; diff --git a/libvdrtools/indy-wallet/src/export_import.rs b/libvdrtools/indy-wallet/src/export_import.rs index e1820596ff..0aa1ab1e90 100644 --- a/libvdrtools/indy-wallet/src/export_import.rs +++ b/libvdrtools/indy-wallet/src/export_import.rs @@ -173,17 +173,6 @@ pub(super) async fn export_continue( Ok(()) } -#[cfg(test)] -async fn import(wallet: &Wallet, reader: T, passphrase: &str) -> IndyResult<()> -where - T: Read, -{ - let (reader, import_key_derivation_data, nonce, chunk_size, header_bytes) = - preparse_file_to_import(reader, passphrase)?; - let import_key = import_key_derivation_data.calc_master_key()?; - finish_import(wallet, reader, import_key, nonce, chunk_size, header_bytes).await -} - pub(super) fn preparse_file_to_import( reader: T, passphrase: &str, diff --git a/libvdrtools/indy-wallet/src/lib.rs b/libvdrtools/indy-wallet/src/lib.rs index 6a3108081a..01129372b2 100644 --- a/libvdrtools/indy-wallet/src/lib.rs +++ b/libvdrtools/indy-wallet/src/lib.rs @@ -1,5 +1,4 @@ -#[macro_use] -extern crate serde_json; +#![allow(clippy::all)] use std::{ collections::{HashMap, HashSet}, @@ -11,7 +10,7 @@ use std::{ }; use indy_api_types::{ - domain::wallet::{Config, Credentials, ExportConfig, Tags}, + domain::wallet::{Config, Credentials, ExportConfig, Record, Tags}, errors::prelude::*, WalletHandle, }; @@ -19,7 +18,7 @@ use indy_utils::{ crypto::chacha20poly1305_ietf::{self, Key as MasterKey}, secret, }; -use log::trace; +use log::{debug, trace}; use serde::{Deserialize, Serialize}; use serde_json::Value as SValue; use std::sync::Mutex; @@ -704,6 +703,65 @@ impl WalletService { Ok(()) } + pub async fn migrate_records( + &self, + old_wh: WalletHandle, + new_wh: WalletHandle, + mut migrate_fn: impl FnMut(Record) -> Result, E>, + ) -> IndyResult<()> + where + E: std::fmt::Display, + { + let old_wallet = self.get_wallet(old_wh).await?; + let new_wallet = self.get_wallet(new_wh).await?; + + let mut records = old_wallet.get_all().await?; + let mut num_records = 0; + + while let Some(WalletRecord { + type_, + id, + value, + tags, + }) = records.next().await? + { + num_records += 1; + let record = Record { + type_: type_.ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidState, + "No type fetched for exported record", + ) + })?, + id, + value: value.ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidState, + "No value fetched for exported record", + ) + })?, + tags: tags.ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidState, + "No tags fetched for exported record", + ) + })?, + }; + + if let Some(record) = migrate_fn(record) + .map_err(|e| IndyError::from_msg(IndyErrorKind::InvalidStructure, e.to_string()))? + { + new_wallet + .add(&record.type_, &record.id, &record.value, &record.tags) + .await?; + } + } + + debug!("{num_records} records have been migrated!"); + + Ok(()) + } + pub async fn export_wallet( &self, wallet_handle: WalletHandle, diff --git a/libvdrtools/indy-wallet/src/storage/mysql/mod.rs b/libvdrtools/indy-wallet/src/storage/mysql/mod.rs index 9461429914..4280e8e5fd 100644 --- a/libvdrtools/indy-wallet/src/storage/mysql/mod.rs +++ b/libvdrtools/indy-wallet/src/storage/mysql/mod.rs @@ -61,7 +61,7 @@ impl StorageIterator for MySQLStorageIterator { } } -#[derive(Deserialize, Debug)] +#[derive(Deserialize, Debug, Clone)] struct Config { pub read_host: String, pub write_host: String, @@ -75,7 +75,7 @@ fn default_connection_limit() -> u32 { 100 } -#[derive(Deserialize)] +#[derive(Deserialize, Clone)] pub struct Credentials { pub user: String, pub pass: String, @@ -99,33 +99,12 @@ impl MySqlStorageType { } } - pub async fn _connect( + async fn _connect( &self, read_only: bool, - config: Option<&str>, - credentials: Option<&str>, + config: Config, + credentials: Credentials, ) -> IndyResult { - let config = config - .map(serde_json::from_str::) - .transpose() - .to_indy(IndyErrorKind::InvalidStructure, "Malformed config json")? - .ok_or(err_msg( - IndyErrorKind::InvalidStructure, - "Absent config json", - ))?; - - let credentials = credentials - .map(serde_json::from_str::) - .transpose() - .to_indy( - IndyErrorKind::InvalidStructure, - "Malformed credentials json", - )? - .ok_or(err_msg( - IndyErrorKind::InvalidStructure, - "Absent credentials json", - ))?; - let host_addr = if read_only { &config.read_host } else { @@ -569,7 +548,6 @@ impl WalletStorage for MySqlStorage { SELECT type, name, value, tags FROM items WHERE wallet_id = ? - ORDER BY id "#, ) .bind(self.wallet_id) @@ -742,6 +720,27 @@ impl WalletStorageType for MySqlStorageType { config: Option<&str>, credentials: Option<&str>, ) -> IndyResult<()> { + let config = config + .map(serde_json::from_str::) + .transpose() + .to_indy(IndyErrorKind::InvalidStructure, "Malformed config json")? + .ok_or(err_msg( + IndyErrorKind::InvalidStructure, + "Absent config json", + ))?; + + let credentials = credentials + .map(serde_json::from_str::) + .transpose() + .to_indy( + IndyErrorKind::InvalidStructure, + "Malformed credentials json", + )? + .ok_or(err_msg( + IndyErrorKind::InvalidStructure, + "Absent credentials json", + ))?; + let mut tx = self ._connect(false, config, credentials) .await? @@ -811,12 +810,86 @@ impl WalletStorageType for MySqlStorageType { credentials: Option<&str>, metadata: &[u8], ) -> IndyResult<()> { - let mut tx = self - ._connect(false, config, credentials) - .await? - .begin() + let mut config = config + .map(serde_json::from_str::) + .transpose() + .to_indy(IndyErrorKind::InvalidStructure, "Malformed config json")? + .ok_or(err_msg( + IndyErrorKind::InvalidStructure, + "Absent config json", + ))?; + + let credentials = credentials + .map(serde_json::from_str::) + .transpose() + .to_indy( + IndyErrorKind::InvalidStructure, + "Malformed credentials json", + )? + .ok_or(err_msg( + IndyErrorKind::InvalidStructure, + "Absent credentials json", + ))?; + + let mut my_sql_connect_options = MySqlConnectOptions::new() + .host(&config.write_host) + .username(&credentials.user) + .password(&credentials.pass); + my_sql_connect_options.log_statements(LevelFilter::Debug); + + let mut pool = MySqlPoolOptions::default() + .max_connections(1) + .test_before_acquire(false) + .connect_with(my_sql_connect_options) .await?; + let mut con = pool.acquire().await?; + + // Basic SQL injection prevention + // since we cannot bind the database identifier + config.db_name = config.db_name.replace('`', "``"); + + sqlx::query(&format!( + "CREATE DATABASE IF NOT EXISTS `{}`;", + config.db_name + )) + .execute(&mut con) + .await?; + + // Replace the previous single use pool + // with the actual one, get a connection + // and create the required tables + pool = self._connect(false, config, credentials).await?; + con = pool.acquire().await?; + + sqlx::query( + r#" + CREATE TABLE IF NOT EXISTS `items` ( + `wallet_id` int NOT NULL, + `type` varchar(256) NOT NULL, + `name` varchar(256) NOT NULL, + `value` blob NOT NULL, + `tags` varchar(256) DEFAULT NULL, + PRIMARY KEY (`wallet_id`, `type`, `name`) + );"#, + ) + .execute(&mut con) + .await?; + + sqlx::query( + r#" + CREATE TABLE IF NOT EXISTS `wallets` ( + `id` int NOT NULL AUTO_INCREMENT, + `name` varchar(64) NOT NULL, + `metadata` varchar(4096) DEFAULT NULL, + PRIMARY KEY (`id`) + );"#, + ) + .execute(&mut con) + .await?; + + let mut tx = pool.begin().await?; + let res = sqlx::query( r#" INSERT INTO wallets (name, metadata) @@ -877,7 +950,30 @@ impl WalletStorageType for MySqlStorageType { config: Option<&str>, credentials: Option<&str>, ) -> IndyResult> { - let read_pool = self._connect(true, config, credentials).await?; + let config = config + .map(serde_json::from_str::) + .transpose() + .to_indy(IndyErrorKind::InvalidStructure, "Malformed config json")? + .ok_or(err_msg( + IndyErrorKind::InvalidStructure, + "Absent config json", + ))?; + + let credentials = credentials + .map(serde_json::from_str::) + .transpose() + .to_indy( + IndyErrorKind::InvalidStructure, + "Malformed credentials json", + )? + .ok_or(err_msg( + IndyErrorKind::InvalidStructure, + "Absent credentials json", + ))?; + + let read_pool = self + ._connect(true, config.clone(), credentials.clone()) + .await?; let write_pool = self._connect(false, config, credentials).await?; let res = sqlx::query_as::<_, (i64,)>( @@ -907,6 +1003,7 @@ impl WalletStorageType for MySqlStorageType { #[cfg(test)] mod tests { + #[allow(unused_imports)] use indy_utils::{assert_kind, environment}; use super::{super::Tag, *}; diff --git a/libvdrtools/indy-wallet/src/wallet.rs b/libvdrtools/indy-wallet/src/wallet.rs index ebb3381024..1146245004 100644 --- a/libvdrtools/indy-wallet/src/wallet.rs +++ b/libvdrtools/indy-wallet/src/wallet.rs @@ -344,6 +344,7 @@ impl Wallet { IndyErrorKind::InvalidStructure, "RecordOptions is malformed json", )?; + match self.cache.get(type_, &etype, &ename, &record_options).await { Some(result) => { cache_hit_metrics.inc_cache_hit(type_).await; @@ -352,7 +353,14 @@ impl Wallet { None => { // no item in cache, lets retrieve it and put it in cache. let metrics_fut = cache_hit_metrics.inc_cache_miss(type_); - let full_options = RecordOptions::id_value_tags(); + let full_options = RecordOptions { + retrieve_type: record_options.retrieve_type, + retrieve_value: true, + retrieve_tags: true, + }; + + let full_options = serde_json::to_string(&full_options).unwrap(); + let storage_fut = self.storage.get(&etype, &ename, &full_options); // run these two futures in parallel. let full_result = join(storage_fut, metrics_fut).await.0?; diff --git a/libvdrtools/src/controllers/non_secrets.rs b/libvdrtools/src/controllers/non_secrets.rs index 33844518b9..733b3d49db 100644 --- a/libvdrtools/src/controllers/non_secrets.rs +++ b/libvdrtools/src/controllers/non_secrets.rs @@ -491,13 +491,13 @@ impl NonSecretsController { res } - fn _check_type(&self, type_: &str) -> IndyResult<()> { - if type_.starts_with(WalletService::PREFIX) { - Err(err_msg( - IndyErrorKind::WalletAccessFailed, - format!("Record of type \"{}\" is not available for fetching", type_), - ))?; - } + fn _check_type(&self, _type: &str) -> IndyResult<()> { + // if type_.starts_with(WalletService::PREFIX) { + // Err(err_msg( + // IndyErrorKind::WalletAccessFailed, + // format!("Record of type \"{}\" is not available for fetching", type_), + // ))?; + // } Ok(()) } diff --git a/libvdrtools/src/controllers/wallet.rs b/libvdrtools/src/controllers/wallet.rs index 4f608ef6b5..a5e45dcea0 100644 --- a/libvdrtools/src/controllers/wallet.rs +++ b/libvdrtools/src/controllers/wallet.rs @@ -3,7 +3,7 @@ use std::sync::Arc; // use async_std::task::spawn_blocking; use indy_api_types::{ - domain::wallet::{Config, Credentials, ExportConfig, KeyConfig}, + domain::wallet::{Config, Credentials, ExportConfig, KeyConfig, Record}, errors::prelude::*, WalletHandle, }; @@ -390,6 +390,20 @@ impl WalletController { res } + pub async fn migrate_records( + &self, + old_wh: WalletHandle, + new_wh: WalletHandle, + migrate_fn: impl FnMut(Record) -> Result, E>, + ) -> IndyResult<()> + where + E: std::fmt::Display, + { + self.wallet_service + .migrate_records(old_wh, new_wh, migrate_fn) + .await + } + /// Generate wallet master key. /// Returned key is compatible with "RAW" key derivation method. /// It allows to avoid expensive key derivation for use cases when wallet keys can be stored in a secure enclave. diff --git a/libvdrtools/src/lib.rs b/libvdrtools/src/lib.rs index 22f1e4ef2d..33850f62e0 100644 --- a/libvdrtools/src/lib.rs +++ b/libvdrtools/src/lib.rs @@ -1,10 +1,9 @@ #![cfg_attr(feature = "fatal_warnings", deny(warnings))] +#![allow(clippy::all)] #[macro_use] extern crate log; -extern crate num_derive; - extern crate num_traits; #[macro_use] @@ -47,16 +46,24 @@ pub use controllers::CredentialDefinitionId; pub use domain::{ anoncreds::{ - credential::{Credential, CredentialValues}, - credential_definition::CredentialDefinition, + credential::{AttributeValues, Credential, CredentialValues}, + credential_definition::{ + CredentialDefinition, CredentialDefinitionCorrectnessProof, CredentialDefinitionData, + CredentialDefinitionPrivateKey, CredentialDefinitionV1, SignatureType, + }, credential_offer::CredentialOffer, credential_request::{CredentialRequest, CredentialRequestMetadata}, + master_secret::MasterSecret, + revocation_registry::{RevocationRegistry, RevocationRegistryV1}, revocation_registry_definition::{ - IssuanceType, RevocationRegistryConfig, RevocationRegistryDefinition, - RevocationRegistryId, + IssuanceType, RegistryType, RevocationRegistryConfig, RevocationRegistryDefinition, + RevocationRegistryDefinitionPrivate, RevocationRegistryDefinitionV1, + RevocationRegistryDefinitionValue, RevocationRegistryDefinitionValuePublicKeys, + RevocationRegistryId, RevocationRegistryInfo, }, + revocation_registry_delta::{RevocationRegistryDelta, RevocationRegistryDeltaV1}, revocation_state::RevocationStates, - schema::{AttributeNames, Schema, SchemaId}, + schema::{AttributeNames, Schema, SchemaId, SchemaV1}, }, crypto::{ did::{DidMethod, DidValue, MyDidInfo}, @@ -67,10 +74,11 @@ pub use domain::{ }; pub use indy_api_types::{ - CommandHandle, PoolHandle, SearchHandle, WalletHandle, INVALID_COMMAND_HANDLE, + CommandHandle, IndyError, PoolHandle, SearchHandle, WalletHandle, INVALID_COMMAND_HANDLE, INVALID_POOL_HANDLE, INVALID_SEARCH_HANDLE, INVALID_WALLET_HANDLE, }; +pub use indy_wallet::WalletRecord; pub use services::AnoncredsHelpers; // Global (lazy inited) instance of Locator diff --git a/libvdrtools/src/services/pool/merkle_tree_factory.rs b/libvdrtools/src/services/pool/merkle_tree_factory.rs index e496e97330..c6b6f7fcee 100644 --- a/libvdrtools/src/services/pool/merkle_tree_factory.rs +++ b/libvdrtools/src/services/pool/merkle_tree_factory.rs @@ -336,7 +336,7 @@ mod tests { fn _write_genesis_txns(pool_name: &str, txns: &str) { let path = get_pool_stored_path_base(pool_name, true, pool_name, POOL_EXT); let mut f = fs::File::create(path.as_path()).unwrap(); - f.write(txns.as_bytes()).unwrap(); + f.write_all(txns.as_bytes()).unwrap(); f.flush().unwrap(); f.sync_all().unwrap(); } diff --git a/libvdrtools/src/services/pool/mod.rs b/libvdrtools/src/services/pool/mod.rs index 3f97359253..313eee04f5 100644 --- a/libvdrtools/src/services/pool/mod.rs +++ b/libvdrtools/src/services/pool/mod.rs @@ -851,7 +851,7 @@ pub mod tests { pool_path.push(pool_name); pool_path.set_extension("txn"); let mut file = fs::File::create(pool_path).unwrap(); - file.write(&gen_txn.as_bytes()).unwrap(); + file.write_all(gen_txn.as_bytes()).unwrap(); let pool_id = next_pool_handle(); let mut pool = Pool::new(pool_name, pool_id, PoolOpenConfig::default()); diff --git a/libvdrtools/src/services/pool/pool.rs b/libvdrtools/src/services/pool/pool.rs index 90438777fc..39aeb32144 100644 --- a/libvdrtools/src/services/pool/pool.rs +++ b/libvdrtools/src/services/pool/pool.rs @@ -1914,7 +1914,7 @@ mod tests { let txns = test::gen_txns().join("\n"); let mut f = test_pool_create_poolfile(pool_name); - f.write(txns.as_bytes()).unwrap(); + f.write_all(txns.as_bytes()).unwrap(); f.flush().unwrap(); f.sync_all().unwrap(); } diff --git a/wallet_migrator/Cargo.toml b/wallet_migrator/Cargo.toml new file mode 100644 index 0000000000..b8bc66b50a --- /dev/null +++ b/wallet_migrator/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "wallet_migrator" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +aries_vcx_core = { path = "../aries_vcx_core", features = ["modular_libs"] } +credx = { package = "indy-credx", git = "https://github.com/anonyome/indy-shared-rs.git", rev = "7342bc624d23ece8845d1a701cd2cdc9cd401bb0" } +vdrtools = { package = "libvdrtools", path = "../libvdrtools" } +serde_json = "1.0.96" +thiserror = "1.0.40" +log = "0.4.19" + +[dev-dependencies] +tokio = { version = "1.28.2", features = ["macros", "rt"] } diff --git a/wallet_migrator/src/credx2anoncreds/conv.rs b/wallet_migrator/src/credx2anoncreds/conv.rs new file mode 100644 index 0000000000..007995c829 --- /dev/null +++ b/wallet_migrator/src/credx2anoncreds/conv.rs @@ -0,0 +1,43 @@ +use vdrtools::types::domain::wallet::Record; + +use crate::error::MigrationResult; + +pub fn convert_master_secret(record: Record) -> MigrationResult { + Ok(record) +} + +pub fn convert_cred(record: Record) -> MigrationResult { + Ok(record) +} + +pub fn convert_cred_def(record: Record) -> MigrationResult { + Ok(record) +} + +pub fn convert_cred_def_priv_key(record: Record) -> MigrationResult { + Ok(record) +} + +pub fn convert_cred_def_correctness_proof(record: Record) -> MigrationResult { + Ok(record) +} + +pub fn convert_schema(record: Record) -> MigrationResult { + Ok(record) +} + +pub fn convert_rev_reg(record: Record) -> MigrationResult { + Ok(record) +} + +pub fn convert_rev_reg_delta(record: Record) -> MigrationResult { + Ok(record) +} + +pub fn convert_rev_reg_def(record: Record) -> MigrationResult { + Ok(record) +} + +pub fn convert_rev_reg_def_priv(record: Record) -> MigrationResult { + Ok(record) +} diff --git a/wallet_migrator/src/credx2anoncreds/mod.rs b/wallet_migrator/src/credx2anoncreds/mod.rs new file mode 100644 index 0000000000..e906693400 --- /dev/null +++ b/wallet_migrator/src/credx2anoncreds/mod.rs @@ -0,0 +1 @@ +pub mod conv; diff --git a/wallet_migrator/src/error.rs b/wallet_migrator/src/error.rs new file mode 100644 index 0000000000..5db1a8c183 --- /dev/null +++ b/wallet_migrator/src/error.rs @@ -0,0 +1,15 @@ +use serde_json::Error as JsonError; +use thiserror::Error as ThisError; +use vdrtools::IndyError; + +pub type MigrationResult = Result; + +#[derive(Debug, ThisError)] +pub enum MigrationError { + #[error("JSON error: {0}")] + Json(#[from] JsonError), + #[error("Indy error: {0}")] + Indy(#[from] IndyError), + #[error("Source and destination wallets must be different!")] + EqualWalletHandles, +} diff --git a/wallet_migrator/src/lib.rs b/wallet_migrator/src/lib.rs new file mode 100644 index 0000000000..0ab296ae45 --- /dev/null +++ b/wallet_migrator/src/lib.rs @@ -0,0 +1,93 @@ +pub mod credx2anoncreds; +pub mod error; +pub mod vdrtools2credx; + +use std::fmt::Display; + +use error::MigrationResult; +use log::{error, info}; +use vdrtools::{Locator, WalletHandle}; + +pub use vdrtools::types::domain::wallet::Record; + +use crate::error::MigrationError; + +/// Retrieves all records from the source wallet and migrates them +/// by applying the `migrate_fn` argument. The records are then +/// placed in the destination wallet. +pub async fn migrate_wallet( + src_wallet_handle: WalletHandle, + dest_wallet_handle: WalletHandle, + migrate_fn: impl FnMut(Record) -> Result, E>, +) -> MigrationResult<()> +where + E: Display, +{ + info!("Starting wallet migration..."); + + if src_wallet_handle == dest_wallet_handle { + error!("Equal wallet handles: {src_wallet_handle:?} {dest_wallet_handle:?}"); + return Err(MigrationError::EqualWalletHandles); + } + + info!( + "Migrating records from wallet with handle {src_wallet_handle:?} to wallet with handle {dest_wallet_handle:?}" + ); + + Locator::instance() + .wallet_controller + .migrate_records(src_wallet_handle, dest_wallet_handle, migrate_fn) + .await?; + + info!("Migration from wallet with handle {src_wallet_handle:?} to wallet with handle {dest_wallet_handle:?} finished successfully!"); + + Ok(()) +} + +#[cfg(test)] +mod tests { + use vdrtools::{ + types::domain::wallet::{Config, Credentials, KeyDerivationMethod}, + Locator, + }; + + #[tokio::test] + #[should_panic] + async fn test_cant_open_wallet_twice() { + let wallet_key = "8dvfYSt5d1taSd6yJdpjq4emkwsPDDLYxkNFysFD2cZY".to_owned(); + let wallet_name = "wallet_with_some_name".to_owned(); + + let credentials = Credentials { + key: wallet_key, + key_derivation_method: KeyDerivationMethod::RAW, + rekey: None, + rekey_derivation_method: KeyDerivationMethod::ARGON2I_MOD, + storage_credentials: None, + }; + + let config = Config { + id: wallet_name, + storage_type: None, + storage_config: None, + cache: None, + }; + + Locator::instance() + .wallet_controller + .create(config.clone(), credentials.clone()) + .await + .unwrap(); + + let _first_wh = Locator::instance() + .wallet_controller + .open(config.clone(), credentials.clone()) + .await + .unwrap(); + + let _second_wh = Locator::instance() + .wallet_controller + .open(config, credentials) + .await + .unwrap(); + } +} diff --git a/wallet_migrator/src/vdrtools2credx/conv.rs b/wallet_migrator/src/vdrtools2credx/conv.rs new file mode 100644 index 0000000000..c0720a68b1 --- /dev/null +++ b/wallet_migrator/src/vdrtools2credx/conv.rs @@ -0,0 +1,106 @@ +use aries_vcx_core::anoncreds::credx_anoncreds::{ + RevocationRegistryInfo, CATEGORY_CREDENTIAL, CATEGORY_CRED_DEF, CATEGORY_CRED_DEF_PRIV, + CATEGORY_CRED_KEY_CORRECTNESS_PROOF, CATEGORY_CRED_MAP_SCHEMA_ID, CATEGORY_CRED_SCHEMA, CATEGORY_LINK_SECRET, + CATEGORY_REV_REG, CATEGORY_REV_REG_DEF, CATEGORY_REV_REG_DEF_PRIV, CATEGORY_REV_REG_DELTA, CATEGORY_REV_REG_INFO, +}; +use vdrtools::{types::domain::wallet::Record, IndyError}; + +use crate::error::MigrationResult; + +// The deltas in libvdrtools are prefixed. For absolutely no reason. +const REV_REG_DELTA_ID_PREFIX: &str = "rev_reg_delta:"; + +pub fn convert_master_secret(mut record: Record) -> MigrationResult { + let master_secret: vdrtools::MasterSecret = serde_json::from_str(&record.value)?; + + record.value = master_secret + .value + .value() + .map_err(IndyError::from)? + .to_dec() + .map_err(IndyError::from)?; + + record.type_ = CATEGORY_LINK_SECRET.to_owned(); + + Ok(record) +} + +pub fn convert_cred(mut record: Record) -> MigrationResult { + record.type_ = CATEGORY_CREDENTIAL.to_owned(); + let _: credx::types::Credential = serde_json::from_str(&record.value)?; + Ok(record) +} + +pub fn convert_cred_def(mut record: Record) -> MigrationResult { + record.type_ = CATEGORY_CRED_DEF.to_owned(); + let _: credx::types::CredentialDefinition = serde_json::from_str(&record.value)?; + Ok(record) +} + +pub fn convert_cred_def_priv_key(mut record: Record) -> MigrationResult { + record.type_ = CATEGORY_CRED_DEF_PRIV.to_owned(); + let _: credx::types::CredentialDefinitionPrivate = serde_json::from_str(&record.value)?; + Ok(record) +} + +pub fn convert_cred_def_correctness_proof(mut record: Record) -> MigrationResult { + record.type_ = CATEGORY_CRED_KEY_CORRECTNESS_PROOF.to_owned(); + let old: vdrtools::CredentialDefinitionCorrectnessProof = serde_json::from_str(&record.value)?; + let new = credx::types::CredentialKeyCorrectnessProof { value: old.value }; + record.value = serde_json::to_string(&new)?; + Ok(record) +} + +pub fn convert_schema(mut record: Record) -> MigrationResult { + record.type_ = CATEGORY_CRED_SCHEMA.to_owned(); + let _: credx::types::Schema = serde_json::from_str(&record.value)?; + Ok(record) +} + +pub fn convert_schema_id(mut record: Record) -> MigrationResult { + record.type_ = CATEGORY_CRED_MAP_SCHEMA_ID.to_owned(); + // The plain ID is stored as a String, + // so not that much to check. + let _ = credx::types::SchemaId(record.value.clone()); + Ok(record) +} + +pub fn convert_rev_reg(mut record: Record) -> MigrationResult { + record.type_ = CATEGORY_REV_REG.to_owned(); + let _: credx::types::RevocationRegistry = serde_json::from_str(&record.value)?; + Ok(record) +} + +pub fn convert_rev_reg_delta(mut record: Record) -> MigrationResult { + record.type_ = CATEGORY_REV_REG_DELTA.to_owned(); + + // Shave off the useless prefix, if found. + record.id = record + .id + .strip_prefix(REV_REG_DELTA_ID_PREFIX) + .map(ToOwned::to_owned) + .unwrap_or(record.id); + + // Them indy devs serializing a String to JSON... + record.value = serde_json::from_str(&record.value)?; + let _: credx::types::RevocationRegistryDelta = serde_json::from_str(&record.value)?; + Ok(record) +} + +pub fn convert_rev_reg_info(mut record: Record) -> MigrationResult { + record.type_ = CATEGORY_REV_REG_INFO.to_owned(); + let _: RevocationRegistryInfo = serde_json::from_str(&record.value)?; + Ok(record) +} + +pub fn convert_rev_reg_def(mut record: Record) -> MigrationResult { + record.type_ = CATEGORY_REV_REG_DEF.to_owned(); + let _: credx::types::RevocationRegistryDefinition = serde_json::from_str(&record.value)?; + Ok(record) +} + +pub fn convert_rev_reg_def_priv(mut record: Record) -> MigrationResult { + record.type_ = CATEGORY_REV_REG_DEF_PRIV.to_owned(); + let _: credx::types::RevocationRegistryDefinitionPrivate = serde_json::from_str(&record.value)?; + Ok(record) +} diff --git a/wallet_migrator/src/vdrtools2credx/mod.rs b/wallet_migrator/src/vdrtools2credx/mod.rs new file mode 100644 index 0000000000..40d2ba79fe --- /dev/null +++ b/wallet_migrator/src/vdrtools2credx/mod.rs @@ -0,0 +1,526 @@ +pub mod conv; + +use log::trace; +use vdrtools::types::domain::wallet::Record; + +use crate::error::MigrationResult; + +pub(crate) const INDY_DID: &str = "Indy::Did"; +pub(crate) const INDY_KEY: &str = "Indy::Key"; +pub(crate) const INDY_MASTER_SECRET: &str = "Indy::MasterSecret"; +pub(crate) const INDY_CRED: &str = "Indy::Credential"; +pub(crate) const INDY_CRED_DEF: &str = "Indy::CredentialDefinition"; +pub(crate) const INDY_CRED_DEF_PRIV: &str = "Indy::CredentialDefinitionPrivateKey"; +pub(crate) const INDY_CRED_DEF_CR_PROOF: &str = "Indy::CredentialDefinitionCorrectnessProof"; +pub(crate) const INDY_SCHEMA: &str = "Indy::Schema"; +pub(crate) const INDY_SCHEMA_ID: &str = "Indy::SchemaId"; +pub(crate) const INDY_REV_REG: &str = "Indy::RevocationRegistry"; +pub(crate) const INDY_REV_REG_DELTA: &str = "cache"; // very intuitive, indy devs +pub(crate) const INDY_REV_REG_INFO: &str = "Indy::RevocationRegistryInfo"; +pub(crate) const INDY_REV_REG_DEF: &str = "Indy::RevocationRegistryDefinition"; +pub(crate) const INDY_REV_REG_DEF_PRIV: &str = "Indy::RevocationRegistryDefinitionPrivate"; + +/// Contains the logic for record mapping and migration. +pub fn migrate_any_record(record: Record) -> MigrationResult> { + trace!("Migrating wallet record {record:?}"); + + let record = match record.type_.as_str() { + // Indy wallet records - to be left alone! + INDY_DID | INDY_KEY => Ok(Some(record)), + // Master secret + INDY_MASTER_SECRET => Some(conv::convert_master_secret(record)).transpose(), + // Credential + INDY_CRED => Some(conv::convert_cred(record)).transpose(), + INDY_CRED_DEF => Some(conv::convert_cred_def(record)).transpose(), + INDY_CRED_DEF_PRIV => Some(conv::convert_cred_def_priv_key(record)).transpose(), + INDY_CRED_DEF_CR_PROOF => Some(conv::convert_cred_def_correctness_proof(record)).transpose(), + // Schema + INDY_SCHEMA => Some(conv::convert_schema(record)).transpose(), + INDY_SCHEMA_ID => Some(conv::convert_schema_id(record)).transpose(), + // Revocation registry + INDY_REV_REG => Some(conv::convert_rev_reg(record)).transpose(), + INDY_REV_REG_DELTA => Some(conv::convert_rev_reg_delta(record)).transpose(), + INDY_REV_REG_INFO => Some(conv::convert_rev_reg_info(record)).transpose(), + INDY_REV_REG_DEF => Some(conv::convert_rev_reg_def(record)).transpose(), + INDY_REV_REG_DEF_PRIV => Some(conv::convert_rev_reg_def_priv(record)).transpose(), + _ => Ok(None), // Ignore unknown/uninteresting records + }; + + trace!("Converted wallet record to {record:?}"); + record +} + +#[cfg(test)] +mod tests { + use std::collections::{HashMap, HashSet}; + + use aries_vcx_core::anoncreds::credx_anoncreds::{ + RevocationRegistryInfo, CATEGORY_CREDENTIAL, CATEGORY_CRED_DEF, CATEGORY_CRED_DEF_PRIV, + CATEGORY_CRED_KEY_CORRECTNESS_PROOF, CATEGORY_CRED_MAP_SCHEMA_ID, CATEGORY_CRED_SCHEMA, CATEGORY_LINK_SECRET, + CATEGORY_REV_REG, CATEGORY_REV_REG_DEF, CATEGORY_REV_REG_DEF_PRIV, CATEGORY_REV_REG_DELTA, + CATEGORY_REV_REG_INFO, + }; + use credx::ursa::bn::BigNumber; + use serde_json::json; + use vdrtools::{ + types::domain::wallet::{Config, Credentials, KeyDerivationMethod}, + Locator, WalletHandle, + }; + + use crate::migrate_wallet; + + use super::*; + + const WALLET_KEY: &str = "8dvfYSt5d1taSd6yJdpjq4emkwsPDDLYxkNFysFD2cZY"; + + #[tokio::test] + async fn test_sqlite_migration() { + let (credentials, config) = make_wallet_reqs("wallet_test_migration".to_owned()); + let (new_credentials, new_config) = make_wallet_reqs("new_better_wallet".to_owned()); + + test_migration(credentials, config, new_credentials, new_config).await; + } + + #[tokio::test] + async fn test_mysql_migration() { + let wallet_name = "wallet_test_migration"; + let new_wallet_name = "new_better_wallet"; + + let (mut credentials, mut config) = make_wallet_reqs(wallet_name.to_owned()); + let (mut new_credentials, mut new_config) = make_wallet_reqs(new_wallet_name.to_owned()); + + config.storage_type = Some("mysql".to_owned()); + new_config.storage_type = Some("mysql".to_owned()); + + let storage_config = json!({ + "read_host": "localhost", + "write_host": "localhost", + "port": 3306, + "db_name": wallet_name, + "default_connection_limit": 50 + }); + + let new_storage_config = json!({ + "read_host": "localhost", + "write_host": "localhost", + "port": 3306, + "db_name": new_wallet_name, + "default_connection_limit": 50 + }); + + let storage_credentials = json!({ + "user": "root", + "pass": "mysecretpassword" + }); + + config.storage_config = Some(storage_config); + credentials.storage_credentials = Some(storage_credentials.clone()); + + new_config.storage_config = Some(new_storage_config); + new_credentials.storage_credentials = Some(storage_credentials); + + test_migration(credentials, config, new_credentials, new_config).await; + } + + macro_rules! add_wallet_item { + ($wh:expr, $category:expr, $val:expr) => { + Locator::instance() + .non_secret_controller + .add_record( + $wh, + $category.to_owned(), + "test_id".to_owned(), + serde_json::to_string(&$val).unwrap(), + None, + ) + .await + .unwrap(); + }; + } + + macro_rules! get_wallet_item { + ($wh:expr, $category:expr, $res:ty) => {{ + let val = get_wallet_item_raw($wh, $category).await; + serde_json::from_str::<$res>(&val).unwrap() + }}; + } + + async fn test_migration( + credentials: Credentials, + config: Config, + new_credentials: Credentials, + new_config: Config, + ) { + // Removes old wallet if it already exists + Locator::instance() + .wallet_controller + .delete(config.clone(), credentials.clone()) + .await + .ok(); + + // Create and open the old wallet + // where we'll store old indy anoncreds types + Locator::instance() + .wallet_controller + .create(config.clone(), credentials.clone()) + .await + .unwrap(); + + let src_wallet_handle = Locator::instance() + .wallet_controller + .open(config.clone(), credentials.clone()) + .await + .unwrap(); + + // Construct and add legacy indy records + // These are dummy records with dummy values + // and are NOT expected to be functional + // + // ################# Ingestion start ################# + + // Master secret + add_wallet_item!(src_wallet_handle, INDY_MASTER_SECRET, make_dummy_master_secret()); + + // Credential + add_wallet_item!(src_wallet_handle, INDY_CRED, make_dummy_cred()); + add_wallet_item!(src_wallet_handle, INDY_CRED_DEF, make_dummy_cred_def()); + add_wallet_item!(src_wallet_handle, INDY_CRED_DEF_PRIV, make_dummy_cred_def_priv_key()); + add_wallet_item!( + src_wallet_handle, + INDY_CRED_DEF_CR_PROOF, + make_dummy_cred_def_correctness_proof() + ); + + // Schema + add_wallet_item!(src_wallet_handle, INDY_SCHEMA, make_dummy_schema()); + add_wallet_item!(src_wallet_handle, INDY_SCHEMA_ID, make_dummy_schema_id()); + + // Revocation registry + add_wallet_item!(src_wallet_handle, INDY_REV_REG, make_dummy_rev_reg()); + add_wallet_item!(src_wallet_handle, INDY_REV_REG_DELTA, make_dummy_rev_reg_delta()); + add_wallet_item!(src_wallet_handle, INDY_REV_REG_INFO, make_dummy_rev_reg_info()); + add_wallet_item!(src_wallet_handle, INDY_REV_REG_DEF, make_dummy_rev_reg_def()); + add_wallet_item!(src_wallet_handle, INDY_REV_REG_DEF_PRIV, make_dummy_rev_reg_def_priv()); + + // ################# Ingestion end ################# + + // Remove new wallet if it already exists + Locator::instance() + .wallet_controller + .delete(new_config.clone(), new_credentials.clone()) + .await + .ok(); + + Locator::instance() + .wallet_controller + .create(new_config.clone(), new_credentials.clone()) + .await + .unwrap(); + + let dest_wallet_handle = Locator::instance() + .wallet_controller + .open(new_config.clone(), new_credentials.clone()) + .await + .unwrap(); + + // Migrate the records + migrate_wallet(src_wallet_handle, dest_wallet_handle, migrate_any_record) + .await + .unwrap(); + + // Old wallet cleanup + Locator::instance() + .wallet_controller + .close(src_wallet_handle) + .await + .unwrap(); + + Locator::instance() + .wallet_controller + .delete(config, credentials) + .await + .unwrap(); + + // ################# Retrieval start ################# + + // Master secret + get_master_secret(dest_wallet_handle).await; + + // Credential + get_wallet_item!(dest_wallet_handle, CATEGORY_CREDENTIAL, credx::types::Credential); + get_wallet_item!( + dest_wallet_handle, + CATEGORY_CRED_DEF, + credx::types::CredentialDefinition + ); + get_wallet_item!( + dest_wallet_handle, + CATEGORY_CRED_DEF_PRIV, + credx::types::CredentialDefinitionPrivate + ); + get_wallet_item!( + dest_wallet_handle, + CATEGORY_CRED_KEY_CORRECTNESS_PROOF, + credx::types::CredentialKeyCorrectnessProof + ); + + // Schema + get_wallet_item!(dest_wallet_handle, CATEGORY_CRED_SCHEMA, credx::types::Schema); + get_wallet_item!(dest_wallet_handle, CATEGORY_CRED_MAP_SCHEMA_ID, credx::types::SchemaId); + + // Revocation registry + get_wallet_item!(dest_wallet_handle, CATEGORY_REV_REG, credx::types::RevocationRegistry); + get_wallet_item!( + dest_wallet_handle, + CATEGORY_REV_REG_DELTA, + credx::types::RevocationRegistryDelta + ); + get_wallet_item!(dest_wallet_handle, CATEGORY_REV_REG_INFO, RevocationRegistryInfo); + get_wallet_item!( + dest_wallet_handle, + CATEGORY_REV_REG_DEF, + credx::types::RevocationRegistryDefinition + ); + get_wallet_item!( + dest_wallet_handle, + CATEGORY_REV_REG_DEF_PRIV, + credx::types::RevocationRegistryDefinitionPrivate + ); + + // ################# Retrieval end ################# + + // New wallet cleanup + Locator::instance() + .wallet_controller + .close(dest_wallet_handle) + .await + .unwrap(); + + Locator::instance() + .wallet_controller + .delete(new_config, new_credentials) + .await + .unwrap(); + } + + fn make_wallet_reqs(wallet_name: String) -> (Credentials, Config) { + let credentials = Credentials { + key: WALLET_KEY.to_owned(), + key_derivation_method: KeyDerivationMethod::RAW, + rekey: None, + rekey_derivation_method: KeyDerivationMethod::ARGON2I_MOD, + storage_credentials: None, + }; + + let config = Config { + id: wallet_name, + storage_type: None, + storage_config: None, + cache: None, + }; + + (credentials, config) + } + + async fn get_wallet_item_raw(wallet_handle: WalletHandle, category: &str) -> String { + let options = r#"{"retrieveType": true, "retrieveValue": true, "retrieveTags": true}"#; + + let record_str = Locator::instance() + .non_secret_controller + .get_record( + wallet_handle, + category.to_owned(), + "test_id".to_owned(), + options.to_owned(), + ) + .await + .unwrap(); + + let record: Record = serde_json::from_str(&record_str).unwrap(); + record.value + } + + // MasterSecret needs special processing + async fn get_master_secret(wallet_handle: WalletHandle) { + let ms_decimal = get_wallet_item_raw(wallet_handle, CATEGORY_LINK_SECRET).await; + let ms_bn = BigNumber::from_dec(&ms_decimal).unwrap(); + + let ursa_ms: credx::ursa::cl::MasterSecret = serde_json::from_value(json!({ "ms": ms_bn })).unwrap(); + let _ = credx::types::MasterSecret { value: ursa_ms }; + } + + fn make_dummy_master_secret() -> vdrtools::MasterSecret { + let ms_str = json!({ + "value": { + "ms": "1234567890" + } + }) + .to_string(); + + serde_json::from_str(&ms_str).unwrap() + } + + fn make_dummy_cred() -> vdrtools::Credential { + let cred_sig_str = json!({ + "p_credential": { + "m_2": "1234567890", + "a": "1234567890", + "e": "1234567890", + "v": "1234567890" + }, + "r_credential": null + }) + .to_string(); + + let sig_cor_proof_str = json!({ + "se": "1234567890", + "c": "1234567890" + }) + .to_string(); + + vdrtools::Credential { + schema_id: vdrtools::SchemaId("test_schema_id".to_owned()), + cred_def_id: vdrtools::CredentialDefinitionId("test_cred_def_id".to_owned()), + rev_reg_id: Some(vdrtools::RevocationRegistryId("test_rev_reg_id".to_owned())), + values: vdrtools::CredentialValues(HashMap::new()), + signature: serde_json::from_str(&cred_sig_str).unwrap(), + signature_correctness_proof: serde_json::from_str(&sig_cor_proof_str).unwrap(), + rev_reg: None, + witness: None, + } + } + + fn make_dummy_cred_def() -> vdrtools::CredentialDefinition { + let primary = json!({ + "n": "1234567890", + "s": "1234567890", + "r": {}, + "rctxt": "1234567890", + "z": "1234567890", + }) + .to_string(); + + vdrtools::CredentialDefinition::CredentialDefinitionV1(vdrtools::CredentialDefinitionV1 { + id: vdrtools::CredentialDefinitionId("test_cred_def_id".to_owned()), + schema_id: vdrtools::SchemaId("test_schema_id".to_owned()), + signature_type: vdrtools::SignatureType::CL, + tag: "{}".to_owned(), + value: vdrtools::CredentialDefinitionData { + primary: serde_json::from_str(&primary).unwrap(), + revocation: None, + }, + }) + } + + fn make_dummy_cred_def_priv_key() -> vdrtools::CredentialDefinitionPrivateKey { + let priv_key = json!({ + "p_key": { + "p": "1234567890", + "q": "1234567890" + } + }) + .to_string(); + + vdrtools::CredentialDefinitionPrivateKey { + value: serde_json::from_str(&priv_key).unwrap(), + } + } + + fn make_dummy_cred_def_correctness_proof() -> vdrtools::CredentialDefinitionCorrectnessProof { + let cor_proof = json!({ + "c": "1234567890", + "xz_cap": "1234567890", + "xr_cap": [] + }) + .to_string(); + + vdrtools::CredentialDefinitionCorrectnessProof { + value: serde_json::from_str(&cor_proof).unwrap(), + } + } + + fn make_dummy_schema() -> vdrtools::Schema { + vdrtools::Schema::SchemaV1(vdrtools::SchemaV1 { + id: vdrtools::SchemaId("test_schema_id".to_owned()), + name: "test_schema_name".to_owned(), + version: "test_schema_version".to_owned(), + attr_names: vdrtools::AttributeNames(HashSet::new()), + seq_no: None, + }) + } + + fn make_dummy_schema_id() -> vdrtools::SchemaId { + vdrtools::SchemaId("test_schema_id".to_owned()) + } + + fn make_dummy_rev_reg() -> vdrtools::RevocationRegistry { + let rev_reg = json!({ + "accum": "21 11ED98357F9B9B3077E633D35A72CECEF107F85DA7BBFBF2873E2EE7E0F27D326 21 1371CDA6174D6F01A39157428768D328B4B80088EB14AA0AAB7F046B645E1A235 6 65BBFAC37012790BB8B283F164BE3C0585AB60CD7B72123E4DC43DDA7A6A4E6D 4 3BB64FAF922865095CD5AA4349C0437D04EA30FB7592D932531732F2DCB83DB8 6 77039B80A78AB4A2476373C6F8ECC5E2D94B8F37F924549AFA247E2D6EE86DEE 4 24E94FB6B5233B22BDF47745AA821A1797BC6504BC11D5B825B4F8137F1E307F" + }).to_string(); + + vdrtools::RevocationRegistry::RevocationRegistryV1(vdrtools::RevocationRegistryV1 { + value: serde_json::from_str(&rev_reg).unwrap(), + }) + } + + fn make_dummy_rev_reg_delta() -> String { + let rev_reg = json!({ + "prevAccum": "21 11ED98357F9B9B3077E633D35A72CECEF107F85DA7BBFBF2873E2EE7E0F27D326 21 1371CDA6174D6F01A39157428768D328B4B80088EB14AA0AAB7F046B645E1A235 6 65BBFAC37012790BB8B283F164BE3C0585AB60CD7B72123E4DC43DDA7A6A4E6D 4 3BB64FAF922865095CD5AA4349C0437D04EA30FB7592D932531732F2DCB83DB8 6 77039B80A78AB4A2476373C6F8ECC5E2D94B8F37F924549AFA247E2D6EE86DEE 4 24E94FB6B5233B22BDF47745AA821A1797BC6504BC11D5B825B4F8137F1E307F", + "accum": "21 11ED98357F9B9B3077E633D35A72CECEF107F85DA7BBFBF2873E2EE7E0F27D326 21 1371CDA6174D6F01A39157428768D328B4B80088EB14AA0AAB7F046B645E1A235 6 65BBFAC37012790BB8B283F164BE3C0585AB60CD7B72123E4DC43DDA7A6A4E6D 4 3BB64FAF922865095CD5AA4349C0437D04EA30FB7592D932531732F2DCB83DB8 6 77039B80A78AB4A2476373C6F8ECC5E2D94B8F37F924549AFA247E2D6EE86DEE 4 24E94FB6B5233B22BDF47745AA821A1797BC6504BC11D5B825B4F8137F1E307F", + "issued": [], + "revoked": [] + }).to_string(); + + let rev_reg_delta = + vdrtools::RevocationRegistryDelta::RevocationRegistryDeltaV1(vdrtools::RevocationRegistryDeltaV1 { + value: serde_json::from_str(&rev_reg).unwrap(), + }); + + // Vdrtools serializes this to String. + // Sad, I know... + json!(rev_reg_delta).to_string() + } + + fn make_dummy_rev_reg_info() -> vdrtools::RevocationRegistryInfo { + vdrtools::RevocationRegistryInfo { + id: vdrtools::RevocationRegistryId("test_rev_reg_id".to_owned()), + curr_id: 1, + used_ids: HashSet::new(), + } + } + + fn make_dummy_rev_reg_def() -> vdrtools::RevocationRegistryDefinition { + let accum_key = json!({ + "z": "1 042CDA7AA76FFD05D0EA1C97F0F238A579AAE4348442298B7F8513277A21D671 1 04C49DDECC3731B11BC98A1495C39DF7F94A297EA6D691DADAF1493300D2977E 1 0D78B673DE9F1CE37FA98E0765B69D963BFF9973317722981943797EFEF1F628 1 1F4DFD2C1ED2BD80D9D92600AB7A1B2911180B4B44C6BC42962084AC4C042385 1 07724871AD4FFC1C30BCAEFE289FAF6F2F322203C34D8D2D3C36DFD816AF9430 1 050F4014E2AFD680A67C197B39D35CA4D03332D6C6922A4D991EC1402B7FF4E6 1 07C0DCAF303CF4B0741447A1A808C8C2BAE6CD30397AAF834428848FEE70FC3D 1 1C028C08BD426B053942A4409F71A5215B6B0B58FF651C72303F1B4C5DDB84C4 1 22DE20332A0E1B0C58F76CBADBF73D0B6875A5F3479AC0E3C4D27A605656BF6E 1 1F461563E404002F9AFE37D09FA98F34B4666D1A4424C89B3C8CE7E85DE23B8A 1 096DA55063F6ABA1B578471DEBDEACA5DE485994F99099BBBB6E326DDF8C3DD2 1 12FFCEFF31CE5781FF6BB9AB279BF8A100E97D43B0F6C31E6FCD6373227E34FD" + }).to_string(); + + vdrtools::RevocationRegistryDefinition::RevocationRegistryDefinitionV1( + vdrtools::RevocationRegistryDefinitionV1 { + id: vdrtools::RevocationRegistryId("test_rev_reg_id".to_owned()), + revoc_def_type: vdrtools::RegistryType::CL_ACCUM, + tag: "{}".to_owned(), + cred_def_id: vdrtools::CredentialDefinitionId("test_cred_def_id".to_owned()), + value: vdrtools::RevocationRegistryDefinitionValue { + issuance_type: vdrtools::IssuanceType::ISSUANCE_BY_DEFAULT, + max_cred_num: 10, + public_keys: vdrtools::RevocationRegistryDefinitionValuePublicKeys { + accum_key: serde_json::from_str(&accum_key).unwrap(), + }, + tails_hash: "abc".to_owned(), + tails_location: "/dev/null".to_owned(), + }, + }, + ) + } + + fn make_dummy_rev_reg_def_priv() -> vdrtools::RevocationRegistryDefinitionPrivate { + let rev_key_priv = json!({ + "gamma": "12345" + }) + .to_string(); + + vdrtools::RevocationRegistryDefinitionPrivate { + value: serde_json::from_str(&rev_key_priv).unwrap(), + } + } +}