From a3d1fa6d3c70502fa8305dc28ba792ae7df78b47 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Fri, 22 Nov 2024 08:30:55 +0100 Subject: [PATCH] replaces with 'rules' and 'rules-uniffi' crate --- Cargo.lock | 1106 ++---- Cargo.toml | 49 +- crates/rules-uniffi/Cargo.toml | 27 + crates/rules-uniffi/src/lib.rs | 0 crates/rules/Cargo.toml | 7 + crates/rules/src/lib.rs | 10 + crates/rules/src/rules/error.rs | 8 + crates/rules/src/rules/mod.rs | 3 + .../collector/key_derivation_outcome.rs | 34 - src/derivation/collector/key_ring.rs | 50 - src/derivation/collector/keys_collector.rs | 169 - .../collector/keys_collector_dependencies.rs | 29 - .../collector/keys_collector_preprocessor.rs | 44 - .../collector/keys_collector_state.rs | 59 - src/derivation/collector/mod.rs | 14 - .../interactors/key_derivation_interactor.rs | 23 - .../host_interaction/interactors/mod.rs | 7 - .../mono_factor_key_derivation_interactor.rs | 16 - .../poly_factor_key_derivation_interactor.rs | 16 - .../key_derivation_response.rs | 21 - .../keys_derivation_interactors.rs | 6 - src/derivation/host_interaction/mod.rs | 9 - .../host_interaction/requests/mod.rs | 5 - .../mono_factor_key_derivation_request.rs | 25 - .../poly_factor_key_derivation_request.rs | 15 - src/derivation/mod.rs | 6 - src/derivation/tests/derivation_tests.rs | 547 --- src/derivation/tests/mod.rs | 1 - .../agnostic_paths/derivation_preset.rs | 93 - .../agnostic_paths/index_agnostic_path.rs | 122 - .../agnostic_paths/mod.rs | 9 - .../quantified_derivation_preset.rs | 17 - .../agnostic_paths/quantities.rs | 4 - src/factor_instances_provider/mod.rs | 7 - .../next_index_assigner/mod.rs | 11 - .../next_derivation_entity_index_assigner.rs | 84 - ...n_entity_index_cache_analyzing_assigner.rs | 37 - ...entity_index_profile_analyzing_assigner.rs | 432 --- ...ion_entity_index_with_ephemeral_offsets.rs | 113 - ...ith_ephemeral_offsets_for_factor_source.rs | 28 - .../provider/factor_instances_cache.rs | 525 --- .../provider/factor_instances_provider.rs | 321 -- .../factor_instances_provider_unit_tests.rs | 1644 --------- .../provider/keyed_instances.rs | 76 - src/factor_instances_provider/provider/mod.rs | 16 - .../factor_instances_provider_outcome.rs | 54 - ...r_instances_provider_outcome_for_factor.rs | 101 - ...ernal_factor_instances_provider_outcome.rs | 221 -- ...r_instances_provider_outcome_for_factor.rs | 100 - .../provider/outcome/mod.rs | 9 - .../provider/provider_adopters/mod.rs | 5 - ...curify_entity_factor_instances_provider.rs | 244 -- ...rtual_entity_creating_instance_provider.rs | 495 --- .../provider/test_sargon_os.rs | 349 -- src/gateway/gateway_read_write.rs | 30 - src/gateway/gateway_readonly.rs | 52 - src/gateway/mod.rs | 13 - src/gateway/on_chain_entity_state.rs | 114 - src/gateway/test_gateway.rs | 230 -- src/lib.rs | 55 - src/samples/mod.rs | 5 - src/samples/sample_values.rs | 498 --- src/signing/collector/mod.rs | 12 - .../signatures_collecting_continuation.rs | 14 - src/signing/collector/signatures_collector.rs | 701 ---- .../signatures_collector_dependencies.rs | 36 - .../signatures_collector_preprocessor.rs | 121 - .../collector/signatures_collector_state.rs | 14 - .../signing_finish_early_strategy.rs | 116 - .../host_interaction/interactors/mod.rs | 7 - .../mono_factor_sign_interactor.rs | 20 - .../poly_factor_sign_interactor.rs | 24 - .../interactors/sign_interactor.rs | 19 - src/signing/host_interaction/mod.rs | 9 - src/signing/host_interaction/requests/mod.rs | 9 - .../requests/mono_factor_sign_request.rs | 30 - .../mono_factor_sign_request_input.rs | 96 - .../requests/poly_factor_sign_request.rs | 84 - .../transaction_sign_request_input.rs | 109 - .../host_interaction/sign_interactors.rs | 6 - src/signing/host_interaction/sign_response.rs | 29 - src/signing/mod.rs | 13 - .../petition_types/factor_list_kind.rs | 36 - src/signing/petition_types/mod.rs | 14 - .../petition_types/petition_for_entity.rs | 571 ---- .../factor_source_referencing.rs | 20 - .../petition_for_factors_types/mod.rs | 8 - .../neglected_factor_instance.rs | 98 - .../petition_for_factors/mod.rs | 16 - .../petition_for_factors.rs | 203 -- .../petition_for_factors_input.rs | 90 - .../petition_for_factors_state.rs | 169 - .../petition_for_factors_state_snapshot.rs | 93 - .../petition_for_factors_status.rs | 115 - .../petition_for_factors_sub_state.rs | 39 - .../petition_for_transaction.rs | 297 -- src/signing/petition_types/petitions.rs | 247 -- .../petition_types/petitions_status.rs | 37 - .../maybe_signed_transactions.rs | 303 -- src/signing/signatures_outcome_types/mod.rs | 10 - .../petition_transaction_outcome.rs | 54 - .../sign_with_factors_outcome.rs | 52 - .../signatures_outcome.rs | 174 - src/signing/tests/mod.rs | 1 - src/signing/tests/signing_tests.rs | 1329 -------- src/signing/tx_to_sign.rs | 70 - src/testing/derivation/mod.rs | 8 - .../derivation/stateless_dummy_indices.rs | 27 - src/testing/derivation/test_keys_collector.rs | 190 -- src/testing/mod.rs | 38 - src/testing/signing/mod.rs | 13 - src/testing/signing/simulated_user.rs | 179 - src/testing/signing/test_interactors/mod.rs | 10 - .../test_interactors/test_interactor.rs | 14 - .../test_parallel_interactor.rs | 77 - .../test_serial_interactor.rs | 59 - .../test_signature_collecting_interactors.rs | 27 - .../signing/test_signatures_collector.rs | 110 - src/types/factor_sources_of_kind.rs | 88 - src/types/hd_signature.rs | 93 - src/types/hd_signature_input.rs | 72 - src/types/hidden_constructor.rs | 15 - src/types/invalid_transaction_if_neglected.rs | 91 - src/types/mod.rs | 19 - src/types/new_methods_on_sargon_types.rs | 53 - src/types/new_types/accounts.rs | 84 - src/types/new_types/appendable_collection.rs | 95 - src/types/new_types/factor_instances.rs | 133 - src/types/new_types/is_securified_entity.rs | 71 - src/types/new_types/key_space.rs | 44 - src/types/new_types/mod.rs | 23 - src/types/new_types/securified_account.rs | 167 - src/types/new_types/securified_accounts.rs | 44 - src/types/new_types/securified_persona.rs | 92 - src/types/new_types/u30.rs | 56 - src/types/new_types/unsecurified_entity.rs | 135 - src/types/new_types/veci.rs | 95 - src/types/owned_types/mod.rs | 5 - src/types/owned_types/owned.rs | 26 - .../owned_types/owned_factor_instance.rs | 38 - src/types/sargon_types.rs | 2983 ----------------- tests/main.rs | 305 -- 142 files changed, 434 insertions(+), 19080 deletions(-) create mode 100644 crates/rules-uniffi/Cargo.toml create mode 100644 crates/rules-uniffi/src/lib.rs create mode 100644 crates/rules/Cargo.toml create mode 100644 crates/rules/src/lib.rs create mode 100644 crates/rules/src/rules/error.rs create mode 100644 crates/rules/src/rules/mod.rs delete mode 100644 src/derivation/collector/key_derivation_outcome.rs delete mode 100644 src/derivation/collector/key_ring.rs delete mode 100644 src/derivation/collector/keys_collector.rs delete mode 100644 src/derivation/collector/keys_collector_dependencies.rs delete mode 100644 src/derivation/collector/keys_collector_preprocessor.rs delete mode 100644 src/derivation/collector/keys_collector_state.rs delete mode 100644 src/derivation/collector/mod.rs delete mode 100644 src/derivation/host_interaction/interactors/key_derivation_interactor.rs delete mode 100644 src/derivation/host_interaction/interactors/mod.rs delete mode 100644 src/derivation/host_interaction/interactors/mono_factor_key_derivation_interactor.rs delete mode 100644 src/derivation/host_interaction/interactors/poly_factor_key_derivation_interactor.rs delete mode 100644 src/derivation/host_interaction/key_derivation_response.rs delete mode 100644 src/derivation/host_interaction/keys_derivation_interactors.rs delete mode 100644 src/derivation/host_interaction/mod.rs delete mode 100644 src/derivation/host_interaction/requests/mod.rs delete mode 100644 src/derivation/host_interaction/requests/mono_factor_key_derivation_request.rs delete mode 100644 src/derivation/host_interaction/requests/poly_factor_key_derivation_request.rs delete mode 100644 src/derivation/mod.rs delete mode 100644 src/derivation/tests/derivation_tests.rs delete mode 100644 src/derivation/tests/mod.rs delete mode 100644 src/factor_instances_provider/agnostic_paths/derivation_preset.rs delete mode 100644 src/factor_instances_provider/agnostic_paths/index_agnostic_path.rs delete mode 100644 src/factor_instances_provider/agnostic_paths/mod.rs delete mode 100644 src/factor_instances_provider/agnostic_paths/quantified_derivation_preset.rs delete mode 100644 src/factor_instances_provider/agnostic_paths/quantities.rs delete mode 100644 src/factor_instances_provider/mod.rs delete mode 100644 src/factor_instances_provider/next_index_assigner/mod.rs delete mode 100644 src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_assigner.rs delete mode 100644 src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_cache_analyzing_assigner.rs delete mode 100644 src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_profile_analyzing_assigner.rs delete mode 100644 src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_with_ephemeral_offsets.rs delete mode 100644 src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_with_ephemeral_offsets_for_factor_source.rs delete mode 100644 src/factor_instances_provider/provider/factor_instances_cache.rs delete mode 100644 src/factor_instances_provider/provider/factor_instances_provider.rs delete mode 100644 src/factor_instances_provider/provider/factor_instances_provider_unit_tests.rs delete mode 100644 src/factor_instances_provider/provider/keyed_instances.rs delete mode 100644 src/factor_instances_provider/provider/mod.rs delete mode 100644 src/factor_instances_provider/provider/outcome/factor_instances_provider_outcome.rs delete mode 100644 src/factor_instances_provider/provider/outcome/factor_instances_provider_outcome_for_factor.rs delete mode 100644 src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs delete mode 100644 src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome_for_factor.rs delete mode 100644 src/factor_instances_provider/provider/outcome/mod.rs delete mode 100644 src/factor_instances_provider/provider/provider_adopters/mod.rs delete mode 100644 src/factor_instances_provider/provider/provider_adopters/securify_entity_factor_instances_provider.rs delete mode 100644 src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs delete mode 100644 src/factor_instances_provider/provider/test_sargon_os.rs delete mode 100644 src/gateway/gateway_read_write.rs delete mode 100644 src/gateway/gateway_readonly.rs delete mode 100644 src/gateway/mod.rs delete mode 100644 src/gateway/on_chain_entity_state.rs delete mode 100644 src/gateway/test_gateway.rs delete mode 100644 src/lib.rs delete mode 100644 src/samples/mod.rs delete mode 100644 src/samples/sample_values.rs delete mode 100644 src/signing/collector/mod.rs delete mode 100644 src/signing/collector/signatures_collecting_continuation.rs delete mode 100644 src/signing/collector/signatures_collector.rs delete mode 100644 src/signing/collector/signatures_collector_dependencies.rs delete mode 100644 src/signing/collector/signatures_collector_preprocessor.rs delete mode 100644 src/signing/collector/signatures_collector_state.rs delete mode 100644 src/signing/collector/signing_finish_early_strategy.rs delete mode 100644 src/signing/host_interaction/interactors/mod.rs delete mode 100644 src/signing/host_interaction/interactors/mono_factor_sign_interactor.rs delete mode 100644 src/signing/host_interaction/interactors/poly_factor_sign_interactor.rs delete mode 100644 src/signing/host_interaction/interactors/sign_interactor.rs delete mode 100644 src/signing/host_interaction/mod.rs delete mode 100644 src/signing/host_interaction/requests/mod.rs delete mode 100644 src/signing/host_interaction/requests/mono_factor_sign_request.rs delete mode 100644 src/signing/host_interaction/requests/mono_factor_sign_request_input.rs delete mode 100644 src/signing/host_interaction/requests/poly_factor_sign_request.rs delete mode 100644 src/signing/host_interaction/requests/transaction_sign_request_input.rs delete mode 100644 src/signing/host_interaction/sign_interactors.rs delete mode 100644 src/signing/host_interaction/sign_response.rs delete mode 100644 src/signing/mod.rs delete mode 100644 src/signing/petition_types/factor_list_kind.rs delete mode 100644 src/signing/petition_types/mod.rs delete mode 100644 src/signing/petition_types/petition_for_entity.rs delete mode 100644 src/signing/petition_types/petition_for_factors_types/factor_source_referencing.rs delete mode 100644 src/signing/petition_types/petition_for_factors_types/mod.rs delete mode 100644 src/signing/petition_types/petition_for_factors_types/neglected_factor_instance.rs delete mode 100644 src/signing/petition_types/petition_for_factors_types/petition_for_factors/mod.rs delete mode 100644 src/signing/petition_types/petition_for_factors_types/petition_for_factors/petition_for_factors.rs delete mode 100644 src/signing/petition_types/petition_for_factors_types/petition_for_factors/petition_for_factors_input.rs delete mode 100644 src/signing/petition_types/petition_for_factors_types/petition_for_factors/petition_for_factors_state.rs delete mode 100644 src/signing/petition_types/petition_for_factors_types/petition_for_factors/petition_for_factors_state_snapshot.rs delete mode 100644 src/signing/petition_types/petition_for_factors_types/petition_for_factors/petition_for_factors_status.rs delete mode 100644 src/signing/petition_types/petition_for_factors_types/petition_for_factors/petition_for_factors_sub_state.rs delete mode 100644 src/signing/petition_types/petition_for_transaction.rs delete mode 100644 src/signing/petition_types/petitions.rs delete mode 100644 src/signing/petition_types/petitions_status.rs delete mode 100644 src/signing/signatures_outcome_types/maybe_signed_transactions.rs delete mode 100644 src/signing/signatures_outcome_types/mod.rs delete mode 100644 src/signing/signatures_outcome_types/petition_transaction_outcome.rs delete mode 100644 src/signing/signatures_outcome_types/sign_with_factors_outcome.rs delete mode 100644 src/signing/signatures_outcome_types/signatures_outcome.rs delete mode 100644 src/signing/tests/mod.rs delete mode 100644 src/signing/tests/signing_tests.rs delete mode 100644 src/signing/tx_to_sign.rs delete mode 100644 src/testing/derivation/mod.rs delete mode 100644 src/testing/derivation/stateless_dummy_indices.rs delete mode 100644 src/testing/derivation/test_keys_collector.rs delete mode 100644 src/testing/mod.rs delete mode 100644 src/testing/signing/mod.rs delete mode 100644 src/testing/signing/simulated_user.rs delete mode 100644 src/testing/signing/test_interactors/mod.rs delete mode 100644 src/testing/signing/test_interactors/test_interactor.rs delete mode 100644 src/testing/signing/test_interactors/test_parallel_interactor.rs delete mode 100644 src/testing/signing/test_interactors/test_serial_interactor.rs delete mode 100644 src/testing/signing/test_signature_collecting_interactors.rs delete mode 100644 src/testing/signing/test_signatures_collector.rs delete mode 100644 src/types/factor_sources_of_kind.rs delete mode 100644 src/types/hd_signature.rs delete mode 100644 src/types/hd_signature_input.rs delete mode 100644 src/types/hidden_constructor.rs delete mode 100644 src/types/invalid_transaction_if_neglected.rs delete mode 100644 src/types/mod.rs delete mode 100644 src/types/new_methods_on_sargon_types.rs delete mode 100644 src/types/new_types/accounts.rs delete mode 100644 src/types/new_types/appendable_collection.rs delete mode 100644 src/types/new_types/factor_instances.rs delete mode 100644 src/types/new_types/is_securified_entity.rs delete mode 100644 src/types/new_types/key_space.rs delete mode 100644 src/types/new_types/mod.rs delete mode 100644 src/types/new_types/securified_account.rs delete mode 100644 src/types/new_types/securified_accounts.rs delete mode 100644 src/types/new_types/securified_persona.rs delete mode 100644 src/types/new_types/u30.rs delete mode 100644 src/types/new_types/unsecurified_entity.rs delete mode 100644 src/types/new_types/veci.rs delete mode 100644 src/types/owned_types/mod.rs delete mode 100644 src/types/owned_types/owned.rs delete mode 100644 src/types/owned_types/owned_factor_instance.rs delete mode 100644 src/types/sargon_types.rs delete mode 100644 tests/main.rs diff --git a/Cargo.lock b/Cargo.lock index 8fecafd3..4898266c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,482 +3,252 @@ version = 3 [[package]] -name = "actix-macros" -version = "0.2.4" +name = "anstream" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ - "quote", - "syn", -] - -[[package]] -name = "actix-rt" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eda4e2a6e042aa4e55ac438a2ae052d3b5da0ecf83d7411e1a368946925208" -dependencies = [ - "actix-macros", - "futures-core", - "tokio", -] - -[[package]] -name = "addr2line" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", ] [[package]] -name = "async-trait" -version = "0.1.80" +name = "anstyle" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] -name = "atty" -version = "0.2.14" +name = "anstyle-parse" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", + "utf8parse", ] [[package]] -name = "autocfg" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" - -[[package]] -name = "backtrace" -version = "0.3.73" +name = "anstyle-query" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", + "windows-sys", ] [[package]] -name = "bitflags" -version = "2.5.0" +name = "anstyle-wincon" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ - "generic-array", + "anstyle", + "windows-sys", ] [[package]] -name = "cc" -version = "1.0.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c891175c3fb232128f48de6590095e59198bbeb8620c310be349bfc3afd12c7b" - -[[package]] -name = "cfg-if" -version = "1.0.0" +name = "anyhow" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" [[package]] -name = "cpufeatures" -version = "0.2.12" +name = "askama" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28" dependencies = [ - "libc", + "askama_derive", + "askama_escape", ] [[package]] -name = "crypto-common" -version = "0.1.6" +name = "askama_derive" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "derive-getters" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6433aac097572ea8ccc60b3f2e756c661c9aeed9225cdd4d0cb119cb7ff6ba" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "derive_more" -version = "1.0.0" -source = "git+https://github.com/JelteF/derive_more?rev=d7f5b9e94d024790682f6fc4dcca13941cce64c8#d7f5b9e94d024790682f6fc4dcca13941cce64c8" -dependencies = [ - "derive_more-impl", -] - -[[package]] -name = "derive_more-impl" -version = "1.0.0" -source = "git+https://github.com/JelteF/derive_more?rev=d7f5b9e94d024790682f6fc4dcca13941cce64c8#d7f5b9e94d024790682f6fc4dcca13941cce64c8" +checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83" dependencies = [ + "askama_parser", + "basic-toml", + "mime", + "mime_guess", "proc-macro2", "quote", + "serde", "syn", - "unicode-xid", ] [[package]] -name = "diff" -version = "0.1.13" +name = "askama_escape" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" +checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" [[package]] -name = "digest" -version = "0.10.7" +name = "askama_parser" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0" dependencies = [ - "block-buffer", - "crypto-common", + "nom", ] [[package]] -name = "either" -version = "1.12.0" +name = "autocfg" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] -name = "enum-as-inner" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "enum-iterator" -version = "2.1.0" +name = "basic-toml" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c280b9e6b3ae19e152d8e31cf47f18389781e119d4013a2a2bb0180e5facc635" +checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8" dependencies = [ - "enum-iterator-derive", + "serde", ] [[package]] -name = "enum-iterator-derive" -version = "1.4.0" +name = "bincode" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" dependencies = [ - "proc-macro2", - "quote", - "syn", + "serde", ] [[package]] -name = "env_logger" -version = "0.7.1" +name = "bytes" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" -dependencies = [ - "atty", - "humantime 1.3.0", - "log", - "regex", - "termcolor", -] +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" [[package]] -name = "env_logger" -version = "0.10.2" +name = "camino" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" dependencies = [ - "humantime 2.1.0", - "is-terminal", - "log", - "regex", - "termcolor", + "serde", ] [[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "ftree" -version = "1.1.0" +name = "cargo-platform" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241f9dd9089e67c0b269989e9f884b12a61f68fc07ea8a4be6af8ee164e1abf7" +checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" dependencies = [ "serde", ] [[package]] -name = "futures" -version = "0.3.30" +name = "cargo_metadata" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror 1.0.69", ] [[package]] -name = "futures-channel" -version = "0.3.30" +name = "clap" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" dependencies = [ - "futures-core", - "futures-sink", + "clap_builder", + "clap_derive", ] [[package]] -name = "futures-core" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" - -[[package]] -name = "futures-executor" -version = "0.3.30" +name = "clap_builder" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" dependencies = [ - "futures-core", - "futures-task", - "futures-util", + "anstream", + "anstyle", + "clap_lex", + "strsim", ] [[package]] -name = "futures-io" -version = "0.3.30" +name = "clap_derive" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" - -[[package]] -name = "futures-macro" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ + "heck", "proc-macro2", "quote", "syn", ] [[package]] -name = "futures-sink" -version = "0.3.30" +name = "clap_lex" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" [[package]] -name = "futures-task" -version = "0.3.30" +name = "colorchoice" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] -name = "futures-util" -version = "0.3.30" +name = "fs-err" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", + "autocfg", ] [[package]] -name = "generic-array" -version = "0.14.7" +name = "glob" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] -name = "getrandom" -version = "0.2.15" +name = "goblin" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "1b363a30c165f666402fe6a3024d3bec7ebc898f96a4a23bd1c99f8dbf3f4f47" dependencies = [ - "cfg-if", - "libc", - "wasi", + "log", + "plain", + "scroll", ] -[[package]] -name = "gimli" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - [[package]] name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "humantime" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" -dependencies = [ - "quick-error", -] - -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - -[[package]] -name = "indexmap" -version = "2.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] -name = "indexset" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18b2866c23046c1e1ff3ed0f45d5fa62c8fbd7e26f6af8b306d1058c3f48a4c3" -dependencies = [ - "ftree", -] - -[[package]] -name = "is-terminal" -version = "0.4.13" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" -dependencies = [ - "hermit-abi 0.4.0", - "libc", - "windows-sys 0.52.0", -] +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] -name = "itertools" -version = "0.13.0" +name = "is_terminal_polyfill" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] -name = "libc" -version = "0.2.155" +name = "itoa" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" - -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] +checksum = "540654e97a3f4470a492cd30ff187bc95d89557a903a2bbf112e2fae98104ef2" [[package]] name = "log" @@ -493,609 +263,467 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] -name = "miniz_oxide" -version = "0.7.4" +name = "mime" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" -dependencies = [ - "adler", -] +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] -name = "mio" -version = "0.8.11" +name = "mime_guess" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" dependencies = [ - "libc", - "wasi", - "windows-sys 0.48.0", + "mime", + "unicase", ] [[package]] -name = "object" -version = "0.36.0" +name = "minimal-lexical" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" -dependencies = [ - "memchr", -] +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] -name = "once_cell" -version = "1.19.0" +name = "nom" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "parking_lot" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.52.5", + "memchr", + "minimal-lexical", ] [[package]] -name = "pin-project-lite" -version = "0.2.14" +name = "once_cell" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] -name = "pin-utils" -version = "0.1.0" +name = "paste" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] -name = "ppv-lite86" -version = "0.2.17" +name = "plain" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" [[package]] -name = "pretty_assertions" -version = "1.4.0" +name = "proc-macro2" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ - "diff", - "yansi", + "unicode-ident", ] [[package]] -name = "pretty_env_logger" -version = "0.4.0" +name = "quote" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ - "env_logger 0.7.1", - "log", + "proc-macro2", ] [[package]] -name = "pretty_env_logger" -version = "0.5.0" -source = "git+https://github.com/seanmonstar/pretty-env-logger/?rev=0e238400e18649415dc710c025e99c009a1bb744#0e238400e18649415dc710c025e99c009a1bb744" +name = "rules" +version = "0.1.0" dependencies = [ - "env_logger 0.10.2", - "log", + "thiserror 2.0.3", ] [[package]] -name = "proc-macro2" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +name = "rules-uniffi" +version = "0.1.0" dependencies = [ - "unicode-ident", + "rules", + "thiserror 2.0.3", + "uniffi", ] [[package]] -name = "quick-error" -version = "1.2.3" +name = "ryu" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] -name = "quote" -version = "1.0.36" +name = "scroll" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6" dependencies = [ - "proc-macro2", + "scroll_derive", ] [[package]] -name = "rand" -version = "0.8.5" +name = "scroll_derive" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932" dependencies = [ - "libc", - "rand_chacha", - "rand_core", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "rand_chacha" -version = "0.3.1" +name = "semver" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" dependencies = [ - "ppv-lite86", - "rand_core", + "serde", ] [[package]] -name = "rand_core" -version = "0.6.4" +name = "serde" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ - "getrandom", + "serde_derive", ] [[package]] -name = "redox_syscall" -version = "0.5.2" +name = "serde_derive" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ - "bitflags", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "regex" -version = "1.10.6" +name = "serde_json" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ - "aho-corasick", + "itoa", "memchr", - "regex-automata", - "regex-syntax", + "ryu", + "serde", ] [[package]] -name = "regex-automata" -version = "0.4.7" +name = "siphasher" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] -name = "regex-syntax" -version = "0.8.4" +name = "smawk" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[package]] -name = "rustc-demangle" -version = "0.1.24" +name = "static_assertions" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] -name = "rustversion" -version = "1.0.17" +name = "strsim" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] -name = "scopeguard" -version = "1.2.0" +name = "syn" +version = "2.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] [[package]] -name = "sensible-env-logger" -version = "0.3.2" +name = "textwrap" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2110d0fb5cbd1f468bba2470ecd079223c06f1279775351273adf58650702ff7" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" dependencies = [ - "log", - "pretty_env_logger 0.4.0", + "smawk", ] [[package]] -name = "serde" -version = "1.0.203" +name = "thiserror" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "serde_derive", + "thiserror-impl 1.0.69", ] [[package]] -name = "serde_derive" -version = "1.0.203" +name = "thiserror" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa" dependencies = [ - "proc-macro2", - "quote", - "syn", + "thiserror-impl 2.0.3", ] [[package]] -name = "sha2" -version = "0.10.8" +name = "thiserror-impl" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ - "cfg-if", - "cpufeatures", - "digest", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "signal-hook-registry" -version = "1.4.2" +name = "thiserror-impl" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" dependencies = [ - "libc", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "slab" -version = "0.4.9" +name = "toml" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ - "autocfg", + "serde", ] [[package]] -name = "smallvec" -version = "1.13.2" +name = "unicase" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" [[package]] -name = "socket2" -version = "0.5.7" +name = "unicode-ident" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] -name = "strum" -version = "0.26.1" -source = "git+https://github.com/Peternator7/strum/?rev=f746c3699acf150112e26c00e6c8ca666d8d068d#f746c3699acf150112e26c00e6c8ca666d8d068d" +name = "uniffi" +version = "0.27.1" +source = "git+https://github.com/mozilla/uniffi-rs/?rev=6f33088e8100a2ea9586c8c3ecf98ab51d5aba62#6f33088e8100a2ea9586c8c3ecf98ab51d5aba62" dependencies = [ - "strum_macros", + "anyhow", + "camino", + "clap", + "uniffi_bindgen", + "uniffi_build", + "uniffi_core", + "uniffi_macros", ] [[package]] -name = "strum_macros" -version = "0.26.1" -source = "git+https://github.com/Peternator7/strum/?rev=f746c3699acf150112e26c00e6c8ca666d8d068d#f746c3699acf150112e26c00e6c8ca666d8d068d" +name = "uniffi_bindgen" +version = "0.27.1" +source = "git+https://github.com/mozilla/uniffi-rs/?rev=6f33088e8100a2ea9586c8c3ecf98ab51d5aba62#6f33088e8100a2ea9586c8c3ecf98ab51d5aba62" dependencies = [ + "anyhow", + "askama", + "camino", + "cargo_metadata", + "clap", + "fs-err", + "glob", + "goblin", "heck", - "proc-macro2", - "quote", - "rustversion", - "syn", + "once_cell", + "paste", + "serde", + "textwrap", + "toml", + "uniffi_meta", + "uniffi_testing", + "uniffi_udl", ] [[package]] -name = "syn" -version = "2.0.67" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff8655ed1d86f3af4ee3fd3263786bc14245ad17c4c7e85ba7187fb3ae028c90" +name = "uniffi_build" +version = "0.27.1" +source = "git+https://github.com/mozilla/uniffi-rs/?rev=6f33088e8100a2ea9586c8c3ecf98ab51d5aba62#6f33088e8100a2ea9586c8c3ecf98ab51d5aba62" dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", + "anyhow", + "camino", + "uniffi_bindgen", ] [[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +name = "uniffi_checksum_derive" +version = "0.27.1" +source = "git+https://github.com/mozilla/uniffi-rs/?rev=6f33088e8100a2ea9586c8c3ecf98ab51d5aba62#6f33088e8100a2ea9586c8c3ecf98ab51d5aba62" dependencies = [ - "winapi-util", + "quote", + "syn", ] [[package]] -name = "thiserror" -version = "1.0.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +name = "uniffi_core" +version = "0.27.1" +source = "git+https://github.com/mozilla/uniffi-rs/?rev=6f33088e8100a2ea9586c8c3ecf98ab51d5aba62#6f33088e8100a2ea9586c8c3ecf98ab51d5aba62" dependencies = [ - "thiserror-impl", + "anyhow", + "bytes", + "camino", + "log", + "once_cell", + "paste", + "static_assertions", ] [[package]] -name = "thiserror-impl" -version = "1.0.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +name = "uniffi_macros" +version = "0.27.1" +source = "git+https://github.com/mozilla/uniffi-rs/?rev=6f33088e8100a2ea9586c8c3ecf98ab51d5aba62#6f33088e8100a2ea9586c8c3ecf98ab51d5aba62" dependencies = [ + "bincode", + "camino", + "fs-err", + "once_cell", "proc-macro2", "quote", + "serde", "syn", + "toml", + "uniffi_meta", ] [[package]] -name = "tokio" -version = "1.38.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" +name = "uniffi_meta" +version = "0.27.1" +source = "git+https://github.com/mozilla/uniffi-rs/?rev=6f33088e8100a2ea9586c8c3ecf98ab51d5aba62#6f33088e8100a2ea9586c8c3ecf98ab51d5aba62" dependencies = [ - "backtrace", - "libc", - "mio", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "windows-sys 0.48.0", + "anyhow", + "bytes", + "siphasher", + "uniffi_checksum_derive", ] [[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "use_factors" -version = "0.1.0" +name = "uniffi_testing" +version = "0.27.1" +source = "git+https://github.com/mozilla/uniffi-rs/?rev=6f33088e8100a2ea9586c8c3ecf98ab51d5aba62#6f33088e8100a2ea9586c8c3ecf98ab51d5aba62" dependencies = [ - "actix-rt", - "async-trait", - "derive-getters", - "derive_more", - "enum-as-inner", - "enum-iterator", - "futures", - "hex", - "indexmap", - "indexset", - "itertools", - "log", + "anyhow", + "camino", + "cargo_metadata", + "fs-err", "once_cell", - "pretty_assertions", - "pretty_env_logger 0.5.0", - "rand", - "sensible-env-logger", - "sha2", - "strum", - "thiserror", - "uuid", ] [[package]] -name = "uuid" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ea73390fe27785838dcbf75b91b1d84799e28f1ce71e6f372a5dc2200c80de5" -dependencies = [ - "getrandom", -] - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[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.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +name = "uniffi_udl" +version = "0.27.1" +source = "git+https://github.com/mozilla/uniffi-rs/?rev=6f33088e8100a2ea9586c8c3ecf98ab51d5aba62#6f33088e8100a2ea9586c8c3ecf98ab51d5aba62" dependencies = [ - "windows-sys 0.52.0", + "anyhow", + "textwrap", + "uniffi_meta", + "uniffi_testing", + "weedle2", ] [[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +name = "utf8parse" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +name = "weedle2" +version = "5.0.0" +source = "git+https://github.com/mozilla/uniffi-rs/?rev=6f33088e8100a2ea9586c8c3ecf98ab51d5aba62#6f33088e8100a2ea9586c8c3ecf98ab51d5aba62" dependencies = [ - "windows-targets 0.48.5", + "nom", ] [[package]] name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.5", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-targets", ] [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" - -[[package]] -name = "yansi" -version = "0.5.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/Cargo.toml b/Cargo.toml index 881c3d00..770dff92 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,40 +1,15 @@ -[package] -name = "use_factors" -version = "0.1.0" -edition = "2021" +[workspace] +resolver = "2" +members = ["crates/rules", "crates/rules-uniffi"] -[dependencies] -actix-rt = "2.10.0" -async-trait = "0.1.80" -derive-getters = "0.4.0" +[profile.release] +incremental = false +panic = 'unwind' +codegen-units = 1 -# 1.0.0 -derive_more = { git = "https://github.com/JelteF/derive_more", rev = "d7f5b9e94d024790682f6fc4dcca13941cce64c8", features = [ - "debug", - "display", - "from_str", -] } +[profile.profiling] +inherits = "release" +debug = true -indexmap = "2.2.6" -indexset = "0.4.0" -itertools = "0.13.0" -once_cell = "1.19.0" -rand = "0.8.5" -sha2 = "0.10.8" -# strum = "0.26.1" -strum = { git = "https://github.com/Peternator7/strum/", rev = "f746c3699acf150112e26c00e6c8ca666d8d068d", features = [ - "derive", -] } -thiserror = "1.0.61" -uuid = { version = "1.9.0", features = ["v4"] } -pretty_assertions = "1.4.0" - - -log = "0.4.20" -sensible-env-logger = "0.3.2" - -pretty_env_logger = { git = "https://github.com/seanmonstar/pretty-env-logger/", rev = "0e238400e18649415dc710c025e99c009a1bb744" } -hex = "0.4.3" -enum-as-inner = "0.6.0" -futures = "0.3.30" -enum-iterator = "2.1.0" +[workspace.dependencies] +thiserror = "2.0.3" diff --git a/crates/rules-uniffi/Cargo.toml b/crates/rules-uniffi/Cargo.toml new file mode 100644 index 00000000..2eeb8a5a --- /dev/null +++ b/crates/rules-uniffi/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "rules-uniffi" +version = "0.1.0" +edition = "2021" + + +[dependencies] +rules = { path = "../rules" } + +# uniffi = "0.27.1" +uniffi = { git = "https://github.com/mozilla/uniffi-rs/", rev = "6f33088e8100a2ea9586c8c3ecf98ab51d5aba62", features = [ + "cli", +] } + +thiserror = { workspace = true } + +[dev-dependencies] +# uniffi = "0.27.1" +uniffi = { git = "https://github.com/mozilla/uniffi-rs/", rev = "6f33088e8100a2ea9586c8c3ecf98ab51d5aba62", features = [ + "bindgen-tests", +] } + +[build-dependencies] +# uniffi = "0.27.1" +uniffi = { git = "https://github.com/mozilla/uniffi-rs/", rev = "6f33088e8100a2ea9586c8c3ecf98ab51d5aba62", features = [ + "build", +] } diff --git a/crates/rules-uniffi/src/lib.rs b/crates/rules-uniffi/src/lib.rs new file mode 100644 index 00000000..e69de29b diff --git a/crates/rules/Cargo.toml b/crates/rules/Cargo.toml new file mode 100644 index 00000000..41a1503d --- /dev/null +++ b/crates/rules/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "rules" +version = "0.1.0" +edition = "2021" + +[dependencies] +thiserror = { workspace = true } diff --git a/crates/rules/src/lib.rs b/crates/rules/src/lib.rs new file mode 100644 index 00000000..57fa7b3c --- /dev/null +++ b/crates/rules/src/lib.rs @@ -0,0 +1,10 @@ +mod rules; + +pub mod prelude { + + pub(crate) use crate::rules::*; + + pub(crate) use thiserror::Error as ThisError; +} + +pub use prelude::*; diff --git a/crates/rules/src/rules/error.rs b/crates/rules/src/rules/error.rs new file mode 100644 index 00000000..a4a0a97c --- /dev/null +++ b/crates/rules/src/rules/error.rs @@ -0,0 +1,8 @@ +use crate::prelude::*; + + +#[derive(Clone, Copy, Debug, PartialEq, Eq, ThisError)] +pub enum Error { + #[error("Unknown")] + Unknown, +} \ No newline at end of file diff --git a/crates/rules/src/rules/mod.rs b/crates/rules/src/rules/mod.rs new file mode 100644 index 00000000..45d3692c --- /dev/null +++ b/crates/rules/src/rules/mod.rs @@ -0,0 +1,3 @@ +mod error; + +pub use error::*; \ No newline at end of file diff --git a/src/derivation/collector/key_derivation_outcome.rs b/src/derivation/collector/key_derivation_outcome.rs deleted file mode 100644 index 3aba886e..00000000 --- a/src/derivation/collector/key_derivation_outcome.rs +++ /dev/null @@ -1,34 +0,0 @@ -use crate::prelude::*; - -/// A collection of all `HierarchicalDeterministicFactorInstance` -/// (Public Keys) which were derived from the referenced -/// `FactorSource`s at the specified `DerivationPath`s -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct KeyDerivationOutcome { - count: usize, // hide ctor... - pub factors_by_source: - IndexMap>, -} - -impl KeyDerivationOutcome { - pub(crate) fn new( - factors_by_source: IndexMap< - FactorSourceIDFromHash, - IndexSet, - >, - ) -> Self { - Self { - count: factors_by_source.len(), - factors_by_source, - } - } - - /// ALL factor instances derived by the KeysCollector - pub fn all_factors(&self) -> FactorInstances { - self.factors_by_source - .clone() - .into_iter() - .flat_map(|(_, v)| v) - .collect() - } -} diff --git a/src/derivation/collector/key_ring.rs b/src/derivation/collector/key_ring.rs deleted file mode 100644 index f3af468c..00000000 --- a/src/derivation/collector/key_ring.rs +++ /dev/null @@ -1,50 +0,0 @@ -use crate::prelude::*; - -/// A collection of `HierarchicalDeterministicFactorInstance` derived from a -/// factor source. -#[derive(Debug)] -pub(crate) struct Keyring { - pub(crate) factor_source_id: FactorSourceIDFromHash, - pub(crate) paths: IndexSet, - derived: RwLock>, -} - -impl Keyring { - pub fn clone_snapshot(&self) -> Self { - Self { - factor_source_id: self.factor_source_id, - paths: self.paths.clone(), - derived: RwLock::new(self.derived.try_read().unwrap().clone()), - } - } - pub(crate) fn new( - factor_source_id: FactorSourceIDFromHash, - paths: IndexSet, - ) -> Self { - Self { - factor_source_id, - paths, - derived: RwLock::new(IndexSet::new()), - } - } - pub(crate) fn factors(&self) -> IndexSet { - self.derived.try_read().unwrap().clone() - } - - pub(crate) fn process_response( - &self, - response: IndexSet, - ) { - assert!(response - .iter() - .all(|f| f.factor_source_id == self.factor_source_id - && !self - .derived - .try_read() - .unwrap() - .iter() - .any(|x| x.public_key == f.public_key))); - - self.derived.try_write().unwrap().extend(response) - } -} diff --git a/src/derivation/collector/keys_collector.rs b/src/derivation/collector/keys_collector.rs deleted file mode 100644 index 4e832fb5..00000000 --- a/src/derivation/collector/keys_collector.rs +++ /dev/null @@ -1,169 +0,0 @@ -use crate::prelude::*; - -/// A coordinator which gathers public keys from several factor sources of different -/// kinds, in increasing friction order, for many transactions and for -/// potentially multiple entities and for many factor instances (derivation paths) -/// for each transaction. -/// -/// By increasing friction order we mean, the quickest and easiest to use FactorSourceKind -/// is last; namely `DeviceFactorSource`, and the most tedious FactorSourceKind is -/// first; namely `LedgerFactorSource`, which user might also lack access to. -pub struct KeysCollector { - /// Stateless immutable values used by the collector to gather public keys - /// from factor sources. - dependencies: KeysCollectorDependencies, - - /// Mutable internal state of the collector which builds up the list - /// of public keys from each used factor source. - state: RwLock, -} - -impl KeysCollector { - pub fn new( - all_factor_sources_in_profile: impl IntoIterator, - derivation_paths: impl Into>>, - interactors: Arc, - ) -> Result { - let derivation_paths = derivation_paths.into(); - let preprocessor = KeysCollectorPreprocessor::new(derivation_paths); - Self::with_preprocessor( - all_factor_sources_in_profile - .into_iter() - .collect::>(), - interactors, - preprocessor, - ) - } - - fn with_preprocessor( - all_factor_sources_in_profile: impl Into>, - interactors: Arc, - preprocessor: KeysCollectorPreprocessor, - ) -> Result { - debug!("Init KeysCollector"); - let all_factor_sources_in_profile = all_factor_sources_in_profile.into(); - let (state, factors) = preprocessor.preprocess(all_factor_sources_in_profile)?; - - let dependencies = KeysCollectorDependencies::new(interactors, factors); - - Ok(Self { - dependencies, - state: RwLock::new(state), - }) - } -} - -// === PUBLIC === -impl KeysCollector { - #[allow(unused)] - pub async fn collect_keys(self) -> KeyDerivationOutcome { - _ = self - .derive_with_factors() // in decreasing "friction order" - .await - .inspect_err(|e| error!("Failed to use factor sources: {:#?}", e)); - self.state.into_inner().unwrap().outcome() - } -} - -// === PRIVATE === -impl KeysCollector { - async fn use_factor_sources(&self, factor_sources_of_kind: &FactorSourcesOfKind) -> Result<()> { - let interactor = self - .dependencies - .interactors - .interactor_for(factor_sources_of_kind.kind); - let factor_sources = factor_sources_of_kind.factor_sources(); - match interactor { - KeyDerivationInteractor::PolyFactor(interactor) => { - // Prepare the request for the interactor - debug!("Creating poly request for interactor"); - let request = self.request_for_parallel_interactor( - factor_sources - .into_iter() - .map(|f| f.factor_source_id()) - .collect(), - )?; - debug!("Dispatching poly request to interactor: {:?}", request); - let response = interactor.derive(request).await?; - self.process_batch_response(response)?; - } - - KeyDerivationInteractor::MonoFactor(interactor) => { - for factor_source in factor_sources { - // Prepare the request for the interactor - debug!("Creating mono request for interactor"); - let request = - self.request_for_serial_interactor(&factor_source.factor_source_id())?; - - debug!("Dispatching mono request to interactor: {:?}", request); - // Produce the results from the interactor - let response = interactor.derive(request).await?; - - // Report the results back to the collector - self.process_batch_response(response)?; - } - } - } - Ok(()) - } - - /// In decreasing "friction order" - async fn derive_with_factors(&self) -> Result<()> { - for factor_sources_of_kind in self.dependencies.factors_of_kind.iter() { - info!( - "Use(?) #{:?} factors of kind: {:?}", - &factor_sources_of_kind.factor_sources().len(), - &factor_sources_of_kind.kind - ); - self.use_factor_sources(factor_sources_of_kind).await?; - } - Ok(()) - } - - fn input_for_interactor( - &self, - factor_source_id: &FactorSourceIDFromHash, - ) -> Result { - let keyring = self - .state - .try_read() - .unwrap() - .keyring_for(factor_source_id)?; - assert_eq!(keyring.factors().len(), 0); - let paths = keyring.paths.clone(); - Ok(MonoFactorKeyDerivationRequest::new( - *factor_source_id, - paths, - )) - } - - fn request_for_parallel_interactor( - &self, - factor_sources_ids: IndexSet, - ) -> Result { - let per_factor_source = factor_sources_ids - .into_iter() - .map(|f| self.input_for_interactor(&f)) - .collect::>>()?; - Ok(PolyFactorKeyDerivationRequest::new( - per_factor_source - .into_iter() - .map(|r| (r.factor_source_id, r)) - .collect(), - )) - } - - fn request_for_serial_interactor( - &self, - factor_source_id: &FactorSourceIDFromHash, - ) -> Result { - self.input_for_interactor(factor_source_id) - } - - fn process_batch_response(&self, response: KeyDerivationResponse) -> Result<()> { - self.state - .try_write() - .unwrap() - .process_batch_response(response) - } -} diff --git a/src/derivation/collector/keys_collector_dependencies.rs b/src/derivation/collector/keys_collector_dependencies.rs deleted file mode 100644 index 2af1a60d..00000000 --- a/src/derivation/collector/keys_collector_dependencies.rs +++ /dev/null @@ -1,29 +0,0 @@ -use crate::prelude::*; - -pub(crate) struct KeysCollectorDependencies { - /// A collection of "interactors" used to sign with factor sources. - pub(super) interactors: Arc, - - /// Factor sources grouped by kind, sorted according to "friction order", - /// that is, we want to control which FactorSourceKind users sign with - /// first, second etc, e.g. typically we prompt user to sign with Ledgers - /// first, and if a user might lack access to that Ledger device, then it is - /// best to "fail fast", otherwise we might waste the users time, if she has - /// e.g. answered security questions and then is asked to use a Ledger - /// she might not have handy at the moment - or might not be in front of a - /// computer and thus unable to make a connection between the Radix Wallet - /// and a Ledger device. - pub(super) factors_of_kind: IndexSet, -} - -impl KeysCollectorDependencies { - pub(crate) fn new( - interactors: Arc, - factors_of_kind: IndexSet, - ) -> Self { - Self { - interactors, - factors_of_kind, - } - } -} diff --git a/src/derivation/collector/keys_collector_preprocessor.rs b/src/derivation/collector/keys_collector_preprocessor.rs deleted file mode 100644 index b2a662e9..00000000 --- a/src/derivation/collector/keys_collector_preprocessor.rs +++ /dev/null @@ -1,44 +0,0 @@ -use crate::prelude::*; - -/// A type for preprocessing of input data for the `KeysCollector`. -/// -/// It analyzes the derivation paths and factor sources to determine the -/// which factor sources are used to derive keys, and in what order. -pub(crate) struct KeysCollectorPreprocessor { - derivation_paths: IndexMap>, -} - -impl KeysCollectorPreprocessor { - pub(crate) fn new( - derivation_paths: IndexMap>, - ) -> Self { - Self { derivation_paths } - } - - pub(crate) fn preprocess( - &self, - all_factor_sources_in_profile: IndexSet, - ) -> Result<(KeysCollectorState, IndexSet)> { - let all_factor_sources_in_profile = all_factor_sources_in_profile - .into_iter() - .map(|f| (f.factor_source_id(), f)) - .collect::>(); - - let unsorted = self - .derivation_paths - .clone() - .keys() - .map(|id| { - all_factor_sources_in_profile - .get(id) - .cloned() - .ok_or(CommonError::UnknownFactorSource) - }) - .collect::>>()?; - - let factor_sources_of_kind = sort_group_factors(unsorted); - let state = KeysCollectorState::new(self.derivation_paths.clone()); - - Ok((state, factor_sources_of_kind)) - } -} diff --git a/src/derivation/collector/keys_collector_state.rs b/src/derivation/collector/keys_collector_state.rs deleted file mode 100644 index 321d9328..00000000 --- a/src/derivation/collector/keys_collector_state.rs +++ /dev/null @@ -1,59 +0,0 @@ -use crate::prelude::*; - -/// The internal mutable state of the KeysCollector, which itself uses -/// interior mutability to allow for mutation without `&mut self`. -/// -/// Holds a collection of keyrings derived from various factor sources. -pub(crate) struct KeysCollectorState { - pub(super) keyrings: RwLock>, -} - -impl KeysCollectorState { - pub(crate) fn new( - derivation_paths: IndexMap>, - ) -> Self { - let keyrings = derivation_paths - .into_iter() - .map(|(factor_source_id, derivation_paths)| { - ( - factor_source_id, - Keyring::new(factor_source_id, derivation_paths), - ) - }) - .collect::>(); - Self { - keyrings: RwLock::new(keyrings), - } - } - - pub(crate) fn outcome(self) -> KeyDerivationOutcome { - let key_rings = self.keyrings.into_inner().unwrap(); - KeyDerivationOutcome::new( - key_rings - .into_iter() - .map(|(k, v)| (k, v.factors())) - .collect(), - ) - } - - pub(crate) fn keyring_for(&self, factor_source_id: &FactorSourceIDFromHash) -> Result { - self.keyrings - .try_read() - .unwrap() - .get(factor_source_id) - .map(|x| x.clone_snapshot()) - .inspect(|k| assert_eq!(k.factor_source_id, *factor_source_id)) - .ok_or(CommonError::UnknownFactorSource) - } - - pub(crate) fn process_batch_response(&self, response: KeyDerivationResponse) -> Result<()> { - for (factor_source_id, factors) in response.per_factor_source.into_iter() { - let mut rings = self.keyrings.try_write().unwrap(); - let keyring = rings - .get_mut(&factor_source_id) - .ok_or(CommonError::UnknownFactorSource)?; - keyring.process_response(factors) - } - Ok(()) - } -} diff --git a/src/derivation/collector/mod.rs b/src/derivation/collector/mod.rs deleted file mode 100644 index 0c613310..00000000 --- a/src/derivation/collector/mod.rs +++ /dev/null @@ -1,14 +0,0 @@ -mod key_derivation_outcome; -mod key_ring; -mod keys_collector; -mod keys_collector_dependencies; -mod keys_collector_preprocessor; -mod keys_collector_state; - -pub(crate) use key_derivation_outcome::*; -pub(crate) use key_ring::*; -pub(crate) use keys_collector_dependencies::*; -pub(crate) use keys_collector_preprocessor::*; -pub(crate) use keys_collector_state::*; - -pub use keys_collector::*; diff --git a/src/derivation/host_interaction/interactors/key_derivation_interactor.rs b/src/derivation/host_interaction/interactors/key_derivation_interactor.rs deleted file mode 100644 index 88b340dd..00000000 --- a/src/derivation/host_interaction/interactors/key_derivation_interactor.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::prelude::*; - -/// An interactor which can derive keys - either in multiple factor sources in -/// one go, or a single one. -pub enum KeyDerivationInteractor { - /// Many factor sources used to derive keys. - PolyFactor(Arc), - - /// A single factor source used to derive keys. - MonoFactor(Arc), -} - -impl KeyDerivationInteractor { - #[allow(unused)] - pub(crate) fn poly(interactor: Arc) -> Self { - Self::PolyFactor(interactor) - } - - #[allow(unused)] - pub(crate) fn mono(interactor: Arc) -> Self { - Self::MonoFactor(interactor) - } -} diff --git a/src/derivation/host_interaction/interactors/mod.rs b/src/derivation/host_interaction/interactors/mod.rs deleted file mode 100644 index 30706d35..00000000 --- a/src/derivation/host_interaction/interactors/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -mod key_derivation_interactor; -mod mono_factor_key_derivation_interactor; -mod poly_factor_key_derivation_interactor; - -pub use key_derivation_interactor::*; -pub use mono_factor_key_derivation_interactor::*; -pub use poly_factor_key_derivation_interactor::*; diff --git a/src/derivation/host_interaction/interactors/mono_factor_key_derivation_interactor.rs b/src/derivation/host_interaction/interactors/mono_factor_key_derivation_interactor.rs deleted file mode 100644 index 96a36539..00000000 --- a/src/derivation/host_interaction/interactors/mono_factor_key_derivation_interactor.rs +++ /dev/null @@ -1,16 +0,0 @@ -use crate::prelude::*; - -/// An "interactor" which can derive keys from a single factor source. -/// -/// By "interactor" we mean a bridge between Sargon and Host application, -/// The KeysCollector (Sargon) will dispatch "request" to the Host application, -/// and async await a Result with either successful response - derived keys - -/// which it will use to update it internal state and continue with the next -/// factor source, or in case of failure the whole process will be aborted. -#[async_trait::async_trait] -pub trait MonoFactorKeyDerivationInteractor: Send + Sync { - async fn derive( - &self, - request: MonoFactorKeyDerivationRequest, - ) -> Result; -} diff --git a/src/derivation/host_interaction/interactors/poly_factor_key_derivation_interactor.rs b/src/derivation/host_interaction/interactors/poly_factor_key_derivation_interactor.rs deleted file mode 100644 index 3fb910fc..00000000 --- a/src/derivation/host_interaction/interactors/poly_factor_key_derivation_interactor.rs +++ /dev/null @@ -1,16 +0,0 @@ -use crate::prelude::*; - -/// An "interactor" which can derive keys from multiple factor sources. -/// -/// By "interactor" we mean a bridge between Sargon and Host application, -/// The KeysCollector (Sargon) will dispatch "request" to the Host application, -/// and async await a Result with either successful response - derived keys - -/// which it will use to update it internal state and continue with the next -/// factor source, or in case of failure the whole process will be aborted. -#[async_trait::async_trait] -pub trait PolyFactorKeyDerivationInteractor: Send + Sync { - async fn derive( - &self, - request: PolyFactorKeyDerivationRequest, - ) -> Result; -} diff --git a/src/derivation/host_interaction/key_derivation_response.rs b/src/derivation/host_interaction/key_derivation_response.rs deleted file mode 100644 index 6c5d6b75..00000000 --- a/src/derivation/host_interaction/key_derivation_response.rs +++ /dev/null @@ -1,21 +0,0 @@ -use crate::prelude::*; - -/// A collection of `IndexSet`, on a -/// per-factor-source basis. In case of MonoKeyDerivation the map will contain -/// a single tuple. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct KeyDerivationResponse { - pub per_factor_source: - IndexMap>, -} - -impl KeyDerivationResponse { - pub fn new( - per_factor_source: IndexMap< - FactorSourceIDFromHash, - IndexSet, - >, - ) -> Self { - Self { per_factor_source } - } -} diff --git a/src/derivation/host_interaction/keys_derivation_interactors.rs b/src/derivation/host_interaction/keys_derivation_interactors.rs deleted file mode 100644 index 044b4622..00000000 --- a/src/derivation/host_interaction/keys_derivation_interactors.rs +++ /dev/null @@ -1,6 +0,0 @@ -use crate::prelude::*; - -/// A collection of "interactors" which can derive keys. -pub trait KeysDerivationInteractors: Sync + Send { - fn interactor_for(&self, kind: FactorSourceKind) -> KeyDerivationInteractor; -} diff --git a/src/derivation/host_interaction/mod.rs b/src/derivation/host_interaction/mod.rs deleted file mode 100644 index 4fa103d1..00000000 --- a/src/derivation/host_interaction/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -mod interactors; -mod key_derivation_response; -mod keys_derivation_interactors; -mod requests; - -pub use interactors::*; -pub use key_derivation_response::*; -pub use keys_derivation_interactors::*; -pub use requests::*; diff --git a/src/derivation/host_interaction/requests/mod.rs b/src/derivation/host_interaction/requests/mod.rs deleted file mode 100644 index 2c85a3b3..00000000 --- a/src/derivation/host_interaction/requests/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod mono_factor_key_derivation_request; -mod poly_factor_key_derivation_request; - -pub use mono_factor_key_derivation_request::*; -pub use poly_factor_key_derivation_request::*; diff --git a/src/derivation/host_interaction/requests/mono_factor_key_derivation_request.rs b/src/derivation/host_interaction/requests/mono_factor_key_derivation_request.rs deleted file mode 100644 index 6fb3dd07..00000000 --- a/src/derivation/host_interaction/requests/mono_factor_key_derivation_request.rs +++ /dev/null @@ -1,25 +0,0 @@ -use crate::prelude::*; - -/// A request to derive keys using a single factor source, dispatched by the -/// interactor to the host, request created by the KeysCollector. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct MonoFactorKeyDerivationRequest { - /// ID of the FactorSource used to derive keys. - pub factor_source_id: FactorSourceIDFromHash, - - /// The derivation paths used to derive keys using - /// the factor source - pub derivation_paths: IndexSet, -} - -impl MonoFactorKeyDerivationRequest { - pub fn new( - factor_source_id: FactorSourceIDFromHash, - derivation_paths: IndexSet, - ) -> Self { - Self { - factor_source_id, - derivation_paths, - } - } -} diff --git a/src/derivation/host_interaction/requests/poly_factor_key_derivation_request.rs b/src/derivation/host_interaction/requests/poly_factor_key_derivation_request.rs deleted file mode 100644 index b91e9568..00000000 --- a/src/derivation/host_interaction/requests/poly_factor_key_derivation_request.rs +++ /dev/null @@ -1,15 +0,0 @@ -use crate::prelude::*; - -/// A collection of `MonoFactorKeyDerivationRequest`, on a per-factor-source basis. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct PolyFactorKeyDerivationRequest { - pub per_factor_source: IndexMap, -} - -impl PolyFactorKeyDerivationRequest { - pub(crate) fn new( - per_factor_source: IndexMap, - ) -> Self { - Self { per_factor_source } - } -} diff --git a/src/derivation/mod.rs b/src/derivation/mod.rs deleted file mode 100644 index 03f79ea4..00000000 --- a/src/derivation/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -mod collector; -mod host_interaction; -mod tests; - -pub use collector::*; -pub use host_interaction::*; diff --git a/src/derivation/tests/derivation_tests.rs b/src/derivation/tests/derivation_tests.rs deleted file mode 100644 index 873056b4..00000000 --- a/src/derivation/tests/derivation_tests.rs +++ /dev/null @@ -1,547 +0,0 @@ -#![cfg(test)] -use crate::prelude::*; - -mod key_derivation_tests { - - use super::CAP26EntityKind::*; - use super::CAP26KeyKind::*; - use super::NetworkID::*; - use super::*; - - #[actix_rt::test] - async fn failure_unknown_factor() { - let res = KeysCollector::new( - IndexSet::new(), - IndexMap::just(( - FactorSourceIDFromHash::fs0(), - IndexSet::just(DerivationPath::new( - Mainnet, - Account, - TransactionSigning, - HDPathComponent::securifying_base_index(0), - )), - )), - Arc::new(TestDerivationInteractors::default()), - ); - assert!(matches!(res, Err(CommonError::UnknownFactorSource))); - } - - #[actix_rt::test] - async fn failure_from_interactor() { - let factor_source = fs_at(0); - let paths = [0, 1, 2] - .into_iter() - .map(|i| { - DerivationPath::unsecurified_hardening_base_index( - Mainnet, - Account, - TransactionSigning, - i, - ) - }) - .collect::>(); - let collector = KeysCollector::new( - HDFactorSource::all(), - [(factor_source.factor_source_id(), paths.clone())] - .into_iter() - .collect::>>(), - Arc::new(TestDerivationInteractors::fail()), - ) - .unwrap(); - let outcome = collector.collect_keys().await; - assert!(outcome.all_factors().factor_instances().is_empty()) - } - - mod multi_key { - use super::*; - - #[actix_rt::test] - async fn multi_keys_same_factor_source_different_indices() { - let factor_source = fs_at(0); - let paths = [0, 1, 2] - .into_iter() - .map(|i| { - DerivationPath::unsecurified_hardening_base_index( - Mainnet, - Account, - TransactionSigning, - i, - ) - }) - .collect::>(); - let collector = - KeysCollector::new_test([(factor_source.factor_source_id(), paths.clone())]); - let outcome = collector.collect_keys().await; - assert_eq!( - outcome - .all_factors() - .into_iter() - .map(|f| f.derivation_path()) - .collect::>(), - paths - ); - - assert!(outcome - .all_factors() - .into_iter() - .all(|f| f.factor_source_id == factor_source.factor_source_id())); - } - - #[actix_rt::test] - async fn multi_keys_multi_factor_sources_single_index_per() { - let path = DerivationPath::account_tx( - Mainnet, - HDPathComponent::unsecurified_hardening_base_index(0), - ); - let paths = IndexSet::just(path); - let factor_sources = HDFactorSource::all(); - - let collector = KeysCollector::new_test( - factor_sources - .iter() - .map(|f| (f.factor_source_id(), paths.clone())) - .collect_vec(), - ); - let outcome = collector.collect_keys().await; - assert_eq!( - outcome - .all_factors() - .into_iter() - .map(|f| f.derivation_path()) - .collect::>(), - paths - ); - - assert_eq!( - outcome - .all_factors() - .into_iter() - .map(|f| f.factor_source_id) - .collect::>(), - factor_sources - .into_iter() - .map(|f| f.factor_source_id()) - .collect::>() - ); - } - - #[actix_rt::test] - async fn multi_keys_multi_factor_sources_multi_paths() { - let paths = [0, 1, 2] - .into_iter() - .map(|i| { - DerivationPath::unsecurified_hardening_base_index( - Mainnet, - Account, - TransactionSigning, - i, - ) - }) - .collect::>(); - - let factor_sources = HDFactorSource::all(); - - let collector = KeysCollector::new_test( - factor_sources - .iter() - .map(|f| (f.factor_source_id(), paths.clone())) - .collect_vec(), - ); - let outcome = collector.collect_keys().await; - - assert_eq!( - outcome - .all_factors() - .into_iter() - .map(|f| f.derivation_path()) - .collect::>(), - paths - ); - - assert_eq!( - outcome - .all_factors() - .into_iter() - .map(|f| f.factor_source_id) - .collect::>(), - factor_sources - .into_iter() - .map(|f| f.factor_source_id()) - .collect::>() - ); - } - - #[actix_rt::test] - async fn multi_keys_multi_factor_sources_multi_paths_complex() { - let mut paths = IndexSet::new(); - - paths.extend([0, 1, 2].into_iter().map(|i| { - DerivationPath::unsecurified_hardening_base_index( - Mainnet, - Account, - TransactionSigning, - i, - ) - })); - - paths.extend([0, 1, 2].into_iter().map(|i| { - DerivationPath::unsecurified_hardening_base_index( - Stokenet, - Account, - TransactionSigning, - i, - ) - })); - - paths.extend([0, 1, 2].into_iter().map(|i| { - DerivationPath::unsecurified_hardening_base_index( - Mainnet, - Identity, - TransactionSigning, - i, - ) - })); - - paths.extend([0, 1, 2].into_iter().map(|i| { - DerivationPath::unsecurified_hardening_base_index( - Stokenet, - Identity, - TransactionSigning, - i, - ) - })); - - paths.extend([0, 1, 2].into_iter().map(|i| { - DerivationPath::unsecurified_hardening_base_index( - Mainnet, - Account, - AuthenticationSigning, - i, - ) - })); - - paths.extend([0, 1, 2].into_iter().map(|i| { - DerivationPath::unsecurified_hardening_base_index( - Stokenet, - Account, - AuthenticationSigning, - i, - ) - })); - - paths.extend([0, 1, 2].into_iter().map(|i| { - DerivationPath::unsecurified_hardening_base_index( - Mainnet, - Identity, - AuthenticationSigning, - i, - ) - })); - - paths.extend([0, 1, 2].into_iter().map(|i| { - DerivationPath::unsecurified_hardening_base_index( - Stokenet, - Identity, - AuthenticationSigning, - i, - ) - })); - - paths.extend( - [ - 0, - 1, - 2, - BIP32_SECURIFIED_HALF, - BIP32_SECURIFIED_HALF + 1, - BIP32_SECURIFIED_HALF + 2, - ] - .into_iter() - .map(HDPathComponent::new_from_index) - .map(|p| DerivationPath::new(Mainnet, Account, TransactionSigning, p)), - ); - - paths.extend( - [ - 0, - 1, - 2, - BIP32_SECURIFIED_HALF, - BIP32_SECURIFIED_HALF + 1, - BIP32_SECURIFIED_HALF + 2, - ] - .into_iter() - .map(HDPathComponent::new_from_index) - .map(|p| DerivationPath::new(Stokenet, Account, TransactionSigning, p)), - ); - - paths.extend( - [ - 0, - 1, - 2, - BIP32_SECURIFIED_HALF, - BIP32_SECURIFIED_HALF + 1, - BIP32_SECURIFIED_HALF + 2, - ] - .into_iter() - .map(HDPathComponent::new_from_index) - .map(|p| DerivationPath::new(Mainnet, Identity, TransactionSigning, p)), - ); - - paths.extend( - [ - 0, - 1, - 2, - BIP32_SECURIFIED_HALF, - BIP32_SECURIFIED_HALF + 1, - BIP32_SECURIFIED_HALF + 2, - ] - .into_iter() - .map(HDPathComponent::new_from_index) - .map(|p| DerivationPath::new(Stokenet, Identity, TransactionSigning, p)), - ); - - paths.extend( - [ - 0, - 1, - 2, - BIP32_SECURIFIED_HALF, - BIP32_SECURIFIED_HALF + 1, - BIP32_SECURIFIED_HALF + 2, - ] - .into_iter() - .map(HDPathComponent::new_from_index) - .map(|p| DerivationPath::new(Mainnet, Account, AuthenticationSigning, p)), - ); - - paths.extend( - [ - 0, - 1, - 2, - BIP32_SECURIFIED_HALF, - BIP32_SECURIFIED_HALF + 1, - BIP32_SECURIFIED_HALF + 2, - ] - .into_iter() - .map(HDPathComponent::new_from_index) - .map(|p| DerivationPath::new(Stokenet, Account, AuthenticationSigning, p)), - ); - - paths.extend( - [ - 0, - 1, - 2, - BIP32_SECURIFIED_HALF, - BIP32_SECURIFIED_HALF + 1, - BIP32_SECURIFIED_HALF + 2, - ] - .into_iter() - .map(HDPathComponent::new_from_index) - .map(|p| DerivationPath::new(Mainnet, Identity, AuthenticationSigning, p)), - ); - - paths.extend( - [ - 0, - 1, - 2, - BIP32_SECURIFIED_HALF, - BIP32_SECURIFIED_HALF + 1, - BIP32_SECURIFIED_HALF + 2, - ] - .into_iter() - .map(HDPathComponent::new_from_index) - .map(|p| DerivationPath::new(Stokenet, Identity, AuthenticationSigning, p)), - ); - - let factor_sources = HDFactorSource::all(); - - let collector = KeysCollector::new_test( - factor_sources - .iter() - .map(|f| (f.factor_source_id(), paths.clone())) - .collect_vec(), - ); - let outcome = collector.collect_keys().await; - - assert_eq!( - outcome - .all_factors() - .into_iter() - .map(|f| f.derivation_path()) - .collect::>(), - paths - ); - - assert!(outcome.all_factors().factor_instances().len() > 200); - - assert_eq!( - outcome - .all_factors() - .into_iter() - .map(|f| f.factor_source_id) - .collect::>(), - factor_sources - .into_iter() - .map(|f| f.factor_source_id()) - .collect::>() - ); - } - } - - mod single_key { - use super::*; - - struct Expected { - index: HDPathComponent, - } - - async fn do_test( - key_space: KeySpace, - factor_source: &HDFactorSource, - network_id: NetworkID, - entity_kind: CAP26EntityKind, - key_kind: CAP26KeyKind, - expected: Expected, - ) { - let collector = - KeysCollector::with(factor_source, network_id, key_kind, entity_kind, key_space); - - let outcome = collector.collect_keys().await; - let factors = outcome.all_factors().factor_instances(); - assert_eq!(factors.len(), 1); - let factor = factors.first().unwrap(); - assert_eq!( - factor.derivation_path(), - DerivationPath::new(network_id, entity_kind, key_kind, expected.index) - ); - assert_eq!(factor.factor_source_id, factor_source.factor_source_id()); - } - - mod securified { - use super::*; - - async fn test( - factor_source: &HDFactorSource, - network_id: NetworkID, - entity_kind: CAP26EntityKind, - key_kind: CAP26KeyKind, - ) { - do_test( - KeySpace::Securified, - factor_source, - network_id, - entity_kind, - key_kind, - Expected { - index: HDPathComponent::securifying_base_index(0), - }, - ) - .await - } - - mod account { - use super::*; - - async fn each_factor(network_id: NetworkID, key_kind: CAP26KeyKind) { - for factor_source in HDFactorSource::all().iter() { - test(factor_source, network_id, Account, key_kind).await - } - } - - #[actix_rt::test] - async fn single_first_account_mainnet_t9n() { - each_factor(Mainnet, TransactionSigning).await - } - } - } - - mod unsecurified { - use super::*; - - async fn test( - factor_source: &HDFactorSource, - network_id: NetworkID, - entity_kind: CAP26EntityKind, - key_kind: CAP26KeyKind, - ) { - do_test( - KeySpace::Unsecurified, - factor_source, - network_id, - entity_kind, - key_kind, - Expected { - index: HDPathComponent::unsecurified_hardening_base_index(0), - }, - ) - .await - } - - mod account { - use super::*; - - async fn each_factor(network_id: NetworkID, key_kind: CAP26KeyKind) { - for factor_source in HDFactorSource::all().iter() { - test(factor_source, network_id, Account, key_kind).await - } - } - - #[actix_rt::test] - async fn single_first_account_mainnet_t9n() { - each_factor(Mainnet, TransactionSigning).await - } - - #[actix_rt::test] - async fn single_first_account_stokenet_t9n() { - each_factor(Mainnet, TransactionSigning).await - } - - #[actix_rt::test] - async fn single_first_account_mainnet_rola() { - each_factor(Mainnet, AuthenticationSigning).await - } - - #[actix_rt::test] - async fn single_first_account_stokenet_rola() { - each_factor(Stokenet, AuthenticationSigning).await - } - } - - mod persona { - use super::*; - - async fn each_factor(network_id: NetworkID, key_kind: CAP26KeyKind) { - for factor_source in HDFactorSource::all().iter() { - test(factor_source, network_id, Identity, key_kind).await - } - } - - #[actix_rt::test] - async fn single_first_persona_mainnet_t9n() { - each_factor(Mainnet, TransactionSigning).await - } - - #[actix_rt::test] - async fn single_first_persona_stokenet_t9n() { - each_factor(Mainnet, TransactionSigning).await - } - - #[actix_rt::test] - async fn single_first_persona_mainnet_rola() { - each_factor(Mainnet, AuthenticationSigning).await - } - - #[actix_rt::test] - async fn single_first_persona_stokenet_rola() { - each_factor(Stokenet, AuthenticationSigning).await - } - } - } - } -} diff --git a/src/derivation/tests/mod.rs b/src/derivation/tests/mod.rs deleted file mode 100644 index 4141518a..00000000 --- a/src/derivation/tests/mod.rs +++ /dev/null @@ -1 +0,0 @@ -mod derivation_tests; diff --git a/src/factor_instances_provider/agnostic_paths/derivation_preset.rs b/src/factor_instances_provider/agnostic_paths/derivation_preset.rs deleted file mode 100644 index bac1ca64..00000000 --- a/src/factor_instances_provider/agnostic_paths/derivation_preset.rs +++ /dev/null @@ -1,93 +0,0 @@ -use crate::prelude::*; - -/// Derivation Presets are Network agnostic and Index agnostic -/// "templates" for DerivationPaths. -#[derive(Clone, Copy, Hash, PartialEq, Eq, enum_iterator::Sequence, derive_more::Debug)] -pub enum DerivationPreset { - /// Used to form DerivationPaths used to derive FactorInstances - /// for "veci": Virtual Entity Creating (Factor)Instance for accounts. - /// `(EntityKind::Account, KeySpace::Unsecurified, KeyKind::TransactionSigning)` - #[debug("A-VECI")] - AccountVeci, - - /// Used to form DerivationPaths used to derive FactorInstances - /// for "mfa" to securify accounts. - /// `(EntityKind::Account, KeySpace::Securified, KeyKind::TransactionSigning)` - #[debug("A-MFA")] - AccountMfa, - - /// Used to form DerivationPaths used to derive FactorInstances - /// for "veci": Virtual Entity Creating (Factor)Instance for personas. - /// `(EntityKind::Identity, KeySpace::Unsecurified, KeyKind::TransactionSigning)` - #[debug("I-VECI")] - IdentityVeci, - - /// Used to form DerivationPaths used to derive FactorInstances - /// for "mfa" to securify personas. - /// `(EntityKind::Identity, KeySpace::Securified, KeyKind::TransactionSigning)` - #[debug("I-MFA")] - IdentityMfa, -} - -// ============= -// Construction -// ============= -impl DerivationPreset { - /// All DerivationPreset's, used to fill cache. - pub fn all() -> IndexSet { - enum_iterator::all::().collect() - } - - /// Selects a `DerivationPreset` for veci based on `CAP26EntityKind`, - /// i.e. either `DerivationPreset::AccountVeci` or `DerivationPreset::IdentityVeci`. - pub fn veci_entity_kind(entity_kind: CAP26EntityKind) -> Self { - match entity_kind { - CAP26EntityKind::Account => Self::AccountVeci, - CAP26EntityKind::Identity => Self::IdentityVeci, - } - } - - /// Selects a `DerivationPreset` for MFA based on `CAP26EntityKind`, - /// i.e. either `DerivationPreset::AccountMfa` or `DerivationPreset::IdentityMfa`. - pub fn mfa_entity_kind(entity_kind: CAP26EntityKind) -> Self { - match entity_kind { - CAP26EntityKind::Account => Self::AccountMfa, - CAP26EntityKind::Identity => Self::IdentityMfa, - } - } -} - -// ============= -// Instance Methods -// ============= -impl DerivationPreset { - /// Returns the `CAP26EntityKind` of the `DerivationPreset`. - pub fn entity_kind(&self) -> CAP26EntityKind { - match self { - Self::AccountVeci | Self::AccountMfa => CAP26EntityKind::Account, - Self::IdentityVeci | Self::IdentityMfa => CAP26EntityKind::Identity, - } - } - - /// Returns the `CAP26KeyKind` of the `DerivationPreset`. - pub fn key_kind(&self) -> CAP26KeyKind { - match self { - Self::AccountVeci | Self::IdentityVeci | Self::AccountMfa | Self::IdentityMfa => { - CAP26KeyKind::TransactionSigning - } - } - } - - /// Returns the `KeySpace` of the `DerivationPreset`. - pub fn key_space(&self) -> KeySpace { - match self { - Self::AccountVeci | Self::IdentityVeci => KeySpace::Unsecurified, - Self::AccountMfa | Self::IdentityMfa => KeySpace::Securified, - } - } - - /// Maps a DerivationPreset to a `IndexAgnosticPath` which is network aware. - pub fn index_agnostic_path_on_network(&self, network_id: NetworkID) -> IndexAgnosticPath { - IndexAgnosticPath::from((network_id, *self)) - } -} diff --git a/src/factor_instances_provider/agnostic_paths/index_agnostic_path.rs b/src/factor_instances_provider/agnostic_paths/index_agnostic_path.rs deleted file mode 100644 index 4e0e2138..00000000 --- a/src/factor_instances_provider/agnostic_paths/index_agnostic_path.rs +++ /dev/null @@ -1,122 +0,0 @@ -use crate::prelude::*; - -use super::quantities; - -/// A DerivationPath which is not indexed. On a specific network. -#[derive(Clone, Copy, Hash, PartialEq, Eq, derive_more::Debug, derive_more::Display)] -#[display("{}/{}/{}/?{}", network_id, entity_kind, key_kind, key_space.indicator())] -#[debug("{:?}/{:?}/{:?}/?{}", network_id, entity_kind, key_kind, key_space.indicator())] -pub struct IndexAgnosticPath { - pub network_id: NetworkID, - pub entity_kind: CAP26EntityKind, - pub key_kind: CAP26KeyKind, - pub key_space: KeySpace, -} - -impl IndexAgnosticPath { - pub fn new( - network_id: NetworkID, - entity_kind: CAP26EntityKind, - key_kind: CAP26KeyKind, - key_space: KeySpace, - ) -> Self { - Self { - network_id, - entity_kind, - key_kind, - key_space, - } - } -} - -impl From<(NetworkID, DerivationPreset)> for IndexAgnosticPath { - fn from((network_id, agnostic_path): (NetworkID, DerivationPreset)) -> Self { - Self::new( - network_id, - agnostic_path.entity_kind(), - agnostic_path.key_kind(), - agnostic_path.key_space(), - ) - } -} - -impl TryFrom for DerivationPreset { - type Error = CommonError; - /// Tries to convert an IndexAgnosticPath to a DerivationPreset, - /// is failing if the path is not a standard DerivationPreset - fn try_from(value: IndexAgnosticPath) -> Result { - match (value.entity_kind, value.key_kind, value.key_space) { - ( - CAP26EntityKind::Account, - CAP26KeyKind::TransactionSigning, - KeySpace::Unsecurified, - ) => Ok(DerivationPreset::AccountVeci), - ( - CAP26EntityKind::Identity, - CAP26KeyKind::TransactionSigning, - KeySpace::Unsecurified, - ) => Ok(DerivationPreset::IdentityVeci), - (CAP26EntityKind::Account, CAP26KeyKind::TransactionSigning, KeySpace::Securified) => { - Ok(DerivationPreset::AccountMfa) - } - (CAP26EntityKind::Identity, CAP26KeyKind::TransactionSigning, KeySpace::Securified) => { - Ok(DerivationPreset::IdentityMfa) - } - _ => Err(CommonError::NonStandardDerivationPath), - } - } -} - -impl From<(IndexAgnosticPath, HDPathComponent)> for DerivationPath { - fn from((path, index): (IndexAgnosticPath, HDPathComponent)) -> Self { - assert_eq!(index.key_space(), path.key_space); - Self::new(path.network_id, path.entity_kind, path.key_kind, index) - } -} - -impl DerivationPath { - pub fn agnostic(&self) -> IndexAgnosticPath { - IndexAgnosticPath { - network_id: self.network_id, - entity_kind: self.entity_kind, - key_kind: self.key_kind, - key_space: self.key_space(), - } - } -} -impl HierarchicalDeterministicFactorInstance { - pub fn agnostic_path(&self) -> IndexAgnosticPath { - self.derivation_path().agnostic() - } -} - -#[cfg(test)] -mod tests { - use super::*; - - type Sut = IndexAgnosticPath; - - #[test] - fn try_from_success() { - NetworkID::all().into_iter().for_each(|n| { - let f = |preset: DerivationPreset| { - let sut = preset.index_agnostic_path_on_network(n); - let back_again = DerivationPreset::try_from(sut).unwrap(); - assert_eq!(back_again, preset); - }; - - DerivationPreset::all().into_iter().for_each(|p| f(p)); - }); - } - - #[test] - fn try_from_fail() { - let path = Sut::new( - NetworkID::Stokenet, - CAP26EntityKind::Account, - CAP26KeyKind::AuthenticationSigning, - KeySpace::Unsecurified, - ); - assert!(DerivationPreset::try_from(path).is_err()); - } -} diff --git a/src/factor_instances_provider/agnostic_paths/mod.rs b/src/factor_instances_provider/agnostic_paths/mod.rs deleted file mode 100644 index 15238a79..00000000 --- a/src/factor_instances_provider/agnostic_paths/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -mod derivation_preset; -mod index_agnostic_path; -mod quantified_derivation_preset; -mod quantities; - -pub use derivation_preset::*; -pub use index_agnostic_path::*; -pub use quantified_derivation_preset::*; -pub use quantities::*; diff --git a/src/factor_instances_provider/agnostic_paths/quantified_derivation_preset.rs b/src/factor_instances_provider/agnostic_paths/quantified_derivation_preset.rs deleted file mode 100644 index 250ef7c8..00000000 --- a/src/factor_instances_provider/agnostic_paths/quantified_derivation_preset.rs +++ /dev/null @@ -1,17 +0,0 @@ -use crate::prelude::*; - -#[derive(Clone, Copy, Hash, PartialEq, Eq, derive_more::Debug)] -#[debug("🎯: {:?} #{}", self.derivation_preset, self.quantity)] -pub struct QuantifiedDerivationPreset { - pub derivation_preset: DerivationPreset, - pub quantity: usize, -} - -impl QuantifiedDerivationPreset { - pub fn new(derivation_preset: DerivationPreset, quantity: usize) -> Self { - Self { - derivation_preset, - quantity, - } - } -} diff --git a/src/factor_instances_provider/agnostic_paths/quantities.rs b/src/factor_instances_provider/agnostic_paths/quantities.rs deleted file mode 100644 index e6349fbf..00000000 --- a/src/factor_instances_provider/agnostic_paths/quantities.rs +++ /dev/null @@ -1,4 +0,0 @@ -use crate::prelude::*; - -/// The quantity of DerivationPreset's to fill cache with. -pub const CACHE_FILLING_QUANTITY: usize = 30; diff --git a/src/factor_instances_provider/mod.rs b/src/factor_instances_provider/mod.rs deleted file mode 100644 index 294823e5..00000000 --- a/src/factor_instances_provider/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -mod agnostic_paths; -mod next_index_assigner; -mod provider; - -pub use agnostic_paths::*; -pub use next_index_assigner::*; -pub use provider::*; diff --git a/src/factor_instances_provider/next_index_assigner/mod.rs b/src/factor_instances_provider/next_index_assigner/mod.rs deleted file mode 100644 index a687d9d3..00000000 --- a/src/factor_instances_provider/next_index_assigner/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -mod next_derivation_entity_index_assigner; -mod next_derivation_entity_index_cache_analyzing_assigner; -mod next_derivation_entity_index_profile_analyzing_assigner; -mod next_derivation_entity_index_with_ephemeral_offsets; -mod next_derivation_entity_index_with_ephemeral_offsets_for_factor_source; - -pub use next_derivation_entity_index_assigner::*; -pub use next_derivation_entity_index_cache_analyzing_assigner::*; -pub use next_derivation_entity_index_profile_analyzing_assigner::*; -pub use next_derivation_entity_index_with_ephemeral_offsets::*; -pub use next_derivation_entity_index_with_ephemeral_offsets_for_factor_source::*; diff --git a/src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_assigner.rs b/src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_assigner.rs deleted file mode 100644 index 9bb67d40..00000000 --- a/src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_assigner.rs +++ /dev/null @@ -1,84 +0,0 @@ -use crate::prelude::*; - -/// An assigner of derivation entity indices, used by the FactorInstancesProvider -/// to map `IndexAgnosticPath` -> `DerivationPath` for some FactorSource on -/// some NetworkID. -/// -/// This assigner works with the: -/// * cache -/// * profile -/// * local offsets -/// -/// More specifically the assigner's `next` method performs approximately this -/// operation: -/// -/// ```ignore -/// pub fn next( -/// &mut self, -/// fs_id: FactorSourceIDFromHash, -/// path: IndexAgnosticPath, -/// ) -> Result { -/// let next_from_cache = self.cache_analyzing.next(fs_id, path).unwrap_or(0); -/// let next_from_profile = self.profile_analyzing.next(fs_id, path).unwrap_or(0); -/// -/// let max_index = std::cmp::max(next_from_profile, next_from_cache); -/// let ephemeral_offset = self.ephemeral_offsets.reserve() -/// -/// max_index + ephemeral_offset -/// ``` -pub struct NextDerivationEntityIndexAssigner { - profile_analyzing: NextDerivationEntityIndexProfileAnalyzingAssigner, - cache_analyzing: NextDerivationEntityIndexCacheAnalyzingAssigner, - ephemeral_offsets: NextDerivationEntityIndexWithEphemeralOffsets, -} - -impl NextDerivationEntityIndexAssigner { - pub fn new( - network_id: NetworkID, - profile: impl Into>, - cache: FactorInstancesCache, - ) -> Self { - let profile_analyzing = - NextDerivationEntityIndexProfileAnalyzingAssigner::new(network_id, profile); - let cache_analyzing = NextDerivationEntityIndexCacheAnalyzingAssigner::new(cache); - let ephemeral_offsets = NextDerivationEntityIndexWithEphemeralOffsets::default(); - Self { - profile_analyzing, - cache_analyzing, - ephemeral_offsets, - } - } - - /// Returns the next index for the given `FactorSourceIDFromHash` and - /// `IndexAgnosticPath`, by analyzing the cache, the profile and adding - /// local ephemeral offsets. - pub fn next( - &self, - factor_source_id: FactorSourceIDFromHash, - index_agnostic_path: IndexAgnosticPath, - ) -> Result { - let default_index = HDPathComponent::new_with_key_space_and_base_index( - index_agnostic_path.key_space, - U30::new(0).unwrap(), - ); - - let maybe_next_from_cache = self - .cache_analyzing - .next(factor_source_id, index_agnostic_path)?; - - let next_from_cache = maybe_next_from_cache.unwrap_or(default_index); - let ephemeral = self - .ephemeral_offsets - .reserve(factor_source_id, index_agnostic_path); - - let maybe_next_from_profile = self - .profile_analyzing - .next(factor_source_id, index_agnostic_path)?; - - let next_from_profile = maybe_next_from_profile.unwrap_or(default_index); - - let max_index = std::cmp::max(next_from_profile, next_from_cache); - - max_index.add_n(ephemeral) - } -} diff --git a/src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_cache_analyzing_assigner.rs b/src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_cache_analyzing_assigner.rs deleted file mode 100644 index 45b09193..00000000 --- a/src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_cache_analyzing_assigner.rs +++ /dev/null @@ -1,37 +0,0 @@ -use crate::prelude::*; - -pub struct NextDerivationEntityIndexCacheAnalyzingAssigner { - cache: FactorInstancesCache, -} -impl NextDerivationEntityIndexCacheAnalyzingAssigner { - pub fn new(cache: FactorInstancesCache) -> Self { - Self { cache } - } - - fn max( - &self, - factor_source_id: FactorSourceIDFromHash, - index_agnostic_path: IndexAgnosticPath, - ) -> Option { - self.cache - .max_index_for(factor_source_id, index_agnostic_path) - } - - /// Returns the next index for the given `FactorSourceIDFromHash` and - /// `IndexAgnosticPath`, by analyzing the cache. In case of read failure - /// will this method return `Err`, if the cache did not contain any data for - /// the given `FactorSourceIDFromHash` and `IndexAgnosticPath`, then `Ok(None)` is returned. - /// - /// If some index was found, this method returns `max + 1`. - /// - /// Can also fail if addition of one would overflow. - pub fn next( - &self, - factor_source_id: FactorSourceIDFromHash, - index_agnostic_path: IndexAgnosticPath, - ) -> Result> { - let max = self.max(factor_source_id, index_agnostic_path); - let Some(max) = max else { return Ok(None) }; - max.add_one().map(Some) - } -} diff --git a/src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_profile_analyzing_assigner.rs b/src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_profile_analyzing_assigner.rs deleted file mode 100644 index 48c3f2ad..00000000 --- a/src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_profile_analyzing_assigner.rs +++ /dev/null @@ -1,432 +0,0 @@ -use crate::prelude::*; - -/// An analyzer of a `Profile` for some `network_id` (i.e. analyzer of `ProfileNetwork`), -/// reading out the max derivation entity index for Unsecurified/Securified Accounts/Personas -/// for some factor source id. -pub struct NextDerivationEntityIndexProfileAnalyzingAssigner { - network_id: NetworkID, - - /// might be empty - unsecurified_accounts_on_network: IndexSet, - - /// might be empty - securified_accounts_on_network: IndexSet, - - /// might be empty - unsecurified_identities_on_network: IndexSet, - - /// might be empty - securified_identities_on_network: IndexSet, -} - -impl NextDerivationEntityIndexProfileAnalyzingAssigner { - /// `Profile` is optional so that one can use the same initializer from `FactorInstancesProvider`, - /// which accepts an optional Profile. Will just default to empty lists if `None` is passed, - /// effectively making this whole assigner NOOP. - pub fn new(network_id: NetworkID, profile: impl Into>) -> Self { - let profile = profile.into(); - let unsecurified_accounts_on_network = profile - .as_ref() - .map(|p| p.unsecurified_accounts_on_network(network_id)) - .unwrap_or_default(); - - let securified_accounts_on_network = profile - .as_ref() - .map(|p| p.securified_accounts_on_network(network_id)) - .unwrap_or_default(); - - let unsecurified_identities_on_network = profile - .as_ref() - .map(|p| p.unsecurified_identities_on_network(network_id)) - .unwrap_or_default(); - - let securified_identities_on_network = profile - .as_ref() - .map(|p| p.securified_identities_on_network(network_id)) - .unwrap_or_default(); - - Self { - network_id, - unsecurified_accounts_on_network, - securified_accounts_on_network, - unsecurified_identities_on_network, - securified_identities_on_network, - } - } - - fn max_entity_veci( - &self, - factor_source_id: FactorSourceIDFromHash, - entities: impl IntoIterator, - securified_entities: impl IntoIterator, - entity_kind: CAP26EntityKind, - key_space: KeySpace, - ) -> Option { - let max_veci = |vecis: IndexSet| -> Option { - vecis - .into_iter() - .map(|x| x.factor_instance()) - .filter(|f| f.factor_source_id == factor_source_id) - .map(|f| f.derivation_path()) - .map(|p| { - AssertMatches { - network_id: self.network_id, - key_kind: CAP26KeyKind::TransactionSigning, - entity_kind, - key_space, - } - .matches(&p) - }) - .map(|fi| fi.index) - .max() - }; - - let of_unsecurified = max_veci(entities.into_iter().map(|x| x.veci()).collect()); - - // The securified entities might have been originally created - having a veci - - // with the same factor source id. - let of_securified = max_veci( - securified_entities - .into_iter() - .filter_map(|x| x.veci()) - .collect(), - ); - - std::cmp::max(of_unsecurified, of_securified) - } - - /// Returns the Max Derivation Entity Index of Unsecurified Accounts controlled - /// by `factor_source_id`, or `None` if no unsecurified account controlled by that - /// factor source id found. - fn max_account_veci( - &self, - factor_source_id: FactorSourceIDFromHash, - ) -> Option { - self.max_entity_veci( - factor_source_id, - self.unsecurified_accounts_on_network.clone(), - self.securified_accounts_on_network - .clone() - .into_iter() - .map(|x| x.securified_entity_control()), - CAP26EntityKind::Account, - KeySpace::Unsecurified, - ) - } - - /// Returns the Max Derivation Entity Index of Unsecurified Personas controlled - /// by `factor_source_id`, or `None` if no unsecurified persona controlled by that - /// factor source id found. - fn max_identity_veci( - &self, - factor_source_id: FactorSourceIDFromHash, - ) -> Option { - self.max_entity_veci( - factor_source_id, - self.unsecurified_identities_on_network.clone(), - self.securified_identities_on_network - .clone() - .into_iter() - .map(|x| x.securified_entity_control()), - CAP26EntityKind::Identity, - KeySpace::Unsecurified, - ) - } - - /// Returns the Max Derivation Entity Index of Securified Accounts controlled - /// by `factor_source_id`, or `None` if no securified account controlled by that - /// factor source id found. - /// By "controlled by" we mean having a MatrixOfFactorInstances which has that - /// factor in **any role** in its MatrixOfFactorInstances. - fn max_account_mfa(&self, factor_source_id: FactorSourceIDFromHash) -> Option { - self.securified_accounts_on_network - .clone() - .into_iter() - .flat_map(|e: SecurifiedAccount| { - e.highest_derivation_path_index( - factor_source_id, - AssertMatches { - network_id: self.network_id, - key_kind: CAP26KeyKind::TransactionSigning, - entity_kind: CAP26EntityKind::Account, - key_space: KeySpace::Securified, - }, - ) - }) - .max() - } - - /// Returns the Max Derivation Entity Index of Securified Persona controlled - /// by `factor_source_id`, or `None` if no securified persona controlled by that - /// factor source id found. - /// By "controlled by" we mean having a MatrixOfFactorInstances which has that - /// factor in **any role** in its MatrixOfFactorInstances. - fn max_identity_mfa( - &self, - factor_source_id: FactorSourceIDFromHash, - ) -> Option { - self.securified_identities_on_network - .clone() - .into_iter() - .flat_map(|e: SecurifiedPersona| { - e.highest_derivation_path_index( - factor_source_id, - AssertMatches { - network_id: self.network_id, - key_kind: CAP26KeyKind::TransactionSigning, - entity_kind: CAP26EntityKind::Identity, - key_space: KeySpace::Securified, - }, - ) - }) - .max() - } - - /// Finds the "next" derivation entity index `HDPathComponent`, for - /// the given `IndexAgnosticPath` adnd `factor_source_id`, which is `Max + 1`. - /// Returns `None` if `Max` is `None` (see `max_account_veci`, `max_identity_mfa` for more details). - /// - /// Returns `Err` if the addition of one would overflow. - pub fn next( - &self, - factor_source_id: FactorSourceIDFromHash, - agnostic_path: IndexAgnosticPath, - ) -> Result> { - if agnostic_path.network_id != self.network_id { - return Err(CommonError::NetworkDiscrepancy); - } - let derivation_preset = DerivationPreset::try_from(agnostic_path)?; - - let max = match derivation_preset { - DerivationPreset::AccountVeci => self.max_account_veci(factor_source_id), - DerivationPreset::AccountMfa => self.max_account_mfa(factor_source_id), - DerivationPreset::IdentityVeci => self.max_identity_veci(factor_source_id), - DerivationPreset::IdentityMfa => self.max_identity_mfa(factor_source_id), - }; - - let Some(max) = max else { return Ok(None) }; - max.add_one().map(Some) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - type Sut = NextDerivationEntityIndexProfileAnalyzingAssigner; - - #[test] - fn test_network_discrepancy() { - let sut = Sut::new(NetworkID::Mainnet, None); - assert_eq!( - sut.next( - FactorSourceIDFromHash::fs0(), - DerivationPreset::AccountVeci.index_agnostic_path_on_network(NetworkID::Stokenet), - ), - Err(CommonError::NetworkDiscrepancy) - ); - } - - #[test] - fn test_next_account_veci_with_single_at_0_is_1() { - let preset = DerivationPreset::AccountVeci; - let network_id = NetworkID::Mainnet; - let sut = Sut::new( - network_id, - Some(Profile::new(HDFactorSource::all(), [&Account::a0()], [])), - ); - let next = sut - .next( - FactorSourceIDFromHash::fs0(), - preset.index_agnostic_path_on_network(network_id), - ) - .unwrap(); - - assert_eq!( - next, - Some(HDPathComponent::unsecurified_hardening_base_index(1)) - ) - } - - #[test] - fn test_next_account_veci_with_unused_factor_is_none() { - let preset = DerivationPreset::AccountVeci; - let network_id = NetworkID::Mainnet; - let sut = Sut::new( - network_id, - Some(Profile::new(HDFactorSource::all(), [&Account::a0()], [])), - ); - let next = sut - .next( - FactorSourceIDFromHash::fs1(), // <-- UNUSED - preset.index_agnostic_path_on_network(network_id), - ) - .unwrap(); - - assert_eq!(next, None) - } - - #[test] - fn test_next_account_mfa_with_single_unsecurified_is_none() { - let preset = DerivationPreset::AccountMfa; - let network_id = NetworkID::Mainnet; - let sut = Sut::new( - network_id, - Some(Profile::new(HDFactorSource::all(), [&Account::a0()], [])), - ); - let next = sut - .next( - FactorSourceIDFromHash::fs0(), - preset.index_agnostic_path_on_network(network_id), - ) - .unwrap(); - - assert_eq!(next, None) - } - - #[test] - fn test_next_account_veci_with_single_at_8_is_9() { - let preset = DerivationPreset::AccountVeci; - let network_id = NetworkID::Mainnet; - let sut = Sut::new( - network_id, - Some(Profile::new( - HDFactorSource::all(), - [ - &Account::a8(), - &Account::a2(), /* securified, should not interfere */ - ], - [], - )), - ); - let next = sut - .next( - FactorSourceIDFromHash::fs10(), - preset.index_agnostic_path_on_network(network_id), - ) - .unwrap(); - - assert_eq!( - next, - Some(HDPathComponent::unsecurified_hardening_base_index(9)) - ) - } - - #[test] - fn test_next_account_mfa_with_single_at_7_is_8() { - let preset = DerivationPreset::AccountMfa; - let network_id = NetworkID::Mainnet; - let sut = Sut::new( - network_id, - Some(Profile::new( - HDFactorSource::all(), - [ - &Account::a8(), /* unsecurified, should not interfere */ - &Account::a7(), - ], - [], - )), - ); - type F = FactorSourceIDFromHash; - for fid in [F::fs2(), F::fs6(), F::fs7(), F::fs8(), F::fs9()] { - let next = sut - .next(fid, preset.index_agnostic_path_on_network(network_id)) - .unwrap(); - - assert_eq!(next, Some(HDPathComponent::securifying_base_index(8))) - } - } - - #[test] - fn test_next_identity_mfa_with_single_at_7_is_8() { - let preset = DerivationPreset::IdentityMfa; - let network_id = NetworkID::Mainnet; - let sut = Sut::new( - network_id, - Some(Profile::new(HDFactorSource::all(), [], [&Persona::p7()])), - ); - type F = FactorSourceIDFromHash; - for fid in [F::fs2(), F::fs6(), F::fs7(), F::fs8(), F::fs9()] { - let next = sut - .next(fid, preset.index_agnostic_path_on_network(network_id)) - .unwrap(); - - assert_eq!(next, Some(HDPathComponent::securifying_base_index(8))) - } - } - - #[test] - fn test_next_identity_veci_with_single_at_1_is_2() { - let preset = DerivationPreset::IdentityVeci; - let network_id = NetworkID::Mainnet; - let sut = Sut::new( - network_id, - Some(Profile::new( - HDFactorSource::all(), - [], - [ - &Persona::p7(), /* securified should not interfere */ - &Persona::p1(), - ], - )), - ); - let next = sut - .next( - FactorSourceIDFromHash::fs1(), - preset.index_agnostic_path_on_network(network_id), - ) - .unwrap(); - - assert_eq!( - next, - Some(HDPathComponent::unsecurified_hardening_base_index(2)) - ) - } - - #[test] - fn test_next_account_veci_with_non_contiguous_at_0_1_7_is_8() { - let fsid = FactorSourceIDFromHash::fs0(); - - let fi0 = HierarchicalDeterministicFactorInstance::mainnet_tx( - CAP26EntityKind::Account, - HDPathComponent::unsecurified_hardening_base_index(0), - fsid, - ); - let fi1 = HierarchicalDeterministicFactorInstance::mainnet_tx( - CAP26EntityKind::Account, - HDPathComponent::unsecurified_hardening_base_index(1), - fsid, - ); - - let fi7 = HierarchicalDeterministicFactorInstance::mainnet_tx( - CAP26EntityKind::Account, - HDPathComponent::unsecurified_hardening_base_index(7), - fsid, - ); - - let network_id = NetworkID::Mainnet; - let accounts = [fi0, fi1, fi7].map(|fi| { - Account::new( - "acco", - AccountAddress::new(network_id, fi.public_key_hash()), - EntitySecurityState::Unsecured(fi), - ThirdPartyDepositPreference::default(), - ) - }); - let sut = Sut::new( - network_id, - Some(Profile::new(HDFactorSource::all(), &accounts, [])), - ); - let next = sut - .next( - fsid, - DerivationPreset::AccountVeci.index_agnostic_path_on_network(network_id), - ) - .unwrap(); - - assert_eq!( - next, - Some(HDPathComponent::unsecurified_hardening_base_index(8)) - ) - } -} diff --git a/src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_with_ephemeral_offsets.rs b/src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_with_ephemeral_offsets.rs deleted file mode 100644 index d2f930d1..00000000 --- a/src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_with_ephemeral_offsets.rs +++ /dev/null @@ -1,113 +0,0 @@ -use crate::prelude::*; - -/// Essentially a map of `NextDerivationEntityIndexWithEphemeralOffsetsForFactorSource` -/// ephemeral offsets used by `NextDerivationEntityIndexAssigner` -/// to add ephemeral offsets to next index calculations. -#[derive(Default, Debug)] -pub struct NextDerivationEntityIndexWithEphemeralOffsets { - ephemeral_offsets_per_factor_source: RwLock< - HashMap< - FactorSourceIDFromHash, - NextDerivationEntityIndexWithEphemeralOffsetsForFactorSource, - >, - >, -} - -impl NextDerivationEntityIndexWithEphemeralOffsets { - /// Reserves the next ephemeral offset for `factor_source_id` for `agnostic_path`. - /// Consecutive calls always returns a new value, which is `previous + 1` (given - /// the same `factor_source_id, agnostic_path`) - pub fn reserve( - &self, - factor_source_id: FactorSourceIDFromHash, - agnostic_path: IndexAgnosticPath, - ) -> HDPathValue { - let mut binding = self.ephemeral_offsets_per_factor_source.write().unwrap(); - if let Some(for_factor) = binding.get_mut(&factor_source_id) { - for_factor.reserve(agnostic_path) - } else { - let new = NextDerivationEntityIndexWithEphemeralOffsetsForFactorSource::default(); - let next = new.reserve(agnostic_path); - binding.insert(factor_source_id, new); - next - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - type Sut = NextDerivationEntityIndexWithEphemeralOffsets; - - #[test] - fn test_contiguous() { - let sut = Sut::default(); - let n = 4; - let indices = (0..n) - .map(|_| { - sut.reserve( - FactorSourceIDFromHash::fs0(), - DerivationPreset::AccountVeci - .index_agnostic_path_on_network(NetworkID::Mainnet), - ) - }) - .collect::>(); - assert_eq!(indices, IndexSet::::from_iter([0, 1, 2, 3])); - } - - #[test] - fn test_zero_for_each_factor_sources_first_time() { - let sut = Sut::default(); - let fsids = HDFactorSource::all() - .into_iter() - .map(|f| f.factor_source_id()) - .collect_vec(); - let indices = fsids - .clone() - .into_iter() - .map(|fsid| { - sut.reserve( - fsid, - DerivationPreset::AccountVeci - .index_agnostic_path_on_network(NetworkID::Mainnet), - ) - }) - .collect_vec(); - assert_eq!(indices, vec![0; fsids.len()]); - } - - #[test] - fn test_zero_for_each_derivation_preset() { - let sut = Sut::default(); - let derivation_presets = DerivationPreset::all(); - let indices = derivation_presets - .clone() - .into_iter() - .map(|preset| { - sut.reserve( - FactorSourceIDFromHash::fs0(), - preset.index_agnostic_path_on_network(NetworkID::Mainnet), - ) - }) - .collect_vec(); - assert_eq!(indices, vec![0; derivation_presets.len()]); - } - - #[test] - fn test_zero_for_each_network() { - let sut = Sut::default(); - let network_ids = NetworkID::all(); - let indices = network_ids - .clone() - .into_iter() - .map(|network_id| { - sut.reserve( - FactorSourceIDFromHash::fs0(), - DerivationPreset::AccountMfa.index_agnostic_path_on_network(network_id), - ) - }) - .collect_vec(); - assert_eq!(indices, vec![0; network_ids.len()]); - } -} diff --git a/src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_with_ephemeral_offsets_for_factor_source.rs b/src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_with_ephemeral_offsets_for_factor_source.rs deleted file mode 100644 index ca0c1b8b..00000000 --- a/src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_with_ephemeral_offsets_for_factor_source.rs +++ /dev/null @@ -1,28 +0,0 @@ -use std::ops::{AddAssign, Index}; - -use crate::prelude::*; - -/// Ephemeral / "Local" offsets, is a collection of counters with offset added -/// on top of next index analysis based on cache or profile. This is used so that -/// the FactorInstanceProvider can consecutively call `next` N times to get a range of -/// of `N` unique indices, added to the otherwise next based on cache/profile analysis. -#[derive(Debug, Default)] -pub struct NextDerivationEntityIndexWithEphemeralOffsetsForFactorSource { - ephemeral_offsets: RwLock>, -} - -impl NextDerivationEntityIndexWithEphemeralOffsetsForFactorSource { - /// Returns the next free index for the IndexAgnosticPath, - /// and increases the local ephemeral offset. - pub fn reserve(&self, agnostic_path: IndexAgnosticPath) -> HDPathValue { - let mut binding = self.ephemeral_offsets.write().unwrap(); - if let Some(existing) = binding.get_mut(&agnostic_path) { - let free = *existing; - existing.add_assign(1); - free - } else { - binding.insert(agnostic_path, 1); - 0 - } - } -} diff --git a/src/factor_instances_provider/provider/factor_instances_cache.rs b/src/factor_instances_provider/provider/factor_instances_cache.rs deleted file mode 100644 index 834b03ff..00000000 --- a/src/factor_instances_provider/provider/factor_instances_cache.rs +++ /dev/null @@ -1,525 +0,0 @@ -use std::{ - borrow::Borrow, - ops::{Add, Index}, -}; - -use crate::prelude::*; - -/// A cache of factor instances. -/// -/// Keyed under FactorSourceID and then under `IndexAgnosticPath`, each holding -/// an ordered set of Factor Instances, with contiguous derivation entity indices, -/// with lowest indices first in the set and highest last. -/// -/// Since an IndexAgnosticPath essentially is the tuple `(NetworkID, DerivationPreset)`, -/// you can think of the implementation to not be: -/// `IndexMap>` -/// but actually: -/// IndexMap>>`, -/// in fact it could be, but not sure it is more readable. But for the sake of visualizing -/// the cache we use that structure. -/// -/// E.g.: -/// ```ignore -/// [ -/// "FactorSourceID": [ -/// "Mainnet": [ -/// DerivationPreset::AccountVeci: [ -/// (0', key...), -/// (1', key...), -/// ... -/// (29', key...), -/// ], -/// DerivationPreset::AccountMfa: [ -/// (0^, key...), -/// (1^, key...), -/// ... -/// (29^, key...), -/// ], -/// DerivationPreset::IdentityVeci: [ -/// (0', key...), -/// ... -/// (29', key...), -/// ], -/// DerivationPreset::IdentityMfa: [ -/// (0^, key...), ..., (29^, key...), -/// ], -/// ], -/// "Stokenet": [ -/// DerivationPreset::AccountVeci: [ -/// (0', key...), ..., (29', key...), -/// ], -/// DerivationPreset::AccountMfa: [ -/// (0^, key...), ..., (29^, key...), -/// ], -/// DerivationPreset::IdentityVeci: [ -/// (0', key...), ... (29', key...), -/// ], -/// DerivationPreset::IdentityMfa: [ -/// (0^, key...), ..., (29^, key...), -/// ], -/// ], -/// ], -/// "FactorSourceID": [ -/// "Mainnet": [ -/// DerivationPreset::AccountVeci: [ -/// (0', key...), ..., (29', key...), -/// ], -/// DerivationPreset::AccountMfa: [ ... ], -/// DerivationPreset::IdentityVeci: [ ... ], -/// DerivationPreset::IdentityMfa: [ ... ], -/// ], -/// "Stokenet": [ -/// DerivationPreset::AccountVeci: [ -/// (0', key...), ..., (29', key...), -/// ], -/// DerivationPreset::AccountMfa: [ ... ], -/// DerivationPreset::IdentityVeci: [ ... ], -/// DerivationPreset::IdentityMfa: [ ... ], -/// ], -/// ], -/// ] -/// ``` -/// -/// This is the "in-memory" form of the cache. We would need to impl `Serde` for -/// it in Sargon. -/// -/// We use `IndexMap` instead of `HashMap` for future proofing when we serialize, -/// deserialize this cache, we want the JSON values to have stable ordering. Note -/// that the only truly **important** ordering is that of `FactorInstances` values, -/// which are ordered since it is a newtype around `IndexSet`. -/// -/// -/// The Serde impl of `IndexAgnosticPath` could be: -/// `"///"` as a string, e.g: -/// `"1/A/TX/U"`, where `U` is "Unsecurified" KeySpace. -/// Or if we don't wanna use such a "custom" one we can use `525`/`616` -/// discriminator for EntityKind and `1460`/`1678` for KeyKind: -/// "1/525/1460/U". -#[derive(Debug, Default, Clone, PartialEq, Eq)] -pub struct FactorInstancesCache { - /// PER FactorSource PER IndexAgnosticPath FactorInstances (matching that IndexAgnosticPath) - map: IndexMap>, -} - -impl FactorInstancesCache { - /// Inserts `instances` under `factor_source_id` by splitting them and grouping - /// them by their `IndexAgnosticPath`. - /// - /// Returns `Err` if any of the instances is in fact does NOT have `factor_source_id`, - /// as its factor source id. - /// - /// Returns `bool` indicating if an index was skipped resulting in non-contiguousness, which - /// we do not use for now. Might be something we enforce or not for certain operations - /// in the future. - pub fn insert_for_factor( - &mut self, - factor_source_id: &FactorSourceIDFromHash, - instances: &FactorInstances, - ) -> Result { - let mut skipped_an_index_resulting_in_non_contiguity = false; - - let instances_by_agnostic_path = InstancesByAgnosticPath::from(instances.clone()); - instances_by_agnostic_path.validate_from_source(factor_source_id)?; - if let Some(existing_for_factor) = self.map.get_mut(factor_source_id) { - for (agnostic_path, instances) in instances_by_agnostic_path { - let instances = instances.factor_instances(); - - if let Some(existing_for_path) = existing_for_factor.get_mut(&agnostic_path) { - if let Some(fi) = instances - .intersection(&existing_for_path.factor_instances()) - .next() - { - return Err(CommonError::CacheAlreadyContainsFactorInstance { - derivation_path: fi.derivation_path(), - }); - } - - if let Some(last) = existing_for_path.factor_instances().last() { - if instances.first().unwrap().derivation_entity_base_index() - != last.derivation_entity_base_index() + 1 - { - warn!( - "Non-contiguous indices, the index `{}` was skipped!", - last.derivation_entity_base_index() + 1 - ); - skipped_an_index_resulting_in_non_contiguity = true; - } - } - existing_for_path.extend(instances); - } else { - existing_for_factor.insert(agnostic_path, FactorInstances::from(instances)); - } - } - } else { - self.map - .insert(*factor_source_id, instances_by_agnostic_path.0); - } - - Ok(skipped_an_index_resulting_in_non_contiguity) - } - - /// Inserts all instance in `per_factor`. - pub fn insert_all( - &mut self, - per_factor: &IndexMap, - ) -> Result<()> { - for (factor_source_id, instances) in per_factor { - _ = self.insert_for_factor(factor_source_id, instances)?; - } - Ok(()) - } - - /// Returns the MAX derivation entity index for the given `factor_source_id` and `index_agnostic_path`. - pub fn max_index_for( - &self, - factor_source_id: impl Borrow, - index_agnostic_path: impl Borrow, - ) -> Option { - self.get_mono_factor(factor_source_id, index_agnostic_path) - .unwrap_or_default() - .factor_instances() - .into_iter() - .map(|fi| fi.derivation_entity_index()) - .max() - } - - /// Returns enough instances to satisfy the requested quantity for each factor source, - /// **OR LESS**, never more, and if less, it means we MUST derive more, and if we - /// must derive more, this function returns the quantities to derive for each factor source, - /// for each derivation preset, not only the originally requested one. - pub fn get_poly_factor_with_quantities( - &self, - factor_source_ids: &IndexSet, - originally_requested_quantified_derivation_preset: &QuantifiedDerivationPreset, - network_id: NetworkID, - ) -> Result { - let target_quantity = originally_requested_quantified_derivation_preset.quantity; - let mut pf_instances = IndexMap::::new(); - let mut pf_pdp_qty_to_derive = - IndexMap::>::new(); - let mut is_quantity_satisfied_for_all_factor_sources = true; - - for factor_source_id in factor_source_ids { - for preset in DerivationPreset::all() { - let index_agnostic_path = preset.index_agnostic_path_on_network(network_id); - let for_preset = self - .get_mono_factor(factor_source_id, index_agnostic_path) - .unwrap_or_default(); - let count_in_cache = for_preset.len(); - if preset == originally_requested_quantified_derivation_preset.derivation_preset { - let satisfies_requested_quantity = count_in_cache >= target_quantity; - if satisfies_requested_quantity { - // The instances in the cache can satisfy the requested quantity - // for this factor source for this derivation preset - pf_instances.append_or_insert_to( - factor_source_id, - // Only take the first `target_quantity` instances - // to be used, the rest are not needed and should - // remain in the cache (later we will call delete on - // all those instances.) - for_preset.split_at(target_quantity).0, - ); - } else { - // The instances in the cache cannot satisfy the requested quantity - // we must derive more! - is_quantity_satisfied_for_all_factor_sources = false; - // Since we are deriving more we might as well ensure that the - // cache is filled with `CACHE_FILLING_QUANTITY` **AFTER** the - // requested quantity is satisfied, meaning we will not only - // derive `CACHE_FILLING_QUANTITY - count_in_cache`, instead we - // derive the `target_quantity` as well. - let quantity_to_derive = - CACHE_FILLING_QUANTITY - count_in_cache + target_quantity; - pf_pdp_qty_to_derive.append_or_insert_element_to( - factor_source_id, - (preset, quantity_to_derive), - ); - // insert all instances to be used directly - pf_instances.append_or_insert_to(factor_source_id, for_preset.clone()); - } - } else { - // Not originally requested derivation preset, calculate number - // of instances to derive IF we are going to derive anyway, - // we wanna FILL the cache for those derivation presets as well. - if count_in_cache < CACHE_FILLING_QUANTITY { - let qty_to_derive = CACHE_FILLING_QUANTITY - count_in_cache; - pf_pdp_qty_to_derive - .append_or_insert_element_to(factor_source_id, (preset, qty_to_derive)); - } - } - } - } - let outcome = if is_quantity_satisfied_for_all_factor_sources { - CachedInstancesWithQuantitiesOutcome::Satisfied(pf_instances) - } else { - CachedInstancesWithQuantitiesOutcome::NotSatisfied { - partial_instances: pf_instances, - quantities_to_derive: pf_pdp_qty_to_derive, - } - }; - Ok(outcome) - } -} - -#[derive(enum_as_inner::EnumAsInner)] -pub enum CachedInstancesWithQuantitiesOutcome { - Satisfied(IndexMap), - NotSatisfied { - partial_instances: IndexMap, - quantities_to_derive: IndexMap>, - }, -} - -impl FactorInstancesCache { - pub fn get_mono_factor( - &self, - factor_source_id: impl Borrow, - index_agnostic_path: impl Borrow, - ) -> Option { - let for_factor = self.map.get(factor_source_id.borrow())?; - let instances = for_factor.get(index_agnostic_path.borrow())?; - Some(instances.clone()) - } - - pub fn delete(&mut self, pf_instances: &IndexMap) { - for (factor_source_id, instances_to_delete) in pf_instances { - if instances_to_delete.is_empty() { - continue; - } - let existing_for_factor = self - .map - .get_mut(factor_source_id) - .expect("expected to delete factors"); - - let instances_to_delete_by_path = - InstancesByAgnosticPath::from(instances_to_delete.clone()); - for (index_agnostic_path, instances_to_delete) in instances_to_delete_by_path { - let instances_to_delete = - IndexSet::::from_iter( - instances_to_delete.into_iter(), - ); - - let existing_for_path = existing_for_factor - .get(&index_agnostic_path) - .expect("expected to delete") - .factor_instances(); - - if !existing_for_path.is_superset(&instances_to_delete) { - panic!("Programmer error! Some of the factors to delete were not in cache!"); - } - let to_keep = existing_for_path - .symmetric_difference(&instances_to_delete) - .cloned() - .collect::(); - - // replace - existing_for_factor.insert(index_agnostic_path, to_keep); - } - } - - self.prune(); - } - - /// "Prunes" the cache from empty collections - fn prune(&mut self) { - let ids = self.factor_source_ids(); - for factor_source_id in ids.iter() { - let inner_map = self.map.get_mut(factor_source_id).unwrap(); - if inner_map.is_empty() { - // empty map, prune it! - self.map.shift_remove(factor_source_id); - continue; - } - // see if pruning of instances inside of values `inner_map` is needed - let inner_ids = inner_map - .keys() - .cloned() - .collect::>(); - for inner_id in inner_ids.iter() { - if inner_map.get(inner_id).unwrap().is_empty() { - // FactorInstances empty, prune it! - inner_map.shift_remove(inner_id); - } - } - } - } - - fn factor_source_ids(&self) -> IndexSet { - self.map.keys().cloned().collect() - } - pub fn insert(&mut self, pf_instances: &IndexMap) { - self.insert_all(pf_instances).expect("works") - } - - /// Reads out the instance of `factor_source_id` without mutating the cache. - pub fn peek_all_instances_of_factor_source( - &self, - factor_source_id: FactorSourceIDFromHash, - ) -> Option> { - self.map.get(&factor_source_id).cloned() - } - - pub fn total_number_of_factor_instances(&self) -> usize { - self.map - .values() - .map(|x| { - x.values() - .map(|y| y.len()) - .reduce(Add::add) - .unwrap_or_default() - }) - .reduce(Add::add) - .unwrap_or_default() - } -} - -#[cfg(test)] -impl FactorInstancesCache { - /// Queries the cache to see if the cache is full for factor_source_id for - /// each DerivationPreset - pub fn is_full(&self, network_id: NetworkID, factor_source_id: FactorSourceIDFromHash) -> bool { - DerivationPreset::all() - .into_iter() - .map(|preset| { - self.get_poly_factor_with_quantities( - &IndexSet::just(factor_source_id), - &QuantifiedDerivationPreset::new(preset, CACHE_FILLING_QUANTITY), - network_id, - ) - }) - .all(|outcome| { - matches!( - outcome, - Ok(CachedInstancesWithQuantitiesOutcome::Satisfied(_)) - ) - }) - } - - pub fn assert_is_full(&self, network_id: NetworkID, factor_source_id: FactorSourceIDFromHash) { - assert!(self.is_full(network_id, factor_source_id)); - } -} - -#[cfg(test)] -mod tests { - - use std::fs; - - use super::*; - - type Sut = FactorInstancesCache; - - #[test] - fn non_contiguous_indices() { - let mut sut = Sut::default(); - let fsid = FactorSourceIDFromHash::fs0(); - let fi0 = HierarchicalDeterministicFactorInstance::mainnet_tx( - CAP26EntityKind::Account, - HDPathComponent::unsecurified_hardening_base_index(0), - fsid, - ); - assert!(!sut - .insert_for_factor(&fsid, &FactorInstances::from_iter([fi0])) - .unwrap()); - let fi2 = HierarchicalDeterministicFactorInstance::mainnet_tx( - CAP26EntityKind::Account, - HDPathComponent::unsecurified_hardening_base_index(2), // OH NO! Skipping `1` - fsid, - ); - assert!(sut - .insert_for_factor(&fsid, &FactorInstances::from_iter([fi2])) - .unwrap(),); - } - - #[test] - fn factor_source_discrepancy() { - let mut sut = Sut::default(); - let fi0 = HierarchicalDeterministicFactorInstance::mainnet_tx( - CAP26EntityKind::Account, - HDPathComponent::unsecurified_hardening_base_index(0), - FactorSourceIDFromHash::fs0(), - ); - assert!(sut - .insert_for_factor( - &FactorSourceIDFromHash::fs1(), - &FactorInstances::from_iter([fi0]) - ) - .is_err()); - } - - #[test] - fn delete() { - let mut sut = Sut::default(); - - let factor_source_ids = HDFactorSource::all() - .into_iter() - .map(|f| f.factor_source_id()) - .collect::>(); - - let n = 30; - let mut to_delete = IndexMap::::new(); - let mut to_remain = IndexMap::::new(); - for factor_source_id in factor_source_ids.clone() { - let fsid = factor_source_id; - let instances = (0..n) - .map(|i| { - let fi = HierarchicalDeterministicFactorInstance::mainnet_tx( - CAP26EntityKind::Account, - HDPathComponent::unsecurified_hardening_base_index(i), - fsid, - ); - if i < 10 { - to_delete.append_or_insert_to(&fsid, IndexSet::just(fi.clone())); - } else { - to_remain.append_or_insert_to(&fsid, IndexSet::just(fi.clone())); - } - fi - }) - .collect::>(); - - sut.insert_for_factor(&fsid, &FactorInstances::from(instances)) - .unwrap(); - } - - sut.delete(&to_delete); - - let path = &IndexAgnosticPath::new( - NetworkID::Mainnet, - CAP26EntityKind::Account, - CAP26KeyKind::TransactionSigning, - KeySpace::Unsecurified, - ); - for (f, instances) in to_remain { - assert_eq!(sut.get_mono_factor(f, path).unwrap(), instances) - } - } - - #[test] - fn throws_if_same_is_added() { - let mut sut = Sut::default(); - let fsid = FactorSourceIDFromHash::fs0(); - let fi0 = HierarchicalDeterministicFactorInstance::mainnet_tx( - CAP26EntityKind::Account, - HDPathComponent::unsecurified_hardening_base_index(0), - fsid, - ); - let fi1 = HierarchicalDeterministicFactorInstance::mainnet_tx( - CAP26EntityKind::Account, - HDPathComponent::unsecurified_hardening_base_index(1), - fsid, - ); - assert!(!sut - .insert_for_factor(&fsid, &FactorInstances::from_iter([fi0.clone(), fi1])) - .unwrap()); - - assert_eq!( - sut.insert_for_factor(&fsid, &FactorInstances::from_iter([fi0.clone()])) - .err() - .unwrap(), - CommonError::CacheAlreadyContainsFactorInstance { - derivation_path: fi0.derivation_path() - } - ); - } -} diff --git a/src/factor_instances_provider/provider/factor_instances_provider.rs b/src/factor_instances_provider/provider/factor_instances_provider.rs deleted file mode 100644 index 21cea2ba..00000000 --- a/src/factor_instances_provider/provider/factor_instances_provider.rs +++ /dev/null @@ -1,321 +0,0 @@ -use std::sync::{Arc, RwLock}; - -use itertools::cloned; - -use crate::{factor_instances_provider::next_index_assigner, prelude::*}; - -/// A coordinator between a cache, an optional profile and the KeysCollector. -/// -/// We can ask this type to provide FactorInstances for some operation, either -/// creation of new virtual accounts or securifying accounts (or analogously for identities). -/// It will try to read instances from the cache, if any, and if there are not enough instances -/// in the cache, it will derive more instances and save them into the cache. -/// -/// We are always reading from the beginning of each FactorInstance collection in the cache, -/// and we are always appending to the end. -/// -/// Whenever we need to derive more, we always derive for all `IndexAgnosticPath` "presets", -/// i.e. we are not only filling the cache with factor instances relevant to the operation -/// but rather we are filling the cache with factor instances for all kinds of operations, i.e. -/// if we did not have `CACHE_FILLING_QUANTITY` instances for "account_mfa", when we tried -/// to read "account_veci" instances, we will derive more "account_mfa" instances as well, -/// so many that at the end of execution we will have `CACHE_FILLING_QUANTITY` instances for -/// both "account_veci" and "account_mfa" (and same for identities). -pub struct FactorInstancesProvider<'a> { - network_id: NetworkID, - factor_sources: IndexSet, - profile: Option, - cache: &'a mut FactorInstancesCache, - interactors: Arc, -} - -/// =============== -/// PUBLIC -/// =============== -impl<'a> FactorInstancesProvider<'a> { - pub fn new( - network_id: NetworkID, - factor_sources: IndexSet, - profile: impl Into>, - cache: &'a mut FactorInstancesCache, - interactors: Arc, - ) -> Self { - Self { - network_id, - factor_sources, - profile: profile.into(), - cache, - interactors, - } - } - - pub async fn provide( - self, - quantified_derivation_preset: QuantifiedDerivationPreset, - ) -> Result { - let mut _self = self; - - _self._provide(quantified_derivation_preset).await - } -} - -/// Uses a `FactorInstancesProvider` to fill the cache with instances for a new FactorSource. -pub struct CacheFiller; -impl CacheFiller { - /// Uses a `FactorInstancesProvider` to fill the `cache` with FactorInstances for a new FactorSource. - /// Saves FactorInstances into the mutable `cache` parameter and returns a - /// copy of the instances. - pub async fn for_new_factor_source( - cache: &mut FactorInstancesCache, - profile: Option, - factor_source: HDFactorSource, - network_id: NetworkID, // typically mainnet - interactors: Arc, - ) -> Result { - let provider = FactorInstancesProvider::new( - network_id, - IndexSet::just(factor_source.clone()), - profile, - cache, - interactors, - ); - let quantities = IndexMap::kv( - factor_source.factor_source_id(), - DerivationPreset::all() - .into_iter() - .map(|dp| (dp, CACHE_FILLING_QUANTITY)) - .collect::>(), - ); - let derived = provider.derive_more(quantities).await?; - - cache.insert(&derived); - - let derived = derived - .get(&factor_source.factor_source_id()) - .unwrap() - .clone(); - let outcome = InternalFactorInstancesProviderOutcomeForFactor::new( - factor_source.factor_source_id(), - derived.clone(), - FactorInstances::default(), - FactorInstances::default(), - derived, - ); - Ok(outcome.into()) - } -} - -/// =============== -/// Private -/// =============== -impl<'a> FactorInstancesProvider<'a> { - async fn _provide( - &mut self, - quantified_derivation_preset: QuantifiedDerivationPreset, - ) -> Result { - let factor_sources = self.factor_sources.clone(); - let network_id = self.network_id; - let cached = self.cache.get_poly_factor_with_quantities( - &factor_sources - .iter() - .map(|f| f.factor_source_id()) - .collect(), - &quantified_derivation_preset, - network_id, - )?; - - match cached { - CachedInstancesWithQuantitiesOutcome::Satisfied(enough_instances) => { - // Remove the instances which are going to be used from the cache - // since we only peeked at them. - self.cache.delete(&enough_instances); - Ok(InternalFactorInstancesProviderOutcome::satisfied_by_cache( - enough_instances, - )) - } - CachedInstancesWithQuantitiesOutcome::NotSatisfied { - quantities_to_derive, - partial_instances, - } => { - self.derive_more_and_cache( - quantified_derivation_preset, - partial_instances, - quantities_to_derive, - ) - .await - } - } - } - - async fn derive_more_and_cache( - &mut self, - quantified_derivation_preset: QuantifiedDerivationPreset, - pf_found_in_cache_leq_requested: IndexMap, - pf_pdp_qty_to_derive: IndexMap>, - ) -> Result { - let pf_newly_derived = self.derive_more(pf_pdp_qty_to_derive).await?; - - let Split { - pf_to_use_directly, - pf_to_cache, - } = self.split( - &quantified_derivation_preset, - &pf_found_in_cache_leq_requested, - &pf_newly_derived, - ); - - self.cache.delete(&pf_found_in_cache_leq_requested); - self.cache.insert(&pf_to_cache); - - let outcome = InternalFactorInstancesProviderOutcome::transpose( - pf_to_cache, - pf_to_use_directly, - pf_found_in_cache_leq_requested, - pf_newly_derived, - ); - let outcome = outcome; - Ok(outcome) - } - - /// Per factor, split the instances into those to use directly and those to cache. - /// based on the originally requested quantity. - fn split( - &self, - originally_requested_quantified_derivation_preset: &QuantifiedDerivationPreset, - pf_found_in_cache_leq_requested: &IndexMap, - pf_newly_derived: &IndexMap, - ) -> Split { - // Start by merging the instances found in cache and the newly derived instances, - // into a single collection of instances per factor source, with the - // instances from cache first in the list (per factor), and then the newly derived. - // this is important so that we consume the instances from cache first. - let pf_derived_appended_to_from_cache = self - .factor_sources - .clone() - .into_iter() - .map(|f| f.factor_source_id()) - .map(|factor_source_id| { - let mut merged = IndexSet::new(); - let from_cache = pf_found_in_cache_leq_requested - .get(&factor_source_id) - .cloned() - .unwrap_or_default(); - let newly_derived = pf_newly_derived - .get(&factor_source_id) - .cloned() - .unwrap_or_default(); - // IMPORTANT: Must put instances from cache **first**... - merged.extend(from_cache); - // ... and THEN the newly derived, so we consume the ones with - // lower index from cache first. - merged.extend(newly_derived); - - (factor_source_id, FactorInstances::from(merged)) - }) - .collect::>(); - - let mut pf_to_use_directly = IndexMap::new(); - let mut pf_to_cache = IndexMap::::new(); - let quantity_originally_requested = - originally_requested_quantified_derivation_preset.quantity; - let preset_originally_requested = - originally_requested_quantified_derivation_preset.derivation_preset; - - // Using the merged map, split the instances into those to use directly and those to cache. - for (factor_source_id, instances) in pf_derived_appended_to_from_cache.clone().into_iter() { - let mut instances_by_derivation_preset = InstancesByDerivationPreset::from(instances); - - if let Some(instances_relevant_to_use_directly_with_abundance) = - instances_by_derivation_preset.remove(preset_originally_requested) - { - let (to_use_directly, to_cache) = instances_relevant_to_use_directly_with_abundance - .split_at(quantity_originally_requested); - pf_to_use_directly.insert(factor_source_id, to_use_directly); - pf_to_cache.insert(factor_source_id, to_cache); - } - - pf_to_cache.append_or_insert_to( - factor_source_id, - instances_by_derivation_preset.all_instances(), - ); - } - - Split { - pf_to_use_directly, - pf_to_cache, - } - } - - async fn derive_more( - &self, - pf_pdp_quantity_to_derive: IndexMap< - FactorSourceIDFromHash, - IndexMap, - >, - ) -> Result> { - let factor_sources = self.factor_sources.clone(); - let network_id = self.network_id; - - let next_index_assigner = NextDerivationEntityIndexAssigner::new( - network_id, - self.profile.clone(), - self.cache.clone(), - ); - - let pf_paths = pf_pdp_quantity_to_derive - .into_iter() - .map(|(factor_source_id, pdp_quantity_to_derive)| { - let paths = pdp_quantity_to_derive - .into_iter() - .map(|(derivation_preset, qty)| { - // `qty` many paths - let paths = (0..qty) - .map(|_| { - let index_agnostic_path = - derivation_preset.index_agnostic_path_on_network(network_id); - let index = next_index_assigner - .next(factor_source_id, index_agnostic_path)?; - Ok(DerivationPath::from((index_agnostic_path, index))) - }) - .collect::>>()?; - - Ok(paths) - }) - .collect::>>>()?; - - // flatten (I was unable to use `flat_map` above combined with `Result`...) - let paths = paths.into_iter().flatten().collect::>(); - - Ok((factor_source_id, paths)) - }) - .collect::>>>()?; - - let keys_collector = - KeysCollector::new(factor_sources, pf_paths.clone(), self.interactors.clone())?; - - let pf_derived = keys_collector.collect_keys().await.factors_by_source; - - let mut pf_instances = IndexMap::::new(); - - for (factor_source_id, paths) in pf_paths { - let derived_for_factor = pf_derived - .get(&factor_source_id) - .cloned() - .unwrap_or_default(); // if None -> Empty -> fail below. - if derived_for_factor.len() < paths.len() { - return Err(CommonError::FactorInstancesProviderDidNotDeriveEnoughFactors); - } - pf_instances.insert( - factor_source_id, - derived_for_factor.into_iter().collect::(), - ); - } - - Ok(pf_instances) - } -} - -struct Split { - pf_to_use_directly: IndexMap, - pf_to_cache: IndexMap, -} diff --git a/src/factor_instances_provider/provider/factor_instances_provider_unit_tests.rs b/src/factor_instances_provider/provider/factor_instances_provider_unit_tests.rs deleted file mode 100644 index 31625fcf..00000000 --- a/src/factor_instances_provider/provider/factor_instances_provider_unit_tests.rs +++ /dev/null @@ -1,1644 +0,0 @@ -#![cfg(test)] - -use std::ops::{Add, AddAssign}; - -use crate::{factor_instances_provider::provider::test_sargon_os::SargonOS, prelude::*}; - -#[actix_rt::test] -async fn create_accounts_when_last_is_used_cache_is_fill_only_with_account_vecis_and_if_profile_is_used_a_new_account_is_created( -) { - let (mut os, bdfs) = SargonOS::with_bdfs().await; - for i in 0..CACHE_FILLING_QUANTITY { - let name = format!("Acco {}", i); - let (acco, stats) = os - .new_mainnet_account_with_bdfs(name.clone()) - .await - .unwrap(); - assert_eq!(acco.name, name); - assert_eq!(stats.debug_was_cached.len(), 0); - assert_eq!(stats.debug_was_derived.len(), 0); - } - assert_eq!( - os.profile_snapshot().get_accounts().len(), - CACHE_FILLING_QUANTITY - ); - - let (acco, stats) = os - .new_mainnet_account_with_bdfs("newly derive") - .await - .unwrap(); - - assert_eq!( - os.profile_snapshot().get_accounts().len(), - CACHE_FILLING_QUANTITY + 1 - ); - - assert_eq!(stats.debug_was_cached.len(), CACHE_FILLING_QUANTITY); - assert_eq!(stats.debug_was_derived.len(), CACHE_FILLING_QUANTITY + 1); - - assert_eq!( - acco.as_unsecurified() - .unwrap() - .factor_instance() - .derivation_entity_index(), - HDPathComponent::unsecurified_hardening_base_index(30) - ); - assert!(os - .cache_snapshot() - .is_full(NetworkID::Mainnet, bdfs.factor_source_id())); - - // and another one - let (acco, stats) = os - .new_mainnet_account_with_bdfs("newly derive 2") - .await - .unwrap(); - - assert_eq!( - os.profile_snapshot().get_accounts().len(), - CACHE_FILLING_QUANTITY + 2 - ); - - assert_eq!(stats.debug_was_cached.len(), 0); - assert_eq!(stats.debug_was_derived.len(), 0); - - assert_eq!( - acco.as_unsecurified() - .unwrap() - .factor_instance() - .derivation_entity_index(), - HDPathComponent::unsecurified_hardening_base_index(31) - ); - assert!( - !os.cache_snapshot() - .is_full(NetworkID::Mainnet, bdfs.factor_source_id()), - "just consumed one, so not full" - ); -} - -#[actix_rt::test] -async fn add_factor_source() { - let mut os = SargonOS::new(); - assert_eq!(os.cache_snapshot().total_number_of_factor_instances(), 0); - assert_eq!(os.profile_snapshot().factor_sources.len(), 0); - let factor_source = HDFactorSource::sample(); - os.add_factor_source(factor_source.clone()).await.unwrap(); - assert!( - os.cache_snapshot() - .is_full(NetworkID::Mainnet, factor_source.factor_source_id()), - "Should have put factors into the cache." - ); - assert_eq!( - os.profile_snapshot().factor_sources, - IndexSet::just(factor_source) - ); -} - -#[actix_rt::test] -async fn adding_accounts_and_clearing_cache_in_between() { - let (mut os, _) = SargonOS::with_bdfs().await; - assert!(os.profile_snapshot().get_accounts().is_empty()); - let (alice, stats) = os.new_mainnet_account_with_bdfs("alice").await.unwrap(); - assert!(!stats.debug_found_in_cache.is_empty()); - assert!(stats.debug_was_cached.is_empty()); - assert!(stats.debug_was_derived.is_empty()); - os.clear_cache(); - - let (bob, stats) = os.new_mainnet_account_with_bdfs("bob").await.unwrap(); - assert!(stats.debug_found_in_cache.is_empty()); - assert!(!stats.debug_was_cached.is_empty()); - assert!(!stats.debug_was_derived.is_empty()); - assert_ne!(alice, bob); - - assert_eq!(os.profile_snapshot().get_accounts().len(), 2); -} - -#[actix_rt::test] -async fn adding_personas_and_clearing_cache_in_between() { - let (mut os, _) = SargonOS::with_bdfs().await; - assert!(os.profile_snapshot().get_personas().is_empty()); - let (batman, stats) = os.new_mainnet_persona_with_bdfs("Batman").await.unwrap(); - - assert_eq!( - batman - .clone() - .security_state - .into_unsecured() - .unwrap() - .derivation_path() - .entity_kind, - CAP26EntityKind::Identity - ); - assert!(!stats.debug_found_in_cache.is_empty()); - assert!(stats.debug_was_cached.is_empty()); - assert!(stats.debug_was_derived.is_empty()); - os.clear_cache(); - - let (satoshi, stats) = os.new_mainnet_persona_with_bdfs("Satoshi").await.unwrap(); - assert!(stats.debug_found_in_cache.is_empty()); - assert!(!stats.debug_was_cached.is_empty()); - assert!(!stats.debug_was_derived.is_empty()); - assert_ne!(batman, satoshi); - - assert_eq!(os.profile_snapshot().get_personas().len(), 2); -} - -#[actix_rt::test] -async fn add_account_and_personas_mixed() { - let (mut os, _) = SargonOS::with_bdfs().await; - assert!(os.profile_snapshot().get_personas().is_empty()); - assert!(os.profile_snapshot().get_accounts().is_empty()); - - let (batman, stats) = os.new_mainnet_persona_with_bdfs("Batman").await.unwrap(); - assert!(stats.debug_was_derived.is_empty()); - - let (alice, stats) = os.new_mainnet_account_with_bdfs("alice").await.unwrap(); - assert!(stats.debug_was_derived.is_empty()); - - let (satoshi, stats) = os.new_mainnet_persona_with_bdfs("Satoshi").await.unwrap(); - assert!(stats.debug_was_derived.is_empty()); - - assert_ne!(batman.entity_address(), satoshi.entity_address()); - - let (bob, stats) = os.new_mainnet_account_with_bdfs("bob").await.unwrap(); - assert!(stats.debug_was_derived.is_empty()); - assert_ne!(alice.entity_address(), bob.entity_address()); - - assert_eq!(os.profile_snapshot().get_personas().len(), 2); - assert_eq!(os.profile_snapshot().get_accounts().len(), 2); -} - -#[actix_rt::test] -async fn adding_accounts_different_networks_different_factor_sources() { - let mut os = SargonOS::new(); - assert_eq!(os.cache_snapshot().total_number_of_factor_instances(), 0); - - let fs_device = HDFactorSource::device(); - let fs_arculus = HDFactorSource::arculus(); - let fs_ledger = HDFactorSource::ledger(); - - os.add_factor_source(fs_device.clone()).await.unwrap(); - os.add_factor_source(fs_arculus.clone()).await.unwrap(); - os.add_factor_source(fs_ledger.clone()).await.unwrap(); - - assert_eq!( - os.cache_snapshot().total_number_of_factor_instances(), - 3 * 4 * CACHE_FILLING_QUANTITY - ); - - assert!(os.profile_snapshot().get_accounts().is_empty()); - assert_eq!(os.profile_snapshot().factor_sources.len(), 3); - - let (alice, stats) = os - .new_account(fs_device.clone(), NetworkID::Mainnet, "Alice") - .await - .unwrap(); - assert!(stats.debug_was_derived.is_empty()); - - let (bob, stats) = os - .new_account(fs_device.clone(), NetworkID::Mainnet, "Bob") - .await - .unwrap(); - assert!(stats.debug_was_derived.is_empty()); - - let (carol, stats) = os - .new_account(fs_device.clone(), NetworkID::Stokenet, "Carol") - .await - .unwrap(); - assert!( - !stats.debug_was_derived.is_empty(), - "Should have derived more, since first time Stokenet is used!" - ); - - let (diana, stats) = os - .new_account(fs_device.clone(), NetworkID::Stokenet, "Diana") - .await - .unwrap(); - assert!(stats.debug_was_derived.is_empty()); - - let (erin, stats) = os - .new_account(fs_arculus.clone(), NetworkID::Mainnet, "Erin") - .await - .unwrap(); - assert!(stats.debug_was_derived.is_empty()); - - let (frank, stats) = os - .new_account(fs_arculus.clone(), NetworkID::Mainnet, "Frank") - .await - .unwrap(); - assert!(stats.debug_was_derived.is_empty()); - - let (grace, stats) = os - .new_account(fs_arculus.clone(), NetworkID::Stokenet, "Grace") - .await - .unwrap(); - assert!( - !stats.debug_was_derived.is_empty(), - "Should have derived more, since first time Stokenet is used with the Arculus!" - ); - - let (helena, stats) = os - .new_account(fs_arculus.clone(), NetworkID::Stokenet, "Helena") - .await - .unwrap(); - assert!(stats.debug_was_derived.is_empty()); - - let (isabel, stats) = os - .new_account(fs_ledger.clone(), NetworkID::Mainnet, "isabel") - .await - .unwrap(); - assert!(stats.debug_was_derived.is_empty()); - - let (jenny, stats) = os - .new_account(fs_ledger.clone(), NetworkID::Mainnet, "Jenny") - .await - .unwrap(); - assert!(stats.debug_was_derived.is_empty()); - - let (klara, stats) = os - .new_account(fs_ledger.clone(), NetworkID::Stokenet, "Klara") - .await - .unwrap(); - assert!( - !stats.debug_was_derived.is_empty(), - "Should have derived more, since first time Stokenet is used with the Ledger!" - ); - - let (lisa, stats) = os - .new_account(fs_ledger.clone(), NetworkID::Stokenet, "Lisa") - .await - .unwrap(); - assert!(stats.debug_was_derived.is_empty()); - - assert_eq!(os.profile_snapshot().get_accounts().len(), 12); - - let accounts = vec![ - alice, bob, carol, diana, erin, frank, grace, helena, isabel, jenny, klara, lisa, - ]; - - let factor_source_count = os.profile_snapshot().factor_sources.len(); - let network_count = os.profile_snapshot().networks.len(); - assert_eq!( - os.cache_snapshot().total_number_of_factor_instances(), - network_count - * factor_source_count - * DerivationPreset::all().len() - * CACHE_FILLING_QUANTITY - - accounts.len() - + factor_source_count // we do `+ factor_source_count` since every time a factor source is used on a new network for the first time, we derive `CACHE_FILLING_QUANTITY + 1` - ); - - assert_eq!( - os.profile_snapshot() - .get_accounts() - .into_iter() - .map(|a| a.entity_address()) - .collect::>(), - accounts - .into_iter() - .map(|a| a.entity_address()) - .collect::>() - ); -} - -#[actix_rt::test] -async fn test_securified_accounts() { - let (mut os, bdfs) = SargonOS::with_bdfs().await; - let alice = os - .new_account_with_bdfs(NetworkID::Mainnet, "Alice") - .await - .unwrap() - .0; - - let bob = os - .new_account_with_bdfs(NetworkID::Mainnet, "Bob") - .await - .unwrap() - .0; - assert_ne!(alice.address(), bob.address()); - let ledger = HDFactorSource::ledger(); - let arculus = HDFactorSource::arculus(); - let yubikey = HDFactorSource::yubikey(); - os.add_factor_source(ledger.clone()).await.unwrap(); - os.add_factor_source(arculus.clone()).await.unwrap(); - os.add_factor_source(yubikey.clone()).await.unwrap(); - let shield_0 = - MatrixOfFactorSources::new([bdfs.clone(), ledger.clone(), arculus.clone()], 2, []); - - let (securified_accounts, stats) = os - .securify_accounts( - IndexSet::from_iter([alice.entity_address(), bob.entity_address()]), - shield_0, - ) - .await - .unwrap(); - - assert!( - !stats.derived_any_new_instance_for_any_factor_source(), - "should have used cache" - ); - - let alice_sec = securified_accounts - .clone() - .into_iter() - .find(|x| x.address() == alice.entity_address()) - .unwrap(); - - assert_eq!( - alice_sec.securified_entity_control().veci.unwrap().clone(), - alice.as_unsecurified().unwrap().veci() - ); - let alice_matrix = alice_sec.securified_entity_control().matrix.clone(); - assert_eq!(alice_matrix.threshold, 2); - - assert_eq!( - alice_matrix - .all_factors() - .into_iter() - .map(|f| f.factor_source_id()) - .collect_vec(), - [ - bdfs.factor_source_id(), - ledger.factor_source_id(), - arculus.factor_source_id() - ] - ); - - assert_eq!( - alice_matrix - .all_factors() - .into_iter() - .map(|f| f.derivation_entity_index()) - .collect_vec(), - [ - HDPathComponent::securifying_base_index(0), - HDPathComponent::securifying_base_index(0), - HDPathComponent::securifying_base_index(0) - ] - ); - - // assert bob - - let bob_sec = securified_accounts - .clone() - .into_iter() - .find(|x| x.address() == bob.entity_address()) - .unwrap(); - - assert_eq!( - bob_sec.securified_entity_control().veci.unwrap().clone(), - bob.as_unsecurified().unwrap().veci() - ); - let bob_matrix = bob_sec.securified_entity_control().matrix.clone(); - assert_eq!(bob_matrix.threshold, 2); - - assert_eq!( - bob_matrix - .all_factors() - .into_iter() - .map(|f| f.factor_source_id()) - .collect_vec(), - [ - bdfs.factor_source_id(), - ledger.factor_source_id(), - arculus.factor_source_id() - ] - ); - - assert_eq!( - bob_matrix - .all_factors() - .into_iter() - .map(|f| f.derivation_entity_index()) - .collect_vec(), - [ - HDPathComponent::securifying_base_index(1), - HDPathComponent::securifying_base_index(1), - HDPathComponent::securifying_base_index(1) - ] - ); - - let carol = os - .new_account(ledger.clone(), NetworkID::Mainnet, "Carol") - .await - .unwrap() - .0; - - assert_eq!( - carol - .as_unsecurified() - .unwrap() - .veci() - .factor_instance() - .derivation_entity_index() - .base_index(), - 0, - "First account created with ledger, should have index 0, even though this ledger was used in the shield, since we are using two different KeySpaces for Securified and Unsecurified accounts." - ); - - let (securified_accounts, stats) = os - .securify_accounts( - IndexSet::just(carol.entity_address()), - MatrixOfFactorSources::new([], 0, [yubikey.clone()]), - ) - .await - .unwrap(); - assert!( - !stats.derived_any_new_instance_for_any_factor_source(), - "should have used cache" - ); - let carol_sec = securified_accounts - .clone() - .into_iter() - .find(|x| x.address() == carol.entity_address()) - .unwrap(); - - let carol_matrix = carol_sec.securified_entity_control().matrix.clone(); - - assert_eq!( - carol_matrix - .all_factors() - .into_iter() - .map(|f| f.factor_source_id()) - .collect_vec(), - [yubikey.factor_source_id()] - ); - - assert_eq!( - carol_matrix - .all_factors() - .into_iter() - .map(|f| f.derivation_entity_index()) - .collect_vec(), - [HDPathComponent::securifying_base_index(0)] - ); - - // Update Alice's shield to only use YubiKey - - let (securified_accounts, stats) = os - .securify_accounts( - IndexSet::from_iter([alice.entity_address(), bob.entity_address()]), - MatrixOfFactorSources::new([], 0, [yubikey.clone()]), - ) - .await - .unwrap(); - assert!( - !stats.derived_any_new_instance_for_any_factor_source(), - "should have used cache" - ); - let alice_sec = securified_accounts - .clone() - .into_iter() - .find(|x| x.address() == alice.entity_address()) - .unwrap(); - - let alice_matrix = alice_sec.securified_entity_control().matrix.clone(); - - assert_eq!( - alice_matrix - .all_factors() - .into_iter() - .map(|f| f.derivation_entity_index()) - .collect_vec(), - [ - HDPathComponent::securifying_base_index(1) // Carol used `0`. - ] - ); -} - -#[actix_rt::test] -async fn cache_is_unchanged_in_case_of_failure() { - let (mut os, bdfs) = SargonOS::with_bdfs().await; - - let factor_sources = os.profile_snapshot().factor_sources.clone(); - assert_eq!( - factor_sources.clone().into_iter().collect_vec(), - vec![bdfs.clone(),] - ); - - let n = CACHE_FILLING_QUANTITY / 2; - - for i in 0..3 * n { - let _ = os - .new_mainnet_account_with_bdfs(format!("Acco: {}", i)) - .await - .unwrap(); - } - - let shield_0 = MatrixOfFactorSources::new([bdfs.clone()], 1, []); - - let all_accounts = os - .profile_snapshot() - .get_accounts() - .into_iter() - .collect_vec(); - - let first_half_of_accounts = all_accounts.clone()[0..n] - .iter() - .cloned() - .collect::>(); - - let second_half_of_accounts = all_accounts.clone()[n..3 * n] - .iter() - .cloned() - .collect::>(); - - assert_eq!( - first_half_of_accounts.len() + second_half_of_accounts.len(), - 3 * n - ); - - let (first_half_securified_accounts, stats) = os - .securify_accounts( - first_half_of_accounts - .clone() - .into_iter() - .map(|a| a.entity_address()) - .collect(), - shield_0.clone(), - ) - .await - .unwrap(); - - assert!( - !stats.derived_any_new_instance_for_any_factor_source(), - "should have used cache" - ); - - assert_eq!( - first_half_securified_accounts - .into_iter() - .map(|a| a - .securified_entity_control() - .primary_role_instances() - .into_iter() - .map(|f| f.derivation_entity_index()) - .next() - .unwrap()) // single factor per role text - .collect_vec(), - (0..CACHE_FILLING_QUANTITY / 2) - .map(|i| HDPathComponent::securifying_base_index(i as u32)) - .collect_vec() - ); - - let cache_before_fail = os.cache_snapshot(); - let fail_interactor = Arc::new(TestDerivationInteractors::fail()); // <--- FAIL - - let res = os - .securify_accounts_with_interactor( - fail_interactor, - second_half_of_accounts - .clone() - .into_iter() - .map(|a| a.entity_address()) - .collect(), - shield_0, - ) - .await; - - assert!(res.is_err()); - assert_eq!( - os.cache_snapshot(), - cache_before_fail, - "Cache should not have changed when failing." - ); -} - -#[actix_rt::test] -async fn securify_accounts_when_cache_is_half_full_single_factor_source() { - let (mut os, bdfs) = SargonOS::with_bdfs().await; - - let factor_sources = os.profile_snapshot().factor_sources.clone(); - assert_eq!( - factor_sources.clone().into_iter().collect_vec(), - vec![bdfs.clone(),] - ); - - let n = CACHE_FILLING_QUANTITY / 2; - - for i in 0..3 * n { - let _ = os - .new_mainnet_account_with_bdfs(format!("Acco: {}", i)) - .await - .unwrap(); - } - - let shield_0 = MatrixOfFactorSources::new([bdfs.clone()], 1, []); - - let all_accounts = os - .profile_snapshot() - .get_accounts() - .into_iter() - .collect_vec(); - - let first_half_of_accounts = all_accounts.clone()[0..n] - .iter() - .cloned() - .collect::>(); - - let second_half_of_accounts = all_accounts.clone()[n..3 * n] - .iter() - .cloned() - .collect::>(); - - assert_eq!( - first_half_of_accounts.len() + second_half_of_accounts.len(), - 3 * n - ); - - let (first_half_securified_accounts, stats) = os - .securify_accounts( - first_half_of_accounts - .clone() - .into_iter() - .map(|a| a.entity_address()) - .collect(), - shield_0.clone(), - ) - .await - .unwrap(); - - assert!( - !stats.derived_any_new_instance_for_any_factor_source(), - "should have used cache" - ); - - assert_eq!( - first_half_securified_accounts - .into_iter() - .map(|a| a - .securified_entity_control() - .primary_role_instances() - .into_iter() - .map(|f| f.derivation_entity_index()) - .next() - .unwrap()) // single factor per role text - .collect_vec(), - (0..CACHE_FILLING_QUANTITY / 2) - .map(|i| HDPathComponent::securifying_base_index(i as u32)) - .collect_vec() - ); - - let (second_half_securified_accounts, stats) = os - .securify_accounts( - second_half_of_accounts - .clone() - .into_iter() - .map(|a| a.entity_address()) - .collect(), - shield_0, - ) - .await - .unwrap(); - - assert!( - stats.derived_any_new_instance_for_any_factor_source(), - "should have derived more" - ); - - assert_eq!( - second_half_securified_accounts - .into_iter() - .map(|a| a - .securified_entity_control() - .primary_role_instances() - .into_iter() - .map(|f| f.derivation_entity_index()) - .next() - .unwrap()) // single factor per role text - .collect_vec(), - (CACHE_FILLING_QUANTITY / 2..(CACHE_FILLING_QUANTITY / 2 + CACHE_FILLING_QUANTITY)) - .map(|i| HDPathComponent::securifying_base_index(i as u32)) - .collect_vec() - ); -} - -#[actix_rt::test] -async fn securify_accounts_when_cache_is_half_full_multiple_factor_sources() { - let (mut os, bdfs) = SargonOS::with_bdfs().await; - - let ledger = HDFactorSource::ledger(); - let arculus = HDFactorSource::arculus(); - let yubikey = HDFactorSource::yubikey(); - os.add_factor_source(ledger.clone()).await.unwrap(); - os.add_factor_source(arculus.clone()).await.unwrap(); - os.add_factor_source(yubikey.clone()).await.unwrap(); - - let factor_sources = os.profile_snapshot().factor_sources.clone(); - assert_eq!( - factor_sources.clone().into_iter().collect_vec(), - vec![ - bdfs.clone(), - ledger.clone(), - arculus.clone(), - yubikey.clone(), - ] - ); - - let n = CACHE_FILLING_QUANTITY / 2; - - for i in 0..3 * n { - let (_account, _stats) = os - .new_mainnet_account_with_bdfs(format!("Acco: {}", i)) - .await - .unwrap(); - } - - let shield_0 = - MatrixOfFactorSources::new([bdfs.clone(), ledger.clone(), arculus.clone()], 2, []); - - let all_accounts = os - .profile_snapshot() - .get_accounts() - .into_iter() - .collect_vec(); - - let first_half_of_accounts = all_accounts.clone()[0..n] - .iter() - .cloned() - .collect::>(); - - let second_half_of_accounts = all_accounts.clone()[n..3 * n] - .iter() - .cloned() - .collect::>(); - - assert_eq!( - first_half_of_accounts.len() + second_half_of_accounts.len(), - 3 * n - ); - - let (first_half_securified_accounts, stats) = os - .securify_accounts( - first_half_of_accounts - .clone() - .into_iter() - .map(|a| a.entity_address()) - .collect(), - shield_0.clone(), - ) - .await - .unwrap(); - assert!( - !stats.derived_any_new_instance_for_any_factor_source(), - "should have used cache" - ); - - assert_eq!( - first_half_securified_accounts - .into_iter() - .map(|a| a - .securified_entity_control() - .primary_role_instances() - .into_iter() - .map(|f| f.derivation_entity_index()) - .map(|x| format!("{:?}", x)) - .collect_vec()) - .collect_vec(), - [ - ["0^", "0^", "0^"], - ["1^", "1^", "1^"], - ["2^", "2^", "2^"], - ["3^", "3^", "3^"], - ["4^", "4^", "4^"], - ["5^", "5^", "5^"], - ["6^", "6^", "6^"], - ["7^", "7^", "7^"], - ["8^", "8^", "8^"], - ["9^", "9^", "9^"], - ["10^", "10^", "10^"], - ["11^", "11^", "11^"], - ["12^", "12^", "12^"], - ["13^", "13^", "13^"], - ["14^", "14^", "14^"] - ] - ); - - let (second_half_securified_accounts, stats) = os - .securify_accounts( - second_half_of_accounts - .clone() - .into_iter() - .map(|a| a.entity_address()) - .collect(), - shield_0, - ) - .await - .unwrap(); - - assert!( - stats.derived_any_new_instance_for_any_factor_source(), - "should have derived more" - ); - - assert!( - stats.found_any_instances_in_cache_for_any_factor_source(), - "should have found some in cache" - ); - - assert_eq!( - second_half_securified_accounts - .into_iter() - .map(|a| a - .securified_entity_control() - .primary_role_instances() - .into_iter() - .map(|f| f.derivation_entity_index()) - .map(|x| format!("{:?}", x)) - .collect_vec()) - .collect_vec(), - [ - ["15^", "15^", "15^"], - ["16^", "16^", "16^"], - ["17^", "17^", "17^"], - ["18^", "18^", "18^"], - ["19^", "19^", "19^"], - ["20^", "20^", "20^"], - ["21^", "21^", "21^"], - ["22^", "22^", "22^"], - ["23^", "23^", "23^"], - ["24^", "24^", "24^"], - ["25^", "25^", "25^"], - ["26^", "26^", "26^"], - ["27^", "27^", "27^"], - ["28^", "28^", "28^"], - ["29^", "29^", "29^"], - ["30^", "30^", "30^"], - ["31^", "31^", "31^"], - ["32^", "32^", "32^"], - ["33^", "33^", "33^"], - ["34^", "34^", "34^"], - ["35^", "35^", "35^"], - ["36^", "36^", "36^"], - ["37^", "37^", "37^"], - ["38^", "38^", "38^"], - ["39^", "39^", "39^"], - ["40^", "40^", "40^"], - ["41^", "41^", "41^"], - ["42^", "42^", "42^"], - ["43^", "43^", "43^"], - ["44^", "44^", "44^"] - ] - ); -} - -#[actix_rt::test] -async fn securify_personas_when_cache_is_half_full_single_factor_source() { - let (mut os, bdfs) = SargonOS::with_bdfs().await; - - let factor_sources = os.profile_snapshot().factor_sources.clone(); - assert_eq!( - factor_sources.clone().into_iter().collect_vec(), - vec![bdfs.clone(),] - ); - - let n = CACHE_FILLING_QUANTITY / 2; - - for i in 0..3 * n { - let _ = os - .new_mainnet_persona_with_bdfs(format!("Persona: {}", i)) - .await - .unwrap(); - } - - let shield_0 = MatrixOfFactorSources::new([bdfs.clone()], 1, []); - - let all_personas = os - .profile_snapshot() - .get_personas() - .into_iter() - .collect_vec(); - - let first_half_of_personas = all_personas.clone()[0..n] - .iter() - .cloned() - .collect::>(); - - let second_half_of_personas = all_personas.clone()[n..3 * n] - .iter() - .cloned() - .collect::>(); - - assert_eq!( - first_half_of_personas.len() + second_half_of_personas.len(), - 3 * n - ); - - let (first_half_securified_personas, stats) = os - .securify_personas( - first_half_of_personas - .clone() - .into_iter() - .map(|a| a.entity_address()) - .collect(), - shield_0.clone(), - ) - .await - .unwrap(); - - assert!( - !stats.derived_any_new_instance_for_any_factor_source(), - "should have used cache" - ); - - assert_eq!( - first_half_securified_personas - .into_iter() - .map(|a| a - .securified_entity_control() - .primary_role_instances() - .into_iter() - .map(|f| f.derivation_entity_index()) - .map(|x| format!("{:?}", x)) - .next() - .unwrap()) // single factor per role text - .collect_vec(), - [ - "0^", "1^", "2^", "3^", "4^", "5^", "6^", "7^", "8^", "9^", "10^", "11^", "12^", "13^", - "14^" - ] - ); - - let (second_half_securified_personas, stats) = os - .securify_personas( - second_half_of_personas - .clone() - .into_iter() - .map(|a| a.entity_address()) - .collect(), - shield_0, - ) - .await - .unwrap(); - - assert!( - stats.derived_any_new_instance_for_any_factor_source(), - "should have derived more" - ); - - assert_eq!( - second_half_securified_personas - .into_iter() - .map(|a| a - .securified_entity_control() - .primary_role_instances() - .into_iter() - .map(|f| f.derivation_entity_index()) - .map(|x| format!("{:?}", x)) - .next() - .unwrap()) // single factor per role text - .collect_vec(), - [ - "15^", "16^", "17^", "18^", "19^", "20^", "21^", "22^", "23^", "24^", "25^", "26^", - "27^", "28^", "29^", "30^", "31^", "32^", "33^", "34^", "35^", "36^", "37^", "38^", - "39^", "40^", "41^", "42^", "43^", "44^" - ] - ); -} - -#[actix_rt::test] -async fn create_single_account() { - let (mut os, bdfs) = SargonOS::with_bdfs().await; - let (alice, stats) = os.new_mainnet_account_with_bdfs("alice").await.unwrap(); - assert!(stats.debug_was_derived.is_empty(), "should have used cache"); - let (sec_accounts, stats) = os - .securify_accounts( - IndexSet::just(alice.entity_address()), - MatrixOfFactorSources::new([], 0, [bdfs]), - ) - .await - .unwrap(); - assert!( - !stats.derived_any_new_instance_for_any_factor_source(), - "should have used cache" - ); - let alice_sec = sec_accounts.into_iter().next().unwrap(); - assert_eq!( - alice_sec - .securified_entity_control() - .primary_role_instances() - .first() - .unwrap() - .derivation_entity_index(), - HDPathComponent::securifying_base_index(0) - ); -} - -#[actix_rt::test] -async fn securified_personas() { - let (mut os, bdfs) = SargonOS::with_bdfs().await; - let batman = os - .new_persona_with_bdfs(NetworkID::Mainnet, "Batman") - .await - .unwrap() - .0; - - let satoshi = os - .new_persona_with_bdfs(NetworkID::Mainnet, "Satoshi") - .await - .unwrap() - .0; - assert_ne!(batman.address(), satoshi.address()); - let ledger = HDFactorSource::ledger(); - let arculus = HDFactorSource::arculus(); - let yubikey = HDFactorSource::yubikey(); - os.add_factor_source(ledger.clone()).await.unwrap(); - os.add_factor_source(arculus.clone()).await.unwrap(); - os.add_factor_source(yubikey.clone()).await.unwrap(); - let shield_0 = - MatrixOfFactorSources::new([bdfs.clone(), ledger.clone(), arculus.clone()], 2, []); - - let (securified_personas, stats) = os - .securify_personas( - IndexSet::from_iter([batman.entity_address(), satoshi.entity_address()]), - shield_0, - ) - .await - .unwrap(); - - assert!( - !stats.derived_any_new_instance_for_any_factor_source(), - "should have used cache" - ); - - let batman_sec = securified_personas - .clone() - .into_iter() - .find(|x| x.address() == batman.entity_address()) - .unwrap(); - - assert_eq!( - batman_sec.securified_entity_control().veci.unwrap().clone(), - batman.as_unsecurified().unwrap().veci() - ); - let batman_matrix = batman_sec.securified_entity_control().primary_role(); - assert_eq!(batman_matrix.threshold, 2); - - assert_eq!( - batman_matrix - .all_factors() - .into_iter() - .map(|f| f.factor_source_id()) - .collect_vec(), - [ - bdfs.factor_source_id(), - ledger.factor_source_id(), - arculus.factor_source_id() - ] - ); - - assert_eq!( - batman_matrix - .all_factors() - .into_iter() - .map(|f| f.derivation_entity_index()) - .collect_vec(), - [ - HDPathComponent::securifying_base_index(0), - HDPathComponent::securifying_base_index(0), - HDPathComponent::securifying_base_index(0) - ] - ); - - // assert satoshi - - let satoshi_sec = securified_personas - .clone() - .into_iter() - .find(|x| x.address() == satoshi.entity_address()) - .unwrap(); - - assert_eq!( - satoshi_sec - .securified_entity_control() - .veci - .unwrap() - .clone(), - satoshi.as_unsecurified().unwrap().veci() - ); - let satoshi_matrix = satoshi_sec.securified_entity_control().primary_role(); - assert_eq!(satoshi_matrix.threshold, 2); - - assert_eq!( - satoshi_matrix - .all_factors() - .into_iter() - .map(|f| f.factor_source_id()) - .collect_vec(), - [ - bdfs.factor_source_id(), - ledger.factor_source_id(), - arculus.factor_source_id() - ] - ); - - assert_eq!( - satoshi_matrix - .all_factors() - .into_iter() - .map(|f| f.derivation_entity_index()) - .collect_vec(), - [ - HDPathComponent::securifying_base_index(1), - HDPathComponent::securifying_base_index(1), - HDPathComponent::securifying_base_index(1) - ] - ); - - let hyde = os - .new_persona(ledger.clone(), NetworkID::Mainnet, "Mr Hyde") - .await - .unwrap() - .0; - - assert_eq!( - hyde - .as_unsecurified() - .unwrap() - .veci() - .factor_instance() - .derivation_entity_index() - .base_index(), - 0, - "First persona created with ledger, should have index 0, even though this ledger was used in the shield, since we are using two different KeySpaces for Securified and Unsecurified personas." - ); - - let (securified_personas, stats) = os - .securify_personas( - IndexSet::just(hyde.entity_address()), - MatrixOfFactorSources::new([], 0, [yubikey.clone()]), - ) - .await - .unwrap(); - assert!( - !stats.derived_any_new_instance_for_any_factor_source(), - "should have used cache" - ); - let hyde_sec = securified_personas - .clone() - .into_iter() - .find(|x| x.address() == hyde.entity_address()) - .unwrap(); - - let hyde_matrix = hyde_sec.securified_entity_control().primary_role(); - - assert_eq!( - hyde_matrix - .all_factors() - .into_iter() - .map(|f| f.factor_source_id()) - .collect_vec(), - [yubikey.factor_source_id()] - ); - - assert_eq!( - hyde_matrix - .all_factors() - .into_iter() - .map(|f| f.derivation_entity_index()) - .collect_vec(), - [HDPathComponent::securifying_base_index(0)] - ); - - // Update Batmans and Satoshis's shield to only use YubiKey - - let (securified_personas, stats) = os - .securify_personas( - IndexSet::from_iter([batman.entity_address(), satoshi.entity_address()]), - MatrixOfFactorSources::new([], 0, [yubikey.clone()]), - ) - .await - .unwrap(); - assert!( - !stats.derived_any_new_instance_for_any_factor_source(), - "should have used cache" - ); - let batman_sec = securified_personas - .clone() - .into_iter() - .find(|x| x.address() == batman.entity_address()) - .unwrap(); - - let batman_matrix = batman_sec.securified_entity_control().primary_role(); - - assert_eq!( - batman_matrix - .all_factors() - .into_iter() - .map(|f| f.derivation_entity_index()) - .collect_vec(), - [HDPathComponent::securifying_base_index(1)] - ); -} - -#[actix_rt::test] -async fn securified_all_accounts_next_veci_does_not_start_at_zero() { - let mut os = SargonOS::new(); - assert_eq!(os.cache_snapshot().total_number_of_factor_instances(), 0); - - let fs_device = HDFactorSource::device(); - let fs_arculus = HDFactorSource::arculus(); - let fs_ledger = HDFactorSource::ledger(); - - os.add_factor_source(fs_device.clone()).await.unwrap(); - os.add_factor_source(fs_arculus.clone()).await.unwrap(); - os.add_factor_source(fs_ledger.clone()).await.unwrap(); - - assert_eq!( - os.cache_snapshot().total_number_of_factor_instances(), - 3 * 4 * CACHE_FILLING_QUANTITY - ); - - assert!(os.profile_snapshot().get_accounts().is_empty()); - assert_eq!(os.profile_snapshot().factor_sources.len(), 3); - - let network = NetworkID::Mainnet; - - // first create CACHE_FILLING_QUANTITY many "unnamed" accounts - - for i in 0..CACHE_FILLING_QUANTITY { - let (_, stats) = os - .new_account(fs_device.clone(), network, format!("@{}", i)) - .await - .unwrap(); - assert!(stats.debug_was_derived.is_empty()); - } - - let unnamed_accounts = os - .profile_snapshot() - .get_accounts() - .into_iter() - .collect_vec(); - - let (_, stats) = os - .securify_accounts( - unnamed_accounts - .clone() - .into_iter() - .map(|a| a.entity_address()) - .collect(), - MatrixOfFactorSources::new([fs_device.clone()], 1, []), - ) - .await - .unwrap(); - - assert!( - !stats.derived_any_new_instance_for_any_factor_source(), - "should have used cache" - ); - - // assert correctness of next index assigner - assert_eq!( - os.profile_snapshot().accounts_on_network(network).len(), - CACHE_FILLING_QUANTITY - ); - - let next_index_profile_assigner = - NextDerivationEntityIndexProfileAnalyzingAssigner::new(network, os.profile_snapshot()); - let next_index = next_index_profile_assigner - .next( - fs_device.factor_source_id(), - DerivationPreset::AccountVeci.index_agnostic_path_on_network(network), - ) - .unwrap() - .unwrap(); - assert_eq!( - next_index, - HDPathComponent::unsecurified_hardening_base_index(30) - ); - - let (alice, stats) = os - .new_account(fs_device.clone(), network, "Alice") - .await - .unwrap(); - assert!( - stats.debug_found_in_cache.is_empty(), - "Cache should have been empty" - ); - assert!( - !stats.debug_was_derived.is_empty(), - "should have filled cache" - ); - - assert_eq!( - alice - .as_unsecurified() - .unwrap() - .veci() - .factor_instance() - .derivation_entity_index(), - HDPathComponent::unsecurified_hardening_base_index(30) // <-- IMPORTANT this tests that we do not start at 0', asserts that the next index from profile analyzer - ); - - // later when securified we want the next index in securified key space to be 30^ - let (securified_alice, stats) = os - .securify_account( - alice.entity_address(), - MatrixOfFactorSources::new([], 0, [fs_device.clone()]), - ) - .await - .unwrap(); - assert!(stats.found_any_instances_in_cache_for_any_factor_source()); - assert!(!stats.derived_any_new_instance_for_any_factor_source()); - - assert_eq!( - securified_alice - .securified_entity_control() - .primary_role_instances() - .into_iter() - .map(|f| (f.factor_source_id(), f.derivation_entity_index())) - .collect::>(), - [( - fs_device.factor_source_id(), - HDPathComponent::securifying_base_index(30) - )] - .into_iter() - .collect::>() - ); -} - -#[actix_rt::test] -async fn securified_accounts_asymmetric_indices() { - let mut os = SargonOS::new(); - assert_eq!(os.cache_snapshot().total_number_of_factor_instances(), 0); - - let fs_device = HDFactorSource::device(); - let fs_arculus = HDFactorSource::arculus(); - let fs_ledger = HDFactorSource::ledger(); - - os.add_factor_source(fs_device.clone()).await.unwrap(); - os.add_factor_source(fs_arculus.clone()).await.unwrap(); - os.add_factor_source(fs_ledger.clone()).await.unwrap(); - - assert_eq!( - os.cache_snapshot().total_number_of_factor_instances(), - 3 * 4 * CACHE_FILLING_QUANTITY - ); - - assert!(os.profile_snapshot().get_accounts().is_empty()); - assert_eq!(os.profile_snapshot().factor_sources.len(), 3); - - let network = NetworkID::Mainnet; - - // first create CACHE_FILLING_QUANTITY many "unnamed" accounts - - for i in 0..CACHE_FILLING_QUANTITY { - let (_, stats) = os - .new_account(fs_device.clone(), network, format!("@{}", i)) - .await - .unwrap(); - assert!(stats.debug_was_derived.is_empty()); - } - - let unnamed_accounts = os - .profile_snapshot() - .get_accounts() - .into_iter() - .collect_vec(); - - let (_, stats) = os - .securify_accounts( - unnamed_accounts - .clone() - .into_iter() - .map(|a| a.entity_address()) - .collect(), - MatrixOfFactorSources::new([fs_device.clone()], 1, []), - ) - .await - .unwrap(); - - assert!( - !stats.derived_any_new_instance_for_any_factor_source(), - "should have used cache" - ); - - let (alice, stats) = os - .new_account(fs_device.clone(), network, "Alice") - .await - .unwrap(); - assert!( - stats.debug_found_in_cache.is_empty(), - "Cache should have been empty" - ); - assert!( - !stats.debug_was_derived.is_empty(), - "should have filled cache" - ); - - let (bob, _) = os - .new_account(fs_device.clone(), network, "Bob") - .await - .unwrap(); - - let (carol, _) = os - .new_account(fs_device.clone(), network, "Carol") - .await - .unwrap(); - - let (diana, _) = os - .new_account(fs_device.clone(), network, "Diana") - .await - .unwrap(); - - assert_eq!( - diana - .as_unsecurified() - .unwrap() - .veci() - .factor_instance() - .derivation_entity_index(), - HDPathComponent::unsecurified_hardening_base_index(33) - ); - - let (securified_alice, stats) = os - .securify_account( - alice.entity_address(), - MatrixOfFactorSources::new([], 0, [fs_device.clone(), fs_arculus.clone()]), - ) - .await - .unwrap(); - assert!(stats.found_any_instances_in_cache_for_any_factor_source()); - assert!(!stats.derived_any_new_instance_for_any_factor_source()); - - assert_eq!( - securified_alice - .securified_entity_control() - .primary_role_instances() - .into_iter() - .map(|f| (f.factor_source_id(), f.derivation_entity_index())) - .collect::>(), - [ - ( - fs_device.factor_source_id(), - HDPathComponent::securifying_base_index(30) - ), - ( - fs_arculus.factor_source_id(), - HDPathComponent::securifying_base_index(0) - ), - ] - .into_iter() - .collect::>() - ); - - let (securified_bob, stats) = os - .securify_account( - bob.entity_address(), - MatrixOfFactorSources::new([], 0, [fs_device.clone(), fs_ledger.clone()]), - ) - .await - .unwrap(); - assert!(stats.found_any_instances_in_cache_for_any_factor_source()); - assert!(!stats.derived_any_new_instance_for_any_factor_source()); - - assert_eq!( - securified_bob - .securified_entity_control() - .primary_role_instances() - .into_iter() - .map(|f| (f.factor_source_id(), f.derivation_entity_index())) - .collect::>(), - [ - ( - fs_device.factor_source_id(), - HDPathComponent::securifying_base_index(31) - ), - ( - fs_ledger.factor_source_id(), - HDPathComponent::securifying_base_index(0) - ), - ] - .into_iter() - .collect::>() - ); - - let (securified_carol, stats) = os - .securify_account( - carol.entity_address(), - MatrixOfFactorSources::new([], 0, [fs_device.clone(), fs_arculus.clone()]), - ) - .await - .unwrap(); - assert!(stats.found_any_instances_in_cache_for_any_factor_source()); - assert!(!stats.derived_any_new_instance_for_any_factor_source()); - - assert_eq!( - securified_carol - .securified_entity_control() - .primary_role_instances() - .into_iter() - .map(|f| (f.factor_source_id(), f.derivation_entity_index())) - .collect::>(), - [ - ( - fs_device.factor_source_id(), - HDPathComponent::securifying_base_index(32) - ), - ( - fs_arculus.factor_source_id(), - HDPathComponent::securifying_base_index(1) - ), - ] - .into_iter() - .collect::>() - ); - - // CLEAR CACHE - os.clear_cache(); - - let shield_3fa = MatrixOfFactorSources::new( - [], - 0, - [fs_device.clone(), fs_arculus.clone(), fs_ledger.clone()], - ); - let (securified_diana, stats) = os - .securify_account(diana.entity_address(), shield_3fa.clone()) - .await - .unwrap(); - assert!(!stats.found_any_instances_in_cache_for_any_factor_source()); - assert!(stats.derived_any_new_instance_for_any_factor_source()); - - let diana_mfa_device = 33; - let diana_mfa_arculus = 2; - let diana_mfa_ledger = 1; - - assert_eq!( - securified_diana - .securified_entity_control() - .primary_role_instances() - .into_iter() - .map(|f| (f.factor_source_id(), f.derivation_entity_index())) - .collect::>(), - [ - ( - fs_device.factor_source_id(), - HDPathComponent::securifying_base_index(diana_mfa_device) - ), - ( - fs_arculus.factor_source_id(), - HDPathComponent::securifying_base_index(diana_mfa_arculus) - ), - ( - fs_ledger.factor_source_id(), - HDPathComponent::securifying_base_index(diana_mfa_ledger) - ), - ] - .into_iter() - .collect::>() - ); - - // lets create 2 * CACHE_FILLING_QUANTITY many more accounts and securify them with - // the same shield as Diana - - os.clear_cache(); // CLEAR CACHE - let mut more_unnamed_accounts = IndexSet::new(); - for i in 0..2 * CACHE_FILLING_QUANTITY { - let (unnamed, _) = os - .new_account(fs_device.clone(), network, format!("more@{}", i)) - .await - .unwrap(); - more_unnamed_accounts.insert(unnamed.entity_address()); - } - - let (many_securified_accounts, stats) = os - .securify_accounts(more_unnamed_accounts.clone(), shield_3fa.clone()) - .await - .unwrap(); - assert!( - stats.derived_any_new_instance_for_any_factor_source(), - "twice the cache size => derive more" - ); - os.clear_cache(); // CLEAR CACHE - for index in 0..many_securified_accounts.len() { - let securified_account = many_securified_accounts - .clone() - .into_iter() - .nth(index) - .unwrap(); - let offset = (index + 1) as HDPathValue; - assert_eq!( - securified_account - .securified_entity_control() - .primary_role_instances() - .into_iter() - .map(|f| (f.factor_source_id(), f.derivation_entity_index())) - .collect::>(), - [ - ( - fs_device.factor_source_id(), - HDPathComponent::securifying_base_index(diana_mfa_device + offset) - ), - ( - fs_arculus.factor_source_id(), - HDPathComponent::securifying_base_index(diana_mfa_arculus + offset) - ), - ( - fs_ledger.factor_source_id(), - HDPathComponent::securifying_base_index(diana_mfa_ledger + offset) - ), - ] - .into_iter() - .collect::>() - ); - } -} diff --git a/src/factor_instances_provider/provider/keyed_instances.rs b/src/factor_instances_provider/provider/keyed_instances.rs deleted file mode 100644 index 4bed7211..00000000 --- a/src/factor_instances_provider/provider/keyed_instances.rs +++ /dev/null @@ -1,76 +0,0 @@ -use std::borrow::Borrow; - -use crate::prelude::*; - -pub struct KeyedInstances(pub IndexMap); - -impl KeyedInstances { - pub fn validate_from_source( - &self, - factor_source_id: impl Borrow, - ) -> Result<()> { - if self - .all_instances() - .into_iter() - .any(|f| f.factor_source_id != *factor_source_id.borrow()) - { - return Err(CommonError::FactorSourceDiscrepancy); - } - Ok(()) - } - - pub fn remove(&mut self, key: impl Borrow) -> Option { - self.0.shift_remove(key.borrow()) - } - pub fn all_instances(&self) -> FactorInstances { - self.0 - .clone() - .into_iter() - .flat_map(|(_, v)| v.factor_instances()) - .collect::() - } - pub fn new(map: IndexMap) -> Self { - Self(map) - } -} - -impl IntoIterator for KeyedInstances { - type Item = as IntoIterator>::Item; - type IntoIter = as IntoIterator>::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -pub type InstancesByAgnosticPath = KeyedInstances; -pub type InstancesByDerivationPreset = KeyedInstances; -impl InstancesByAgnosticPath { - pub fn into_derivation_preset(self) -> InstancesByDerivationPreset { - let map = self - .into_iter() - .map(|(k, v)| (DerivationPreset::try_from(k).unwrap(), v)) - .collect::>(); - InstancesByDerivationPreset::new(map) - } -} - -impl From for InstancesByAgnosticPath { - fn from(value: FactorInstances) -> Self { - let map = value - .factor_instances() - .into_iter() - .into_group_map_by(|f| f.agnostic_path()) - .into_iter() - .map(|(k, v)| (k, FactorInstances::from_iter(v))) - .collect::>(); - - Self::new(map) - } -} - -impl From for InstancesByDerivationPreset { - fn from(value: FactorInstances) -> Self { - InstancesByAgnosticPath::from(value).into_derivation_preset() - } -} diff --git a/src/factor_instances_provider/provider/mod.rs b/src/factor_instances_provider/provider/mod.rs deleted file mode 100644 index 80646312..00000000 --- a/src/factor_instances_provider/provider/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -mod factor_instances_cache; -mod factor_instances_provider; -mod keyed_instances; -mod outcome; -mod provider_adopters; - -#[cfg(test)] -mod factor_instances_provider_unit_tests; -#[cfg(test)] -mod test_sargon_os; - -pub use factor_instances_cache::*; -pub use factor_instances_provider::*; -pub use keyed_instances::*; -pub use outcome::*; -pub use provider_adopters::*; diff --git a/src/factor_instances_provider/provider/outcome/factor_instances_provider_outcome.rs b/src/factor_instances_provider/provider/outcome/factor_instances_provider_outcome.rs deleted file mode 100644 index 8aaa532e..00000000 --- a/src/factor_instances_provider/provider/outcome/factor_instances_provider_outcome.rs +++ /dev/null @@ -1,54 +0,0 @@ -use crate::prelude::*; - -/// Identical to `InternalFactorInstancesProviderOutcome` but `FactorInstancesProviderOutcomeForFactor` instead of `InternalFactorInstancesProviderOutcomeForFactor`, having -/// renamed field values to make it clear that `to_cache` instances already have been cached. -#[derive(Clone, Debug)] -pub struct FactorInstancesProviderOutcome { - pub per_factor: IndexMap, -} - -impl From for FactorInstancesProviderOutcome { - fn from(value: InternalFactorInstancesProviderOutcome) -> Self { - Self { - per_factor: value - .per_factor - .into_iter() - .map(|(k, v)| (k, v.into())) - .collect(), - } - } -} - -#[cfg(test)] -impl FactorInstancesProviderOutcome { - pub fn newly_derived_instances_from_all_factor_sources(&self) -> FactorInstances { - self.per_factor - .values() - .flat_map(|x| x.debug_was_derived.factor_instances()) - .collect() - } - - pub fn total_number_of_newly_derived_instances(&self) -> usize { - self.newly_derived_instances_from_all_factor_sources().len() - } - - pub fn derived_any_new_instance_for_any_factor_source(&self) -> bool { - self.total_number_of_newly_derived_instances() > 0 - } - - pub fn instances_found_in_cache_from_all_factor_sources(&self) -> FactorInstances { - self.per_factor - .values() - .flat_map(|x| x.debug_found_in_cache.factor_instances()) - .collect() - } - - pub fn total_number_of_instances_found_in_cache(&self) -> usize { - self.instances_found_in_cache_from_all_factor_sources() - .len() - } - - pub fn found_any_instances_in_cache_for_any_factor_source(&self) -> bool { - self.total_number_of_instances_found_in_cache() > 0 - } -} diff --git a/src/factor_instances_provider/provider/outcome/factor_instances_provider_outcome_for_factor.rs b/src/factor_instances_provider/provider/outcome/factor_instances_provider_outcome_for_factor.rs deleted file mode 100644 index 44e628a0..00000000 --- a/src/factor_instances_provider/provider/outcome/factor_instances_provider_outcome_for_factor.rs +++ /dev/null @@ -1,101 +0,0 @@ -use crate::prelude::*; - -/// Identical to `InternalFactorInstancesProviderOutcomeForFactor` but with -/// different field names, making it clear that the instances of `to_cache` field in the -/// "non-final" counterpart has already been cached, thus here named -/// `debug_was_cached`. -/// Furthermore all fields except `to_use_directly` are renamed to `debug_*` to make it clear they are only included for debugging purposes, -/// in fact, they are all put behind `#[cfg(test)]` -#[derive(Clone, derive_more::Debug)] -#[debug("{}", self.debug_string())] -pub struct FactorInstancesProviderOutcomeForFactor { - #[allow(dead_code)] - hidden: HiddenConstructor, - - /// The FactorSourceID of all the factor instances of this type. - pub factor_source_id: FactorSourceIDFromHash, - - /// FactorInstances which are not saved into the cache. - /// - /// Might be empty - pub to_use_directly: FactorInstances, - - /// FactorInstances which were saved into the cache - /// - /// Might be empty - /// - /// Useful for unit tests. - #[cfg(test)] - pub debug_was_cached: FactorInstances, - - /// FactorInstances which was found in the cache before the operation was - /// executed. - /// - /// Might be empty - /// - /// Useful for unit tests. - /// - /// Might overlap with `to_use_directly` - #[cfg(test)] - pub debug_found_in_cache: FactorInstances, - - /// FactorInstances which was derived. - /// - /// Might be empty - /// - /// Useful for unit tests. - /// - /// Might overlap with `to_cache` and `to_use_directly` - #[cfg(test)] - pub debug_was_derived: FactorInstances, -} -#[allow(dead_code)] -impl FactorInstancesProviderOutcomeForFactor { - #[cfg(test)] - fn debug_string_for_tests(&self) -> String { - format!( - "OutcomeForFactor[factor: {}\n\n\t⚡️to_use_directly: {:?}, \n\n\t➡️💾was_cached: {:?}, \n\n\t💾➡️found_in_cache: {:?}\n\n\t🔮was_derived: {:?}\n\n]", - self.factor_source_id, self.to_use_directly, self.debug_was_cached, self.debug_found_in_cache, self.debug_was_derived - ) - } - - fn debug_string_no_test(&self) -> String { - format!( - "OutcomeForFactor[factor: {}, \n\n\t⚡️to_use_directly: {:?}]", - self.factor_source_id, self.to_use_directly - ) - } - - fn debug_string(&self) -> String { - #[cfg(test)] - return self.debug_string_for_tests(); - - #[cfg(not(test))] - return self.debug_string_no_test(); - } -} - -impl From - for FactorInstancesProviderOutcomeForFactor -{ - fn from(value: InternalFactorInstancesProviderOutcomeForFactor) -> Self { - #[cfg(test)] - let _self = Self { - hidden: HiddenConstructor, - factor_source_id: value.factor_source_id, - to_use_directly: value.to_use_directly, - debug_was_cached: value.to_cache, - debug_found_in_cache: value.found_in_cache, - debug_was_derived: value.newly_derived, - }; - - #[cfg(not(test))] - let _self = Self { - hidden: HiddenConstructor, - factor_source_id: value.factor_source_id, - to_use_directly: value.to_use_directly, - }; - - _self - } -} diff --git a/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs b/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs deleted file mode 100644 index 48b848e3..00000000 --- a/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs +++ /dev/null @@ -1,221 +0,0 @@ -use crate::prelude::*; - -#[derive(Clone, Debug)] -pub struct InternalFactorInstancesProviderOutcome { - pub per_factor: - IndexMap, -} - -impl InternalFactorInstancesProviderOutcome { - pub fn new( - per_factor: IndexMap< - FactorSourceIDFromHash, - InternalFactorInstancesProviderOutcomeForFactor, - >, - ) -> Self { - Self { per_factor } - } - - /// Outcome of FactorInstances just from cache, none have been derived. - pub fn satisfied_by_cache( - pf_found_in_cache: IndexMap, - ) -> Self { - Self::new( - pf_found_in_cache - .into_iter() - .map(|(k, v)| { - ( - k, - InternalFactorInstancesProviderOutcomeForFactor::satisfied_by_cache(k, v), - ) - }) - .collect(), - ) - } - - /// "Transposes" a **collection** of `IndexMap` into `IndexMap` (`InternalFactorInstancesProviderOutcomeForFactor` is essentially a collection of FactorInstance) - pub fn transpose( - pf_to_cache: IndexMap, - pf_to_use_directly: IndexMap, - pf_found_in_cache: IndexMap, - pf_newly_derived: IndexMap, - ) -> Self { - struct Builder { - factor_source_id: FactorSourceIDFromHash, - - /// Might be empty - pub to_cache: IndexSet, - /// Might be empty - pub to_use_directly: IndexSet, - - /// LESS IMPORTANT - for tests... - /// might overlap with `to_use_directly` - pub found_in_cache: IndexSet, - /// might overlap with `to_cache` and `to_use_directly` - pub newly_derived: IndexSet, - } - impl Builder { - fn build(self) -> InternalFactorInstancesProviderOutcomeForFactor { - let to_cache = FactorInstances::from(self.to_cache); - let to_use_directly = FactorInstances::from(self.to_use_directly); - let found_in_cache = FactorInstances::from(self.found_in_cache); - let newly_derived = FactorInstances::from(self.newly_derived); - InternalFactorInstancesProviderOutcomeForFactor::new( - self.factor_source_id, - to_cache, - to_use_directly, - found_in_cache, - newly_derived, - ) - } - fn new(factor_source_id: FactorSourceIDFromHash) -> Self { - Self { - factor_source_id, - to_cache: IndexSet::new(), - to_use_directly: IndexSet::new(), - found_in_cache: IndexSet::new(), - newly_derived: IndexSet::new(), - } - } - } - let mut builders = IndexMap::::new(); - - for (factor_source_id, instances) in pf_found_in_cache { - if let Some(builder) = builders.get_mut(&factor_source_id) { - builder.found_in_cache.extend(instances.factor_instances()); - } else { - let mut builder = Builder::new(factor_source_id); - builder.found_in_cache.extend(instances.factor_instances()); - builders.insert(factor_source_id, builder); - } - } - - for (factor_source_id, instances) in pf_newly_derived { - if let Some(builder) = builders.get_mut(&factor_source_id) { - builder.newly_derived.extend(instances.factor_instances()); - } else { - let mut builder = Builder::new(factor_source_id); - builder.newly_derived.extend(instances.factor_instances()); - builders.insert(factor_source_id, builder); - } - } - - for (factor_source_id, instances) in pf_to_cache { - if let Some(builder) = builders.get_mut(&factor_source_id) { - builder.to_cache.extend(instances.factor_instances()); - } else { - let mut builder = Builder::new(factor_source_id); - builder.to_cache.extend(instances.factor_instances()); - builders.insert(factor_source_id, builder); - } - } - - for (factor_source_id, instances) in pf_to_use_directly { - if let Some(builder) = builders.get_mut(&factor_source_id) { - builder.to_use_directly.extend(instances.factor_instances()); - } else { - let mut builder = Builder::new(factor_source_id); - builder.to_use_directly.extend(instances.factor_instances()); - builders.insert(factor_source_id, builder); - } - } - - Self::new( - builders - .into_iter() - .map(|(k, v)| (k, v.build())) - .collect::>(), - ) - } -} - -#[cfg(test)] -mod tests { - use super::*; - type Sut = InternalFactorInstancesProviderOutcome; - - #[test] - fn only_to_cache() { - let i = HierarchicalDeterministicFactorInstance::fia0(); - - let sut = Sut::transpose( - IndexMap::kv( - FactorSourceIDFromHash::fs0(), - FactorInstances::just(i.clone()), - ), - IndexMap::new(), - IndexMap::new(), - IndexMap::new(), - ); - assert_eq!( - sut.per_factor.get(&i.factor_source_id()).unwrap().to_cache, - FactorInstances::just(i) - ) - } - - #[test] - fn only_to_use_directly() { - let i = HierarchicalDeterministicFactorInstance::fia0(); - - let sut = Sut::transpose( - IndexMap::new(), - IndexMap::kv( - FactorSourceIDFromHash::fs0(), - FactorInstances::just(i.clone()), - ), - IndexMap::new(), - IndexMap::new(), - ); - assert_eq!( - sut.per_factor - .get(&i.factor_source_id()) - .unwrap() - .to_use_directly, - FactorInstances::just(i) - ) - } - - #[test] - fn only_found_in_cache() { - let i = HierarchicalDeterministicFactorInstance::fia0(); - - let sut = Sut::transpose( - IndexMap::new(), - IndexMap::new(), - IndexMap::kv( - FactorSourceIDFromHash::fs0(), - FactorInstances::just(i.clone()), - ), - IndexMap::new(), - ); - assert_eq!( - sut.per_factor - .get(&i.factor_source_id()) - .unwrap() - .found_in_cache, - FactorInstances::just(i) - ) - } - - #[test] - fn only_newly_derived() { - let i = HierarchicalDeterministicFactorInstance::fia0(); - - let sut = Sut::transpose( - IndexMap::new(), - IndexMap::new(), - IndexMap::new(), - IndexMap::kv( - FactorSourceIDFromHash::fs0(), - FactorInstances::just(i.clone()), - ), - ); - assert_eq!( - sut.per_factor - .get(&i.factor_source_id()) - .unwrap() - .newly_derived, - FactorInstances::just(i) - ) - } -} diff --git a/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome_for_factor.rs b/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome_for_factor.rs deleted file mode 100644 index 00ad8e6f..00000000 --- a/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome_for_factor.rs +++ /dev/null @@ -1,100 +0,0 @@ -use crate::prelude::*; - -#[derive(Clone, derive_more::Debug)] -#[debug( - "InternalFactorInstancesProviderOutcomeForFactor[ factor: {:?}\n\n\t⚡️ to_use_directly: {:?}\n\n\t➡️💾to_cache: {:?}\n\n\t💾➡️found_in_cache: {:?}\n\n\t🔮derived: {:?}\n\n]\n", - factor_source_id, - to_use_directly, - to_cache, - found_in_cache, - newly_derived -)] -pub struct InternalFactorInstancesProviderOutcomeForFactor { - #[allow(dead_code)] - hidden: HiddenConstructor, - - /// The FactorSourceID of all the factor instances of this type. - pub factor_source_id: FactorSourceIDFromHash, - - /// FactorInstances which are saved into the cache - /// - /// Might be empty - pub to_cache: FactorInstances, - - /// FactorInstances which are not saved into the cache. - /// - /// Might be empty - pub to_use_directly: FactorInstances, - - /// FactorInstances which was found in the cache before the operation was - /// executed. - /// - /// Might be empty - /// - /// Useful for unit tests. - /// - /// Might overlap with `to_use_directly` - pub found_in_cache: FactorInstances, - - /// FactorInstances which was newly derived. - /// - /// Might be empty - /// - /// Useful for unit tests. - /// - /// Might overlap with `to_cache` and `to_use_directly` - pub newly_derived: FactorInstances, -} - -impl InternalFactorInstancesProviderOutcomeForFactor { - pub fn new( - factor_source_id: FactorSourceIDFromHash, - to_cache: FactorInstances, - to_use_directly: FactorInstances, - found_in_cache: FactorInstances, - newly_derived: FactorInstances, - ) -> Self { - let assert_factor = |xs: &FactorInstances| { - assert!( - xs.factor_instances() - .iter() - .all(|x| x.factor_source_id() == factor_source_id), - "Discrepancy factor source id" - ); - }; - assert_factor(&to_cache); - assert_factor(&to_use_directly); - assert_factor(&found_in_cache); - assert_factor(&newly_derived); - - Self { - hidden: HiddenConstructor, - factor_source_id, - to_cache, - to_use_directly, - found_in_cache, - newly_derived, - } - } - - pub fn satisfied_by_cache( - factor_source_id: FactorSourceIDFromHash, - found_in_cache: FactorInstances, - ) -> Self { - let to_use_directly = found_in_cache.clone(); - - // nothing to cache - let to_cache = FactorInstances::default(); - - // nothing was derived - let newly_derived = FactorInstances::default(); - - Self::new( - factor_source_id, - to_cache, - to_use_directly, - found_in_cache, - newly_derived, - ) - } -} diff --git a/src/factor_instances_provider/provider/outcome/mod.rs b/src/factor_instances_provider/provider/outcome/mod.rs deleted file mode 100644 index 846c204d..00000000 --- a/src/factor_instances_provider/provider/outcome/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -mod factor_instances_provider_outcome; -mod factor_instances_provider_outcome_for_factor; -mod internal_factor_instances_provider_outcome; -mod internal_factor_instances_provider_outcome_for_factor; - -pub use factor_instances_provider_outcome::*; -pub use factor_instances_provider_outcome_for_factor::*; -pub use internal_factor_instances_provider_outcome::*; -pub use internal_factor_instances_provider_outcome_for_factor::*; diff --git a/src/factor_instances_provider/provider/provider_adopters/mod.rs b/src/factor_instances_provider/provider/provider_adopters/mod.rs deleted file mode 100644 index 2b0676ad..00000000 --- a/src/factor_instances_provider/provider/provider_adopters/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod securify_entity_factor_instances_provider; -mod virtual_entity_creating_instance_provider; - -pub use securify_entity_factor_instances_provider::*; -pub use virtual_entity_creating_instance_provider::*; diff --git a/src/factor_instances_provider/provider/provider_adopters/securify_entity_factor_instances_provider.rs b/src/factor_instances_provider/provider/provider_adopters/securify_entity_factor_instances_provider.rs deleted file mode 100644 index 253010d7..00000000 --- a/src/factor_instances_provider/provider/provider_adopters/securify_entity_factor_instances_provider.rs +++ /dev/null @@ -1,244 +0,0 @@ -use crate::prelude::*; - -pub struct SecurifyEntityFactorInstancesProvider; -impl SecurifyEntityFactorInstancesProvider { - /// Reads FactorInstances for every `factor_source` in matrix_of_factor_sources - /// on `network_id` of kind `account_mfa`, - /// meaning `(EntityKind::Account, KeyKind::TransactionSigning, KeySpace::Securified)`, - /// from cache, if any, otherwise derives more of that kind AND other kinds: - /// identity_veci, account_veci, identity_mfa - /// and saves into the cache and returns a collection of instances, per factor source, - /// split into factor instance to use directly and factor instances which was cached, into - /// the mutable `cache` parameter. - /// - /// We are always reading from the beginning of each FactorInstance collection in the cache, - /// and we are always appending to the end. - pub async fn for_account_mfa( - cache: &mut FactorInstancesCache, - profile: Profile, - matrix_of_factor_sources: MatrixOfFactorSources, - account_addresses: IndexSet, - interactors: Arc, - ) -> Result { - Self::for_entity_mfa::( - cache, - profile, - matrix_of_factor_sources, - account_addresses, - interactors, - ) - .await - } - - /// Reads FactorInstances for every `factor_source` in matrix_of_factor_sources - /// on `network_id` of kind `identity_mfa`, - /// meaning `(EntityKind::Identity, KeyKind::TransactionSigning, KeySpace::Securified)`, - /// from cache, if any, otherwise derives more of that kind AND other kinds: - /// identity_veci, account_veci, account_mfa - /// and saves into the cache and returns a collection of instances, per factor source, - /// split into factor instance to use directly and factor instances which was cached, into - /// the mutable `cache` parameter. - /// - /// We are always reading from the beginning of each FactorInstance collection in the cache, - /// and we are always appending to the end. - pub async fn for_persona_mfa( - cache: &mut FactorInstancesCache, - profile: Profile, - matrix_of_factor_sources: MatrixOfFactorSources, - persona_addresses: IndexSet, - interactors: Arc, - ) -> Result { - Self::for_entity_mfa::( - cache, - profile, - matrix_of_factor_sources, - persona_addresses, - interactors, - ) - .await - } - - /// Reads FactorInstances for every `factor_source` in matrix_of_factor_sources - /// on `network_id` of kind `account_mfa` or `identity_mfa` depending on Entity kind, - /// meaning `(EntityKind::_, KeyKind::TransactionSigning, KeySpace::Securified)`, - /// from cache, if any, otherwise derives more of that kind AND other kinds: - /// identity_veci, account_veci, identity_mfa/account_mfa - /// and saves into the cache and returns a collection of instances, per factor source, - /// split into factor instance to use directly and factor instances which was cached, into - /// the mutable `cache` parameter. - /// - /// We are always reading from the beginning of each FactorInstance collection in the cache, - /// and we are always appending to the end. - pub async fn for_entity_mfa( - cache: &mut FactorInstancesCache, - profile: Profile, - matrix_of_factor_sources: MatrixOfFactorSources, - addresses_of_entities: IndexSet, - interactors: Arc, - ) -> Result { - let factor_sources_to_use = matrix_of_factor_sources.all_factors(); - let factor_sources = profile.factor_sources.clone(); - assert!( - factor_sources.is_superset(&factor_sources_to_use), - "Missing FactorSources" - ); - assert!(!addresses_of_entities.is_empty(), "No entities"); - assert!( - addresses_of_entities - .iter() - .all(|e| profile.contains_entity_by_address::(e)), - "unknown entity" - ); - let network_id = addresses_of_entities.first().unwrap().network_id(); - assert!( - addresses_of_entities - .iter() - .all(|a| a.network_id() == network_id), - "wrong network" - ); - - let entity_kind = E::kind(); - - let provider = FactorInstancesProvider::new( - network_id, - factor_sources_to_use, - profile, - cache, - interactors, - ); - - let outcome = provider - .provide(QuantifiedDerivationPreset::new( - DerivationPreset::mfa_entity_kind(entity_kind), - addresses_of_entities.len(), - )) - .await?; - - Ok(outcome.into()) - } -} - -#[cfg(test)] -mod tests { - - use std::ops::Add; - - use crate::{factor_instances_provider::provider::test_sargon_os::SargonOS, prelude::*}; - - type Sut = SecurifyEntityFactorInstancesProvider; - - #[should_panic] - #[actix_rt::test] - async fn mfa_panics_if_entities_empty() { - let fs = HDFactorSource::fs0(); - let a = Account::sample_unsecurified(); - let _ = Sut::for_account_mfa( - &mut FactorInstancesCache::default(), - Profile::new([fs.clone()], [&a], []), - MatrixOfFactorSources::new([], 1, [fs.clone()]), - IndexSet::new(), // <---- EMPTY => should_panic - Arc::new(TestDerivationInteractors::default()), - ) - .await - .unwrap(); - } - - #[should_panic] - #[actix_rt::test] - async fn mfa_panics_if_entity_unknown() { - let fs = HDFactorSource::fs0(); - let a = Account::sample_unsecurified(); - let _ = Sut::for_account_mfa( - &mut FactorInstancesCache::default(), - Profile::new([fs.clone()], [&a], []), - MatrixOfFactorSources::new([], 1, [fs.clone()]), - IndexSet::just(Account::a1().entity_address()), // <---- unknown => should_panic - Arc::new(TestDerivationInteractors::default()), - ) - .await - .unwrap(); - } - - #[should_panic] - #[actix_rt::test] - async fn mfa_panics_if_wrong_network() { - let fs = HDFactorSource::fs0(); - let network = NetworkID::Mainnet; - let mainnet_account = Account::unsecurified_on_network( - "main", - network, - HierarchicalDeterministicFactorInstance::tx_on_network( - CAP26EntityKind::Account, - network, - HDPathComponent::unsecurified_hardening_base_index(0), - fs.factor_source_id(), - ), - ); - let network = NetworkID::Stokenet; - let stokenet_account = Account::unsecurified_on_network( - "stoknet", - network, - HierarchicalDeterministicFactorInstance::tx_on_network( - CAP26EntityKind::Account, - network, - HDPathComponent::unsecurified_hardening_base_index(0), - fs.factor_source_id(), - ), - ); - let profile = Profile::new([fs.clone()], [&mainnet_account, &stokenet_account], []); - assert_eq!(profile.networks.len(), 2); - let _ = Sut::for_account_mfa( - &mut FactorInstancesCache::default(), - profile, - MatrixOfFactorSources::new([], 1, [fs.clone()]), - IndexSet::from_iter([ - mainnet_account.entity_address(), - stokenet_account.entity_address(), - ]), // <---- wrong network => should_panic - Arc::new(TestDerivationInteractors::default()), - ) - .await - .unwrap(); - } - - #[actix_rt::test] - async fn securify_accounts_and_personas_with_override_factor() { - // this is mostly a soundness test for the two functions `for_persona_mfa` and `for_account_mfa` - // using `os` because I'm lazy. We might in fact remove `for_persona_mfa` and `for_account_mfa` - // and only use the `for_entity_mfa` function... but we have these to get code coverage. - let (mut os, bdfs) = SargonOS::with_bdfs().await; - - let (batman, stats) = os.new_mainnet_persona_with_bdfs("Batman").await.unwrap(); - assert!(stats.debug_was_derived.is_empty()); - - let (alice, stats) = os.new_mainnet_account_with_bdfs("alice").await.unwrap(); - assert!(stats.debug_was_derived.is_empty()); - - let shield_0 = MatrixOfFactorSources::new([], 0, [bdfs.clone()]); - let mut cache = os.cache_snapshot(); - let interactors = Arc::new(TestDerivationInteractors::default()); - let outcome = Sut::for_account_mfa( - &mut cache, - os.profile_snapshot(), - shield_0.clone(), - IndexSet::just(alice.entity_address()), - interactors.clone(), - ) - .await - .unwrap(); - let outcome = outcome.per_factor.get(&bdfs.factor_source_id()).unwrap(); - assert_eq!(outcome.to_use_directly.len(), 1); - - let outcome = Sut::for_persona_mfa( - &mut cache, - os.profile_snapshot(), - shield_0.clone(), - IndexSet::just(batman.entity_address()), - interactors.clone(), - ) - .await - .unwrap(); - let outcome = outcome.per_factor.get(&bdfs.factor_source_id()).unwrap(); - assert_eq!(outcome.to_use_directly.len(), 1); - } -} diff --git a/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs b/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs deleted file mode 100644 index 4d132752..00000000 --- a/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs +++ /dev/null @@ -1,495 +0,0 @@ -use crate::prelude::*; - -/// Uses a `FactorInstancesProvider` provide a VECI for a new virtual entity. -pub struct VirtualEntityCreatingInstanceProvider; -impl VirtualEntityCreatingInstanceProvider { - /// Uses a `FactorInstancesProvider` to provide a VECI for a new virtual entity. - /// - /// Reads FactorInstances for `factor_source` on `network_id` of kind `account_veci`, - /// meaning `(EntityKind::Account, KeyKind::TransactionSigning, KeySpace::Unsecurified)`, - /// from cache, if any, otherwise derives more of that kind AND other kinds: - /// identity_veci, account_mfa, identity_mfa - /// and saves into the cache and returns a collection of instances, split into - /// factor instance to use directly and factor instances which was cached, into - /// the mutable `cache` parameter. - /// - /// We are always reading from the beginning of each FactorInstance collection in the cache, - /// and we are always appending to the end. - pub async fn for_account_veci( - cache: &mut FactorInstancesCache, - profile: Option, - factor_source: HDFactorSource, - network_id: NetworkID, - interactors: Arc, - ) -> Result { - Self::for_entity_veci( - CAP26EntityKind::Account, - cache, - profile, - factor_source, - network_id, - interactors, - ) - .await - } - - /// Reads FactorInstances for `factor_source` on `network_id` of kind `persona_veci`, - /// meaning `(EntityKind::Identity, KeyKind::TransactionSigning, KeySpace::Unsecurified)`, - /// from cache, if any, otherwise derives more of that kind AND other kinds: - /// account_veci, account_mfa, identity_mfa - /// and saves into the cache and returns a collection of instances, split into - /// factor instance to use directly and factor instances which was cached, into - /// the mutable `cache` parameter. - /// - /// We are always reading from the beginning of each FactorInstance collection in the cache, - /// and we are always appending to the end. - pub async fn for_persona_veci( - cache: &mut FactorInstancesCache, - profile: Option, - factor_source: HDFactorSource, - network_id: NetworkID, - interactors: Arc, - ) -> Result { - Self::for_entity_veci( - CAP26EntityKind::Identity, - cache, - profile, - factor_source, - network_id, - interactors, - ) - .await - } - - /// Reads FactorInstances for `factor_source` on `network_id` of kind `account_veci`, - /// meaning `(EntityKind::Account, KeyKind::TransactionSigning, KeySpace::Unsecurified)`, - /// from cache, if any, otherwise derives more of that kind AND other kinds: - /// identity_veci, account_mfa, identity_mfa - /// and saves into the cache and returns a collection of instances, split into - /// factor instance to use directly and factor instances which was cached, into - /// the mutable `cache` parameter. - /// - /// We are always reading from the beginning of each FactorInstance collection in the cache, - /// and we are always appending to the end. - pub async fn for_entity_veci( - entity_kind: CAP26EntityKind, - cache: &mut FactorInstancesCache, - profile: Option, - factor_source: HDFactorSource, - network_id: NetworkID, - interactors: Arc, - ) -> Result { - let provider = FactorInstancesProvider::new( - network_id, - IndexSet::just(factor_source.clone()), - profile, - cache, - interactors, - ); - let outcome = provider - .provide(QuantifiedDerivationPreset::new( - DerivationPreset::veci_entity_kind(entity_kind), - 1, - )) - .await?; - - let outcome = outcome - .per_factor - .get(&factor_source.factor_source_id()) - .cloned() - .expect("Expected to have instances for the factor source"); - - Ok(outcome.into()) - } -} - -#[cfg(test)] -mod tests { - - use super::*; - type Sut = VirtualEntityCreatingInstanceProvider; - - #[actix_rt::test] - async fn cache_is_always_filled_persona_veci_then_after_all_used_we_start_over_at_zero_if_no_profile_is_used( - ) { - let network = NetworkID::Mainnet; - let bdfs = HDFactorSource::sample(); - let mut cache = FactorInstancesCache::default(); - - let outcome = Sut::for_persona_veci( - &mut cache, - None, - bdfs.clone(), - network, - Arc::new(TestDerivationInteractors::default()), - ) - .await - .unwrap(); - - assert_eq!(outcome.factor_source_id, bdfs.factor_source_id()); - - assert_eq!(outcome.debug_found_in_cache.len(), 0); - - assert_eq!( - outcome.debug_was_cached.len(), - DerivationPreset::all().len() * CACHE_FILLING_QUANTITY - ); - - assert_eq!( - outcome.debug_was_derived.len(), - DerivationPreset::all().len() * CACHE_FILLING_QUANTITY + 1 - ); - - let instances_used_directly = outcome.to_use_directly.factor_instances(); - assert_eq!(instances_used_directly.len(), 1); - let instances_used_directly = instances_used_directly.first().unwrap(); - - assert_eq!( - instances_used_directly.derivation_entity_index(), - HDPathComponent::Hardened(HDPathComponentHardened::Unsecurified( - UnsecurifiedIndex::unsecurified_hardening_base_index(0) - )) - ); - - cache.assert_is_full(network, bdfs.factor_source_id()); - - let cached = cache - .peek_all_instances_of_factor_source(bdfs.factor_source_id()) - .unwrap(); - - let persona_veci_paths = cached - .clone() - .get(&DerivationPreset::IdentityVeci.index_agnostic_path_on_network(network)) - .unwrap() - .factor_instances() - .into_iter() - .map(|x| x.derivation_path()) - .collect_vec(); - - assert_eq!(persona_veci_paths.len(), CACHE_FILLING_QUANTITY); - - assert!(persona_veci_paths - .iter() - .all(|x| x.entity_kind == CAP26EntityKind::Identity - && x.network_id == network - && x.key_space() == KeySpace::Unsecurified - && x.key_kind == CAP26KeyKind::TransactionSigning)); - - let persona_veci_indices = persona_veci_paths - .into_iter() - .map(|x| x.index) - .collect_vec(); - - assert_eq!( - persona_veci_indices.first().unwrap().clone(), - HDPathComponent::unsecurified_hardening_base_index(1) - ); - - assert_eq!( - persona_veci_indices.last().unwrap().clone(), - HDPathComponent::unsecurified_hardening_base_index(30) - ); - } - - #[actix_rt::test] - async fn cache_is_always_filled_account_veci_then_after_all_used_we_start_over_at_zero_if_no_profile_is_used( - ) { - let network = NetworkID::Mainnet; - let bdfs = HDFactorSource::sample(); - let mut cache = FactorInstancesCache::default(); - - let outcome = Sut::for_account_veci( - &mut cache, - None, - bdfs.clone(), - network, - Arc::new(TestDerivationInteractors::default()), - ) - .await - .unwrap(); - - assert_eq!(outcome.factor_source_id, bdfs.factor_source_id()); - - assert_eq!(outcome.debug_found_in_cache.len(), 0); - - assert_eq!( - outcome.debug_was_cached.len(), - DerivationPreset::all().len() * CACHE_FILLING_QUANTITY - ); - - assert_eq!( - outcome.debug_was_derived.len(), - DerivationPreset::all().len() * CACHE_FILLING_QUANTITY + 1 - ); - - let instances_used_directly = outcome.to_use_directly.factor_instances(); - assert_eq!(instances_used_directly.len(), 1); - let instances_used_directly = instances_used_directly.first().unwrap(); - - assert_eq!( - instances_used_directly.derivation_entity_index(), - HDPathComponent::Hardened(HDPathComponentHardened::Unsecurified( - UnsecurifiedIndex::unsecurified_hardening_base_index(0) - )) - ); - - cache.assert_is_full(network, bdfs.factor_source_id()); - - let cached = cache - .peek_all_instances_of_factor_source(bdfs.factor_source_id()) - .unwrap(); - - let account_veci_paths = cached - .clone() - .get(&DerivationPreset::AccountVeci.index_agnostic_path_on_network(network)) - .unwrap() - .factor_instances() - .into_iter() - .map(|x| x.derivation_path()) - .collect_vec(); - - assert_eq!(account_veci_paths.len(), CACHE_FILLING_QUANTITY); - - assert!(account_veci_paths - .iter() - .all(|x| x.entity_kind == CAP26EntityKind::Account - && x.network_id == network - && x.key_space() == KeySpace::Unsecurified - && x.key_kind == CAP26KeyKind::TransactionSigning)); - - let account_veci_indices = account_veci_paths - .into_iter() - .map(|x| x.index) - .collect_vec(); - - assert_eq!( - account_veci_indices.first().unwrap().clone(), - HDPathComponent::unsecurified_hardening_base_index(1) - ); - - assert_eq!( - account_veci_indices.last().unwrap().clone(), - HDPathComponent::unsecurified_hardening_base_index(30) - ); - - let account_mfa_paths = cached - .clone() - .get(&DerivationPreset::AccountMfa.index_agnostic_path_on_network(network)) - .unwrap() - .factor_instances() - .into_iter() - .map(|x| x.derivation_path()) - .collect_vec(); - - assert!(account_mfa_paths - .iter() - .all(|x| x.entity_kind == CAP26EntityKind::Account - && x.network_id == network - && x.key_space() == KeySpace::Securified - && x.key_kind == CAP26KeyKind::TransactionSigning)); - - let account_mfa_indices = account_mfa_paths.into_iter().map(|x| x.index).collect_vec(); - - assert_eq!( - account_mfa_indices.first().unwrap().clone(), - HDPathComponent::securifying_base_index(0) - ); - - assert_eq!( - account_mfa_indices.last().unwrap().clone(), - HDPathComponent::securifying_base_index(29) - ); - - let identity_mfa_paths = cached - .clone() - .get(&DerivationPreset::IdentityMfa.index_agnostic_path_on_network(network)) - .unwrap() - .factor_instances() - .into_iter() - .map(|x| x.derivation_path()) - .collect_vec(); - - assert!(identity_mfa_paths - .iter() - .all(|x| x.entity_kind == CAP26EntityKind::Identity - && x.network_id == network - && x.key_space() == KeySpace::Securified - && x.key_kind == CAP26KeyKind::TransactionSigning)); - - let identity_mfa_indices = identity_mfa_paths - .into_iter() - .map(|x| x.index) - .collect_vec(); - - assert_eq!( - identity_mfa_indices.first().unwrap().clone(), - HDPathComponent::securifying_base_index(0) - ); - - assert_eq!( - identity_mfa_indices.last().unwrap().clone(), - HDPathComponent::securifying_base_index(29) - ); - - let identity_veci_paths = cached - .clone() - .get(&DerivationPreset::IdentityVeci.index_agnostic_path_on_network(network)) - .unwrap() - .factor_instances() - .into_iter() - .map(|x| x.derivation_path()) - .collect_vec(); - - assert!(identity_veci_paths - .iter() - .all(|x| x.entity_kind == CAP26EntityKind::Identity - && x.network_id == network - && x.key_space() == KeySpace::Unsecurified - && x.key_kind == CAP26KeyKind::TransactionSigning)); - - let identity_veci_indices = identity_veci_paths - .into_iter() - .map(|x| x.index) - .collect_vec(); - - assert_eq!( - identity_veci_indices.first().unwrap().clone(), - HDPathComponent::unsecurified_hardening_base_index(0) - ); - - assert_eq!( - identity_veci_indices.last().unwrap().clone(), - HDPathComponent::unsecurified_hardening_base_index(29) - ); - - // lets create another account (same network, same factor source) - - let outcome = Sut::for_account_veci( - &mut cache, - None, - bdfs.clone(), - network, - Arc::new(TestDerivationInteractors::default()), - ) - .await - .unwrap(); - - assert_eq!(outcome.factor_source_id, bdfs.factor_source_id()); - assert_eq!(outcome.debug_found_in_cache.len(), 1); // This time we found in cache - assert_eq!(outcome.debug_was_cached.len(), 0); - assert_eq!(outcome.debug_was_derived.len(), 0); - - let instances_used_directly = outcome.to_use_directly.factor_instances(); - assert_eq!(instances_used_directly.len(), 1); - let instances_used_directly = instances_used_directly.first().unwrap(); - - assert_eq!( - instances_used_directly.derivation_entity_index(), - HDPathComponent::Hardened(HDPathComponentHardened::Unsecurified( - UnsecurifiedIndex::unsecurified_hardening_base_index(1) // Next one! - )) - ); - - assert!(!cache.is_full(network, bdfs.factor_source_id())); // not full anymore, since we just used a veci - - let cached = cache - .peek_all_instances_of_factor_source(bdfs.factor_source_id()) - .unwrap(); - - let account_veci_paths = cached - .clone() - .get(&DerivationPreset::AccountVeci.index_agnostic_path_on_network(network)) - .unwrap() - .factor_instances() - .into_iter() - .map(|x| x.derivation_path()) - .collect_vec(); - - assert_eq!(account_veci_paths.len(), CACHE_FILLING_QUANTITY - 1); - - assert!(account_veci_paths - .iter() - .all(|x| x.entity_kind == CAP26EntityKind::Account - && x.network_id == network - && x.key_space() == KeySpace::Unsecurified - && x.key_kind == CAP26KeyKind::TransactionSigning)); - - let account_veci_indices = account_veci_paths - .into_iter() - .map(|x| x.index) - .collect_vec(); - - assert_eq!( - account_veci_indices.first().unwrap().clone(), - HDPathComponent::unsecurified_hardening_base_index(2) // first is not `1` anymore - ); - - assert_eq!( - account_veci_indices.last().unwrap().clone(), - HDPathComponent::unsecurified_hardening_base_index(30) - ); - - // create 29 more accounts, then we should be able to crate one more which should ONLY derive - // more instances for ACCOUNT VECI, and not Identity Veci, Identity MFA and Account MFA, since that is - // not needed. - for _ in 0..29 { - let outcome = Sut::for_account_veci( - &mut cache, - None, - bdfs.clone(), - network, - Arc::new(TestDerivationInteractors::default()), - ) - .await - .unwrap(); - - assert_eq!(outcome.factor_source_id, bdfs.factor_source_id()); - - assert_eq!(outcome.debug_found_in_cache.len(), 1); - assert_eq!(outcome.debug_was_cached.len(), 0); - assert_eq!(outcome.debug_was_derived.len(), 0); - } - - let cached = cache - .peek_all_instances_of_factor_source(bdfs.factor_source_id()) - .unwrap(); - - assert!( - cached - .get(&DerivationPreset::AccountVeci.index_agnostic_path_on_network(network)) - .is_none(), - "should have used the last instance..." - ); - - // Great, now lets create one more account, and this time we should derive more instances for - // it. We should derive 31 instances, 30 for account veci to cache and 1 to use directly. - // we should NOT derive more instances for Identity Veci, Identity MFA and Account MFA, since - // that cache is already full. - let outcome = Sut::for_account_veci( - &mut cache, - None, - bdfs.clone(), - network, - Arc::new(TestDerivationInteractors::default()), - ) - .await - .unwrap(); - - assert_eq!(outcome.factor_source_id, bdfs.factor_source_id()); - - assert_eq!(outcome.debug_found_in_cache.len(), 0); - assert_eq!(outcome.debug_was_cached.len(), CACHE_FILLING_QUANTITY); // ONLY 30, not 120... - assert_eq!(outcome.debug_was_derived.len(), CACHE_FILLING_QUANTITY + 1); - - let instances_used_directly = outcome.to_use_directly.factor_instances(); - assert_eq!(instances_used_directly.len(), 1); - let instances_used_directly = instances_used_directly.first().unwrap(); - - assert_eq!( - instances_used_directly.derivation_entity_index(), - HDPathComponent::Hardened(HDPathComponentHardened::Unsecurified( - UnsecurifiedIndex::unsecurified_hardening_base_index(0) // IMPORTANT! Index 0 is used again! Why?! Well because are not using a Profile here, and we are not eagerly filling cache just before we are using the last index. - )) - ); - } -} diff --git a/src/factor_instances_provider/provider/test_sargon_os.rs b/src/factor_instances_provider/provider/test_sargon_os.rs deleted file mode 100644 index d0d2ae76..00000000 --- a/src/factor_instances_provider/provider/test_sargon_os.rs +++ /dev/null @@ -1,349 +0,0 @@ -#![cfg(test)] - -use crate::prelude::*; - -/// Should be merged with SargonOS in Sargon repo... -/// contains three fundamentally new methods: -/// * new_account (using `FactorInstancesProvider`) -/// * new_persona (using `FactorInstancesProvider`) -/// * securify_accounts (using `FactorInstancesProvider`) -/// * add_factor_source (using `FactorInstancesProvider`) -pub(super) struct SargonOS { - /// FactorInstancesCache of prederived FactorInstances for each factor source in Profile. - pub(super) cache: FactorInstancesCache, - profile: RwLock, -} - -impl SargonOS { - pub(super) fn profile_snapshot(&self) -> Profile { - self.profile.try_read().unwrap().clone() - } - - pub(super) fn new() -> Self { - Arc::new(TestDerivationInteractors::default()); - Self { - cache: FactorInstancesCache::default(), - profile: RwLock::new(Profile::default()), - } - } - - pub(super) async fn with_bdfs() -> (Self, HDFactorSource) { - let mut self_ = Self::new(); - let bdfs = HDFactorSource::device(); - self_.add_factor_source(bdfs.clone()).await.unwrap(); - (self_, bdfs) - } - - pub(super) fn cache_snapshot(&self) -> FactorInstancesCache { - self.cache.clone() - } - - pub(super) fn clear_cache(&mut self) { - println!("💣 CLEAR CACHE"); - self.cache = FactorInstancesCache::default() - } - - pub(super) async fn new_mainnet_account_with_bdfs( - &mut self, - name: impl AsRef, - ) -> Result<(Account, FactorInstancesProviderOutcomeForFactor)> { - self.new_account_with_bdfs(NetworkID::Mainnet, name).await - } - - pub(super) async fn new_account_with_bdfs( - &mut self, - network: NetworkID, - name: impl AsRef, - ) -> Result<(Account, FactorInstancesProviderOutcomeForFactor)> { - let bdfs = self.profile_snapshot().bdfs(); - self.new_account(bdfs, network, name).await - } - - pub(super) async fn new_account( - &mut self, - factor_source: HDFactorSource, - network: NetworkID, - name: impl AsRef, - ) -> Result<(Account, FactorInstancesProviderOutcomeForFactor)> { - self.new_entity(factor_source, network, name).await - } - - pub(super) async fn new_mainnet_persona_with_bdfs( - &mut self, - name: impl AsRef, - ) -> Result<(Persona, FactorInstancesProviderOutcomeForFactor)> { - self.new_persona_with_bdfs(NetworkID::Mainnet, name).await - } - - pub(super) async fn new_persona_with_bdfs( - &mut self, - network: NetworkID, - name: impl AsRef, - ) -> Result<(Persona, FactorInstancesProviderOutcomeForFactor)> { - let bdfs = self.profile_snapshot().bdfs(); - self.new_persona(bdfs, network, name).await - } - - pub(super) async fn new_persona( - &mut self, - factor_source: HDFactorSource, - network: NetworkID, - name: impl AsRef, - ) -> Result<(Persona, FactorInstancesProviderOutcomeForFactor)> { - self.new_entity(factor_source, network, name).await - } - - pub(super) async fn new_entity( - &mut self, - factor_source: HDFactorSource, - network: NetworkID, - name: impl AsRef, - ) -> Result<(E, FactorInstancesProviderOutcomeForFactor)> { - let profile_snapshot = self.profile_snapshot(); - let outcome = VirtualEntityCreatingInstanceProvider::for_entity_veci( - E::kind(), - &mut self.cache, - Some(profile_snapshot), - factor_source.clone(), - network, - Arc::new(TestDerivationInteractors::default()), - ) - .await - .unwrap(); - - let outcome_for_factor = outcome; - - let instances_to_use_directly = outcome_for_factor.to_use_directly.clone(); - - assert_eq!(instances_to_use_directly.len(), 1); - let instance = instances_to_use_directly.first().unwrap(); - - let address = E::Address::new(network, instance.public_key_hash()); - let security_state = EntitySecurityState::Unsecured(instance); - let entity = E::new( - name, - address, - security_state, - ThirdPartyDepositPreference::default(), - ); - self.profile - .try_write() - .unwrap() - .insert_entities(IndexSet::just(Into::::into( - entity.clone(), - ))) - .unwrap(); - - Ok((entity, outcome_for_factor)) - } - - pub(super) async fn securify_account( - &mut self, - account_addresses: AccountAddress, - shield: MatrixOfFactorSources, - ) -> Result<(SecurifiedAccount, FactorInstancesProviderOutcome)> { - let (accounts, stats) = self - .securify_accounts(IndexSet::just(account_addresses), shield) - .await?; - assert_eq!(accounts.len(), 1); - let account = accounts.into_iter().next().unwrap(); - Ok((account, stats)) - } - - pub(super) async fn securify_accounts( - &mut self, - account_addresses: IndexSet, - shield: MatrixOfFactorSources, - ) -> Result<(SecurifiedAccounts, FactorInstancesProviderOutcome)> { - self.securify_accounts_with_interactor( - Arc::new(TestDerivationInteractors::default()), - account_addresses, - shield, - ) - .await - } - - pub(super) async fn securify_accounts_with_interactor( - &mut self, - interactor: Arc, - account_addresses: IndexSet, - shield: MatrixOfFactorSources, - ) -> Result<(SecurifiedAccounts, FactorInstancesProviderOutcome)> { - assert!(!account_addresses.is_empty()); - let network = account_addresses.first().unwrap().network_id(); - let (entities, stats) = self - .securify_entities_with_interactor::( - interactor, - account_addresses, - shield, - ) - .await?; - Ok((SecurifiedAccounts::new(network, entities).unwrap(), stats)) - } - - pub(super) async fn securify_personas( - &mut self, - identity_addresses: IndexSet, - shield: MatrixOfFactorSources, - ) -> Result<(SecurifiedPersonas, FactorInstancesProviderOutcome)> { - self.securify_personas_with_interactor( - Arc::new(TestDerivationInteractors::default()), - identity_addresses, - shield, - ) - .await - } - - pub(super) async fn securify_personas_with_interactor( - &mut self, - interactor: Arc, - identity_addresses: IndexSet, - shield: MatrixOfFactorSources, - ) -> Result<(SecurifiedPersonas, FactorInstancesProviderOutcome)> { - assert!(!identity_addresses.is_empty()); - let network = identity_addresses.first().unwrap().network_id(); - let (entities, stats) = self - .securify_entities_with_interactor::( - interactor, - identity_addresses, - shield, - ) - .await?; - Ok((SecurifiedPersonas::new(network, entities).unwrap(), stats)) - } - - pub(super) async fn securify_entities_with_interactor( - &mut self, - interactor: Arc, - addresses_of_entities: IndexSet<::Address>, - shield: MatrixOfFactorSources, - ) -> Result<(IndexSet, FactorInstancesProviderOutcome)> { - let profile_snapshot = self.profile_snapshot(); - - let outcome = SecurifyEntityFactorInstancesProvider::for_entity_mfa::( - &mut self.cache, - profile_snapshot.clone(), - shield.clone(), - addresses_of_entities.clone(), - interactor, - ) - .await?; - - let mut instance_per_factor = outcome - .clone() - .per_factor - .into_iter() - .map(|(k, outcome_per_factor)| (k, outcome_per_factor.to_use_directly)) - .collect::>(); - - assert_eq!( - instance_per_factor - .keys() - .cloned() - .collect::>(), - shield - .all_factors() - .into_iter() - .map(|f| f.factor_source_id()) - .collect::>() - ); - - // Now we need to map the flat set of instances into many MatrixOfFactorInstances, and assign - // one to each account - let updated_entities = addresses_of_entities - .clone() - .into_iter() - .map(|a| { - let entity = profile_snapshot.get_entity::(&a).unwrap(); - let matrix_of_instances = - MatrixOfFactorInstances::fulfilling_matrix_of_factor_sources_with_instances( - &mut instance_per_factor, - shield.clone(), - ) - .unwrap(); - - let access_controller = match entity.security_state() { - EntitySecurityState::Unsecured(_) => { - AccessController::from_unsecurified_address(a) - } - EntitySecurityState::Securified(sec) => sec.access_controller.clone(), - }; - let veci = match entity.security_state() { - EntitySecurityState::Unsecured(veci) => Some(veci), - EntitySecurityState::Securified(sec) => { - sec.veci.clone().map(|x| x.factor_instance()) - } - }; - let sec = SecurifiedEntityControl::new( - matrix_of_instances, - access_controller, - veci.map(|x| VirtualEntityCreatingInstance::new(x, entity.address())), - ); - - E::new( - entity.name(), - entity.entity_address(), - sec, - entity.third_party_deposit(), - ) - }) - .collect::>(); - - for entity in updated_entities.clone().into_iter() { - self.profile - .try_write() - .unwrap() - .update_entity::(entity.into()) - } - assert!( - instance_per_factor.values().all(|x| x.is_empty()), - "should have used all instances, but have unused instances: {:?}", - instance_per_factor - ); - - Ok((updated_entities, outcome)) - } - - /// Pre-Derives FactorInstances and saves them into the cache - pub(super) async fn add_factor_source(&mut self, factor_source: HDFactorSource) -> Result<()> { - let profile_snapshot = self.profile_snapshot(); - assert!( - !profile_snapshot - .factor_sources - .iter() - .any(|x| x.factor_source_id() == factor_source.factor_source_id()), - "factor already in Profile" - ); - let outcome = CacheFiller::for_new_factor_source( - &mut self.cache, - Some(profile_snapshot), - factor_source.clone(), - NetworkID::Mainnet, - Arc::new(TestDerivationInteractors::default()), - ) - .await - .unwrap(); - - assert_eq!(outcome.factor_source_id, factor_source.factor_source_id()); - - assert_eq!(outcome.debug_found_in_cache.len(), 0); - - assert_eq!( - outcome.debug_was_cached.len(), - DerivationPreset::all().len() * CACHE_FILLING_QUANTITY - ); - - assert_eq!( - outcome.debug_was_derived.len(), - DerivationPreset::all().len() * CACHE_FILLING_QUANTITY - ); - - self.profile - .try_write() - .unwrap() - .add_factor_source(factor_source.clone()) - .unwrap(); - - Ok(()) - } -} diff --git a/src/gateway/gateway_read_write.rs b/src/gateway/gateway_read_write.rs deleted file mode 100644 index 8ac8b709..00000000 --- a/src/gateway/gateway_read_write.rs +++ /dev/null @@ -1,30 +0,0 @@ -use crate::prelude::*; - -#[async_trait::async_trait] -pub trait Gateway: GatewayReadonly { - async fn simulate_network_activity_for(&self, owner: AddressOfAccountOrPersona) -> Result<()>; - - async fn set_securified_entity( - &self, - securified: SecurifiedEntityControl, - owner: AddressOfAccountOrPersona, - ) -> Result<()>; - - async fn set_securified_account( - &self, - securified: SecurifiedEntityControl, - owner: &AccountAddress, - ) -> Result<()> { - self.set_securified_entity(securified, owner.clone().into()) - .await - } - - async fn set_securified_persona( - &self, - securified: SecurifiedEntityControl, - owner: &IdentityAddress, - ) -> Result<()> { - self.set_securified_entity(securified, owner.clone().into()) - .await - } -} diff --git a/src/gateway/gateway_readonly.rs b/src/gateway/gateway_readonly.rs deleted file mode 100644 index 3f5e0f73..00000000 --- a/src/gateway/gateway_readonly.rs +++ /dev/null @@ -1,52 +0,0 @@ -use std::ops::Index; - -use crate::prelude::*; - -#[async_trait::async_trait] -pub trait GatewayReadonly: Sync + Send { - async fn has_internet_connection(&self) -> bool; - async fn is_key_hash_known(&self, hash: PublicKeyHash) -> Result; - - async fn query_public_key_hash_is_known( - &self, - hashes: IndexSet, - ) -> Result> { - let mut is_known_map = HashMap::::new(); - for hash in hashes.into_iter() { - let is_known = self.is_key_hash_known(hash.clone()).await?; - is_known_map.insert(hash, is_known); - } - Ok(is_known_map) - } - - async fn get_entity_addresses_of_by_public_key_hashes( - &self, - hashes: HashSet, - ) -> Result>>; - - async fn get_on_chain_entity( - &self, - address: AddressOfAccountOrPersona, - ) -> Result>; - - async fn get_on_chain_account( - &self, - account_address: &AccountAddress, - ) -> Result> { - self.get_on_chain_entity(account_address.clone().into()) - .await - } - - async fn get_owner_key_hashes( - &self, - address: AddressOfAccountOrPersona, - ) -> Result>> { - let on_chain_account = self.get_on_chain_entity(address).await?; - return Ok(on_chain_account.map(|account| account.owner_keys().clone())); - } - - async fn is_securified(&self, address: AddressOfAccountOrPersona) -> Result { - let entity = self.get_on_chain_entity(address).await?; - Ok(entity.map(|x| x.is_securified()).unwrap_or(false)) - } -} diff --git a/src/gateway/mod.rs b/src/gateway/mod.rs deleted file mode 100644 index 08cb93ba..00000000 --- a/src/gateway/mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -mod gateway_read_write; -mod gateway_readonly; -mod on_chain_entity_state; - -#[cfg(test)] -mod test_gateway; - -pub(crate) use gateway_read_write::*; -pub(crate) use gateway_readonly::*; -pub(crate) use on_chain_entity_state::*; - -#[cfg(test)] -pub(crate) use test_gateway::*; diff --git a/src/gateway/on_chain_entity_state.rs b/src/gateway/on_chain_entity_state.rs deleted file mode 100644 index 427067aa..00000000 --- a/src/gateway/on_chain_entity_state.rs +++ /dev/null @@ -1,114 +0,0 @@ -#![allow(unused)] - -use crate::prelude::*; - -/// A snapshot of the information that Gateway can hand us -/// about an entities Address - or queried by a PublicKeyHash -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct OnChainEntityState { - pub address: AddressOfAccountOrPersona, - /// `None` if not securified, `Some` if securified - pub access_controller: Option, - pub owner_keys: Vec, - /// TODO: we should read this... - pub third_party_deposits: (), -} - -impl OnChainEntityState { - pub fn new( - address: impl Into, - access_controller: impl Into>, - owner_keys: impl IntoIterator, - ) -> Self { - Self { - address: address.into(), - access_controller: access_controller.into(), - owner_keys: owner_keys.into_iter().collect_vec(), - third_party_deposits: (), - } - } - - pub fn unsecurified(owner: AddressOfAccountOrPersona, owner_key: PublicKeyHash) -> Self { - Self::new(owner, None, [owner_key]) - } - - pub fn securified( - owner: AddressOfAccountOrPersona, - access_controller: AccessController, - owner_keys: IndexSet, - ) -> Self { - Self::new(owner, access_controller, owner_keys) - } -} - -impl OnChainEntityState { - pub fn address(&self) -> AddressOfAccountOrPersona { - self.address.clone() - } - - pub fn owner_keys(&self) -> HashSet { - self.owner_keys.clone().into_iter().collect() - } - - pub fn is_securified(&self) -> bool { - self.access_controller.is_some() - } -} - -impl HasSampleValues for OnChainEntityState { - fn sample() -> Self { - Self::securified( - AddressOfAccountOrPersona::sample(), - AccessController::sample(), - IndexSet::from_iter([PublicKeyHash::sample(), PublicKeyHash::sample_other()]), - ) - } - - fn sample_other() -> Self { - Self::unsecurified( - AddressOfAccountOrPersona::sample(), - PublicKeyHash::sample_other(), - ) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - type Sut = OnChainEntityState; - - #[test] - fn equality() { - assert_eq!(Sut::sample(), Sut::sample()); - assert_eq!(Sut::sample_other(), Sut::sample_other()); - } - - #[test] - fn inequality() { - assert_ne!(Sut::sample(), Sut::sample_other()); - } - - #[test] - fn securified_is_securified() { - assert!(Sut::sample().is_securified()); - } - - #[test] - fn address() { - assert_eq!(Sut::sample().address(), AddressOfAccountOrPersona::sample()); - } - - #[test] - fn unsecurified_is_not_securified() { - assert!(!Sut::sample_other().is_securified()); - } - - #[test] - fn owner_keys() { - assert_eq!( - Sut::sample().owner_keys(), - HashSet::from_iter([PublicKeyHash::sample(), PublicKeyHash::sample_other()]) - ); - } -} diff --git a/src/gateway/test_gateway.rs b/src/gateway/test_gateway.rs deleted file mode 100644 index 6795448d..00000000 --- a/src/gateway/test_gateway.rs +++ /dev/null @@ -1,230 +0,0 @@ -#![cfg(test)] -#![allow(unused)] - -use crate::prelude::*; - -pub struct TestGateway { - has_internet_connection: bool, - /// contains only current state for each entity - entities: RwLock>, - - /// contains historic state, we only ever add to this set, never remove. - known_hashes: RwLock>, -} - -impl TestGateway { - pub fn clone_snapshot(&self) -> Self { - Self { - has_internet_connection: self.has_internet_connection, - known_hashes: RwLock::new(self.known_hashes.try_read().unwrap().clone()), - entities: RwLock::new(self.entities.try_read().unwrap().clone()), - } - } - pub fn new(has_internet_connection: bool) -> Self { - Self { - has_internet_connection, - known_hashes: RwLock::new(HashSet::new()), - entities: RwLock::new(HashMap::new()), - } - } -} - -impl Default for TestGateway { - fn default() -> Self { - Self::new(true) - } -} - -impl TestGateway { - #[allow(unused)] - pub fn debug_print(&self) { - println!( - "⛩️ known_hashes: {:?}", - self.known_hashes.try_read().unwrap() - ); - println!("⛩️ entities: {:?}", self.entities.try_read().unwrap().keys()); - } -} - -#[async_trait::async_trait] -impl GatewayReadonly for TestGateway { - async fn has_internet_connection(&self) -> bool { - self.has_internet_connection - } - - async fn is_key_hash_known(&self, hash: PublicKeyHash) -> Result { - let is_known = self.known_hashes.try_read().unwrap().contains(&hash); - Ok(is_known) - } - async fn get_entity_addresses_of_by_public_key_hashes( - &self, - hashes: HashSet, - ) -> Result>> { - let entities = self.entities.try_read().unwrap(); - let states = entities.values(); - - Ok(hashes - .iter() - .filter_map(|k| { - // N.B. we want this to always be single element (Axiom 1). - let mut entities_references_hash = HashSet::::new(); - for state in states.clone().filter(|x| x.owner_keys().contains(k)) { - entities_references_hash.insert(state.address()); - } - if entities_references_hash.is_empty() { - None - } else { - Some((k.clone(), entities_references_hash)) - } - }) - .collect::>>()) - } - - async fn get_on_chain_entity( - &self, - address: AddressOfAccountOrPersona, - ) -> Result> { - Ok(self.entities.try_read().unwrap().get(&address).cloned()) - } -} - -impl TestGateway { - async fn assert_not_securified(&self, address: &AddressOfAccountOrPersona) -> Result<()> { - let is_already_securified = self.is_securified(address.clone()).await?; - assert!( - !is_already_securified, - "Cannot unsecurify an already securified entity" - ); - Ok(()) - } - - fn contains(&self, address: &AddressOfAccountOrPersona) -> bool { - self.entities.try_read().unwrap().contains_key(address) - } -} - -#[async_trait::async_trait] -impl Gateway for TestGateway { - async fn simulate_network_activity_for(&self, owner: AddressOfAccountOrPersona) -> Result<()> { - self.assert_not_securified(&owner).await?; - - let owner_key = owner.public_key_hash(); - - if self.contains(&owner) || self.known_hashes.try_read().unwrap().contains(&owner_key) { - panic!("update not supported") - } else { - self.entities.try_write().unwrap().insert( - owner.clone(), - OnChainEntityState::unsecurified(owner, owner_key.clone()), - ); - self.known_hashes.try_write().unwrap().insert(owner_key); - } - Ok(()) - } - - async fn set_securified_entity( - &self, - securified: SecurifiedEntityControl, - owner: AddressOfAccountOrPersona, - ) -> Result<()> { - self.assert_not_securified(&owner).await?; - - let owner_keys = securified - .matrix - .all_factors() - .iter() - .map(|f| f.public_key_hash()) - .collect::>(); - - if self.contains(&owner) { - self.entities.try_write().unwrap().remove(&owner); - } - - self.known_hashes - .try_write() - .unwrap() - .extend(owner_keys.clone()); - - self.entities.try_write().unwrap().insert( - owner.clone(), - OnChainEntityState::securified(owner, securified.access_controller.clone(), owner_keys), - ); - - Ok(()) - } -} - -mod tests { - - use super::*; - - type Sut = TestGateway; - - #[actix_rt::test] - async fn test_has_internet_connection() { - let has_internet_connection = true; - let sut = Sut::new(has_internet_connection); - let does_have_internet = sut.has_internet_connection().await; - assert_eq!(does_have_internet, has_internet_connection); - - let has_internet_connection = false; - let sut = Sut::new(has_internet_connection); - let does_have_internet = sut.has_internet_connection().await; - assert_eq!(does_have_internet, has_internet_connection); - } - - #[actix_rt::test] - async fn test_set_securified_account() { - let sut = Sut::new(true); - let address = AccountAddress::sample(); - let value = SecurifiedEntityControl::sample(); - sut.set_securified_account(value.clone(), &address) - .await - .unwrap(); - let on_chain = sut.get_on_chain_account(&address).await.unwrap(); - let is_securified = sut.is_securified(address.clone().into()).await.unwrap(); - assert!(is_securified); - assert_eq!( - on_chain - .unwrap() - .access_controller - .unwrap() - .metadata - .unwrap() - .scrypto_access_rules, - ScryptoAccessRule::from(value.matrix) - ); - let is_pub_key_known = sut - .query_public_key_hash_is_known(IndexSet::just(address.public_key_hash())) - .await - .unwrap(); - assert_eq!( - is_pub_key_known.get(&address.public_key_hash()).unwrap(), - &false // veci is not retained... - ); - } - - #[actix_rt::test] - async fn test_set_securified_persona() { - let sut = Sut::new(true); - let address = IdentityAddress::sample(); - let value = SecurifiedEntityControl::sample(); - sut.set_securified_persona(value.clone(), &address) - .await - .unwrap(); - let on_chain = sut - .get_on_chain_entity(AddressOfAccountOrPersona::Identity(address.clone())) - .await - .unwrap(); - assert_eq!( - on_chain - .unwrap() - .access_controller - .unwrap() - .metadata - .unwrap() - .scrypto_access_rules, - ScryptoAccessRule::from(value.matrix) - ); - } -} diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index 779e635b..00000000 --- a/src/lib.rs +++ /dev/null @@ -1,55 +0,0 @@ -#![allow(internal_features)] -#![feature(core_intrinsics)] -#![feature(iter_repeat_n)] -#![feature(async_closure)] -#![allow(unused_imports)] -#![feature(step_trait)] - -mod derivation; -mod factor_instances_provider; -mod gateway; -mod samples; -mod signing; -mod types; - -#[cfg(test)] -mod testing; - -pub mod prelude { - pub use crate::derivation::*; - pub use crate::gateway::*; - - pub(crate) use crate::samples::*; - - pub use crate::factor_instances_provider::*; - pub use crate::signing::*; - pub use crate::types::*; - - #[cfg(test)] - pub(crate) use crate::testing::*; - - pub(crate) use derive_getters::Getters; - pub(crate) use enum_as_inner::EnumAsInner; - pub(crate) use indexmap::{IndexMap, IndexSet}; - pub(crate) use itertools::Itertools; - pub(crate) use std::cell::RefCell; - pub(crate) use std::cmp::Ordering; - pub(crate) use std::future::Future; - pub(crate) use std::ops::{Deref, DerefMut}; - pub(crate) use std::pin::Pin; - pub(crate) use std::time::SystemTime; - pub(crate) use uuid::Uuid; - - pub(crate) use std::ops::Range; - - pub(crate) use sha2::{Digest, Sha256}; - - pub(crate) use std::{ - collections::{HashMap, HashSet}, - sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard}, - }; - - pub(crate) use log::*; -} - -pub use prelude::*; diff --git a/src/samples/mod.rs b/src/samples/mod.rs deleted file mode 100644 index 0305be30..00000000 --- a/src/samples/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -#![allow(unused)] - -mod sample_values; - -pub(crate) use sample_values::*; diff --git a/src/samples/sample_values.rs b/src/samples/sample_values.rs deleted file mode 100644 index 569cd7f6..00000000 --- a/src/samples/sample_values.rs +++ /dev/null @@ -1,498 +0,0 @@ -#![allow(unused)] - -use crate::prelude::*; - -impl HDFactorSource { - /// Device - pub(crate) fn fs0() -> Self { - Self::device() - } - - /// Ledger - pub(crate) fn fs1() -> Self { - Self::ledger() - } - - /// Ledger - pub(crate) fn fs2() -> Self { - Self::ledger() - } - - /// Arculus - pub(crate) fn fs3() -> Self { - Self::arculus() - } - - /// Arculus - pub(crate) fn fs4() -> Self { - Self::arculus() - } - - /// Yubikey - pub(crate) fn fs5() -> Self { - Self::yubikey() - } - - /// Yubikey - pub(crate) fn fs6() -> Self { - Self::yubikey() - } - - /// Off Device - pub(crate) fn fs7() -> Self { - Self::off_device() - } - - /// Off Device - pub(crate) fn fs8() -> Self { - Self::off_device() - } - - /// Security Questions - pub(crate) fn fs9() -> Self { - Self::security_question() - } - - /// DeviceFactorSource - pub(crate) fn fs10() -> Self { - Self::device() - } - - pub(crate) fn all() -> IndexSet { - IndexSet::from_iter(ALL_FACTOR_SOURCES.clone()) - } -} - -use once_cell::sync::Lazy; - -pub(crate) static ID_STEPPER: Lazy = Lazy::new(UuidStepper::new); - -impl UuidStepper { - pub(crate) fn next() -> Uuid { - ID_STEPPER._next() - } -} - -pub(crate) static ALL_FACTOR_SOURCES: Lazy<[HDFactorSource; 11]> = Lazy::new(|| { - [ - HDFactorSource::fs0(), - HDFactorSource::fs1(), - HDFactorSource::fs2(), - HDFactorSource::fs3(), - HDFactorSource::fs4(), - HDFactorSource::fs5(), - HDFactorSource::fs6(), - HDFactorSource::fs7(), - HDFactorSource::fs8(), - HDFactorSource::fs9(), - HDFactorSource::fs10(), - ] -}); - -pub(crate) fn fs_at(index: usize) -> HDFactorSource { - ALL_FACTOR_SOURCES[index].clone() -} - -pub(crate) fn fs_id_at(index: usize) -> FactorSourceIDFromHash { - fs_at(index).factor_source_id() -} - -impl FactorSourceIDFromHash { - /// Device - pub(crate) fn fs0() -> Self { - fs_id_at(0) - } - - /// Ledger - pub(crate) fn fs1() -> Self { - fs_id_at(1) - } - - /// Ledger - pub(crate) fn fs2() -> Self { - fs_id_at(2) - } - - /// Arculus - pub(crate) fn fs3() -> Self { - fs_id_at(3) - } - - /// Arculus - pub(crate) fn fs4() -> Self { - fs_id_at(4) - } - - /// Yubikey - pub(crate) fn fs5() -> Self { - fs_id_at(5) - } - - /// Yubikey - pub(crate) fn fs6() -> Self { - fs_id_at(6) - } - - /// Off Device - pub(crate) fn fs7() -> Self { - fs_id_at(7) - } - - /// Off Device - pub(crate) fn fs8() -> Self { - fs_id_at(8) - } - - /// Security Questions - pub(crate) fn fs9() -> Self { - fs_id_at(9) - } - - /// Device - pub(crate) fn fs10() -> Self { - fs_id_at(10) - } -} - -impl HierarchicalDeterministicFactorInstance { - pub(crate) fn f( - entity_kind: CAP26EntityKind, - idx: HDPathComponent, - ) -> impl Fn(FactorSourceIDFromHash) -> Self { - move |id: FactorSourceIDFromHash| Self::mainnet_tx(entity_kind, idx, id) - } -} - -impl PublicKeyHash { - pub fn repeat(byte: u8) -> Self { - Self::new([byte; 32]) - } - pub fn sample_0() -> Self { - Self::repeat(0x50) - } - pub fn sample_1() -> Self { - Self::repeat(0x51) - } - pub fn sample_2() -> Self { - Self::repeat(0x52) - } - pub fn sample_3() -> Self { - Self::repeat(0x53) - } - pub fn sample_4() -> Self { - Self::repeat(0x54) - } - pub fn sample_5() -> Self { - Self::repeat(0x55) - } - pub fn sample_6() -> Self { - Self::repeat(0x56) - } - pub fn sample_7() -> Self { - Self::repeat(0x57) - } - pub fn sample_8() -> Self { - Self::repeat(0x58) - } - pub fn sample_9() -> Self { - Self::repeat(0x59) - } -} - -impl MatrixOfFactorInstances { - /// Securified { Single Threshold only } - pub(crate) fn m2(fi: F) -> Self - where - F: Fn(FactorSourceIDFromHash) -> HierarchicalDeterministicFactorInstance, - { - Self::single_threshold(fi(FactorSourceIDFromHash::fs0())) - } - - /// Securified { Single Override only } - pub(crate) fn m3(fi: F) -> Self - where - F: Fn(FactorSourceIDFromHash) -> HierarchicalDeterministicFactorInstance, - { - Self::single_override(fi(FactorSourceIDFromHash::fs1())) - } - - /// Securified { Threshold factors only #3 } - pub(crate) fn m4(fi: F) -> Self - where - F: Fn(FactorSourceIDFromHash) -> HierarchicalDeterministicFactorInstance, - { - type F = FactorSourceIDFromHash; - Self::threshold_only([F::fs0(), F::fs3(), F::fs5()].map(fi), 2) - } - - /// Securified { Override factors only #2 } - pub(crate) fn m5(fi: F) -> Self - where - F: Fn(FactorSourceIDFromHash) -> HierarchicalDeterministicFactorInstance, - { - type F = FactorSourceIDFromHash; - Self::override_only([F::fs1(), F::fs4()].map(&fi)) - } - - /// Securified { Threshold #3 and Override factors #2 } - pub(crate) fn m6(fi: F) -> Self - where - F: Fn(FactorSourceIDFromHash) -> HierarchicalDeterministicFactorInstance, - { - type F = FactorSourceIDFromHash; - Self::new( - [F::fs0(), F::fs3(), F::fs5()].map(&fi), - 2, - [F::fs1(), F::fs4()].map(&fi), - ) - } - - /// Securified { Threshold only # 5/5 } - pub(crate) fn m7(fi: F) -> Self - where - F: Fn(FactorSourceIDFromHash) -> HierarchicalDeterministicFactorInstance, - { - type F = FactorSourceIDFromHash; - Self::threshold_only( - [F::fs2(), F::fs6(), F::fs7(), F::fs8(), F::fs9()].map(&fi), - 5, - ) - } - /// Securified { Threshold 1/1 and Override factors #1 } - pub(crate) fn m8(fi: F) -> Self - where - F: Fn(FactorSourceIDFromHash) -> HierarchicalDeterministicFactorInstance, - { - type F = FactorSourceIDFromHash; - Self::new([F::fs1()].map(&fi), 1, [F::fs8()].map(&fi)) - } -} - -impl HierarchicalDeterministicFactorInstance { - /// 0 | unsecurified | device - pub fn fi0(entity_kind: CAP26EntityKind) -> Self { - Self::mainnet_tx( - entity_kind, - HDPathComponent::unsecurified_hardening_base_index(0), - FactorSourceIDFromHash::fs0(), - ) - } - - /// Account: 0 | unsecurified | device - pub fn fia0() -> Self { - Self::fi0(CAP26EntityKind::Account) - } - /// Identity: 0 | unsecurified | device - pub fn fii0() -> Self { - Self::fi0(CAP26EntityKind::Identity) - } - - /// 1 | unsecurified | ledger - pub fn fi1(entity_kind: CAP26EntityKind) -> Self { - Self::mainnet_tx( - entity_kind, - HDPathComponent::unsecurified_hardening_base_index(1), - FactorSourceIDFromHash::fs1(), - ) - } - - /// Account: 1 | unsecurified | ledger - pub fn fia1() -> Self { - Self::fi1(CAP26EntityKind::Account) - } - /// Identity: 1 | unsecurified | ledger - pub fn fii1() -> Self { - Self::fi1(CAP26EntityKind::Identity) - } - - /// 8 | Unsecurified { Device } (fs10) - pub fn fi10(entity_kind: CAP26EntityKind) -> Self { - Self::mainnet_tx( - entity_kind, - HDPathComponent::unsecurified_hardening_base_index(8), - FactorSourceIDFromHash::fs10(), - ) - } - - /// Account: 8 | Unsecurified { Device } (fs10) - pub fn fia10() -> Self { - Self::fi10(CAP26EntityKind::Account) - } - - /// Identity: 8 | Unsecurified { Device } (fs10) - pub fn fii10() -> Self { - Self::fi10(CAP26EntityKind::Identity) - } -} - -impl Account { - /// Alice | 0 | Unsecurified { Device } - pub(crate) fn a0() -> Self { - Self::unsecurified_mainnet("Alice", HierarchicalDeterministicFactorInstance::fia0()) - } - - /// Bob | 1 | Unsecurified { Ledger } - pub(crate) fn a1() -> Self { - Self::unsecurified_mainnet("Bob", HierarchicalDeterministicFactorInstance::fia1()) - } - - /// Carla | 2 | Securified { Single Threshold only } - pub(crate) fn a2() -> Self { - Self::securified_mainnet("Carla", AccountAddress::sample_2(), || { - let idx = HDPathComponent::securifying_base_index(2); - MatrixOfFactorInstances::m2(HierarchicalDeterministicFactorInstance::f( - Self::entity_kind(), - idx, - )) - }) - } - - /// David | 3 | Securified { Single Override only } - pub(crate) fn a3() -> Self { - Self::securified_mainnet("David", AccountAddress::sample_3(), || { - let idx = HDPathComponent::securifying_base_index(3); - MatrixOfFactorInstances::m3(HierarchicalDeterministicFactorInstance::f( - Self::entity_kind(), - idx, - )) - }) - } - - /// Emily | 4 | Securified { Threshold factors only #3 } - pub(crate) fn a4() -> Self { - Self::securified_mainnet("Emily", AccountAddress::sample_4(), || { - let idx = HDPathComponent::securifying_base_index(4); - MatrixOfFactorInstances::m4(HierarchicalDeterministicFactorInstance::f( - Self::entity_kind(), - idx, - )) - }) - } - - /// Frank | 5 | Securified { Override factors only #2 } - pub(crate) fn a5() -> Self { - Self::securified_mainnet("Frank", AccountAddress::sample_5(), || { - let idx = HDPathComponent::securifying_base_index(5); - MatrixOfFactorInstances::m5(HierarchicalDeterministicFactorInstance::f( - Self::entity_kind(), - idx, - )) - }) - } - - /// Grace | 6 | Securified { Threshold #3 and Override factors #2 } - pub(crate) fn a6() -> Self { - Self::securified_mainnet("Grace", AccountAddress::sample_6(), || { - let idx = HDPathComponent::securifying_base_index(6); - MatrixOfFactorInstances::m6(HierarchicalDeterministicFactorInstance::f( - Self::entity_kind(), - idx, - )) - }) - } - - /// Ida | 7 | Securified { Threshold only # 5/5 } - pub(crate) fn a7() -> Self { - Self::securified_mainnet("Ida", AccountAddress::sample_7(), || { - let idx = HDPathComponent::securifying_base_index(7); - MatrixOfFactorInstances::m7(HierarchicalDeterministicFactorInstance::f( - Self::entity_kind(), - idx, - )) - }) - } - - /// Jenny | 8 | Unsecurified { Device } (fs10) - pub(crate) fn a8() -> Self { - Self::unsecurified_mainnet("Jenny", HierarchicalDeterministicFactorInstance::fia10()) - } - - /// Klara | 9 | Securified { Threshold 1/1 and Override factors #1 } - pub(crate) fn a9() -> Self { - Self::securified_mainnet("Klara", AccountAddress::sample_9(), || { - let idx = HDPathComponent::securifying_base_index(9); - MatrixOfFactorInstances::m8(HierarchicalDeterministicFactorInstance::f( - Self::entity_kind(), - idx, - )) - }) - } -} - -impl Persona { - /// Satoshi | 0 | Unsecurified { Device } - pub(crate) fn p0() -> Self { - Self::unsecurified_mainnet("Satoshi", HierarchicalDeterministicFactorInstance::fii0()) - } - - /// Batman | 1 | Unsecurified { Ledger } - pub(crate) fn p1() -> Self { - Self::unsecurified_mainnet("Batman", HierarchicalDeterministicFactorInstance::fii1()) - } - - /// Ziggy | 2 | Securified { Single Threshold only } - pub(crate) fn p2() -> Self { - Self::securified_mainnet("Ziggy", IdentityAddress::sample_2(), || { - let idx = HDPathComponent::securifying_base_index(2); - MatrixOfFactorInstances::m2(HierarchicalDeterministicFactorInstance::f( - Self::entity_kind(), - idx, - )) - }) - } - - /// Superman | 3 | Securified { Single Override only } - pub(crate) fn p3() -> Self { - Self::securified_mainnet("Superman", IdentityAddress::sample_3(), || { - let idx = HDPathComponent::securifying_base_index(3); - MatrixOfFactorInstances::m3(HierarchicalDeterministicFactorInstance::f( - Self::entity_kind(), - idx, - )) - }) - } - - /// Banksy | 4 | Securified { Threshold factors only #3 } - pub(crate) fn p4() -> Self { - Self::securified_mainnet("Banksy", IdentityAddress::sample_4(), || { - let idx = HDPathComponent::securifying_base_index(4); - MatrixOfFactorInstances::m4(HierarchicalDeterministicFactorInstance::f( - Self::entity_kind(), - idx, - )) - }) - } - - /// Voltaire | 5 | Securified { Override factors only #2 } - pub(crate) fn p5() -> Self { - Self::securified_mainnet("Voltaire", IdentityAddress::sample_5(), || { - let idx = HDPathComponent::securifying_base_index(5); - MatrixOfFactorInstances::m5(HierarchicalDeterministicFactorInstance::f( - Self::entity_kind(), - idx, - )) - }) - } - - /// Kasparov | 6 | Securified { Threshold #3 and Override factors #2 } - pub(crate) fn p6() -> Self { - Self::securified_mainnet("Kasparov", IdentityAddress::sample_6(), || { - let idx = HDPathComponent::securifying_base_index(6); - MatrixOfFactorInstances::m6(HierarchicalDeterministicFactorInstance::f( - Self::entity_kind(), - idx, - )) - }) - } - - /// Pelé | 7 | Securified { Threshold only # 5/5 } - pub(crate) fn p7() -> Self { - Self::securified_mainnet("Pelé", IdentityAddress::sample_7(), || { - let idx = HDPathComponent::securifying_base_index(7); - MatrixOfFactorInstances::m7(HierarchicalDeterministicFactorInstance::f( - Self::entity_kind(), - idx, - )) - }) - } -} diff --git a/src/signing/collector/mod.rs b/src/signing/collector/mod.rs deleted file mode 100644 index 5b5d59c4..00000000 --- a/src/signing/collector/mod.rs +++ /dev/null @@ -1,12 +0,0 @@ -mod signatures_collecting_continuation; -mod signatures_collector; -mod signatures_collector_dependencies; -mod signatures_collector_preprocessor; -mod signatures_collector_state; -mod signing_finish_early_strategy; - -pub(crate) use signatures_collector_preprocessor::*; - -pub use signatures_collecting_continuation::*; -pub use signatures_collector::*; -pub use signing_finish_early_strategy::*; diff --git a/src/signing/collector/signatures_collecting_continuation.rs b/src/signing/collector/signatures_collecting_continuation.rs deleted file mode 100644 index 45d6351b..00000000 --- a/src/signing/collector/signatures_collecting_continuation.rs +++ /dev/null @@ -1,14 +0,0 @@ -/// Whether to continue collecting signatures or finish early. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum SignaturesCollectingContinuation { - /// It is meaningless to continue collecting signatures, either since either - /// all transactions are valid, and the collector is configured to finish early - /// in that case, or some transaction is invalid and the collector is configured - /// finish early in that case. - FinishEarly, - - /// We should continue collecting signatures, either since the collector is - /// configured to not finish early, even though we can, or since we cannot - /// finish early since not enough factor sources have been signed with. - Continue, -} diff --git a/src/signing/collector/signatures_collector.rs b/src/signing/collector/signatures_collector.rs deleted file mode 100644 index a6f0533a..00000000 --- a/src/signing/collector/signatures_collector.rs +++ /dev/null @@ -1,701 +0,0 @@ -use crate::prelude::*; - -use super::{ - signatures_collector_dependencies::*, signatures_collector_preprocessor::*, - signatures_collector_state::*, -}; - -use SignaturesCollectingContinuation::*; - -/// A coordinator which gathers signatures from several factor sources of different -/// kinds, in increasing friction order, for many transactions and for -/// potentially multiple entities and for many factor instances (derivation paths) -/// for each transaction. -/// -/// By increasing friction order we mean, the quickest and easiest to use FactorSourceKind -/// is last; namely `DeviceFactorSource`, and the most tedious FactorSourceKind is -/// first; namely `LedgerFactorSource`, which user might also lack access to. -pub struct SignaturesCollector { - /// Stateless immutable values used by the collector to gather signatures - /// from factor sources. - dependencies: SignaturesCollectorDependencies, - - /// Mutable internal state of the collector which builds up the list - /// of signatures from each used factor source. - state: RefCell, -} - -// === PUBLIC === -impl SignaturesCollector { - pub fn new( - finish_early_strategy: SigningFinishEarlyStrategy, - transactions: impl IntoIterator, - interactors: Arc, - profile: &Profile, - ) -> Result { - Self::with_signers_extraction( - finish_early_strategy, - profile.factor_sources.clone(), - transactions.into_iter().collect::>(), - interactors, - |i| TXToSign::extracting_from_intent_and_profile(&i, profile), - ) - } - - pub async fn collect_signatures(self) -> SignaturesOutcome { - _ = self - .sign_with_factors() // in decreasing "friction order" - .await - .inspect_err(|e| error!("Failed to use factor sources: {:#?}", e)); - - self.outcome() - } -} - -// === INTERNAL === -impl SignaturesCollector { - /// Used by our tests. But Sargon will typically wanna use `SignaturesCollector::new` and passing - /// it a - pub(crate) fn with( - finish_early_strategy: SigningFinishEarlyStrategy, - all_factor_sources_in_profile: IndexSet, - transactions: IndexSet, - interactors: Arc, - ) -> Self { - debug!("Init SignaturesCollector"); - let preprocessor = SignaturesCollectorPreprocessor::new(transactions); - let (petitions, factors) = preprocessor.preprocess(all_factor_sources_in_profile); - - let dependencies = - SignaturesCollectorDependencies::new(finish_early_strategy, interactors, factors); - let state = SignaturesCollectorState::new(petitions); - - Self { - dependencies, - state: RefCell::new(state), - } - } - - pub(crate) fn with_signers_extraction( - finish_early_strategy: SigningFinishEarlyStrategy, - all_factor_sources_in_profile: IndexSet, - transactions: IndexSet, - interactors: Arc, - extract_signers: F, - ) -> Result - where - F: Fn(TransactionIntent) -> Result, - { - let transactions = transactions - .into_iter() - .map(extract_signers) - .collect::>>()?; - - let collector = Self::with( - finish_early_strategy, - all_factor_sources_in_profile, - transactions, - interactors, - ); - - Ok(collector) - } -} - -// === PRIVATE === -impl SignaturesCollector { - /// Returning `Continue` means that we should continue collecting signatures. - /// - /// Returning `FinishEarly` if it is meaningless to continue collecting signatures, - /// either since all transactions are valid and this collector is configured - /// to finish early in that case, or if some transaction is invalid and this - /// collector is configured to finish early in that case. - /// - /// N.B. this method does not concern itself with how many or which - /// factor sources are left to sign with, that is handled by the main loop, - /// i.e. this might return `Continue` even though there is not factor sources - /// left to sign with. - fn continuation(&self) -> SignaturesCollectingContinuation { - let finish_early_strategy = self.dependencies.finish_early_strategy; - let when_all_transactions_are_valid = - finish_early_strategy.when_all_transactions_are_valid.0; - let when_some_transaction_is_invalid = - finish_early_strategy.when_some_transaction_is_invalid.0; - - let petitions_status = self.state.borrow().petitions.borrow().status(); - - if petitions_status.are_all_valid() { - if when_all_transactions_are_valid == FinishEarly { - info!("All valid && should finish early => finish early"); - return FinishEarly; - } else { - debug!( - "All valid, BUT the collector is configured to NOT finish early => Continue" - ); - } - } else if petitions_status.is_some_invalid() { - if when_some_transaction_is_invalid == FinishEarly { - info!("Some invalid && should finish early => finish early"); - return FinishEarly; - } else { - debug!("Some transactions invalid, BUT the collector is configured to NOT finish early in case of failures => Continue"); - } - } - - Continue - } - - fn should_neglect_factors_due_to_irrelevant( - &self, - factor_sources_of_kind: &FactorSourcesOfKind, - ) -> bool { - let state = self.state.borrow(); - let petitions = state.petitions.borrow(); - petitions.should_neglect_factors_due_to_irrelevant(factor_sources_of_kind) - } - - fn neglected_factors_due_to_irrelevant( - &self, - factor_sources_of_kind: &FactorSourcesOfKind, - ) -> bool { - if self.should_neglect_factors_due_to_irrelevant(factor_sources_of_kind) { - info!( - "Neglecting all factors of kind: {} since they are all irrelevant (all TX referencing those factors have already failed)", - factor_sources_of_kind.kind - ); - self.process_batch_response(SignWithFactorsOutcome::irrelevant(factor_sources_of_kind)); - true - } else { - false - } - } - - async fn sign_with_factors_of_kind(&self, factor_sources_of_kind: &FactorSourcesOfKind) { - info!( - "Use(?) #{:?} factors of kind: {:?}", - &factor_sources_of_kind.factor_sources().len(), - &factor_sources_of_kind.kind - ); - - let interactor = self - .dependencies - .interactors - .interactor_for(factor_sources_of_kind.kind); - let factor_sources = factor_sources_of_kind.factor_sources(); - match interactor { - // PolyFactor Interactor: Many Factor Sources at once - SignInteractor::PolyFactor(interactor) => { - // Prepare the request for the interactor - debug!("Creating poly request for interactor"); - let request = self.request_for_parallel_interactor(factor_sources_of_kind); - if !request.invalid_transactions_if_neglected.is_empty() { - info!( - "If factors {:?} are neglected, invalid TXs: {:?}", - request.per_factor_source.keys(), - request.invalid_transactions_if_neglected - ) - } - debug!("Dispatching poly request to interactor: {:?}", request); - let response = interactor.sign(request).await; - debug!("Got response from poly interactor: {:?}", response); - self.process_batch_response(response); - } - - // MonoFactor Interactor: One Factor Sources at a time - // After each factor source we pass the result to the collector - // updating its internal state so that we state about being able - // to skip the next factor source or not. - SignInteractor::MonoFactor(interactor) => { - for factor_source in factor_sources { - // Prepare the request for the interactor - debug!("Creating mono request for interactor"); - let request = - self.request_for_serial_interactor(&factor_source.factor_source_id()); - - if !request.invalid_transactions_if_neglected.is_empty() { - info!( - "If factor {:?} are neglected, invalid TXs: {:?}", - request.input.factor_source_id, - request.invalid_transactions_if_neglected - ) - } - - debug!("Dispatching mono request to interactor: {:?}", request); - // Produce the results from the interactor - let response = interactor.sign(request).await; - debug!("Got response from mono interactor: {:?}", response); - - // Report the results back to the collector - self.process_batch_response(response); - - if self.continuation() == FinishEarly { - break; - } - } - } - } - } - - /// In decreasing "friction order" - async fn sign_with_factors(&self) -> Result<()> { - let factors_of_kind = self.dependencies.factors_of_kind.clone(); - for factor_sources_of_kind in factors_of_kind.iter() { - if self.continuation() == FinishEarly { - break; - } - if self.neglected_factors_due_to_irrelevant(factor_sources_of_kind) { - continue; - } - self.sign_with_factors_of_kind(factor_sources_of_kind).await; - } - info!("FINISHED WITH ALL FACTORS"); - Ok(()) - } - - fn input_for_interactor( - &self, - factor_source_id: &FactorSourceIDFromHash, - ) -> MonoFactorSignRequestInput { - self.state - .borrow() - .petitions - .borrow() - .input_for_interactor(factor_source_id) - } - - fn request_for_serial_interactor( - &self, - factor_source_id: &FactorSourceIDFromHash, - ) -> MonoFactorSignRequest { - let batch_signing_request = self.input_for_interactor(factor_source_id); - - MonoFactorSignRequest::new( - batch_signing_request, - self.invalid_transactions_if_neglected_factor_sources(IndexSet::just( - *factor_source_id, - )) - .into_iter() - .collect::>(), - ) - } - - fn request_for_parallel_interactor( - &self, - factor_sources_of_kind: &FactorSourcesOfKind, - ) -> PolyFactorSignRequest { - let factor_source_ids = factor_sources_of_kind - .factor_sources() - .iter() - .map(|f| f.factor_source_id()) - .collect::>(); - let per_factor_source = factor_source_ids - .clone() - .iter() - .map(|fid| (*fid, self.input_for_interactor(fid))) - .collect::>(); - - let invalid_transactions_if_neglected = - self.invalid_transactions_if_neglected_factor_sources(factor_source_ids); - - // Prepare the request for the interactor - PolyFactorSignRequest::new( - factor_sources_of_kind.kind, - per_factor_source, - invalid_transactions_if_neglected, - ) - } - - fn invalid_transactions_if_neglected_factor_sources( - &self, - factor_source_ids: IndexSet, - ) -> IndexSet { - self.state - .borrow() - .petitions - .borrow() - .invalid_transactions_if_neglected_factors(factor_source_ids) - } - - fn process_batch_response(&self, response: SignWithFactorsOutcome) { - let state = self.state.borrow_mut(); - let petitions = state.petitions.borrow_mut(); - petitions.process_batch_response(response) - } - - fn outcome(self) -> SignaturesOutcome { - let expected_number_of_transactions; - { - let state = self.state.borrow_mut(); - let petitions = state.petitions.borrow_mut(); - expected_number_of_transactions = petitions.txid_to_petition.borrow().len(); - } - let outcome = self.state.into_inner().petitions.into_inner().outcome(); - assert_eq!( - outcome.failed_transactions().len() + outcome.successful_transactions().len(), - expected_number_of_transactions - ); - if !outcome.successful() { - warn!( - "Failed to sign, invalid tx: {:?}, petition", - outcome.failed_transactions() - ) - } - outcome - } -} - -#[cfg(test)] -mod tests { - - use std::iter; - - use super::*; - - impl SignaturesCollector { - /// Used by tests - pub(crate) fn petitions(self) -> Petitions { - self.state.into_inner().petitions.into_inner() - } - } - - #[test] - fn invalid_profile_unknown_account() { - let res = SignaturesCollector::new( - SigningFinishEarlyStrategy::default(), - [TransactionIntent::new([Account::a0().entity_address()], [])], - Arc::new(TestSignatureCollectingInteractors::new( - SimulatedUser::prudent_no_fail(), - )), - &Profile::new(IndexSet::new(), [], []), - ); - assert!(matches!(res, Err(CommonError::UnknownEntity))); - } - - #[test] - fn invalid_profile_unknown_persona() { - let res = SignaturesCollector::new( - SigningFinishEarlyStrategy::default(), - [TransactionIntent::new([], [Persona::p0().entity_address()])], - Arc::new(TestSignatureCollectingInteractors::new( - SimulatedUser::prudent_no_fail(), - )), - &Profile::new(IndexSet::new(), [], []), - ); - assert!(matches!(res, Err(CommonError::UnknownPersona))); - } - - #[actix_rt::test] - async fn valid_profile() { - let factors_sources = HDFactorSource::all(); - let persona = Persona::p0(); - let collector = SignaturesCollector::new( - SigningFinishEarlyStrategy::default(), - [TransactionIntent::new([], [persona.entity_address()])], - Arc::new(TestSignatureCollectingInteractors::new( - SimulatedUser::prudent_no_fail(), - )), - &Profile::new(factors_sources, [], [&persona]), - ) - .unwrap(); - let outcome = collector.collect_signatures().await; - assert!(outcome.successful()) - } - - #[actix_rt::test] - async fn continues_even_with_failed_tx_when_configured_to() { - let factor_sources = &HDFactorSource::all(); - let a0 = &Account::a0(); - let a1 = &Account::a1(); - - let t0 = TransactionIntent::address_of([a1], []); - let t1 = TransactionIntent::address_of([a0], []); - - let profile = Profile::new(factor_sources.clone(), [a0, a1], []); - - let collector = SignaturesCollector::new( - SigningFinishEarlyStrategy::new( - WhenAllTransactionsAreValid(FinishEarly), - WhenSomeTransactionIsInvalid(Continue), - ), - IndexSet::::from_iter([t0.clone(), t1.clone()]), - Arc::new(TestSignatureCollectingInteractors::new( - SimulatedUser::prudent_with_failures(SimulatedFailures::with_simulated_failures([ - FactorSourceIDFromHash::fs1(), - ])), - )), - &profile, - ) - .unwrap(); - - let outcome = collector.collect_signatures().await; - assert!(!outcome.successful()); - assert_eq!(outcome.failed_transactions().len(), 1); - assert_eq!(outcome.successful_transactions().len(), 1); - } - - #[actix_rt::test] - async fn continues_even_when_all_valid_if_configured_to() { - sensible_env_logger::safe_init!(); - let test = async move |when_all_valid: WhenAllTransactionsAreValid, - expected_sig_count: usize| { - let factor_sources = &HDFactorSource::all(); - let a5 = &Account::a5(); - - let t0 = TransactionIntent::address_of([a5], []); - - let profile = Profile::new(factor_sources.clone(), [a5], []); - - let collector = SignaturesCollector::new( - SigningFinishEarlyStrategy::new( - when_all_valid, - WhenSomeTransactionIsInvalid::default(), - ), - IndexSet::<_>::just(t0.clone()), - Arc::new(TestSignatureCollectingInteractors::new( - SimulatedUser::prudent_no_fail(), - )), - &profile, - ) - .unwrap(); - - let outcome = collector.collect_signatures().await; - assert!(outcome.successful()); - assert_eq!( - outcome.signatures_of_successful_transactions().len(), - expected_sig_count - ); - }; - - test(WhenAllTransactionsAreValid(FinishEarly), 1).await; - test(WhenAllTransactionsAreValid(Continue), 2).await; - } - - #[test] - fn factor_source_kinds_order() { - let kinds = HDFactorSource::all() - .into_iter() - .map(|f| f.factor_source_kind()) - .collect::>(); - let mut kinds = kinds.into_iter().collect_vec(); - kinds.sort(); - let kinds = kinds.into_iter().collect::>(); - assert_eq!( - kinds, - IndexSet::::from_iter([ - FactorSourceKind::Ledger, - FactorSourceKind::Arculus, - FactorSourceKind::Yubikey, - FactorSourceKind::SecurityQuestions, - FactorSourceKind::OffDeviceMnemonic, - FactorSourceKind::Device, - ]) - ) - } - - #[test] - fn test_profile() { - let factor_sources = &HDFactorSource::all(); - let a0 = &Account::a0(); - let a1 = &Account::a1(); - let a2 = &Account::a2(); - let a6 = &Account::a6(); - - let p0 = &Persona::p0(); - let p1 = &Persona::p1(); - let p2 = &Persona::p2(); - let p6 = &Persona::p6(); - - let t0 = TransactionIntent::address_of([a0, a1], [p0, p1]); - let t1 = TransactionIntent::address_of([a0, a1, a2], []); - let t2 = TransactionIntent::address_of([], [p0, p1, p2]); - let t3 = TransactionIntent::address_of([a6], [p6]); - - let profile = Profile::new(factor_sources.clone(), [a0, a1, a2, a6], [p0, p1, p2, p6]); - - let collector = SignaturesCollector::new( - SigningFinishEarlyStrategy::default(), - IndexSet::::from_iter([ - t0.clone(), - t1.clone(), - t2.clone(), - t3.clone(), - ]), - Arc::new(TestSignatureCollectingInteractors::new( - SimulatedUser::prudent_no_fail(), - )), - &profile, - ) - .unwrap(); - - let petitions = collector.petitions(); - - assert_eq!(petitions.txid_to_petition.borrow().len(), 4); - - { - let petitions_ref = petitions.txid_to_petition.borrow(); - let petition = petitions_ref.get(&t3.intent_hash).unwrap(); - let for_entities = petition.for_entities.borrow().clone(); - let pet6 = for_entities.get(&a6.address()).unwrap(); - - let paths6 = pet6 - .all_factor_instances() - .iter() - .map(|f| f.factor_instance().derivation_path()) - .collect_vec(); - - pretty_assertions::assert_eq!( - paths6, - iter::repeat_n( - DerivationPath::new( - NetworkID::Mainnet, - CAP26EntityKind::Account, - CAP26KeyKind::TransactionSigning, - HDPathComponent::securifying_base_index(6) - ), - 5 - ) - .collect_vec() - ); - } - - let assert_petition = |t: &TransactionIntent, - threshold_factors: HashMap< - AddressOfAccountOrPersona, - HashSet, - >, - override_factors: HashMap< - AddressOfAccountOrPersona, - HashSet, - >| { - let petitions_ref = petitions.txid_to_petition.borrow(); - let petition = petitions_ref.get(&t.intent_hash).unwrap(); - assert_eq!(petition.intent_hash, t.intent_hash); - - let mut addresses = threshold_factors.keys().collect::>(); - addresses.extend(override_factors.keys().collect::>()); - - assert_eq!( - petition - .for_entities - .borrow() - .keys() - .collect::>(), - addresses - ); - - assert!(petition - .for_entities - .borrow() - .iter() - .all(|(a, p)| { p.entity == *a })); - - assert!(petition - .for_entities - .borrow() - .iter() - .all(|(_, p)| { p.intent_hash == t.intent_hash })); - - for (k, v) in petition.for_entities.borrow().iter() { - let threshold = threshold_factors.get(k); - if let Some(actual_threshold) = &v.threshold_factors { - let threshold = threshold.unwrap().clone(); - assert_eq!( - actual_threshold - .borrow() - .factor_instances() - .into_iter() - .map(|f| f.factor_source_id) - .collect::>(), - threshold - ); - } else { - assert!(threshold.is_none()); - } - - let override_ = override_factors.get(k); - if let Some(actual_override) = &v.override_factors { - let override_ = override_.unwrap().clone(); - assert_eq!( - actual_override - .borrow() - .factor_instances() - .into_iter() - .map(|f| f.factor_source_id) - .collect::>(), - override_ - ); - } else { - assert!(override_.is_none()); - } - } - }; - assert_petition( - &t0, - HashMap::from_iter([ - (a0.address(), HashSet::just(FactorSourceIDFromHash::fs0())), - (a1.address(), HashSet::just(FactorSourceIDFromHash::fs1())), - (p0.address(), HashSet::just(FactorSourceIDFromHash::fs0())), - (p1.address(), HashSet::just(FactorSourceIDFromHash::fs1())), - ]), - HashMap::new(), - ); - - assert_petition( - &t1, - HashMap::from_iter([ - (a0.address(), HashSet::just(FactorSourceIDFromHash::fs0())), - (a1.address(), HashSet::just(FactorSourceIDFromHash::fs1())), - (a2.address(), HashSet::just(FactorSourceIDFromHash::fs0())), - ]), - HashMap::new(), - ); - - assert_petition( - &t2, - HashMap::from_iter([ - (p0.address(), HashSet::just(FactorSourceIDFromHash::fs0())), - (p1.address(), HashSet::just(FactorSourceIDFromHash::fs1())), - (p2.address(), HashSet::just(FactorSourceIDFromHash::fs0())), - ]), - HashMap::new(), - ); - - assert_petition( - &t3, - HashMap::from_iter([ - ( - a6.address(), - HashSet::from_iter([ - FactorSourceIDFromHash::fs0(), - FactorSourceIDFromHash::fs3(), - FactorSourceIDFromHash::fs5(), - ]), - ), - ( - p6.address(), - HashSet::from_iter([ - FactorSourceIDFromHash::fs0(), - FactorSourceIDFromHash::fs3(), - FactorSourceIDFromHash::fs5(), - ]), - ), - ]), - HashMap::from_iter([ - ( - a6.address(), - HashSet::from_iter([ - FactorSourceIDFromHash::fs1(), - FactorSourceIDFromHash::fs4(), - ]), - ), - ( - p6.address(), - HashSet::from_iter([ - FactorSourceIDFromHash::fs1(), - FactorSourceIDFromHash::fs4(), - ]), - ), - ]), - ); - } -} diff --git a/src/signing/collector/signatures_collector_dependencies.rs b/src/signing/collector/signatures_collector_dependencies.rs deleted file mode 100644 index 0bfa193b..00000000 --- a/src/signing/collector/signatures_collector_dependencies.rs +++ /dev/null @@ -1,36 +0,0 @@ -use crate::prelude::*; - -pub(super) struct SignaturesCollectorDependencies { - /// If `true` we stop collecting signatures as soon as all transactions are - /// valid. This is typically always set to `true`, but can be useful for - /// tests to set to `false` to see how the system behaves. - pub(super) finish_early_strategy: SigningFinishEarlyStrategy, - - /// A collection of "interactors" used to sign with factor sources. - pub(super) interactors: Arc, - - /// Factor sources grouped by kind, sorted according to "friction order", - /// that is, we want to control which FactorSourceKind users sign with - /// first, second etc, e.g. typically we prompt user to sign with Ledgers - /// first, and if a user might lack access to that Ledger device, then it is - /// best to "fail fast", otherwise we might waste the users time, if she has - /// e.g. answered security questions and then is asked to use a Ledger - /// she might not have handy at the moment - or might not be in front of a - /// computer and thus unable to make a connection between the Radix Wallet - /// and a Ledger device. - pub(super) factors_of_kind: IndexSet, -} - -impl SignaturesCollectorDependencies { - pub(crate) fn new( - finish_early_strategy: SigningFinishEarlyStrategy, - interactors: Arc, - factors_of_kind: IndexSet, - ) -> Self { - Self { - finish_early_strategy, - interactors, - factors_of_kind, - } - } -} diff --git a/src/signing/collector/signatures_collector_preprocessor.rs b/src/signing/collector/signatures_collector_preprocessor.rs deleted file mode 100644 index 2e68d8f5..00000000 --- a/src/signing/collector/signatures_collector_preprocessor.rs +++ /dev/null @@ -1,121 +0,0 @@ -use crate::prelude::*; - -pub(crate) struct SignaturesCollectorPreprocessor { - transactions: IndexSet, -} - -pub(crate) fn sort_group_factors( - used_factor_sources: HashSet, -) -> IndexSet { - let factors_of_kind: HashMap> = used_factor_sources - .into_iter() - .into_grouping_map_by(|x| x.factor_source_kind()) - .collect::>(); - - let mut factors_of_kind = factors_of_kind - .into_iter() - .map(|(k, v)| (k, v.into_iter().sorted().collect::>())) - .collect::>>(); - - factors_of_kind.sort_keys(); - - factors_of_kind - .into_iter() - .map(|(k, v)| FactorSourcesOfKind::new(k, v).expect("All factors should be of the same kind, since this is calling iter on a Map, using kind as key. Did you just move around lines of code?")) - .collect::>() -} - -impl SignaturesCollectorPreprocessor { - pub(super) fn new(transactions: IndexSet) -> Self { - Self { transactions } - } - - pub(super) fn preprocess( - self, - all_factor_sources_in_profile: IndexSet, - ) -> (Petitions, IndexSet) { - let transactions = self.transactions; - let mut petitions_for_all_transactions = - IndexMap::::new(); - - let all_factor_sources_in_profile = all_factor_sources_in_profile - .into_iter() - .map(|f| (f.factor_source_id(), f)) - .collect::>(); - - let mut factor_to_payloads = HashMap::>::new(); - - let mut used_factor_sources = HashSet::::new(); - - let mut use_factor_in_tx = |id: &FactorSourceIDFromHash, txid: &IntentHash| { - if let Some(ref mut txids) = factor_to_payloads.get_mut(id) { - txids.insert(txid.clone()); - } else { - factor_to_payloads.insert(*id, IndexSet::just(txid.clone())); - } - - assert!(!factor_to_payloads.is_empty()); - - let factor_source = all_factor_sources_in_profile - .get(id) - .expect("Should have all factor sources"); - used_factor_sources.insert(factor_source.clone()); - - assert!(!used_factor_sources.is_empty()); - }; - - for transaction in transactions.into_iter() { - let mut petitions_for_entities = - HashMap::::new(); - - for entity in transaction.entities_requiring_auth() { - let address = entity.address(); - match entity.security_state() { - EntitySecurityState::Securified(sec) => { - let primary_role_matrix = sec.matrix; - - let mut add = |factors: Vec| { - factors.into_iter().for_each(|f| { - let factor_source_id = f.factor_source_id; - use_factor_in_tx(&factor_source_id, &transaction.intent_hash); - }) - }; - - add(primary_role_matrix.override_factors.clone()); - add(primary_role_matrix.threshold_factors.clone()); - let petition = PetitionForEntity::new_securified( - transaction.intent_hash.clone(), - address.clone(), - primary_role_matrix, - ); - petitions_for_entities.insert(address.clone(), petition); - } - EntitySecurityState::Unsecured(uec) => { - let factor_instance = uec; - let factor_source_id = factor_instance.factor_source_id; - use_factor_in_tx(&factor_source_id, &transaction.intent_hash); - let petition = PetitionForEntity::new_unsecurified( - transaction.intent_hash.clone(), - address.clone(), - factor_instance, - ); - petitions_for_entities.insert(address.clone(), petition); - } - } - } - - let petition_of_tx = PetitionForTransaction::new( - transaction.intent_hash.clone(), - petitions_for_entities, - ); - - petitions_for_all_transactions.insert(transaction.intent_hash, petition_of_tx); - } - - let factors_of_kind = sort_group_factors(used_factor_sources); - - let petitions = Petitions::new(factor_to_payloads, petitions_for_all_transactions); - - (petitions, factors_of_kind) - } -} diff --git a/src/signing/collector/signatures_collector_state.rs b/src/signing/collector/signatures_collector_state.rs deleted file mode 100644 index 659094c0..00000000 --- a/src/signing/collector/signatures_collector_state.rs +++ /dev/null @@ -1,14 +0,0 @@ -use crate::prelude::*; - -#[derive(derive_more::Debug)] -#[debug("{:#?}", petitions.borrow())] -pub(super) struct SignaturesCollectorState { - pub(super) petitions: RefCell, -} -impl SignaturesCollectorState { - pub(crate) fn new(petitions: Petitions) -> Self { - Self { - petitions: RefCell::new(petitions), - } - } -} diff --git a/src/signing/collector/signing_finish_early_strategy.rs b/src/signing/collector/signing_finish_early_strategy.rs deleted file mode 100644 index b71c7efd..00000000 --- a/src/signing/collector/signing_finish_early_strategy.rs +++ /dev/null @@ -1,116 +0,0 @@ -use crate::prelude::*; - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct WhenAllTransactionsAreValid(pub SignaturesCollectingContinuation); - -impl WhenAllTransactionsAreValid { - pub fn finish_early() -> Self { - Self(SignaturesCollectingContinuation::FinishEarly) - } - pub fn r#continue() -> Self { - Self(SignaturesCollectingContinuation::Continue) - } -} - -impl Default for WhenAllTransactionsAreValid { - fn default() -> Self { - Self::finish_early() - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct WhenSomeTransactionIsInvalid(pub SignaturesCollectingContinuation); - -impl WhenSomeTransactionIsInvalid { - pub fn finish_early() -> Self { - Self(SignaturesCollectingContinuation::FinishEarly) - } - pub fn r#continue() -> Self { - Self(SignaturesCollectingContinuation::Continue) - } -} - -impl Default for WhenSomeTransactionIsInvalid { - fn default() -> Self { - Self::r#continue() - } -} - -/// Strategy to use for finishing early, i.e. stop collecting more signatures -#[derive(Clone, Default, Copy, Debug, PartialEq, Eq)] -pub struct SigningFinishEarlyStrategy { - pub(crate) when_all_transactions_are_valid: WhenAllTransactionsAreValid, - pub(crate) when_some_transaction_is_invalid: WhenSomeTransactionIsInvalid, -} -impl SigningFinishEarlyStrategy { - pub fn new( - when_all_transactions_are_valid: WhenAllTransactionsAreValid, - when_some_transaction_is_invalid: WhenSomeTransactionIsInvalid, - ) -> Self { - Self { - when_all_transactions_are_valid, - when_some_transaction_is_invalid, - } - } - - #[allow(unused)] - pub(crate) fn r#continue() -> Self { - Self::new( - WhenAllTransactionsAreValid::r#continue(), - WhenSomeTransactionIsInvalid::r#continue(), - ) - } - - #[allow(unused)] - pub(crate) fn finish_early() -> Self { - Self::new( - WhenAllTransactionsAreValid::finish_early(), - WhenSomeTransactionIsInvalid::finish_early(), - ) - } -} - -#[cfg(test)] -mod tests { - use super::*; - type Sut = SigningFinishEarlyStrategy; - - #[test] - fn test_continue() { - let sut = Sut::r#continue(); - assert_eq!( - sut.when_all_transactions_are_valid.0, - SignaturesCollectingContinuation::Continue - ); - assert_eq!( - sut.when_some_transaction_is_invalid.0, - SignaturesCollectingContinuation::Continue - ); - } - - #[test] - fn test_finish_early() { - let sut = Sut::finish_early(); - assert_eq!( - sut.when_all_transactions_are_valid.0, - SignaturesCollectingContinuation::FinishEarly - ); - assert_eq!( - sut.when_some_transaction_is_invalid.0, - SignaturesCollectingContinuation::FinishEarly - ); - } - - #[test] - fn test_default_is_finish_when_valid_continue_if_invalid() { - let sut = Sut::default(); - assert_eq!( - sut.when_all_transactions_are_valid.0, - SignaturesCollectingContinuation::FinishEarly - ); - assert_eq!( - sut.when_some_transaction_is_invalid.0, - SignaturesCollectingContinuation::Continue - ); - } -} diff --git a/src/signing/host_interaction/interactors/mod.rs b/src/signing/host_interaction/interactors/mod.rs deleted file mode 100644 index dc69c7af..00000000 --- a/src/signing/host_interaction/interactors/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -mod mono_factor_sign_interactor; -mod poly_factor_sign_interactor; -mod sign_interactor; - -pub use mono_factor_sign_interactor::*; -pub use poly_factor_sign_interactor::*; -pub use sign_interactor::*; diff --git a/src/signing/host_interaction/interactors/mono_factor_sign_interactor.rs b/src/signing/host_interaction/interactors/mono_factor_sign_interactor.rs deleted file mode 100644 index 0b6f9e48..00000000 --- a/src/signing/host_interaction/interactors/mono_factor_sign_interactor.rs +++ /dev/null @@ -1,20 +0,0 @@ -use crate::prelude::*; - -/// A interactor for a factor source kind which support performing -/// *Batch* signing *serially*. -/// -/// Meaning we initiate and prompt user for signing with one factor source -/// at a time, where each signing operation is support batch signing, that is -/// signing multiple transactions each with multiple keys (derivations paths). -/// -/// The user might chose to SKIP the current factor source, and move on to the -/// next one. -/// -/// Example of a MonoFactor Batch Signing Driver is SecurityQuestionsFactorSource, -/// where it does not make any sense to let user in poly answer multiple -/// questions from different security questions factor sources (in fact we -/// might not even even allow multiple SecurityQuestionsFactorSources to be used). -#[async_trait::async_trait] -pub trait MonoFactorSignInteractor { - async fn sign(&self, request: MonoFactorSignRequest) -> SignWithFactorsOutcome; -} diff --git a/src/signing/host_interaction/interactors/poly_factor_sign_interactor.rs b/src/signing/host_interaction/interactors/poly_factor_sign_interactor.rs deleted file mode 100644 index 11973262..00000000 --- a/src/signing/host_interaction/interactors/poly_factor_sign_interactor.rs +++ /dev/null @@ -1,24 +0,0 @@ -use crate::prelude::*; - -/// A interactor for a factor source kind which supports *Batch* usage of -/// multiple factor sources in poly. -/// -/// Most FactorSourceKinds does in fact NOT support poly usage, -/// e.g. signing using multiple factors sources at once, but some do, -/// typically the DeviceFactorSource does, i.e. we can load multiple -/// mnemonics from secure storage in one go and sign with all of them -/// "in poly". -/// -/// This is a bit of a misnomer, as we don't actually use them in poly, -/// but rather we iterate through all mnemonics and derive public keys/ -/// or sign a payload with each of them in sequence -/// -/// The user does not have the ability to SKIP a certain factor source, -/// instead either ALL factor sources are used to sign the transactions -/// or none. -/// -/// Example of a PolyFactor Batch Signing Driver is that for DeviceFactorSource. -#[async_trait::async_trait] -pub trait PolyFactorSignInteractor { - async fn sign(&self, request: PolyFactorSignRequest) -> SignWithFactorsOutcome; -} diff --git a/src/signing/host_interaction/interactors/sign_interactor.rs b/src/signing/host_interaction/interactors/sign_interactor.rs deleted file mode 100644 index 737c5baf..00000000 --- a/src/signing/host_interaction/interactors/sign_interactor.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::prelude::*; - -/// An interactor which can sign transactions - either in poly or mono. -pub enum SignInteractor { - PolyFactor(Arc), - MonoFactor(Arc), -} - -impl SignInteractor { - #[allow(unused)] - pub fn poly(interactor: Arc) -> Self { - Self::PolyFactor(interactor) - } - - #[allow(unused)] - pub fn mono(interactor: Arc) -> Self { - Self::MonoFactor(interactor) - } -} diff --git a/src/signing/host_interaction/mod.rs b/src/signing/host_interaction/mod.rs deleted file mode 100644 index 118e95b4..00000000 --- a/src/signing/host_interaction/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -mod interactors; -mod requests; -mod sign_interactors; -mod sign_response; - -pub use interactors::*; -pub use requests::*; -pub use sign_interactors::*; -pub use sign_response::*; diff --git a/src/signing/host_interaction/requests/mod.rs b/src/signing/host_interaction/requests/mod.rs deleted file mode 100644 index 4819c69a..00000000 --- a/src/signing/host_interaction/requests/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -mod mono_factor_sign_request; -mod mono_factor_sign_request_input; -mod poly_factor_sign_request; -mod transaction_sign_request_input; - -pub use mono_factor_sign_request::*; -pub(crate) use mono_factor_sign_request_input::*; -pub use poly_factor_sign_request::*; -pub(crate) use transaction_sign_request_input::*; diff --git a/src/signing/host_interaction/requests/mono_factor_sign_request.rs b/src/signing/host_interaction/requests/mono_factor_sign_request.rs deleted file mode 100644 index 959ca6be..00000000 --- a/src/signing/host_interaction/requests/mono_factor_sign_request.rs +++ /dev/null @@ -1,30 +0,0 @@ -use crate::prelude::*; - -/// A request to sign a batch of transactions with a single factor source. -#[derive(derive_more::Debug, Clone)] -#[debug("input: {:#?}", input)] -pub struct MonoFactorSignRequest { - /// The input needed to sign the transactions. - pub input: MonoFactorSignRequestInput, - - /// A collection of transactions which would be invalid if the user skips - /// signing with this factor source, or if we fail to sign - pub invalid_transactions_if_neglected: IndexSet, -} - -impl MonoFactorSignRequest { - pub fn new( - input: MonoFactorSignRequestInput, - invalid_transactions_if_neglected: IndexSet, - ) -> Self { - Self { - input, - invalid_transactions_if_neglected, - } - } - - #[allow(unused)] - pub(crate) fn factor_source_kind(&self) -> FactorSourceKind { - self.input.factor_source_kind() - } -} diff --git a/src/signing/host_interaction/requests/mono_factor_sign_request_input.rs b/src/signing/host_interaction/requests/mono_factor_sign_request_input.rs deleted file mode 100644 index ce42e719..00000000 --- a/src/signing/host_interaction/requests/mono_factor_sign_request_input.rs +++ /dev/null @@ -1,96 +0,0 @@ -use crate::prelude::*; - -/// A batch of transactions each batching over multiple keys (derivation paths) -/// to sign each transaction with. -#[derive(Clone, Debug, PartialEq, Eq, std::hash::Hash)] -pub struct MonoFactorSignRequestInput { - /// The ID of the factor source used to sign each per_transaction - pub factor_source_id: FactorSourceIDFromHash, - - // The `factor_source_id` of each item must match `self.factor_source_id`. - pub per_transaction: Vec, -} - -impl MonoFactorSignRequestInput { - /// # Panics - /// Panics if `per_transaction` is empty - /// - /// Also panics if `per_transaction` if the factor source id - /// of each request does not match `factor_source_id`. - pub(crate) fn new( - factor_source_id: FactorSourceIDFromHash, - per_transaction: IndexSet, - ) -> Self { - assert!( - !per_transaction.is_empty(), - "Invalid input. No transaction to sign, this is a programmer error." - ); - - assert!(per_transaction - .iter() - .all(|f| f.factor_source_id == factor_source_id), "Discprepancy! Input for one of the transactions has a mismatching FactorSourceIDFromHash, this is a programmer error."); - - Self { - factor_source_id, - per_transaction: per_transaction.into_iter().collect(), - } - } - - /// Returns the factor source kind of the factor source id. - #[allow(unused)] - pub(crate) fn factor_source_kind(&self) -> FactorSourceKind { - self.factor_source_id.kind - } -} - -impl HasSampleValues for MonoFactorSignRequestInput { - /// Creates a new MonoFactorSignRequestInput with sample values. - fn sample() -> Self { - Self::new( - FactorSourceIDFromHash::sample(), - IndexSet::just(TransactionSignRequestInput::sample()), - ) - } - - /// Creates a new MonoFactorSignRequestInput with sample values. - fn sample_other() -> Self { - Self::new( - FactorSourceIDFromHash::sample_other(), - IndexSet::just(TransactionSignRequestInput::sample_other()), - ) - } -} - -#[cfg(test)] -mod tests { - use super::*; - type Sut = MonoFactorSignRequestInput; - - #[test] - fn equality() { - assert_eq!(Sut::sample(), Sut::sample()); - assert_eq!(Sut::sample_other(), Sut::sample_other()); - } - - #[test] - fn inequality() { - assert_ne!(Sut::sample(), Sut::sample_other()); - } - - #[test] - #[should_panic(expected = "Invalid input. No transaction to sign, this is a programmer error.")] - fn panics_if_per_transaction_is_empty() { - Sut::new(FactorSourceIDFromHash::sample(), IndexSet::new()); - } - - #[test] - #[should_panic( - expected = "Discprepancy! Input for one of the transactions has a mismatching FactorSourceIDFromHash, this is a programmer error." - )] - fn panics_if_factor_source_mismatch() { - Sut::new( - FactorSourceIDFromHash::sample(), - IndexSet::just(TransactionSignRequestInput::sample_other()), - ); - } -} diff --git a/src/signing/host_interaction/requests/poly_factor_sign_request.rs b/src/signing/host_interaction/requests/poly_factor_sign_request.rs deleted file mode 100644 index 97df356c..00000000 --- a/src/signing/host_interaction/requests/poly_factor_sign_request.rs +++ /dev/null @@ -1,84 +0,0 @@ -use crate::prelude::*; - -/// A collection of **many** factor sources to use to sign, transactions with multiple keys -/// (derivations paths). -#[derive(derive_more::Debug, Clone)] -#[debug("per_factor_source: {:#?}", per_factor_source)] -pub struct PolyFactorSignRequest { - factor_source_kind: FactorSourceKind, - - /// Per factor source, a set of transactions to sign, with - /// multiple derivations paths. - pub per_factor_source: IndexMap, - - /// A collection of transactions which would be invalid if the user skips - /// signing with this factor source. - pub invalid_transactions_if_neglected: IndexSet, -} - -impl PolyFactorSignRequest { - /// # Panics - /// Panics if `per_factor_source` is empty - /// - /// Panics if not all factor sources are of the same kind - pub(crate) fn new( - factor_source_kind: FactorSourceKind, - per_factor_source: IndexMap, - invalid_transactions_if_neglected: IndexSet, - ) -> Self { - assert!( - !per_factor_source.is_empty(), - "Invalid input, per_factor_source must not be empty, this is a programmer error." - ); - assert!( - per_factor_source - .values() - .all(|f| f.factor_source_id.kind == factor_source_kind), - "Discrepancy! All factor sources must be of the same kind, this is a programmer error." - ); - - Self { - factor_source_kind, - per_factor_source, - invalid_transactions_if_neglected, - } - } - - pub fn factor_source_ids(&self) -> IndexSet { - self.per_factor_source.keys().cloned().collect() - } - - #[allow(unused)] - pub(crate) fn factor_source_kind(&self) -> FactorSourceKind { - self.factor_source_kind - } -} - -#[cfg(test)] -mod tests { - use super::*; - type Sut = PolyFactorSignRequest; - - #[test] - #[should_panic( - expected = "Invalid input, per_factor_source must not be empty, this is a programmer error." - )] - fn panics_if_per_factor_source_is_empty() { - Sut::new(FactorSourceKind::Device, IndexMap::new(), IndexSet::new()); - } - - #[test] - #[should_panic( - expected = "Discrepancy! All factor sources must be of the same kind, this is a programmer error." - )] - fn panics_if_wrong_factor_source_kind() { - Sut::new( - FactorSourceKind::Arculus, - IndexMap::just(( - FactorSourceIDFromHash::sample(), - MonoFactorSignRequestInput::sample(), - )), - IndexSet::new(), - ); - } -} diff --git a/src/signing/host_interaction/requests/transaction_sign_request_input.rs b/src/signing/host_interaction/requests/transaction_sign_request_input.rs deleted file mode 100644 index 229360c5..00000000 --- a/src/signing/host_interaction/requests/transaction_sign_request_input.rs +++ /dev/null @@ -1,109 +0,0 @@ -use crate::prelude::*; - -/// A batch of keys (derivation paths) all being factor instances of a HDFactorSource -/// with id `factor_source_id` to sign a single transaction with, which hash -/// is `intent_hash`. -#[derive(PartialEq, Eq, Clone, Debug, Hash)] -pub struct TransactionSignRequestInput { - /// Hash to sign - intent_hash: IntentHash, - - /// ID of factor to use to sign - pub(crate) factor_source_id: FactorSourceIDFromHash, - - /// The derivation paths to use to derive the private keys to sign with. The - /// `factor_source_id` of each item must match `factor_source_id`. - owned_factor_instances: Vec, -} - -impl TransactionSignRequestInput { - /// # Panics - /// Panics if any of the owned factor instances does not match the `factor_source_id`. - /// - /// Panics if `owned_factor_instances` is empty. - pub(crate) fn new( - intent_hash: IntentHash, - factor_source_id: FactorSourceIDFromHash, - owned_factor_instances: IndexSet, - ) -> Self { - assert!( - !owned_factor_instances.is_empty(), - "Invalid input, `owned_factor_instances` must not be empty." - ); - assert!(owned_factor_instances - .iter() - .all(|f| f.by_factor_source(factor_source_id)), "Discrepancy! Mismatch between FactorSourceIDFromHash of owned factor instances and specified FactorSourceIDFromHash, this is a programmer error."); - Self { - intent_hash, - factor_source_id, - owned_factor_instances: owned_factor_instances.into_iter().collect_vec(), - } - } - - #[allow(unused)] - pub fn signature_inputs(&self) -> IndexSet { - self.owned_factor_instances - .clone() - .into_iter() - .map(|fi| HDSignatureInput::new(self.intent_hash.clone(), fi)) - .collect() - } -} - -impl HasSampleValues for TransactionSignRequestInput { - fn sample() -> Self { - Self::new( - IntentHash::sample(), - FactorSourceIDFromHash::sample(), - IndexSet::just(OwnedFactorInstance::sample()), - ) - } - - fn sample_other() -> Self { - Self::new( - IntentHash::sample_other(), - FactorSourceIDFromHash::sample_other(), - IndexSet::just(OwnedFactorInstance::sample_other()), - ) - } -} - -#[cfg(test)] -mod tests_batch_req { - use super::*; - - type Sut = TransactionSignRequestInput; - - #[test] - fn equality() { - assert_eq!(Sut::sample(), Sut::sample()); - assert_eq!(Sut::sample_other(), Sut::sample_other()); - } - - #[test] - fn inequality() { - assert_ne!(Sut::sample(), Sut::sample_other()); - } - - #[test] - #[should_panic(expected = "Invalid input, `owned_factor_instances` must not be empty.")] - fn panics_if_owned_factors_is_empty() { - Sut::new( - IntentHash::sample(), - FactorSourceIDFromHash::sample(), - IndexSet::new(), - ); - } - - #[test] - #[should_panic( - expected = "Discrepancy! Mismatch between FactorSourceIDFromHash of owned factor instances and specified FactorSourceIDFromHash, this is a programmer error." - )] - fn panics_mismatch_factor_source_id() { - Sut::new( - IntentHash::sample(), - FactorSourceIDFromHash::sample(), - IndexSet::just(OwnedFactorInstance::sample_other()), - ); - } -} diff --git a/src/signing/host_interaction/sign_interactors.rs b/src/signing/host_interaction/sign_interactors.rs deleted file mode 100644 index 42c983a5..00000000 --- a/src/signing/host_interaction/sign_interactors.rs +++ /dev/null @@ -1,6 +0,0 @@ -use crate::prelude::*; - -/// A collection of "interactors" which can sign transactions. -pub trait SignInteractors { - fn interactor_for(&self, kind: FactorSourceKind) -> SignInteractor; -} diff --git a/src/signing/host_interaction/sign_response.rs b/src/signing/host_interaction/sign_response.rs deleted file mode 100644 index 4aa6664f..00000000 --- a/src/signing/host_interaction/sign_response.rs +++ /dev/null @@ -1,29 +0,0 @@ -use crate::prelude::*; - -/// The response of a batch signing request, either a PolyFactor or MonoFactor signing -/// request, matters not, because the goal is to have signed all transactions with -/// enough keys (derivation paths) needed for it to be valid when submitted to the -/// Radix network. -#[derive(Clone, PartialEq, Eq, derive_more::Debug)] -#[debug("SignResponse {{ signatures: {:#?} }}", signatures.values().map(|f| format!("{:#?}", f)).join(", "))] -pub struct SignResponse { - pub signatures: IndexMap>, -} - -impl SignResponse { - pub fn new(signatures: IndexMap>) -> Self { - Self { signatures } - } - - pub fn with_signatures(signatures: IndexSet) -> Self { - let signatures = signatures - .into_iter() - .into_group_map_by(|x| x.factor_source_id()); - Self::new( - signatures - .into_iter() - .map(|(k, v)| (k, IndexSet::from_iter(v))) - .collect(), - ) - } -} diff --git a/src/signing/mod.rs b/src/signing/mod.rs deleted file mode 100644 index 6e4c8073..00000000 --- a/src/signing/mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -mod collector; -mod host_interaction; -mod petition_types; -mod signatures_outcome_types; -mod tests; -mod tx_to_sign; - -pub(crate) use tx_to_sign::*; - -pub use collector::*; -pub use host_interaction::*; -pub use petition_types::*; -pub use signatures_outcome_types::*; diff --git a/src/signing/petition_types/factor_list_kind.rs b/src/signing/petition_types/factor_list_kind.rs deleted file mode 100644 index bcdbe2b1..00000000 --- a/src/signing/petition_types/factor_list_kind.rs +++ /dev/null @@ -1,36 +0,0 @@ -use crate::HasSampleValues; - -/// A kind of factor list, either threshold, or override kind. -#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] -pub enum FactorListKind { - Threshold, - Override, -} - -impl HasSampleValues for FactorListKind { - fn sample() -> Self { - Self::Threshold - } - - fn sample_other() -> Self { - Self::Override - } -} - -#[cfg(test)] -mod tests { - use super::*; - - type Sut = FactorListKind; - - #[test] - fn equality() { - assert_eq!(Sut::sample(), Sut::sample()); - assert_eq!(Sut::sample_other(), Sut::sample_other()); - } - - #[test] - fn inequality() { - assert_ne!(Sut::sample(), Sut::sample_other()); - } -} diff --git a/src/signing/petition_types/mod.rs b/src/signing/petition_types/mod.rs deleted file mode 100644 index 432cedf4..00000000 --- a/src/signing/petition_types/mod.rs +++ /dev/null @@ -1,14 +0,0 @@ -mod factor_list_kind; -mod petition_for_entity; -mod petition_for_factors_types; -mod petition_for_transaction; -mod petitions; -mod petitions_status; - -pub(crate) use factor_list_kind::*; -pub(crate) use petition_for_entity::*; -pub(crate) use petition_for_transaction::*; -pub(crate) use petitions::*; -pub(crate) use petitions_status::*; - -pub use petition_for_factors_types::*; diff --git a/src/signing/petition_types/petition_for_entity.rs b/src/signing/petition_types/petition_for_entity.rs deleted file mode 100644 index 0416d607..00000000 --- a/src/signing/petition_types/petition_for_entity.rs +++ /dev/null @@ -1,571 +0,0 @@ -use crate::prelude::*; - -/// Petition of signatures from an entity in a transaction. -/// Essentially a wrapper around a tuple -/// `{ threshold: PetitionForFactors, override: PetitionForFactors }` -#[derive(Clone, PartialEq, Eq, derive_more::Debug)] -#[debug("{}", self.debug_str())] -pub(crate) struct PetitionForEntity { - /// The owner of these factors - pub(crate) entity: AddressOfAccountOrPersona, - - /// Index and hash of transaction - pub(crate) intent_hash: IntentHash, - - /// Petition with threshold factors - pub(crate) threshold_factors: Option>, - - /// Petition with override factors - pub(crate) override_factors: Option>, -} - -impl PetitionForEntity { - pub(super) fn new( - intent_hash: IntentHash, - entity: AddressOfAccountOrPersona, - threshold_factors: impl Into>, - override_factors: impl Into>, - ) -> Self { - let threshold_factors = threshold_factors.into(); - let override_factors = override_factors.into(); - if threshold_factors.is_none() && override_factors.is_none() { - panic!("Programmer error! Must have at least one factors list."); - } - Self { - entity, - intent_hash, - threshold_factors: threshold_factors.map(RefCell::new), - override_factors: override_factors.map(RefCell::new), - } - } - - /// Creates a new Petition from an entity which is securified, i.e. has a matrix of factors. - pub(crate) fn new_securified( - intent_hash: IntentHash, - entity: AddressOfAccountOrPersona, - matrix: MatrixOfFactorInstances, - ) -> Self { - Self::new( - intent_hash, - entity, - PetitionForFactors::new_threshold(matrix.threshold_factors, matrix.threshold as i8), - PetitionForFactors::new_override(matrix.override_factors), - ) - } - - /// Creates a new Petition from an entity which is unsecurified, i.e. has a single factor. - pub(crate) fn new_unsecurified( - intent_hash: IntentHash, - entity: AddressOfAccountOrPersona, - instance: HierarchicalDeterministicFactorInstance, - ) -> Self { - Self::new( - intent_hash, - entity, - PetitionForFactors::new_unsecurified(instance), - None, - ) - } - - /// Returns `true` if signatures requirement has been fulfilled, either by - /// override factors or by threshold factors - pub(crate) fn has_signatures_requirement_been_fulfilled(&self) -> bool { - self.status() == PetitionForFactorsStatus::Finished(PetitionFactorsStatusFinished::Success) - } - - /// Returns `true` if the transaction of this petition already has failed due - /// to too many factors neglected - pub(crate) fn has_failed(&self) -> bool { - self.status() == PetitionForFactorsStatus::Finished(PetitionFactorsStatusFinished::Fail) - } - - /// Returns the aggregate of **all** owned factor instances from both lists, either threshold or override. - pub(crate) fn all_factor_instances(&self) -> IndexSet { - self.access_both_list_then_form_union(|l| l.factor_instances()) - .into_iter() - .map(|f| OwnedFactorInstance::owned_factor_instance(self.entity.clone(), f.clone())) - .collect::>() - } - - /// Returns the aggregate of all **neglected** factor instances from both lists, either threshold or override, - /// that is, all factor instances but filtered out only those from FactorSources which have been neglected. - pub(crate) fn all_neglected_factor_instances(&self) -> IndexSet { - self.access_both_list_then_form_union(|f| f.all_neglected()) - } - - /// Returns the aggregate of all **neglected** factor sources from both lists, either threshold or override. - pub(crate) fn all_neglected_factor_sources(&self) -> IndexSet { - self.all_neglected_factor_instances() - .into_iter() - .map(|n| n.as_neglected_factor()) - .collect::>() - } - - /// Returrns the aggregate of all signatures from both lists, either threshold or override. - pub(crate) fn all_signatures(&self) -> IndexSet { - self.access_both_list_then_form_union(|f| f.all_signatures()) - } - - /// Mutates this petition by adding a signature to it. The signature is added to the relevant - /// list, either threshold or override. - /// - /// # Panics - /// Panics if this factor source has already been neglected or signed with. - /// - /// Or panics if the factor source is not known to this petition. - pub(crate) fn add_signature(&self, signature: HDSignature) { - self.access_both_list(|l| l.add_signature_if_relevant(&signature), |t, o| { - match (t, o) { - (Some(true), Some(true)) => { - unreachable!("Matrix of FactorInstances does not allow for a factor to be present in both threshold and override list, thus this will never happen.") - } - (Some(false), Some(false)) => panic!("Factor source not found in any of the lists."), - (None, None) => panic!("Programmer error! Must have at least one factors list."), - _ => (), - } - }) - } - - /// Queries if the authorization of the entity in this transaction already is irrelevant, since - /// too many factors have been neglected. - pub(crate) fn should_neglect_factors_due_to_irrelevant( - &self, - factor_source_ids: IndexSet, - ) -> bool { - assert!(self.references_any_factor_source(&factor_source_ids)); - match self.status() { - PetitionForFactorsStatus::Finished(PetitionFactorsStatusFinished::Fail) => true, - PetitionForFactorsStatus::Finished(PetitionFactorsStatusFinished::Success) => false, - PetitionForFactorsStatus::InProgress => false, - } - } - - /// Returns this petitions entity if the transaction would be invalid if the given factor sources - /// would be neglected. - pub(crate) fn invalid_transaction_if_neglected_factors( - &self, - factor_source_ids: IndexSet, - ) -> Option { - let status_if_neglected = self.status_if_neglected_factors(factor_source_ids); - match status_if_neglected { - PetitionForFactorsStatus::Finished(finished_reason) => match finished_reason { - PetitionFactorsStatusFinished::Fail => Some(self.entity.clone()), - PetitionFactorsStatusFinished::Success => None, - }, - PetitionForFactorsStatus::InProgress => None, - } - } - - pub(crate) fn status_if_neglected_factors( - &self, - factor_source_ids: IndexSet, - ) -> PetitionForFactorsStatus { - let simulation = self.clone(); - for factor_source_id in factor_source_ids.iter() { - simulation.neglect_if_referenced(NeglectedFactor::new( - NeglectFactorReason::Simulation, - *factor_source_id, - )) - } - simulation.status() - } - - /// Queries if this petition references any of the factor sources in the set of ids - /// by checking bot hteh threshold and the override factors list. - pub(crate) fn references_any_factor_source( - &self, - factor_source_ids: &IndexSet, - ) -> bool { - factor_source_ids - .iter() - .any(|f| self.references_factor_source_with_id(f)) - } - - /// Queries if this petition references the factor source with the given id, by - /// checking both the threshold and override factors list. - pub(crate) fn references_factor_source_with_id(&self, id: &FactorSourceIDFromHash) -> bool { - self.access_both_list( - |p| p.references_factor_source_with_id(id), - |a, b| a.unwrap_or(false) || b.unwrap_or(false), - ) - } - - /// If this petitions references the neglected factor source, disregarding if it is a threshold - /// or override factor, it will be neglected. If the factor is not known to any of the lists - /// nothing happens. - pub(crate) fn neglect_if_referenced(&self, neglected: NeglectedFactor) { - self.access_both_list(|p| p.neglect_if_referenced(neglected.clone()), |_, _| ()); - } - - /// The "aggregated" status of this petition, i.e. the status of the threshold factors - /// and the status of the override factors merged together. E.g. (Threshold: InProgress, Override: InProgress) -> - /// Inprogress. And (Threshold: Finished(Fail), Override: InProgress) -> InProgress, - /// (Threshold: Finished(Fail), Override: Finished(Fail)) -> Finished(Fail) but - /// (Threshold: Finished(Success), Override: Inprogress) -> Finished(Success) - since - /// want to be able to finish early if the petition for this entity is already successful. - pub(crate) fn status(&self) -> PetitionForFactorsStatus { - use PetitionFactorsStatusFinished::*; - use PetitionForFactorsStatus::*; - - self.access_both_list( - |p| p.status(), - |maybe_threshold, maybe_override| { - if let Some(t) = &maybe_threshold { - trace!("Threshold factor status: {:?}", t); - } - if let Some(o) = &maybe_override { - trace!("Override factor status: {:?}", o); - } - match (maybe_threshold, maybe_override) { - (None, None) => { - panic!("Programmer error! Should have at least one factors list.") - } - (Some(threshold), None) => threshold, - (None, Some(r#override)) => r#override, - (Some(threshold), Some(r#override)) => match (threshold, r#override) { - (InProgress, InProgress) => PetitionForFactorsStatus::InProgress, - (Finished(Fail), InProgress) => PetitionForFactorsStatus::InProgress, - (InProgress, Finished(Fail)) => PetitionForFactorsStatus::InProgress, - (Finished(Fail), Finished(Fail)) => { - PetitionForFactorsStatus::Finished(Fail) - } - (Finished(Success), _) => PetitionForFactorsStatus::Finished(Success), - (_, Finished(Success)) => PetitionForFactorsStatus::Finished(Success), - }, - } - }, - ) - } -} - -// === Private === -impl PetitionForEntity { - /// Derefs and calls `access` on both lists respectively, if they exist. Then combines the results - /// of each list access using `combine`. - /// - /// This method is useful when you want to read out state for both list and somehow combine - /// that result, e.g. to form a union of all signatures - but not wanting to juggle `RefCell` - /// and `Option` repeatedly. - fn access_both_list( - &self, - access: impl Fn(&PetitionForFactors) -> T, - combine: impl Fn(Option, Option) -> U, - ) -> U { - let access_list_if_exists = |list: &Option>| { - list.as_ref().map(|refcell| access(&refcell.borrow())) - }; - let t = access_list_if_exists(&self.threshold_factors); - let o = access_list_if_exists(&self.override_factors); - combine(t, o) - } - - /// Derefes and calls `access` on both lists respectively, if they exist. The result of the `access` - /// of each list is then combined together using `IndexSet::union` and returned. - fn access_both_list_then_form_union( - &self, - access: impl Fn(&PetitionForFactors) -> IndexSet, - ) -> IndexSet - where - T: Eq + std::hash::Hash + Clone, - { - self.access_both_list( - |l| access(l), - |t, o| { - t.unwrap_or_default() - .union(&o.unwrap_or_default()) - .cloned() - .collect::>() - }, - ) - } - - #[allow(unused)] - fn debug_str(&self) -> String { - let thres: String = self - .threshold_factors - .clone() - .map(|f| format!("threshold_factors {:#?}", f.borrow())) - .unwrap_or_default(); - - let overr: String = self - .override_factors - .clone() - .map(|f| format!("override_factors {:#?}", f.borrow())) - .unwrap_or_default(); - - format!( - "intent_hash: {:#?}, entity: {:#?}, {:#?}{:#?}", - self.intent_hash, self.entity, thres, overr - ) - } -} - -// === SAMPLE VALUES === -impl PetitionForEntity { - fn from_entity(entity: impl Into, intent_hash: IntentHash) -> Self { - let entity = entity.into(); - match entity.security_state() { - EntitySecurityState::Securified(sec) => { - Self::new_securified(intent_hash, entity.address(), sec.matrix) - } - EntitySecurityState::Unsecured(factor) => { - Self::new_unsecurified(intent_hash, entity.address(), factor) - } - } - } -} - -impl HasSampleValues for PetitionForEntity { - fn sample() -> Self { - Self::from_entity(Account::sample_securified(), IntentHash::sample()) - } - - fn sample_other() -> Self { - Self::from_entity(Account::sample_unsecurified(), IntentHash::sample_other()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - type Sut = PetitionForEntity; - - #[test] - fn multiple_device_as_override_skipped_both_is_invalid() { - let d0 = HDFactorSource::fs0(); - let d1 = HDFactorSource::fs10(); - assert_eq!(d0.factor_source_kind(), FactorSourceKind::Device); - assert_eq!(d1.factor_source_kind(), FactorSourceKind::Device); - - let matrix = - MatrixOfFactorInstances::override_only([d0.clone(), d1.clone()].into_iter().map(|f| { - HierarchicalDeterministicFactorInstance::mainnet_tx_account( - HDPathComponent::securifying_base_index(0), - f.factor_source_id(), - ) - })); - let entity = AddressOfAccountOrPersona::Account(AccountAddress::sample()); - let tx = IntentHash::sample_third(); - let sut = Sut::new_securified(tx.clone(), entity.clone(), matrix); - let invalid = sut - .invalid_transaction_if_neglected_factors(IndexSet::from_iter([ - d0.factor_source_id(), - d1.factor_source_id(), - ])) - .unwrap(); - - assert_eq!(invalid.clone(), entity); - } - - #[test] - fn multiple_device_as_override_skipped_one_is_valid() { - let d0 = HDFactorSource::fs0(); - let d1 = HDFactorSource::fs10(); - assert_eq!(d0.factor_source_kind(), FactorSourceKind::Device); - assert_eq!(d1.factor_source_kind(), FactorSourceKind::Device); - - let matrix = - MatrixOfFactorInstances::override_only([d0.clone(), d1.clone()].into_iter().map(|f| { - HierarchicalDeterministicFactorInstance::mainnet_tx_account( - HDPathComponent::securifying_base_index(0), - f.factor_source_id(), - ) - })); - let entity = AddressOfAccountOrPersona::Account(AccountAddress::sample()); - let tx = IntentHash::sample_third(); - let sut = Sut::new_securified(tx.clone(), entity.clone(), matrix); - let invalid = - sut.invalid_transaction_if_neglected_factors(IndexSet::just(d0.factor_source_id())); - assert!(invalid.is_none()); - } - - #[test] - fn multiple_device_as_threshold_skipped_both_is_invalid() { - let d0 = HDFactorSource::fs0(); - let d1 = HDFactorSource::fs10(); - assert_eq!(d0.factor_source_kind(), FactorSourceKind::Device); - assert_eq!(d1.factor_source_kind(), FactorSourceKind::Device); - - let matrix = MatrixOfFactorInstances::threshold_only( - [d0.clone(), d1.clone()].into_iter().map(|f| { - HierarchicalDeterministicFactorInstance::mainnet_tx_account( - HDPathComponent::securifying_base_index(0), - f.factor_source_id(), - ) - }), - 2, - ); - - let entity = AddressOfAccountOrPersona::Account(AccountAddress::sample()); - let tx = IntentHash::sample_third(); - let sut = Sut::new_securified(tx.clone(), entity.clone(), matrix); - let invalid = sut - .invalid_transaction_if_neglected_factors(IndexSet::from_iter([ - d0.factor_source_id(), - d1.factor_source_id(), - ])) - .unwrap(); - assert_eq!(invalid, entity); - } - - #[test] - fn two_device_as_threshold_of_2_skipped_one_is_invalid() { - let d0 = HDFactorSource::fs0(); - let d1 = HDFactorSource::fs10(); - assert_eq!(d0.factor_source_kind(), FactorSourceKind::Device); - assert_eq!(d1.factor_source_kind(), FactorSourceKind::Device); - - let matrix = MatrixOfFactorInstances::threshold_only( - [d0.clone(), d1.clone()].into_iter().map(|f| { - HierarchicalDeterministicFactorInstance::mainnet_tx_account( - HDPathComponent::securifying_base_index(0), - f.factor_source_id(), - ) - }), - 2, - ); - - let entity = AddressOfAccountOrPersona::Account(AccountAddress::sample()); - let tx = IntentHash::sample_third(); - let sut = Sut::new_securified(tx.clone(), entity.clone(), matrix); - - let invalid = sut - .invalid_transaction_if_neglected_factors(IndexSet::just(d1.factor_source_id())) - .unwrap(); - - assert_eq!(invalid, entity); - } - - #[test] - fn two_device_as_threshold_of_1_skipped_one_is_valid() { - let d0 = HDFactorSource::fs0(); - let d1 = HDFactorSource::fs10(); - assert_eq!(d0.factor_source_kind(), FactorSourceKind::Device); - assert_eq!(d1.factor_source_kind(), FactorSourceKind::Device); - - let matrix = MatrixOfFactorInstances::threshold_only( - [d0.clone(), d1.clone()].into_iter().map(|f| { - HierarchicalDeterministicFactorInstance::mainnet_tx_account( - HDPathComponent::securifying_base_index(0), - f.factor_source_id(), - ) - }), - 1, - ); - - let entity = AddressOfAccountOrPersona::Account(AccountAddress::sample()); - let tx = IntentHash::sample_third(); - let sut = Sut::new_securified(tx.clone(), entity.clone(), matrix); - - let invalid = - sut.invalid_transaction_if_neglected_factors(IndexSet::just(d1.factor_source_id())); - - assert!(invalid.is_none()); - } - - #[test] - fn debug() { - assert!(!format!("{:?}", Sut::sample()).is_empty()); - } - - #[test] - #[should_panic(expected = "Programmer error! Must have at least one factors list.")] - fn invalid_empty_factors() { - Sut::new( - IntentHash::sample(), - AddressOfAccountOrPersona::sample(), - None, - None, - ); - } - - #[test] - #[should_panic(expected = "Factor source not found in any of the lists.")] - fn cannot_add_unrelated_signature() { - let sut = Sut::sample(); - sut.add_signature(HDSignature::sample()); - } - - #[test] - #[should_panic(expected = "A factor MUST NOT be present in both threshold AND override list.")] - fn factor_should_not_be_used_in_both_lists() { - Account::securified_mainnet("Alice", AccountAddress::sample(), || { - let idx = HDPathComponent::securifying_base_index(0); - let fi = HierarchicalDeterministicFactorInstance::f(CAP26EntityKind::Account, idx); - MatrixOfFactorInstances::new( - [FactorSourceIDFromHash::fs0()].map(&fi), - 1, - [FactorSourceIDFromHash::fs0()].map(&fi), - ) - }); - } - - #[test] - #[should_panic] - fn cannot_add_same_signature_twice() { - let intent_hash = IntentHash::sample(); - let entity = Account::securified_mainnet("Alice", AccountAddress::sample(), || { - let idx = HDPathComponent::securifying_base_index(0); - let fi = HierarchicalDeterministicFactorInstance::f(CAP26EntityKind::Account, idx); - MatrixOfFactorInstances::new( - [FactorSourceIDFromHash::fs0()].map(&fi), - 1, - [FactorSourceIDFromHash::fs1()].map(&fi), - ) - }); - let sut = Sut::from_entity(entity.clone(), intent_hash.clone()); - let sign_input = HDSignatureInput::new( - intent_hash, - OwnedFactorInstance::new( - entity.address(), - HierarchicalDeterministicFactorInstance::mainnet_tx_account( - HDPathComponent::unsecurified_hardening_base_index(0), - FactorSourceIDFromHash::fs0(), - ), - ), - ); - let signature = HDSignature::produced_signing_with_input(sign_input); - - sut.add_signature(signature.clone()); - sut.add_signature(signature.clone()); - } - - #[test] - fn invalid_transactions_if_neglected_success() { - let sut = Sut::sample(); - sut.add_signature(HDSignature::produced_signing_with_input( - HDSignatureInput::new( - sut.intent_hash.clone(), - OwnedFactorInstance::new( - sut.entity.clone(), - HierarchicalDeterministicFactorInstance::mainnet_tx_account( - HDPathComponent::securifying_base_index(6), - FactorSourceIDFromHash::fs1(), - ), - ), - ), - )); - let can_skip = |f: FactorSourceIDFromHash| { - assert!(sut - // Already signed with override factor `FactorSourceIDFromHash::fs1()`. Thus - // can skip - .invalid_transaction_if_neglected_factors(IndexSet::just(f)) - .is_none()) - }; - can_skip(FactorSourceIDFromHash::fs0()); - can_skip(FactorSourceIDFromHash::fs3()); - can_skip(FactorSourceIDFromHash::fs4()); - can_skip(FactorSourceIDFromHash::fs5()); - } - - #[test] - fn inequality() { - assert_ne!(Sut::sample(), Sut::sample_other()) - } - - #[test] - fn equality() { - assert_eq!(Sut::sample(), Sut::sample()); - assert_eq!(Sut::sample_other(), Sut::sample_other()); - } -} diff --git a/src/signing/petition_types/petition_for_factors_types/factor_source_referencing.rs b/src/signing/petition_types/petition_for_factors_types/factor_source_referencing.rs deleted file mode 100644 index e3c26f31..00000000 --- a/src/signing/petition_types/petition_for_factors_types/factor_source_referencing.rs +++ /dev/null @@ -1,20 +0,0 @@ -use crate::prelude::*; - -/// A trait for types which reference a factor source. -pub(crate) trait FactorSourceReferencing: std::hash::Hash + PartialEq + Eq + Clone { - fn factor_source_id(&self) -> FactorSourceIDFromHash; -} - -impl FactorSourceReferencing for HierarchicalDeterministicFactorInstance { - fn factor_source_id(&self) -> FactorSourceIDFromHash { - self.factor_source_id - } -} - -impl FactorSourceReferencing for HDSignature { - fn factor_source_id(&self) -> FactorSourceIDFromHash { - self.owned_factor_instance() - .factor_instance() - .factor_source_id - } -} diff --git a/src/signing/petition_types/petition_for_factors_types/mod.rs b/src/signing/petition_types/petition_for_factors_types/mod.rs deleted file mode 100644 index fabdddcf..00000000 --- a/src/signing/petition_types/petition_for_factors_types/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -mod factor_source_referencing; -mod neglected_factor_instance; -mod petition_for_factors; - -pub(crate) use factor_source_referencing::*; -pub(crate) use petition_for_factors::*; - -pub use neglected_factor_instance::*; diff --git a/src/signing/petition_types/petition_for_factors_types/neglected_factor_instance.rs b/src/signing/petition_types/petition_for_factors_types/neglected_factor_instance.rs deleted file mode 100644 index 075091fe..00000000 --- a/src/signing/petition_types/petition_for_factors_types/neglected_factor_instance.rs +++ /dev/null @@ -1,98 +0,0 @@ -use crate::prelude::*; - -/// A neglected factor, with a reason. -#[derive(Clone, PartialEq, Eq, Hash)] -pub struct AbstractNeglectedFactor { - /// The reason why this factor was neglected. - pub(crate) reason: NeglectFactorReason, - - /// The neglected factor - pub(crate) content: T, -} - -impl AbstractNeglectedFactor { - pub fn new(reason: NeglectFactorReason, content: T) -> Self { - Self { reason, content } - } -} - -impl std::fmt::Debug for AbstractNeglectedFactor { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Neglected") - .field("reason", &self.reason) - .field("content", &self.content) - .finish() - } -} - -impl NeglectedFactorInstance { - /// Maps from `Neglected` - /// to `Neglected`, - pub(crate) fn as_neglected_factor(&self) -> NeglectedFactor { - NeglectedFactor::new(self.reason, self.factor_source_id()) - } -} -impl FactorSourceReferencing for NeglectedFactorInstance { - fn factor_source_id(&self) -> FactorSourceIDFromHash { - self.content.factor_source_id() - } -} - -impl FactorSourceReferencing for NeglectedFactor { - fn factor_source_id(&self) -> FactorSourceIDFromHash { - self.content - } -} - -impl HasSampleValues for NeglectedFactorInstance { - fn sample() -> Self { - Self::new( - NeglectFactorReason::UserExplicitlySkipped, - HierarchicalDeterministicFactorInstance::sample(), - ) - } - fn sample_other() -> Self { - Self::new( - NeglectFactorReason::Failure, - HierarchicalDeterministicFactorInstance::sample_other(), - ) - } -} - -/// ID to some neglected factor source, with the reason why it was neglected (skipped/failed) -pub(crate) type NeglectedFactor = AbstractNeglectedFactor; - -/// IDs to some neglected factor source, with the reason why they were neglected (skipped/failed) -pub type NeglectedFactors = AbstractNeglectedFactor>; - -/// A HierarchicalDeterministicFactorInstance which was rejected, with the reason why (skipped/failed) -pub(crate) type NeglectedFactorInstance = - AbstractNeglectedFactor; - -/// Reason why some FactorSource was neglected, either explicitly skipped by the user -/// or implicitly neglected due to failure. -#[derive(Clone, Copy, PartialEq, Eq, Hash, derive_more::Debug, derive_more::Display)] -pub enum NeglectFactorReason { - /// A FactorSource got neglected since user explicitly skipped it. - #[display("User Skipped")] - #[debug("UserExplicitlySkipped")] - UserExplicitlySkipped, - - /// A FactorSource got neglected implicitly due to failure - #[display("Failure")] - #[debug("Failure")] - Failure, - - /// A FactorSource got neglected implicitly since it is irrelevant, - /// all transactions which references the FactorSource have already - /// failed, thus pointless in using it. - #[display("Irrelevant")] - #[debug("Irrelevant")] - Irrelevant, - - /// We simulate neglect in order to see what the status of petitions - /// would be if a FactorSource would be neglected. - #[display("Simulation")] - #[debug("Simulation")] - Simulation, -} diff --git a/src/signing/petition_types/petition_for_factors_types/petition_for_factors/mod.rs b/src/signing/petition_types/petition_for_factors_types/petition_for_factors/mod.rs deleted file mode 100644 index 937d3359..00000000 --- a/src/signing/petition_types/petition_for_factors_types/petition_for_factors/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -#[allow(clippy::module_inception)] -mod petition_for_factors; - -mod petition_for_factors_input; -mod petition_for_factors_state; -mod petition_for_factors_state_snapshot; -mod petition_for_factors_status; -mod petition_for_factors_sub_state; - -use petition_for_factors_input::*; -use petition_for_factors_state::*; -use petition_for_factors_state_snapshot::*; -use petition_for_factors_sub_state::*; - -pub(crate) use petition_for_factors::*; -pub(crate) use petition_for_factors_status::*; diff --git a/src/signing/petition_types/petition_for_factors_types/petition_for_factors/petition_for_factors.rs b/src/signing/petition_types/petition_for_factors_types/petition_for_factors/petition_for_factors.rs deleted file mode 100644 index 8d7175b0..00000000 --- a/src/signing/petition_types/petition_for_factors_types/petition_for_factors/petition_for_factors.rs +++ /dev/null @@ -1,203 +0,0 @@ -use super::*; -use crate::prelude::*; - -/// Petition of signatures from a factors list of an entity in a transaction. -#[derive(Clone, PartialEq, Eq, derive_more::Debug)] -#[debug("{}", self.debug_str())] -pub(crate) struct PetitionForFactors { - pub(crate) factor_list_kind: FactorListKind, - - /// Factors to sign with and the required number of them. - pub(crate) input: PetitionForFactorsInput, - state: RefCell, -} - -impl HasSampleValues for PetitionForFactors { - fn sample() -> Self { - Self::new(FactorListKind::Threshold, PetitionForFactorsInput::sample()) - } - - fn sample_other() -> Self { - Self::new( - FactorListKind::Override, - PetitionForFactorsInput::sample_other(), - ) - } -} - -impl PetitionForFactors { - pub(crate) fn new(factor_list_kind: FactorListKind, input: PetitionForFactorsInput) -> Self { - Self { - factor_list_kind, - input, - state: RefCell::new(PetitionForFactorsState::new()), - } - } - - pub(crate) fn factor_instances(&self) -> IndexSet { - self.input.factors.clone() - } - - pub(crate) fn all_neglected(&self) -> IndexSet { - self.state.borrow().all_neglected() - } - - pub(crate) fn all_signatures(&self) -> IndexSet { - self.state.borrow().all_signatures() - } - - pub(crate) fn new_threshold( - factors: Vec, - threshold: i8, - ) -> Option { - if factors.is_empty() { - return None; - } - Some(Self::new( - FactorListKind::Threshold, - PetitionForFactorsInput::new_threshold(IndexSet::from_iter(factors), threshold), - )) - } - - pub(crate) fn new_unsecurified(factor: HierarchicalDeterministicFactorInstance) -> Self { - Self::new_threshold(vec![factor], 1).expect("Factors is not empty") // define as 1/1 threshold factor, which is a good definition. - } - - pub(crate) fn new_override( - factors: Vec, - ) -> Option { - if factors.is_empty() { - return None; - } - Some(Self::new( - FactorListKind::Override, - PetitionForFactorsInput::new_override(IndexSet::from_iter(factors)), - )) - } - - pub(crate) fn neglect_if_referenced(&self, neglected: NeglectedFactor) { - let factor_source_id = &neglected.factor_source_id(); - if let Some(_x_) = self.reference_to_factor_source_with_id(factor_source_id) { - debug!( - "PetitionForFactors = kind {:?} neglect factor source with id: {}, reason: {}", - self.factor_list_kind, factor_source_id, neglected.reason - ); - self.neglect(neglected) - } else { - debug!( - "PetitionForFactors = kind {:?} did not reference factor source with id: {}", - self.factor_list_kind, factor_source_id - ); - } - } - - fn neglect(&self, neglected: NeglectedFactor) { - let factor_instance = - self.expect_reference_to_factor_source_with_id(&neglected.factor_source_id()); - self.state - .borrow_mut() - .neglect(&NeglectedFactorInstance::new( - neglected.reason, - factor_instance.clone(), - )); - } - - pub(crate) fn has_owned_instance_with_id( - &self, - owned_factor_instance: &OwnedFactorInstance, - ) -> bool { - self.has_instance_with_id(owned_factor_instance.factor_instance()) - } - - pub(crate) fn has_instance_with_id( - &self, - factor_instance: &HierarchicalDeterministicFactorInstance, - ) -> bool { - self.input.factors.iter().any(|f| f == factor_instance) - } - - pub(crate) fn add_signature_if_relevant(&self, signature: &HDSignature) -> bool { - if self.has_owned_instance_with_id(signature.owned_factor_instance()) { - self.add_signature(signature); - true - } else { - false - } - } - - /// # Panics - /// Panics if this factor source has already been neglected or signed with. - fn add_signature(&self, signature: &HDSignature) { - let state = self.state.borrow_mut(); - state.add_signature(signature) - } - - pub(crate) fn references_factor_source_with_id( - &self, - factor_source_id: &FactorSourceIDFromHash, - ) -> bool { - self.reference_to_factor_source_with_id(factor_source_id) - .is_some() - } - - fn expect_reference_to_factor_source_with_id( - &self, - factor_source_id: &FactorSourceIDFromHash, - ) -> &HierarchicalDeterministicFactorInstance { - self.reference_to_factor_source_with_id(factor_source_id) - .expect("Programmer error! Factor source not found in factors.") - } - - fn reference_to_factor_source_with_id( - &self, - factor_source_id: &FactorSourceIDFromHash, - ) -> Option<&HierarchicalDeterministicFactorInstance> { - self.input.reference_factor_source_with_id(factor_source_id) - } - - fn state_snapshot(&self) -> PetitionForFactorsStateSnapshot { - self.state.borrow().snapshot() - } - - fn is_finished_successfully(&self) -> bool { - self.input.is_fulfilled_by(self.state_snapshot()) - } - - fn is_finished_with_fail(&self) -> bool { - let snapshot = self.state_snapshot(); - let is_finished_with_fail = self.input.is_failure_with(snapshot.clone()); - trace!( - "is_finished_with_fail: {:?} from input: {:?}, snapshot: {:?}", - is_finished_with_fail, - self.input, - snapshot - ); - is_finished_with_fail - } - - fn get_finished_with(&self) -> Option { - if self.is_finished_successfully() { - Some(PetitionFactorsStatusFinished::Success) - } else if self.is_finished_with_fail() { - Some(PetitionFactorsStatusFinished::Fail) - } else { - None - } - } - - pub(crate) fn status(&self) -> PetitionForFactorsStatus { - if let Some(finished_state) = self.get_finished_with() { - return PetitionForFactorsStatus::Finished(finished_state); - } - PetitionForFactorsStatus::InProgress - } - - #[allow(unused)] - pub(crate) fn debug_str(&self) -> String { - format!( - "PetitionForFactors(input: {:#?}, state_snapshot: {:#?})", - self.input, - self.state_snapshot() - ) - } -} diff --git a/src/signing/petition_types/petition_for_factors_types/petition_for_factors/petition_for_factors_input.rs b/src/signing/petition_types/petition_for_factors_types/petition_for_factors/petition_for_factors_input.rs deleted file mode 100644 index 76cf8ae1..00000000 --- a/src/signing/petition_types/petition_for_factors_types/petition_for_factors/petition_for_factors_input.rs +++ /dev/null @@ -1,90 +0,0 @@ -use super::*; -use crate::prelude::*; - -/// The input passed to a PetitionsForFactors -#[derive(Clone, PartialEq, Eq, derive_more::Debug)] -#[debug("PetitionForFactorsInput(factors: {:#?})", self.factors)] -pub(crate) struct PetitionForFactorsInput { - /// Factors to sign with. - pub(super) factors: IndexSet, - - /// Number of required factors to sign with. - pub(super) required: i8, -} - -impl HasSampleValues for PetitionForFactorsInput { - fn sample() -> Self { - Self::new( - IndexSet::from_iter([ - HierarchicalDeterministicFactorInstance::sample(), - HierarchicalDeterministicFactorInstance::sample_other(), - ]), - 1, - ) - } - - fn sample_other() -> Self { - Self::new( - IndexSet::from_iter([HierarchicalDeterministicFactorInstance::sample_other()]), - 1, - ) - } -} - -impl PetitionForFactorsInput { - pub(super) fn new( - factors: IndexSet, - required: i8, - ) -> Self { - Self { factors, required } - } - - pub(super) fn new_threshold( - factors: IndexSet, - threshold: i8, - ) -> Self { - Self::new(factors, threshold) - } - - pub(super) fn new_override(factors: IndexSet) -> Self { - Self::new(factors, 1) // we need just one, anyone, factor for threshold. - } - - pub(crate) fn reference_factor_source_with_id( - &self, - factor_source_id: &FactorSourceIDFromHash, - ) -> Option<&HierarchicalDeterministicFactorInstance> { - self.factors - .iter() - .find(|f| f.factor_source_id == *factor_source_id) - } - - fn factors_count(&self) -> i8 { - self.factors.len() as i8 - } - - fn remaining_factors_until_success(&self, snapshot: PetitionForFactorsStateSnapshot) -> i8 { - self.required - snapshot.signed_count() - } - - pub(super) fn is_fulfilled_by(&self, snapshot: PetitionForFactorsStateSnapshot) -> bool { - self.remaining_factors_until_success(snapshot) <= 0 - } - - fn factors_left_to_prompt(&self, snapshot: PetitionForFactorsStateSnapshot) -> i8 { - self.factors_count() - snapshot.prompted_count() - } - - pub(super) fn is_failure_with(&self, snapshot: PetitionForFactorsStateSnapshot) -> bool { - let signed_or_pending = - self.factors_left_to_prompt(snapshot.clone()) + snapshot.signed_count(); - let is_failure_with = signed_or_pending < self.required; - trace!( - "is_failure_with: {:?}, signed_or_pending: {:?}, required: {:?}", - is_failure_with, - signed_or_pending, - self.required - ); - is_failure_with - } -} diff --git a/src/signing/petition_types/petition_for_factors_types/petition_for_factors/petition_for_factors_state.rs b/src/signing/petition_types/petition_for_factors_types/petition_for_factors/petition_for_factors_state.rs deleted file mode 100644 index d2e241d0..00000000 --- a/src/signing/petition_types/petition_for_factors_types/petition_for_factors/petition_for_factors_state.rs +++ /dev/null @@ -1,169 +0,0 @@ -use std::cell::Ref; - -use super::*; -use crate::prelude::*; - -/// Mutable state of `PetitionForFactors`, keeping track of which factors that -/// have either signed or been neglected. -#[derive(Clone, PartialEq, Eq, derive_more::Debug)] -#[debug("PetitionForFactorsState(signed: {:?}, neglected: {:?})", signed.borrow().clone(), neglected.borrow().clone())] -pub(crate) struct PetitionForFactorsState { - /// Factors that have signed. - signed: RefCell>, - - /// Neglected factors, either due to user explicitly skipping, or due - /// implicitly neglected to failure. - neglected: RefCell>, -} - -impl PetitionForFactorsState { - /// Creates a new `PetitionForFactorsState`. - pub(super) fn new() -> Self { - Self { - signed: RefCell::new(PetitionForFactorsSubState::<_>::new()), - neglected: RefCell::new(PetitionForFactorsSubState::<_>::new()), - } - } - - /// A reference to the neglected factors so far. - pub(super) fn neglected(&self) -> Ref> { - self.neglected.borrow() - } - - /// A reference to the factors which have been signed with so far. - pub(super) fn signed(&self) -> Ref> { - self.signed.borrow() - } - - /// A set of signatures from factors that have been signed with so far. - pub(crate) fn all_signatures(&self) -> IndexSet { - self.signed().snapshot() - } - - /// A set factors have been neglected so far. - pub(crate) fn all_neglected(&self) -> IndexSet { - self.neglected().snapshot() - } - - /// # Panics - /// Panics if this factor source has already been neglected or signed with. - fn assert_not_referencing_factor_source(&self, factor_source_id: FactorSourceIDFromHash) { - assert!( - !self.references_factor_source_by_id(factor_source_id), - "Programmer error! Factor source {:#?} already used, should only be referenced once.", - factor_source_id, - ); - } - - /// # Panics - /// Panics if this factor source has already been neglected or signed and - /// this is not a simulation. - pub(crate) fn neglect(&self, neglected: &NeglectedFactorInstance) { - if neglected.reason != NeglectFactorReason::Simulation { - self.assert_not_referencing_factor_source(neglected.factor_source_id()); - } - self.neglected.borrow_mut().insert(neglected); - } - - /// # Panics - /// Panics if this factor source has already been neglected or signed with. - pub(crate) fn add_signature(&self, signature: &HDSignature) { - self.assert_not_referencing_factor_source(signature.factor_source_id()); - self.signed.borrow_mut().insert(signature) - } - - pub(super) fn snapshot(&self) -> PetitionForFactorsStateSnapshot { - PetitionForFactorsStateSnapshot::new(self.signed().snapshot(), self.neglected().snapshot()) - } - - fn references_factor_source_by_id(&self, factor_source_id: FactorSourceIDFromHash) -> bool { - self.signed() - .references_factor_source_by_id(factor_source_id) - || self - .neglected() - .references_factor_source_by_id(factor_source_id) - } -} - -#[cfg(test)] -mod tests { - - use super::*; - - type Sut = PetitionForFactorsState; - - impl PetitionForFactorsState { - fn test_neglect(&self, id: &HierarchicalDeterministicFactorInstance, simulated: bool) { - self.neglect(&NeglectedFactorInstance::new( - if simulated { - NeglectFactorReason::Simulation - } else { - NeglectFactorReason::UserExplicitlySkipped - }, - id.clone(), - )) - } - } - - #[test] - #[should_panic] - fn skipping_twice_panics() { - let sut = Sut::new(); - let fi = HierarchicalDeterministicFactorInstance::sample(); - sut.test_neglect(&fi, false); - sut.test_neglect(&fi, false); - } - - #[test] - #[should_panic] - fn signing_twice_panics() { - let sut = Sut::new(); - let sig = HDSignature::sample(); - sut.add_signature(&sig); - sut.add_signature(&sig); - } - - #[test] - #[should_panic] - fn skipping_already_signed_panics() { - let sut = Sut::new(); - - let intent_hash = IntentHash::sample(); - - let factor_instance = HierarchicalDeterministicFactorInstance::mainnet_tx_account( - HDPathComponent::unsecurified_hardening_base_index(0), - FactorSourceIDFromHash::fs0(), - ); - let sign_input = HDSignatureInput::new( - intent_hash, - OwnedFactorInstance::new(AddressOfAccountOrPersona::sample(), factor_instance.clone()), - ); - let signature = HDSignature::produced_signing_with_input(sign_input); - - sut.add_signature(&signature); - - sut.test_neglect(&factor_instance, false); - } - - #[test] - #[should_panic] - fn signing_already_skipped_panics() { - let sut = Sut::new(); - - let intent_hash = IntentHash::sample(); - let factor_instance = HierarchicalDeterministicFactorInstance::mainnet_tx_account( - HDPathComponent::unsecurified_hardening_base_index(0), - FactorSourceIDFromHash::fs0(), - ); - - sut.test_neglect(&factor_instance, false); - - let sign_input = HDSignatureInput::new( - intent_hash, - OwnedFactorInstance::new(AddressOfAccountOrPersona::sample(), factor_instance.clone()), - ); - - let signature = HDSignature::produced_signing_with_input(sign_input); - sut.add_signature(&signature); - } -} diff --git a/src/signing/petition_types/petition_for_factors_types/petition_for_factors/petition_for_factors_state_snapshot.rs b/src/signing/petition_types/petition_for_factors_types/petition_for_factors/petition_for_factors_state_snapshot.rs deleted file mode 100644 index af5e731a..00000000 --- a/src/signing/petition_types/petition_for_factors_types/petition_for_factors/petition_for_factors_state_snapshot.rs +++ /dev/null @@ -1,93 +0,0 @@ -use crate::prelude::*; - -/// An immutable "snapshot" of `PetitionForFactorsState` -#[derive(Clone, PartialEq, Eq, derive_more::Debug)] -#[debug("{}", self.debug_str())] -pub(super) struct PetitionForFactorsStateSnapshot { - /// Factors that have signed. - signed: IndexSet, - - /// Factors that has been neglected. - neglected: IndexSet, -} - -impl PetitionForFactorsStateSnapshot { - pub(super) fn new( - signed: IndexSet, - neglected: IndexSet, - ) -> Self { - Self { signed, neglected } - } - - pub(super) fn prompted_count(&self) -> i8 { - self.signed_count() + self.neglected_count() - } - - pub(super) fn signed_count(&self) -> i8 { - self.signed.len() as i8 - } - - fn neglected_count(&self) -> i8 { - self.neglected.len() as i8 - } - - #[allow(unused)] - fn debug_str(&self) -> String { - let signatures = self - .signed - .clone() - .into_iter() - .map(|s| format!("{:?}", s)) - .join(", "); - - let neglected = self - .neglected - .clone() - .into_iter() - .map(|s| format!("{:?}", s)) - .join(", "); - - format!("signatures: {:#?}, neglected: {:#?}", signatures, neglected) - } -} - -impl HasSampleValues for PetitionForFactorsStateSnapshot { - fn sample() -> Self { - Self::new( - IndexSet::from_iter([HDSignature::sample(), HDSignature::sample_other()]), - IndexSet::from_iter([ - NeglectedFactorInstance::sample(), - NeglectedFactorInstance::sample_other(), - ]), - ) - } - fn sample_other() -> Self { - Self::new( - IndexSet::just(HDSignature::sample_other()), - IndexSet::just(NeglectedFactorInstance::sample_other()), - ) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - type Sut = PetitionForFactorsStateSnapshot; - - #[test] - fn equality() { - assert_eq!(Sut::sample(), Sut::sample()); - assert_eq!(Sut::sample_other(), Sut::sample_other()); - } - - #[test] - fn inequality() { - assert_ne!(Sut::sample(), Sut::sample_other()) - } - - #[test] - fn debug() { - assert!(!format!("{:?}", Sut::sample()).is_empty()); - } -} diff --git a/src/signing/petition_types/petition_for_factors_types/petition_for_factors/petition_for_factors_status.rs b/src/signing/petition_types/petition_for_factors_types/petition_for_factors/petition_for_factors_status.rs deleted file mode 100644 index e1ec45b8..00000000 --- a/src/signing/petition_types/petition_for_factors_types/petition_for_factors/petition_for_factors_status.rs +++ /dev/null @@ -1,115 +0,0 @@ -/// The status of building using a certain list of factors, e.g. threshold or -/// override factors list. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub(crate) enum PetitionForFactorsStatus { - /// In progress, still gathering output from factors (signatures or public keys). - InProgress, - - /// Finished building with factors, either successfully or failed. - Finished(PetitionFactorsStatusFinished), -} - -/// Finished building with factors, either successfully or failed. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub(crate) enum PetitionFactorsStatusFinished { - /// Successful completion of building with factors. - Success, - - /// Failure building with factors, either a simulated status, as in what - /// would happen if we skipped a factor source, or a real failure, as in, - /// the user explicitly chose to skip a factor source even though she was - /// advised it would result in some transaction failing. Or we failed to - /// use a required factor source for what some reason. - Fail, -} - -impl PetitionForFactorsStatus { - /// Reduces / aggergates a list of `PetitionForFactorsStatus` into some - /// other status, e.g. `PetitionsStatus`. - pub(crate) fn aggregate( - statuses: impl IntoIterator, - valid: T, - invalid: T, - pending: T, - ) -> T { - let statuses = statuses.into_iter().collect::>(); - - let are_all_valid = statuses.iter().all(|s| { - matches!( - s, - PetitionForFactorsStatus::Finished(PetitionFactorsStatusFinished::Success) - ) - }); - - if are_all_valid { - return valid; - } - - let is_some_invalid = statuses.iter().any(|s| { - matches!( - s, - PetitionForFactorsStatus::Finished(PetitionFactorsStatusFinished::Fail) - ) - }); - - if is_some_invalid { - return invalid; - } - - pending - } -} - -#[cfg(test)] -mod tests { - use super::*; - - type Sut = PetitionForFactorsStatus; - use super::PetitionFactorsStatusFinished::*; - use super::PetitionForFactorsStatus::*; - - #[test] - fn aggregate_invalid() { - let invalid = Some(1); - let irrelevant = None; - assert_eq!( - Sut::aggregate( - vec![InProgress, Finished(Fail), Finished(Success)], - irrelevant, - invalid, - irrelevant - ), - invalid - ) - } - - #[test] - fn aggregate_pending() { - let pending = Some(1); - let irrelevant = None; - assert_eq!( - Sut::aggregate( - vec![InProgress, Finished(Success), Finished(Success)], - irrelevant, - irrelevant, - pending, - ), - pending - ) - } - - #[test] - fn aggregate_valid() { - let valid = Some(1); - let irrelevant = None; - assert_eq!( - Sut::aggregate( - vec![Finished(Success), Finished(Success)], - valid, - irrelevant, - irrelevant - ), - valid - ) - } -} diff --git a/src/signing/petition_types/petition_for_factors_types/petition_for_factors/petition_for_factors_sub_state.rs b/src/signing/petition_types/petition_for_factors_types/petition_for_factors/petition_for_factors_sub_state.rs deleted file mode 100644 index 6c40a2f7..00000000 --- a/src/signing/petition_types/petition_for_factors_types/petition_for_factors/petition_for_factors_sub_state.rs +++ /dev/null @@ -1,39 +0,0 @@ -use crate::prelude::*; - -/// A sub-state of `PetitionForFactorsState` which can be used to track factors -/// that have signed or skipped. -#[derive(Clone, PartialEq, Eq, derive_more::Debug)] -#[debug("[{}]", factors.borrow().clone().into_iter().map(|f| format!("{:?}", f)).join(", "))] -pub(crate) struct PetitionForFactorsSubState -where - F: FactorSourceReferencing + std::fmt::Debug, -{ - /// Factors that have signed or skipped - factors: RefCell>, -} - -impl PetitionForFactorsSubState { - pub(super) fn new() -> Self { - Self { - factors: RefCell::new(IndexSet::new()), - } - } - - pub(super) fn insert(&self, factor: &F) { - self.factors.borrow_mut().insert(factor.clone()); - } - - pub(super) fn snapshot(&self) -> IndexSet { - self.factors.borrow().clone() - } - - pub(super) fn references_factor_source_by_id( - &self, - factor_source_id: FactorSourceIDFromHash, - ) -> bool { - self.factors - .borrow() - .iter() - .any(|sf| sf.factor_source_id() == factor_source_id) - } -} diff --git a/src/signing/petition_types/petition_for_transaction.rs b/src/signing/petition_types/petition_for_transaction.rs deleted file mode 100644 index a0841a57..00000000 --- a/src/signing/petition_types/petition_for_transaction.rs +++ /dev/null @@ -1,297 +0,0 @@ -use crate::prelude::*; - -/// Petition of signatures for a transaction. -/// Essentially a wrapper around `Iterator`. -#[derive(derive_more::Debug, PartialEq, Eq)] -#[debug("{}", self.debug_str())] -pub(crate) struct PetitionForTransaction { - /// Hash of transaction to sign - pub(crate) intent_hash: IntentHash, - - pub(crate) for_entities: RefCell>, -} - -impl PetitionForTransaction { - pub(crate) fn new( - intent_hash: IntentHash, - for_entities: HashMap, - ) -> Self { - Self { - intent_hash, - for_entities: RefCell::new(for_entities), - } - } - - /// Returns `(true, _)` if this transaction has been successfully signed by - /// all required factor instances. - /// - /// Returns `(false, _)` if not enough factor instances have signed. - /// - /// The second value in the tuple `(_, IndexSet, _)` contains all - /// the signatures, even if it the transaction was failed, all signatures - /// will be returned (which might be empty). - /// - /// The third value in the tuple `(_, _, IndexSet)` contains the - /// id of all the factor sources which was skipped. - pub(crate) fn outcome(self) -> PetitionTransactionOutcome { - let for_entities = self - .for_entities - .into_inner() - .values() - .map(|x| x.to_owned()) - .collect_vec(); - - let transaction_valid = for_entities - .iter() - .all(|b| b.has_signatures_requirement_been_fulfilled()); - - let signatures = for_entities - .iter() - .flat_map(|x| x.all_signatures()) - .collect::>(); - - let neglected_factors = for_entities - .iter() - .flat_map(|x| x.all_neglected_factor_sources()) - .collect::>(); - - PetitionTransactionOutcome::new( - transaction_valid, - self.intent_hash.clone(), - signatures, - neglected_factors, - ) - } - - pub(crate) fn has_tx_failed(&self) -> bool { - self.for_entities.borrow().values().any(|p| p.has_failed()) - } - - pub(crate) fn all_relevant_factor_instances_of_source( - &self, - factor_source_id: &FactorSourceIDFromHash, - ) -> IndexSet { - assert!(!self.has_tx_failed()); - self.for_entities - .borrow() - .values() - .filter(|&p| { - if p.has_failed() { - debug!("OMITTING petition since it HAS failed: {:?}", p); - false - } else { - debug!("INCLUDING petition since it has NOT failed: {:?}", p); - true - } - }) - .cloned() - .flat_map(|petition| petition.all_factor_instances()) - .filter(|f| f.factor_source_id() == *factor_source_id) - .collect() - } - - pub(crate) fn add_signature(&self, signature: HDSignature) { - let for_entities = self.for_entities.borrow_mut(); - let for_entity = for_entities - .get(&signature.owned_factor_instance().owner) - .expect("Should not have added signature to irrelevant PetitionForTransaction, did you pass the wrong signature to the wrong PetitionForTransaction?"); - for_entity.add_signature(signature.clone()); - } - - pub(crate) fn neglect_factor_source(&self, neglected: NeglectedFactor) { - let mut for_entities = self.for_entities.borrow_mut(); - for petition in for_entities.values_mut() { - petition.neglect_if_referenced(neglected.clone()) - } - } - - pub(crate) fn input_for_interactor( - &self, - factor_source_id: &FactorSourceIDFromHash, - ) -> TransactionSignRequestInput { - assert!(!self.should_neglect_factors_due_to_irrelevant(IndexSet::just(*factor_source_id))); - assert!(!self.has_tx_failed()); - TransactionSignRequestInput::new( - self.intent_hash.clone(), - *factor_source_id, - self.all_relevant_factor_instances_of_source(factor_source_id), - ) - } - - pub(crate) fn status_of_each_petition_for_entity(&self) -> Vec { - self.for_entities - .borrow() - .values() - .map(|petition| petition.status()) - .collect() - } - - pub(crate) fn invalid_transaction_if_neglected_factors( - &self, - factor_source_ids: IndexSet, - ) -> Option { - if self.has_tx_failed() { - // No need to display already failed tx. - return None; - } - let entities = self - .for_entities - .borrow() - .iter() - .filter_map(|(_, petition)| { - petition.invalid_transaction_if_neglected_factors(factor_source_ids.clone()) - }) - .collect_vec(); - - if entities.is_empty() { - return None; - } - - Some(InvalidTransactionIfNeglected::new( - self.intent_hash.clone(), - entities, - )) - } - - pub(crate) fn should_neglect_factors_due_to_irrelevant( - &self, - factor_source_ids: IndexSet, - ) -> bool { - self.for_entities - .borrow() - .values() - .filter(|&p| p.references_any_factor_source(&factor_source_ids)) - .cloned() - .all(|petition| { - petition.should_neglect_factors_due_to_irrelevant(factor_source_ids.clone()) - }) - } - - #[allow(unused)] - fn debug_str(&self) -> String { - let entities = self - .for_entities - .borrow() - .iter() - .map(|p| format!("PetitionForEntity({:#?})", p.1)) - .join(", "); - - format!("PetitionForTransaction(for_entities: [{}])", entities) - } -} - -impl HasSampleValues for PetitionForTransaction { - fn sample() -> Self { - let intent_hash = IntentHash::sample(); - let entity = Account::sample_securified(); - Self::new( - intent_hash.clone(), - HashMap::just(( - entity.address(), - PetitionForEntity::new( - intent_hash.clone(), - entity.address(), - PetitionForFactors::sample(), - PetitionForFactors::sample_other(), - ), - )), - ) - } - - fn sample_other() -> Self { - let intent_hash = IntentHash::sample_other(); - let entity = Persona::sample_unsecurified(); - Self::new( - intent_hash.clone(), - HashMap::just(( - entity.address(), - PetitionForEntity::new( - intent_hash.clone(), - entity.address(), - PetitionForFactors::sample_other(), - None, - ), - )), - ) - } -} - -#[cfg(test)] -mod tests { - - use super::*; - - type Sut = PetitionForTransaction; - - #[test] - fn equality() { - assert_eq!(Sut::sample(), Sut::sample()); - assert_eq!(Sut::sample_other(), Sut::sample_other()); - } - - #[test] - fn inequality() { - assert_ne!(Sut::sample(), Sut::sample_other()); - } - - #[test] - fn debug() { - assert!(!format!("{:?}", Sut::sample()).is_empty()); - } - - #[test] - fn all_relevant_factor_instances_of_source_ok() { - let intent_hash = IntentHash::sample(); - - let account = Account::a5(); - let matrix = match account.security_state() { - EntitySecurityState::Securified(sec) => sec.matrix.clone(), - EntitySecurityState::Unsecured(_) => panic!(), - }; - let petition = - PetitionForEntity::new_securified(intent_hash.clone(), account.address(), matrix); - - let sut = Sut::new( - IntentHash::sample(), - HashMap::just((account.address(), petition)), - ); - sut.neglect_factor_source(NeglectedFactor::new( - NeglectFactorReason::Failure, - FactorSourceIDFromHash::fs1(), - )); - - assert_eq!( - sut.all_relevant_factor_instances_of_source(&FactorSourceIDFromHash::fs4()) - .len(), - 1 - ); - } - - #[test] - #[should_panic] - fn all_relevant_factor_instances_of_source_panics_if_invalid() { - let intent_hash = IntentHash::sample(); - - let account = Account::a5(); - let matrix = match account.security_state() { - EntitySecurityState::Securified(sec) => sec.matrix.clone(), - EntitySecurityState::Unsecured(_) => panic!(), - }; - let petition = - PetitionForEntity::new_securified(intent_hash.clone(), account.address(), matrix); - - let sut = Sut::new( - IntentHash::sample(), - HashMap::just((account.address(), petition)), - ); - sut.neglect_factor_source(NeglectedFactor::new( - NeglectFactorReason::Failure, - FactorSourceIDFromHash::fs1(), - )); - sut.neglect_factor_source(NeglectedFactor::new( - NeglectFactorReason::Failure, - FactorSourceIDFromHash::fs4(), - )); - let _ = sut.all_relevant_factor_instances_of_source(&FactorSourceIDFromHash::fs4()); - } -} diff --git a/src/signing/petition_types/petitions.rs b/src/signing/petition_types/petitions.rs deleted file mode 100644 index a2ca645d..00000000 --- a/src/signing/petition_types/petitions.rs +++ /dev/null @@ -1,247 +0,0 @@ -#![allow(clippy::non_canonical_partial_ord_impl)] - -use crate::prelude::*; - -#[derive(derive_more::Debug, PartialEq, Eq)] -#[debug("{}", self.debug_str())] -pub(crate) struct Petitions { - /// Lookup from factor to TXID. - /// - /// - /// The same HDFactorSource might be required by many payloads - /// and per payload might be required by many entities, e.g. transactions - /// `t0` and `t1`, where - /// `t0` is signed by accounts: A and B - /// `t1` is signed by accounts: A, C and D, - /// - /// Where A, B, C and D, all use the factor source, e.g. some arculus - /// card which the user has setup as a factor (source) for all these accounts. - pub(crate) factor_source_to_intent_hashes: - HashMap>, - - /// Lookup from TXID to signatures builders, sorted according to the order of - /// transactions passed to the SignaturesBuilder. - pub(crate) txid_to_petition: RefCell>, -} - -impl Petitions { - pub(crate) fn new( - factor_source_to_intent_hashes: HashMap>, - txid_to_petition: IndexMap, - ) -> Self { - Self { - factor_source_to_intent_hashes, - txid_to_petition: RefCell::new(txid_to_petition), - } - } - - pub(crate) fn outcome(self) -> SignaturesOutcome { - let txid_to_petition = self.txid_to_petition.into_inner(); - let mut failed_transactions = MaybeSignedTransactions::empty(); - let mut successful_transactions = MaybeSignedTransactions::empty(); - let mut neglected_factor_sources = IndexSet::::new(); - for (intent_hash, petition_of_transaction) in txid_to_petition.into_iter() { - let outcome = petition_of_transaction.outcome(); - let signatures = outcome.signatures; - - if outcome.transaction_valid { - successful_transactions.add_signatures(intent_hash, signatures); - } else { - failed_transactions.add_signatures(intent_hash, signatures); - } - neglected_factor_sources.extend(outcome.neglected_factors) - } - - SignaturesOutcome::new( - successful_transactions, - failed_transactions, - neglected_factor_sources, - ) - } - - pub(crate) fn each_petition( - &self, - factor_source_ids: IndexSet, - each: impl Fn(&PetitionForTransaction) -> T, - combine: impl Fn(Vec) -> U, - ) -> U { - let for_each = factor_source_ids - .clone() - .iter() - .flat_map(|f| { - self.factor_source_to_intent_hashes - .get(f) - .expect("Should be able to lookup intent hash for each factor source, did you call this method with irrelevant factor sources? Or did you recently change the preprocessor logic of the SignaturesCollector, if you did you've missed adding an entry for `factor_source_to_intent_hash`.map") - .iter() - .map(|intent_hash| { - let binding = self.txid_to_petition.borrow(); - let value = binding.get(intent_hash).expect("Should have a petition for each transaction, did you recently change the preprocessor logic of the SignaturesCollector, if you did you've missed adding an entry for `txid_to_petition`.map"); - each(value) - }) - }).collect_vec(); - combine(for_each) - } - - pub(crate) fn invalid_transactions_if_neglected_factors( - &self, - factor_source_ids: IndexSet, - ) -> IndexSet { - self.each_petition( - factor_source_ids.clone(), - |p| p.invalid_transaction_if_neglected_factors(factor_source_ids.clone()), - |i| i.into_iter().flatten().collect(), - ) - } - - pub(crate) fn should_neglect_factors_due_to_irrelevant( - &self, - factor_sources_of_kind: &FactorSourcesOfKind, - ) -> bool { - let ids = factor_sources_of_kind - .factor_sources() - .iter() - .map(|f| f.factor_source_id()) - .collect::>(); - self.each_petition( - ids.clone(), - |p| p.should_neglect_factors_due_to_irrelevant(ids.clone()), - |i| i.into_iter().all(|x| x), - ) - } - - /// # Panics - /// Panics if no petition deem usage of `FactorSource` with id - /// `factor_source_id` relevant. We SHOULD have checked this already with - /// `should_neglect_factors_due_to_irrelevant` from SignatureCollector main - /// loop, i.e. we should not have called this method from SignaturesCollector - /// if `should_neglect_factors_due_to_irrelevant` returned true. - pub(crate) fn input_for_interactor( - &self, - factor_source_id: &FactorSourceIDFromHash, - ) -> MonoFactorSignRequestInput { - self.each_petition( - IndexSet::just(*factor_source_id), - |p| { - if p.has_tx_failed() { - None - } else { - Some(p.input_for_interactor(factor_source_id)) - } - }, - |i| { - MonoFactorSignRequestInput::new( - *factor_source_id, - i.into_iter().flatten().collect::>(), - ) - }, - ) - } - - pub(crate) fn status(&self) -> PetitionsStatus { - self.each_petition( - self.factor_source_to_intent_hashes - .keys() - .cloned() - .collect(), - |p| p.status_of_each_petition_for_entity(), - |i| PetitionsStatus::reducing(i.into_iter().flatten()), - ) - } - - fn add_signature(&self, signature: &HDSignature) { - let binding = self.txid_to_petition.borrow(); - let petition = binding.get(signature.intent_hash()).expect("Should have a petition for each transaction, did you recently change the preprocessor logic of the SignaturesCollector, if you did you've missed adding an entry for `txid_to_petition`.map"); - petition.add_signature(signature.clone()) - } - - fn neglect_factor_source_with_id(&self, neglected: NeglectedFactor) { - self.each_petition( - IndexSet::just(neglected.factor_source_id()), - |p| p.neglect_factor_source(neglected.clone()), - |_| (), - ) - } - - pub(crate) fn process_batch_response(&self, response: SignWithFactorsOutcome) { - match response { - SignWithFactorsOutcome::Signed { - produced_signatures, - } => { - for (k, v) in produced_signatures.signatures.clone().iter() { - info!("Signed with {} (#{} signatures)", k, v.len()); - } - produced_signatures - .signatures - .values() - .flatten() - .for_each(|s| self.add_signature(s)); - } - SignWithFactorsOutcome::Neglected(neglected_factors) => { - let reason = neglected_factors.reason; - for neglected_factor_source_id in neglected_factors.content.iter() { - info!("Neglected {}", neglected_factor_source_id); - self.neglect_factor_source_with_id(NeglectedFactor::new( - reason, - *neglected_factor_source_id, - )) - } - } - } - } - - #[allow(unused)] - fn debug_str(&self) -> String { - self.txid_to_petition - .borrow() - .iter() - .map(|p| format!("Petitions({:#?}: {:#?})", p.0, p.1)) - .join(" + ") - } -} - -impl HasSampleValues for Petitions { - fn sample() -> Self { - let p0 = PetitionForTransaction::sample(); - Self::new( - HashMap::just(( - FactorSourceIDFromHash::fs0(), - IndexSet::just(p0.intent_hash.clone()), - )), - IndexMap::just((p0.intent_hash.clone(), p0)), - ) - } - - fn sample_other() -> Self { - let p1 = PetitionForTransaction::sample(); - Self::new( - HashMap::just(( - FactorSourceIDFromHash::fs1(), - IndexSet::just(p1.intent_hash.clone()), - )), - IndexMap::just((p1.intent_hash.clone(), p1)), - ) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - type Sut = Petitions; - - #[test] - fn equality_of_samples() { - assert_eq!(Sut::sample(), Sut::sample()); - assert_eq!(Sut::sample_other(), Sut::sample_other()); - } - - #[test] - fn inequality_of_samples() { - assert_ne!(Sut::sample(), Sut::sample_other()); - } - - #[test] - fn debug() { - assert!(!format!("{:?}", Sut::sample()).is_empty()); - } -} diff --git a/src/signing/petition_types/petitions_status.rs b/src/signing/petition_types/petitions_status.rs deleted file mode 100644 index 7199f014..00000000 --- a/src/signing/petition_types/petitions_status.rs +++ /dev/null @@ -1,37 +0,0 @@ -use crate::prelude::*; - -/// An aggregation of the status of all petitions for transaction, -/// if all transactions are valid, if some are invalid, if none are invalid -/// (but all are not yet valid). -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub(crate) enum PetitionsStatus { - /// All transactions are valid. - AllAreValid, - - /// Some transaction is invalid (one or more), and some might be valid. - SomeIsInvalid, - - /// Not all transactions are valid, but none are invalid. - InProgressNoneInvalid, -} - -impl PetitionsStatus { - /// returns true if all petitions are valid. - pub(crate) fn are_all_valid(&self) -> bool { - matches!(self, Self::AllAreValid) - } - - /// returns true if some petitions are invalid. - pub(crate) fn is_some_invalid(&self) -> bool { - matches!(self, Self::SomeIsInvalid) - } - - pub(crate) fn reducing(statuses: impl IntoIterator) -> Self { - PetitionForFactorsStatus::aggregate( - statuses.into_iter().collect_vec(), - Self::AllAreValid, - Self::SomeIsInvalid, - Self::InProgressNoneInvalid, - ) - } -} diff --git a/src/signing/signatures_outcome_types/maybe_signed_transactions.rs b/src/signing/signatures_outcome_types/maybe_signed_transactions.rs deleted file mode 100644 index cc60556e..00000000 --- a/src/signing/signatures_outcome_types/maybe_signed_transactions.rs +++ /dev/null @@ -1,303 +0,0 @@ -use crate::prelude::*; - -#[derive(Debug, PartialEq, Eq, Clone)] -pub(crate) struct MaybeSignedTransactions { - /// Collection of transactions which might be signed or not. - pub(super) transactions: IndexMap>, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct SignedTransaction { - /// The transaction intent hash. - pub(crate) intent_hash: IntentHash, - /// The signatures for this transaction. - pub(crate) signatures: IndexSet, -} -impl SignedTransaction { - pub(crate) fn new(intent_hash: IntentHash, signatures: IndexSet) -> Self { - Self { - intent_hash, - signatures, - } - } -} - -impl MaybeSignedTransactions { - fn new(transactions: IndexMap>) -> Self { - Self { transactions } - } - - /// Constructs a new empty `MaybeSignedTransactions` which can be used - /// as a "builder". - pub(crate) fn empty() -> Self { - Self::new(IndexMap::new()) - } - - /// Returns whether or not this `MaybeSignedTransactions` contains - /// any transactions. - pub(crate) fn is_empty(&self) -> bool { - self.transactions.is_empty() - } - - pub(crate) fn transactions(&self) -> Vec { - self.transactions - .clone() - .into_iter() - .map(|(k, v)| SignedTransaction::new(k, v)) - .collect_vec() - } - - /// Validates that all values, all signatures, have the same `intent_hash` - /// as its key. - /// - /// Also validates that the input of every signature is unique - to identify - /// if the same signer has been used twice, would be a programmer error. - /// - /// # Panics - /// Panics if any signature has a different `intent_hash` than its key. - fn validate(&self) { - for (intent_hash, signatures) in self.transactions.iter() { - assert!( - signatures.iter().all(|s| s.intent_hash() == intent_hash), - "Discrepancy between intent hash and signature intent hash." - ); - } - let all_signatures = self.all_signatures(); - let all_signatures_count = all_signatures.len(); - let inputs = self - .all_signatures() - .iter() - .map(|s| s.input.clone()) - .collect::>(); - assert_eq!( - all_signatures_count, - inputs.len(), - "Discrepancy, the same signer has been used twice." - ); - } - - /// Inserts a set of signatures for transaction with `intent_hash`, if - /// the transaction was already present, the signatures are added to the - /// existing set, if the transaction was not already present a new set is - /// created. - /// - /// # Panics - /// Panics if any signature has a different `intent_hash` than its key. - /// - /// Panics if any signatures in `signature` is not new, that is, already present - /// in `transactions`. - pub(crate) fn add_signatures( - &mut self, - intent_hash: IntentHash, - signatures: IndexSet, - ) { - if let Some(ref mut sigs) = self.transactions.get_mut(&intent_hash) { - let old_count = sigs.len(); - let delta_count = signatures.len(); - sigs.extend(signatures); - assert_eq!( - sigs.len(), - old_count + delta_count, - "Discrepancy, some signature in signatures to add found in existing set." - ); - } else { - self.transactions.insert(intent_hash, signatures); - } - self.validate(); - } - - /// Returns all the signatures for all the transactions. - pub(crate) fn all_signatures(&self) -> IndexSet { - self.transactions - .values() - .flat_map(|v| v.iter()) - .cloned() - .collect() - } -} - -impl HasSampleValues for MaybeSignedTransactions { - fn sample() -> Self { - let tx_a = IntentHash::sample(); - let tx_a_input_x = HDSignatureInput::new( - tx_a.clone(), - OwnedFactorInstance::new( - AddressOfAccountOrPersona::sample(), - HierarchicalDeterministicFactorInstance::mainnet_tx_account( - HDPathComponent::unsecurified_hardening_base_index(0), - FactorSourceIDFromHash::sample(), - ), - ), - ); - let tx_a_input_y = HDSignatureInput::new( - tx_a.clone(), - OwnedFactorInstance::new( - AddressOfAccountOrPersona::sample(), - HierarchicalDeterministicFactorInstance::mainnet_tx_account( - HDPathComponent::unsecurified_hardening_base_index(1), - FactorSourceIDFromHash::sample_other(), - ), - ), - ); - let tx_a_sig_x = HDSignature::produced_signing_with_input(tx_a_input_x); - let tx_a_sig_y = HDSignature::produced_signing_with_input(tx_a_input_y); - - let tx_b = IntentHash::sample_other(); - let tx_b_input_x = HDSignatureInput::new( - tx_b.clone(), - OwnedFactorInstance::new( - AddressOfAccountOrPersona::sample(), - HierarchicalDeterministicFactorInstance::mainnet_tx_account( - HDPathComponent::unsecurified_hardening_base_index(2), - FactorSourceIDFromHash::sample_third(), - ), - ), - ); - let tx_b_input_y = HDSignatureInput::new( - tx_b.clone(), - OwnedFactorInstance::new( - AddressOfAccountOrPersona::sample(), - HierarchicalDeterministicFactorInstance::mainnet_tx_account( - HDPathComponent::unsecurified_hardening_base_index(3), - FactorSourceIDFromHash::sample_fourth(), - ), - ), - ); - - let tx_b_sig_x = HDSignature::produced_signing_with_input(tx_b_input_x); - let tx_b_sig_y = HDSignature::produced_signing_with_input(tx_b_input_y); - - Self::new( - [ - (tx_a, IndexSet::from_iter([tx_a_sig_x, tx_a_sig_y])), - (tx_b, IndexSet::from_iter([tx_b_sig_x, tx_b_sig_y])), - ] - .into_iter() - .collect::>>(), - ) - } - - fn sample_other() -> Self { - let tx_a = IntentHash::sample_third(); - let tx_a_input_x = HDSignatureInput::new( - tx_a.clone(), - OwnedFactorInstance::new( - AddressOfAccountOrPersona::sample(), - HierarchicalDeterministicFactorInstance::mainnet_tx_account( - HDPathComponent::unsecurified_hardening_base_index(10), - FactorSourceIDFromHash::sample(), - ), - ), - ); - let tx_a_input_y = HDSignatureInput::new( - tx_a.clone(), - OwnedFactorInstance::new( - AddressOfAccountOrPersona::sample(), - HierarchicalDeterministicFactorInstance::mainnet_tx_account( - HDPathComponent::unsecurified_hardening_base_index(11), - FactorSourceIDFromHash::sample_other(), - ), - ), - ); - let tx_a_input_z = HDSignatureInput::new( - tx_a.clone(), - OwnedFactorInstance::new( - AddressOfAccountOrPersona::sample(), - HierarchicalDeterministicFactorInstance::mainnet_tx_account( - HDPathComponent::unsecurified_hardening_base_index(12), - FactorSourceIDFromHash::sample_third(), - ), - ), - ); - let tx_a_sig_x = HDSignature::produced_signing_with_input(tx_a_input_x); - let tx_a_sig_y = HDSignature::produced_signing_with_input(tx_a_input_y); - let tx_a_sig_z = HDSignature::produced_signing_with_input(tx_a_input_z); - - Self::new( - [( - tx_a, - IndexSet::from_iter([tx_a_sig_x, tx_a_sig_y, tx_a_sig_z]), - )] - .into_iter() - .collect::>>(), - ) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - type Sut = MaybeSignedTransactions; - - #[test] - fn equality_of_samples() { - assert_eq!(Sut::sample(), Sut::sample()); - assert_eq!(Sut::sample_other(), Sut::sample_other()); - } - - #[test] - fn inequality_of_samples() { - assert_ne!(Sut::sample(), Sut::sample_other()); - } - - #[test] - #[should_panic( - expected = "Discrepancy, some signature in signatures to add found in existing set." - )] - fn panics_when_adding_same_signature() { - let mut sut = Sut::sample(); - let tx = IntentHash::sample(); - let input = HDSignatureInput::new( - tx.clone(), - OwnedFactorInstance::new( - AddressOfAccountOrPersona::sample(), - HierarchicalDeterministicFactorInstance::mainnet_tx_account( - HDPathComponent::unsecurified_hardening_base_index(0), - FactorSourceIDFromHash::sample(), - ), - ), - ); - let signature = HDSignature::produced_signing_with_input(input); - - sut.add_signatures(tx, IndexSet::from_iter([signature])); - } - - #[test] - #[should_panic(expected = "Discrepancy between intent hash and signature intent hash.")] - fn panics_when_intent_hash_key_does_not_match_signature() { - let mut sut = Sut::sample(); - let tx = IntentHash::sample(); - let input = HDSignatureInput::new( - tx, - OwnedFactorInstance::new( - AddressOfAccountOrPersona::sample(), - HierarchicalDeterministicFactorInstance::mainnet_tx_account( - HDPathComponent::unsecurified_hardening_base_index(0), - FactorSourceIDFromHash::sample(), - ), - ), - ); - let signature = HDSignature::produced_signing_with_input(input); - - sut.add_signatures(IntentHash::sample_other(), IndexSet::from_iter([signature])); - } - - #[test] - #[should_panic(expected = "Discrepancy, the same signer has been used twice.")] - fn panics_when_same_signer_used_twice() { - let mut sut = Sut::empty(); - let factor_instance = OwnedFactorInstance::sample(); - let tx = IntentHash::sample(); - let input = HDSignatureInput::new(tx.clone(), factor_instance.clone()); - let sig_a = HDSignature { - input: input.clone(), - signature: Signature::sample(), - }; - let sig_b = HDSignature { - input: input.clone(), - signature: Signature::sample_other(), - }; - sut.add_signatures(tx, IndexSet::from_iter([sig_a, sig_b])); - } -} diff --git a/src/signing/signatures_outcome_types/mod.rs b/src/signing/signatures_outcome_types/mod.rs deleted file mode 100644 index 5720f571..00000000 --- a/src/signing/signatures_outcome_types/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -mod maybe_signed_transactions; -mod petition_transaction_outcome; -mod sign_with_factors_outcome; -mod signatures_outcome; - -pub(crate) use petition_transaction_outcome::*; - -pub use maybe_signed_transactions::*; -pub use sign_with_factors_outcome::*; -pub use signatures_outcome::*; diff --git a/src/signing/signatures_outcome_types/petition_transaction_outcome.rs b/src/signing/signatures_outcome_types/petition_transaction_outcome.rs deleted file mode 100644 index f726a5b1..00000000 --- a/src/signing/signatures_outcome_types/petition_transaction_outcome.rs +++ /dev/null @@ -1,54 +0,0 @@ -use crate::prelude::*; - -/// The outcome of collecting signatures for a specific -/// transasction - either valid or invalid - and a -/// set of collected signatues (might be empty) and -/// a set of neglected factors (might be empty). -#[derive(Clone, PartialEq, Eq)] -pub(crate) struct PetitionTransactionOutcome { - intent_hash: IntentHash, - pub(crate) transaction_valid: bool, - pub(crate) signatures: IndexSet, - pub(crate) neglected_factors: IndexSet, -} - -impl PetitionTransactionOutcome { - /// # Panics - /// Panics if the intent hash in any signatures does not - /// match `intent_hash` - pub(crate) fn new( - transaction_valid: bool, - intent_hash: IntentHash, - signatures: IndexSet, - neglected_factors: IndexSet, - ) -> Self { - assert!( - signatures.iter().all(|s| *s.intent_hash() == intent_hash), - "Discprenacy! Mismatching intent hash found in a signature." - ); - Self { - intent_hash, - transaction_valid, - signatures, - neglected_factors, - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - type Sut = PetitionTransactionOutcome; - - #[test] - #[should_panic(expected = "Discprenacy! Mismatching intent hash found in a signature.")] - fn panic() { - Sut::new( - true, - IntentHash::sample(), - IndexSet::just(HDSignature::sample_other()), - IndexSet::new(), - ); - } -} diff --git a/src/signing/signatures_outcome_types/sign_with_factors_outcome.rs b/src/signing/signatures_outcome_types/sign_with_factors_outcome.rs deleted file mode 100644 index 2b7d8f8e..00000000 --- a/src/signing/signatures_outcome_types/sign_with_factors_outcome.rs +++ /dev/null @@ -1,52 +0,0 @@ -use crate::prelude::*; - -#[derive(Clone, PartialEq, Eq, derive_more::Debug)] -pub enum SignWithFactorsOutcome { - /// The user successfully signed with the factor source(s), the associated - /// value contains the produces signatures and any relevant metadata. - #[debug("Signed: {:#?}", produced_signatures)] - Signed { produced_signatures: SignResponse }, - - /// The factor source got neglected, either due to user explicitly skipping - /// or due to failure - #[debug("Neglected")] - Neglected(NeglectedFactors), -} - -impl SignWithFactorsOutcome { - #[allow(unused)] - pub fn signed(produced_signatures: SignResponse) -> Self { - Self::Signed { - produced_signatures, - } - } - - #[allow(unused)] - pub(crate) fn failure_with_factors(ids: IndexSet) -> Self { - Self::Neglected(NeglectedFactors::new(NeglectFactorReason::Failure, ids)) - } - - #[allow(unused)] - pub(crate) fn user_skipped_factors(ids: IndexSet) -> Self { - Self::Neglected(NeglectedFactors::new( - NeglectFactorReason::UserExplicitlySkipped, - ids, - )) - } - - #[allow(unused)] - pub(crate) fn user_skipped_factor(id: FactorSourceIDFromHash) -> Self { - Self::user_skipped_factors(IndexSet::from_iter([id])) - } - - pub(crate) fn irrelevant(factor_sources_of_kind: &FactorSourcesOfKind) -> Self { - Self::Neglected(NeglectedFactors::new( - NeglectFactorReason::Irrelevant, - factor_sources_of_kind - .factor_sources() - .into_iter() - .map(|f| f.factor_source_id()) - .collect(), - )) - } -} diff --git a/src/signing/signatures_outcome_types/signatures_outcome.rs b/src/signing/signatures_outcome_types/signatures_outcome.rs deleted file mode 100644 index 0e8c06c0..00000000 --- a/src/signing/signatures_outcome_types/signatures_outcome.rs +++ /dev/null @@ -1,174 +0,0 @@ -use crate::prelude::*; - -/// The outcome of a SignaturesCollector, containing a collection for transactions -/// which would be successful if submitted to the network (from a signatures point of view) -/// and a collection of transactions which would fail if submitted to the network, -/// since not enough signatures have been gathered. And a collection of factor sources -/// which were skipped. -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct SignaturesOutcome { - /// A potentially empty collection of transactions which which would be - /// successful if submitted to the network (from a signatures point of view). - /// - /// Potentially empty - successful_transactions: MaybeSignedTransactions, - - /// A collection of transactions which would fail if submitted to the network, - /// since not enough signatures have been gathered. - /// - /// Potentially empty - failed_transactions: MaybeSignedTransactions, - - /// List of all neglected factor sources, either explicitly skipped by user or - /// implicitly neglected due to failure. - neglected_factor_sources: IndexSet, -} - -impl SignaturesOutcome { - /// # Panics - /// Panics if the `successful_transactions` or `failed_transactions` shared - /// either any transaction intent hash, or any signature. - pub(crate) fn new( - successful_transactions: MaybeSignedTransactions, - failed_transactions: MaybeSignedTransactions, - neglected_factor_sources: impl IntoIterator, - ) -> Self { - let neglected_factor_sources = neglected_factor_sources - .into_iter() - .collect::>(); - - let successful_hashes: IndexSet = successful_transactions - .transactions - .keys() - .cloned() - .collect(); - - let failure_hashes: IndexSet = - failed_transactions.transactions.keys().cloned().collect(); - - let valid = successful_hashes - .intersection(&failure_hashes) - .collect_vec() - .is_empty(); - - assert!( - valid, - "Discrepancy, found intent hash in both successful and failed transactions, this is a programmer error." - ); - - assert!(failed_transactions.is_empty() || !neglected_factor_sources.is_empty(), "Discrepancy, found failed transactions but no neglected factor sources, this is a programmer error."); - - Self { - successful_transactions, - failed_transactions, - neglected_factor_sources, - } - } - - pub fn successful(&self) -> bool { - self.failed_transactions.is_empty() - } - - pub fn signatures_of_successful_transactions(&self) -> IndexSet { - self.successful_transactions.all_signatures() - } - - pub fn successful_transactions(&self) -> Vec { - self.successful_transactions.clone().transactions() - } - - pub fn failed_transactions(&self) -> Vec { - self.failed_transactions.clone().transactions() - } - - pub fn neglected_factor_sources(&self) -> IndexSet { - self.neglected_factor_sources.clone() - } - - #[allow(unused)] - fn ids_of_neglected_factor_sources_filter( - &self, - filter: fn(&NeglectedFactor) -> bool, - ) -> IndexSet { - self.neglected_factor_sources() - .into_iter() - .filter(filter) - .map(|n| n.factor_source_id()) - .collect() - } - - #[allow(unused)] - pub fn ids_of_neglected_factor_sources(&self) -> IndexSet { - self.ids_of_neglected_factor_sources_filter(|_| true) - } - - #[allow(unused)] - pub(crate) fn ids_of_neglected_factor_sources_skipped_by_user( - &self, - ) -> IndexSet { - self.ids_of_neglected_factor_sources_filter(|nf| { - nf.reason == NeglectFactorReason::UserExplicitlySkipped - }) - } - - #[allow(unused)] - pub(crate) fn ids_of_neglected_factor_sources_failed( - &self, - ) -> IndexSet { - self.ids_of_neglected_factor_sources_filter(|nf| nf.reason == NeglectFactorReason::Failure) - } - - #[allow(unused)] - pub(crate) fn ids_of_neglected_factor_sources_irrelevant( - &self, - ) -> IndexSet { - self.ids_of_neglected_factor_sources_filter(|nf| { - nf.reason == NeglectFactorReason::Irrelevant - }) - } - - #[allow(unused)] - pub(crate) fn signatures_of_failed_transactions(&self) -> IndexSet { - self.failed_transactions.all_signatures() - } - - #[allow(unused)] - /// All signatures from both successful transactions and failed transactions. - pub(crate) fn all_signatures(&self) -> IndexSet { - self.signatures_of_successful_transactions() - .union(&self.signatures_of_failed_transactions()) - .cloned() - .collect() - } -} - -#[cfg(test)] -mod tests { - - use super::*; - type Sut = SignaturesOutcome; - - #[test] - #[should_panic( - expected = "Discrepancy, found intent hash in both successful and failed transactions, this is a programmer error." - )] - fn new_panics_if_intent_hash_is_in_both_failed_and_success_collection() { - Sut::new( - MaybeSignedTransactions::sample(), - MaybeSignedTransactions::sample(), - [], - ); - } - - #[test] - #[should_panic( - expected = "Discrepancy, found failed transactions but no neglected factor sources, this is a programmer error." - )] - fn new_panics_if_failed_tx_is_not_empty_but_neglected_is() { - Sut::new( - MaybeSignedTransactions::empty(), - MaybeSignedTransactions::sample(), - [], - ); - } -} diff --git a/src/signing/tests/mod.rs b/src/signing/tests/mod.rs deleted file mode 100644 index f78236a8..00000000 --- a/src/signing/tests/mod.rs +++ /dev/null @@ -1 +0,0 @@ -mod signing_tests; diff --git a/src/signing/tests/signing_tests.rs b/src/signing/tests/signing_tests.rs deleted file mode 100644 index 65f6d830..00000000 --- a/src/signing/tests/signing_tests.rs +++ /dev/null @@ -1,1329 +0,0 @@ -#![cfg(test)] -use crate::prelude::*; - -mod tests { - - use super::*; - - mod multi_tx { - - use super::*; - - async fn multi_accounts_multi_personas_all_single_factor_controlled_with_sim_user( - sim: SimulatedUser, - ) { - let factor_sources = &HDFactorSource::all(); - let a0 = &Account::a0(); - let a1 = &Account::a1(); - let a2 = &Account::a2(); - - let p0 = &Persona::p0(); - let p1 = &Persona::p1(); - let p2 = &Persona::p2(); - - let t0 = TransactionIntent::address_of([a0, a1], [p0, p1]); - let t1 = TransactionIntent::address_of([a0, a1, a2], []); - let t2 = TransactionIntent::address_of([], [p0, p1, p2]); - - let profile = Profile::new(factor_sources.clone(), [a0, a1, a2], [p0, p1, p2]); - - let collector = SignaturesCollector::new( - SigningFinishEarlyStrategy::default(), - IndexSet::::from_iter([t0.clone(), t1.clone(), t2.clone()]), - Arc::new(TestSignatureCollectingInteractors::new(sim)), - &profile, - ) - .unwrap(); - - let outcome = collector.collect_signatures().await; - assert!(outcome.successful()); - assert!(outcome.failed_transactions().is_empty()); - assert_eq!(outcome.signatures_of_successful_transactions().len(), 10); - assert_eq!( - outcome - .successful_transactions() - .into_iter() - .map(|t| t.intent_hash) - .collect::>(), - HashSet::from_iter([ - t0.clone().intent_hash, - t1.clone().intent_hash, - t2.clone().intent_hash, - ]) - ); - let st0 = outcome - .successful_transactions() - .into_iter() - .find(|st| st.intent_hash == t0.intent_hash) - .unwrap(); - - assert_eq!( - st0.signatures - .clone() - .into_iter() - .map(|s| s.owned_factor_instance().owner.clone()) - .collect::>(), - HashSet::from_iter([a0.address(), a1.address(), p0.address(), p1.address()]) - ); - - let st1 = outcome - .successful_transactions() - .into_iter() - .find(|st| st.intent_hash == t1.intent_hash) - .unwrap(); - - assert_eq!( - st1.signatures - .clone() - .into_iter() - .map(|s| s.owned_factor_instance().owner.clone()) - .collect::>(), - HashSet::from_iter([a0.address(), a1.address(), a2.address()]) - ); - - let st2 = outcome - .successful_transactions() - .into_iter() - .find(|st| st.intent_hash == t2.intent_hash) - .unwrap(); - - assert_eq!( - st2.signatures - .clone() - .into_iter() - .map(|s| s.owned_factor_instance().owner.clone()) - .collect::>(), - HashSet::from_iter([p0.address(), p1.address(), p2.address()]) - ); - - // Assert sorted in increasing "friction order". - assert_eq!( - outcome - .signatures_of_successful_transactions() - .iter() - .map(|f| { f.factor_source_id().kind }) - .collect::>(), - IndexSet::::from_iter([ - FactorSourceKind::Device, - FactorSourceKind::Ledger - ]) - ); - } - - #[derive(Clone, Debug)] - struct Vector { - simulated_user: SimulatedUser, - expected: Expected, - } - #[derive(Clone, Debug, PartialEq, Eq)] - struct Expected { - successful_txs_signature_count: usize, - signed_factor_source_kinds: IndexSet, - expected_neglected_factor_source_count: usize, - } - async fn multi_securified_entities_with_sim_user(vector: Vector) { - let factor_sources = &HDFactorSource::all(); - - let a4 = &Account::a4(); - let a5 = &Account::a5(); - let a6 = &Account::a6(); - - let p4 = &Persona::p4(); - let p5 = &Persona::p5(); - let p6 = &Persona::p6(); - - let t0 = TransactionIntent::address_of([a5], [p5]); - let t1 = TransactionIntent::address_of([a4, a5, a6], []); - let t2 = TransactionIntent::address_of([a4, a6], [p4, p6]); - let t3 = TransactionIntent::address_of([], [p4, p5, p6]); - - let profile = Profile::new(factor_sources.clone(), [a4, a5, a6], [p4, p5, p6]); - - let collector = SignaturesCollector::new( - SigningFinishEarlyStrategy::default(), - IndexSet::::from_iter([ - t0.clone(), - t1.clone(), - t2.clone(), - t3.clone(), - ]), - Arc::new(TestSignatureCollectingInteractors::new( - vector.simulated_user, - )), - &profile, - ) - .unwrap(); - - let outcome = collector.collect_signatures().await; - - assert_eq!( - outcome.neglected_factor_sources().len(), - vector.expected.expected_neglected_factor_source_count - ); - - assert!(outcome.successful()); - assert!(outcome.failed_transactions().is_empty()); - assert_eq!( - outcome.signatures_of_successful_transactions().len(), - vector.expected.successful_txs_signature_count - ); - assert_eq!( - outcome - .successful_transactions() - .into_iter() - .map(|t| t.intent_hash) - .collect::>(), - HashSet::from_iter([ - t0.clone().intent_hash, - t1.clone().intent_hash, - t2.clone().intent_hash, - t3.clone().intent_hash, - ]) - ); - - // Assert sorted in increasing "friction order". - assert_eq!( - outcome - .signatures_of_successful_transactions() - .iter() - .map(|f| { f.factor_source_id().kind }) - .collect::>(), - vector.expected.signed_factor_source_kinds - ); - } - - mod with_failure { - use std::rc::Rc; - - use super::*; - - #[actix_rt::test] - async fn multi_securified_entities() { - multi_securified_entities_with_sim_user(Vector { - simulated_user: SimulatedUser::prudent_with_failures( - SimulatedFailures::with_simulated_failures([FactorSourceIDFromHash::fs1()]), - ), - expected: Expected { - successful_txs_signature_count: 24, - // We always end early - // `Device` FactorSourceKind never got used since it - // we are done after YubiKey. - signed_factor_source_kinds: IndexSet::::from_iter([ - FactorSourceKind::Arculus, - FactorSourceKind::Yubikey, - ]), - expected_neglected_factor_source_count: 1, - }, - }) - .await; - } - - #[actix_rt::test] - async fn failed_threshold_successful_override() { - sensible_env_logger::safe_init!(); - let factor_sources = &HDFactorSource::all(); - let a9 = &Account::a9(); - let tx0 = TransactionIntent::address_of([a9], []); - - let all_transactions = [tx0.clone()]; - - let profile = Profile::new(factor_sources.clone(), [a9], []); - - let collector = SignaturesCollector::new( - SigningFinishEarlyStrategy::default(), - all_transactions, - Arc::new(TestSignatureCollectingInteractors::new( - SimulatedUser::prudent_with_failures( - SimulatedFailures::with_simulated_failures([ - FactorSourceIDFromHash::fs1(), - ]), - ), - )), - &profile, - ) - .unwrap(); - - let outcome = collector.collect_signatures().await; - assert!(outcome.successful()); - assert_eq!( - outcome - .successful_transactions() - .into_iter() - .map(|t| t.intent_hash.clone()) - .collect_vec(), - vec![tx0.clone().intent_hash] - ); - assert_eq!( - outcome - .all_signatures() - .into_iter() - .map(|s| s.factor_source_id()) - .collect_vec(), - vec![FactorSourceIDFromHash::fs8()] - ); - } - - #[actix_rt::test] - async fn many_failing_tx() { - let factor_sources = &HDFactorSource::all(); - let a0 = &Account::a0(); - let p3 = &Persona::p3(); - let failing_transactions = (0..100) - .map(|_| TransactionIntent::address_of([a0], [])) - .collect::>(); - let tx = TransactionIntent::address_of([], [p3]); - let mut all_transactions = failing_transactions.clone(); - all_transactions.insert(tx.clone()); - - let profile = Profile::new(factor_sources.clone(), [a0], [p3]); - - let collector = SignaturesCollector::new( - SigningFinishEarlyStrategy::default(), - all_transactions, - Arc::new(TestSignatureCollectingInteractors::new( - SimulatedUser::prudent_with_failures( - SimulatedFailures::with_simulated_failures([ - FactorSourceIDFromHash::fs0(), - ]), - ), - )), - &profile, - ) - .unwrap(); - - let outcome = collector.collect_signatures().await; - assert!(!outcome.successful()); - assert_eq!( - outcome - .failed_transactions() - .iter() - .map(|t| t.intent_hash.clone()) - .collect_vec(), - failing_transactions - .iter() - .map(|t| t.intent_hash.clone()) - .collect_vec() - ); - - assert_eq!( - outcome - .ids_of_neglected_factor_sources_failed() - .into_iter() - .collect_vec(), - vec![FactorSourceIDFromHash::fs0()] - ); - - assert!(outcome - .ids_of_neglected_factor_sources_skipped_by_user() - .is_empty()); - - assert_eq!( - outcome - .successful_transactions() - .into_iter() - .map(|t| t.intent_hash) - .collect_vec(), - vec![tx.intent_hash] - ) - } - - #[actix_rt::test] - async fn same_tx_is_not_shown_to_user_in_case_of_already_failure() { - sensible_env_logger::safe_init!(); - let factor_sources = HDFactorSource::all(); - - let a7 = Account::a7(); - let a0 = Account::a0(); - - let tx0 = TransactionIntent::new([a7.entity_address(), a0.entity_address()], []); - let tx1 = TransactionIntent::new([a0.entity_address()], []); - - let profile = Profile::new(factor_sources.clone(), [&a7, &a0], []); - - type Tuple = (FactorSourceKind, IndexSet); - type Tuples = Vec; - let tuples = Rc::>::new(RefCell::new(Tuples::default())); - let tuples_clone = tuples.clone(); - let collector = SignaturesCollector::new( - SigningFinishEarlyStrategy::default(), - [tx0.clone(), tx1.clone()], - Arc::new(TestSignatureCollectingInteractors::new( - SimulatedUser::with_spy( - move |kind, invalid| { - let tuple = (kind, invalid); - let mut x = RefCell::borrow_mut(&tuples_clone); - x.push(tuple) - }, - SimulatedUserMode::Prudent, - SimulatedFailures::with_simulated_failures([ - FactorSourceIDFromHash::fs2(), // will cause any TX with a7 to fail - ]), - ), - )), - &profile, - ) - .unwrap(); - - let outcome = collector.collect_signatures().await; - - let tuples = tuples.borrow().clone(); - assert_eq!( - tuples, - vec![ - ( - FactorSourceKind::Ledger, - IndexSet::just(InvalidTransactionIfNeglected::new( - tx0.clone().intent_hash, - [a7.address()] - )) - ), - // Important that we do NOT display any mentioning of `tx0` here again! - ( - FactorSourceKind::Device, - IndexSet::just(InvalidTransactionIfNeglected::new( - tx1.clone().intent_hash, - [a0.address()] - )) - ), - ] - ); - - assert!(!outcome.successful()); - assert_eq!( - outcome.ids_of_neglected_factor_sources_failed(), - IndexSet::::just(FactorSourceIDFromHash::fs2()) - ); - assert_eq!( - outcome.ids_of_neglected_factor_sources_irrelevant(), - IndexSet::::from_iter([ - FactorSourceIDFromHash::fs6(), - FactorSourceIDFromHash::fs7(), - FactorSourceIDFromHash::fs8(), - FactorSourceIDFromHash::fs9() - ]) - ); - assert_eq!( - outcome - .successful_transactions() - .into_iter() - .map(|t| t.intent_hash) - .collect_vec(), - vec![tx1.intent_hash.clone()] - ); - - assert_eq!( - outcome - .failed_transactions() - .into_iter() - .map(|t| t.intent_hash) - .collect_vec(), - vec![tx0.intent_hash.clone()] - ); - - assert_eq!(outcome.all_signatures().len(), 1); - - assert!(outcome - .all_signatures() - .into_iter() - .map(|s| s.intent_hash().clone()) - .all(|i| i == tx1.intent_hash)); - - assert_eq!( - outcome - .all_signatures() - .into_iter() - .map(|s| s.derivation_path()) - .collect_vec(), - vec![DerivationPath::new( - NetworkID::Mainnet, - CAP26EntityKind::Account, - CAP26KeyKind::TransactionSigning, - HDPathComponent::unsecurified_hardening_base_index(0) - )] - ) - } - } - - mod no_fail { - use super::*; - - #[actix_rt::test] - async fn multi_accounts_multi_personas_all_single_factor_controlled() { - multi_accounts_multi_personas_all_single_factor_controlled_with_sim_user( - SimulatedUser::prudent_no_fail(), - ) - .await; - - // Same result with lazy user, not able to skip without failures. - multi_accounts_multi_personas_all_single_factor_controlled_with_sim_user( - SimulatedUser::lazy_sign_minimum([]), - ) - .await - } - - #[actix_rt::test] - async fn multi_securified_entities() { - multi_securified_entities_with_sim_user(Vector { - simulated_user: SimulatedUser::prudent_no_fail(), - expected: Expected { - successful_txs_signature_count: 32, - // We always end early - // `Device` FactorSourceKind never got used since it - // we are done after YubiKey. - signed_factor_source_kinds: IndexSet::::from_iter([ - FactorSourceKind::Ledger, - FactorSourceKind::Arculus, - FactorSourceKind::Yubikey, - ]), - expected_neglected_factor_source_count: 0, - }, - }) - .await; - - multi_securified_entities_with_sim_user(Vector { - simulated_user: SimulatedUser::lazy_sign_minimum([]), - expected: Expected { - successful_txs_signature_count: 24, - // We always end early, this lazy user was able to skip - // Ledger. - signed_factor_source_kinds: IndexSet::::from_iter([ - FactorSourceKind::Arculus, - FactorSourceKind::Yubikey, - FactorSourceKind::Device, - ]), - expected_neglected_factor_source_count: 2, - }, - }) - .await; - } - } - } - - mod single_tx { - use super::*; - - mod multiple_entities { - use super::*; - - #[actix_rt::test] - async fn prudent_user_single_tx_two_accounts_same_factor_source() { - let collector = SignaturesCollector::test_prudent([TXToSign::new([ - Account::unsecurified_mainnet( - "A0", - HierarchicalDeterministicFactorInstance::mainnet_tx( - CAP26EntityKind::Account, - HDPathComponent::unsecurified_hardening_base_index(0), - FactorSourceIDFromHash::fs0(), - ), - ), - Account::unsecurified_mainnet( - "A1", - HierarchicalDeterministicFactorInstance::mainnet_tx( - CAP26EntityKind::Account, - HDPathComponent::unsecurified_hardening_base_index(1), - FactorSourceIDFromHash::fs0(), - ), - ), - ])]); - - let outcome = collector.collect_signatures().await; - assert!(outcome.successful()); - let signatures = outcome.all_signatures(); - assert_eq!(signatures.len(), 2); - assert_eq!( - signatures - .into_iter() - .map(|s| s.derivation_path()) - .collect::>(), - [ - DerivationPath::account_tx( - NetworkID::Mainnet, - HDPathComponent::unsecurified_hardening_base_index(0) - ), - DerivationPath::account_tx( - NetworkID::Mainnet, - HDPathComponent::unsecurified_hardening_base_index(1) - ), - ] - .into_iter() - .collect::>() - ) - } - - #[actix_rt::test] - async fn prudent_user_single_tx_two_accounts_different_factor_sources() { - let collector = SignaturesCollector::test_prudent([TXToSign::new([ - Account::a0(), - Account::a1(), - ])]); - - let outcome = collector.collect_signatures().await; - assert!(outcome.successful()); - let signatures = outcome.all_signatures(); - assert_eq!(signatures.len(), 2); - } - } - - mod single_entity { - - use super::*; - - async fn prudent_user_single_tx_e0() { - let collector = SignaturesCollector::test_prudent([TXToSign::new([E::e0()])]); - let outcome = collector.collect_signatures().await; - assert!(outcome.successful()); - let signatures = outcome.all_signatures(); - assert_eq!(signatures.len(), 1); - } - - async fn prudent_user_single_tx_e0_assert_correct_intent_hash_is_signed() { - let tx = TXToSign::new([E::e0()]); - let collector = SignaturesCollector::test_prudent([tx.clone()]); - let signature = &collector.collect_signatures().await.all_signatures()[0]; - assert_eq!(signature.intent_hash(), &tx.intent_hash); - assert_eq!(signature.derivation_path().entity_kind, E::kind()); - } - - async fn prudent_user_single_tx_e0_assert_correct_owner_has_signed() { - let entity = E::e0(); - let tx = TXToSign::new([entity.clone()]); - let collector = SignaturesCollector::test_prudent([tx.clone()]); - let signature = &collector.collect_signatures().await.all_signatures()[0]; - assert_eq!(signature.owned_factor_instance().owner, entity.address()); - } - - async fn prudent_user_single_tx_e0_assert_correct_owner_factor_instance_signed< - E: IsEntity, - >() { - let entity = E::e0(); - let tx = TXToSign::new([entity.clone()]); - let collector = SignaturesCollector::test_prudent([tx.clone()]); - let signature = &collector.collect_signatures().await.all_signatures()[0]; - - assert_eq!( - signature.owned_factor_instance().factor_instance(), - entity - .security_state() - .all_factor_instances() - .first() - .unwrap() - ); - } - - async fn prudent_user_single_tx_e1() { - let collector = SignaturesCollector::test_prudent([TXToSign::new([E::e1()])]); - let outcome = collector.collect_signatures().await; - assert!(outcome.successful()); - let signatures = outcome.all_signatures(); - assert_eq!(signatures.len(), 1); - } - - async fn prudent_user_single_tx_e2() { - let collector = SignaturesCollector::test_prudent([TXToSign::new([E::e2()])]); - let outcome = collector.collect_signatures().await; - assert!(outcome.successful()); - let signatures = outcome.all_signatures(); - assert_eq!(signatures.len(), 1); - } - - async fn prudent_user_single_tx_e3() { - let collector = SignaturesCollector::test_prudent([TXToSign::new([E::e3()])]); - let outcome = collector.collect_signatures().await; - assert!(outcome.successful()); - let signatures = outcome.all_signatures(); - assert_eq!(signatures.len(), 1); - } - - async fn prudent_user_single_tx_e4() { - let collector = SignaturesCollector::test_prudent([TXToSign::new([E::e4()])]); - let outcome = collector.collect_signatures().await; - assert!(outcome.successful()); - let signatures = outcome.all_signatures(); - assert_eq!(signatures.len(), 2); - } - - async fn prudent_user_single_tx_e5() { - let collector = SignaturesCollector::test_prudent([TXToSign::new([E::e5()])]); - let outcome = collector.collect_signatures().await; - assert!(outcome.successful()); - let signatures = outcome.all_signatures(); - assert_eq!(signatures.len(), 1); - } - - async fn prudent_user_single_tx_e6() { - let collector = SignaturesCollector::test_prudent([TXToSign::new([E::e6()])]); - let outcome = collector.collect_signatures().await; - assert!(outcome.successful()); - let signatures = outcome.all_signatures(); - assert_eq!(signatures.len(), 1); - } - - async fn prudent_user_single_tx_e7() { - let collector = SignaturesCollector::test_prudent([TXToSign::new([E::e7()])]); - let outcome = collector.collect_signatures().await; - assert!(outcome.successful()); - let signatures = outcome.all_signatures(); - - assert_eq!(signatures.len(), 5); - } - - async fn lazy_sign_minimum_user_single_tx_e0() { - let collector = SignaturesCollector::test_lazy_sign_minimum_no_failures([ - TXToSign::new([E::e0()]), - ]); - let outcome = collector.collect_signatures().await; - assert!(outcome.successful()); - let signatures = outcome.all_signatures(); - assert_eq!(signatures.len(), 1); - } - - async fn lazy_sign_minimum_user_single_tx_e1() { - let collector = SignaturesCollector::test_lazy_sign_minimum_no_failures([ - TXToSign::new([E::e1()]), - ]); - let outcome = collector.collect_signatures().await; - assert!(outcome.successful()); - let signatures = outcome.all_signatures(); - assert_eq!(signatures.len(), 1); - } - - async fn lazy_sign_minimum_user_single_tx_e2() { - let collector = SignaturesCollector::test_lazy_sign_minimum_no_failures([ - TXToSign::new([E::e2()]), - ]); - let outcome = collector.collect_signatures().await; - assert!(outcome.successful()); - let signatures = outcome.all_signatures(); - assert_eq!(signatures.len(), 1); - } - - async fn lazy_sign_minimum_user_e3() { - let collector = SignaturesCollector::test_lazy_sign_minimum_no_failures([ - TXToSign::new([E::e3()]), - ]); - let outcome = collector.collect_signatures().await; - assert!(outcome.successful()); - let signatures = outcome.all_signatures(); - assert_eq!(signatures.len(), 1); - } - - async fn lazy_sign_minimum_user_e4() { - let collector = SignaturesCollector::test_lazy_sign_minimum_no_failures([ - TXToSign::new([E::e4()]), - ]); - let outcome = collector.collect_signatures().await; - assert!(outcome.successful()); - let signatures = outcome.all_signatures(); - assert_eq!(signatures.len(), 2); - } - - async fn lazy_sign_minimum_user_e5() { - let collector = SignaturesCollector::test_lazy_sign_minimum_no_failures([ - TXToSign::new([E::e5()]), - ]); - let outcome = collector.collect_signatures().await; - assert!(outcome.successful()); - let signatures = outcome.all_signatures(); - assert_eq!(signatures.len(), 1); - } - - async fn lazy_sign_minimum_user_e6() { - let collector = SignaturesCollector::test_lazy_sign_minimum_no_failures([ - TXToSign::new([E::e6()]), - ]); - let outcome = collector.collect_signatures().await; - assert!(outcome.successful()); - let signatures = outcome.all_signatures(); - - assert_eq!(signatures.len(), 2); - } - - async fn lazy_sign_minimum_user_e7() { - let collector = SignaturesCollector::test_lazy_sign_minimum_no_failures([ - TXToSign::new([E::e7()]), - ]); - let outcome = collector.collect_signatures().await; - assert!(outcome.successful()); - let signatures = outcome.all_signatures(); - - assert_eq!(signatures.len(), 5); - } - - async fn lazy_sign_minimum_user_e5_last_factor_used() { - let entity = E::e5(); - let collector = SignaturesCollector::test_lazy_sign_minimum_no_failures([ - TXToSign::new([entity.clone()]), - ]); - let outcome = collector.collect_signatures().await; - assert!(outcome.successful()); - let signatures = outcome.all_signatures(); - assert_eq!(signatures.len(), 1); - - let signature = &signatures[0]; - - assert_eq!( - signature - .owned_factor_instance() - .factor_instance() - .factor_source_id, - FactorSourceIDFromHash::fs4() - ); - - assert_eq!( - outcome.ids_of_neglected_factor_sources(), - IndexSet::just(FactorSourceIDFromHash::fs1()) - ) - } - - async fn lazy_sign_minimum_all_known_factors_used_as_override_factors_signed_with_device_for_entity< - E: IsEntity, - >() { - let collector = SignaturesCollector::test_lazy_sign_minimum_no_failures([ - TXToSign::new([E::securified_mainnet("Alice", E::Address::sample(), || { - let idx = HDPathComponent::securifying_base_index(0); - MatrixOfFactorInstances::override_only( - HDFactorSource::all().into_iter().map(|f| { - HierarchicalDeterministicFactorInstance::mainnet_tx_account( - idx, - f.factor_source_id(), - ) - }), - ) - })]), - ]); - let outcome = collector.collect_signatures().await; - assert!(outcome.successful()); - let signatures = outcome.all_signatures(); - assert_eq!(signatures.len(), 2); - - assert!(signatures - .into_iter() - .all(|s| s.factor_source_id().kind == FactorSourceKind::Device)); - } - - async fn lazy_always_skip_user_single_tx_e0() { - let collector = - SignaturesCollector::test_lazy_always_skip([TXToSign::new([E::e0()])]); - let outcome = collector.collect_signatures().await; - assert!(!outcome.successful()); - let signatures = outcome.all_signatures(); - assert!(signatures.is_empty()); - } - - async fn fail_get_neglected_e0() { - let failing = IndexSet::<_>::just(FactorSourceIDFromHash::fs0()); - let collector = SignaturesCollector::test_prudent_with_failures( - [TXToSign::new([E::e0()])], - SimulatedFailures::with_simulated_failures(failing.clone()), - ); - let outcome = collector.collect_signatures().await; - assert!(!outcome.successful()); - let neglected = outcome.ids_of_neglected_factor_sources(); - assert_eq!(neglected, failing); - } - - async fn lazy_always_skip_user_single_tx_e1() { - let collector = - SignaturesCollector::test_lazy_always_skip([TXToSign::new([E::e1()])]); - let outcome = collector.collect_signatures().await; - assert!(!outcome.successful()); - let signatures = outcome.all_signatures(); - assert!(signatures.is_empty()); - } - - async fn lazy_always_skip_user_single_tx_e2() { - let collector = - SignaturesCollector::test_lazy_always_skip([TXToSign::new([E::e2()])]); - let outcome = collector.collect_signatures().await; - assert!(!outcome.successful()); - let signatures = outcome.all_signatures(); - assert!(signatures.is_empty()); - } - - async fn lazy_always_skip_user_e3() { - let collector = - SignaturesCollector::test_lazy_always_skip([TXToSign::new([E::e3()])]); - let outcome = collector.collect_signatures().await; - assert!(!outcome.successful()); - let signatures = outcome.all_signatures(); - assert!(signatures.is_empty()); - } - - async fn lazy_always_skip_user_e4() { - let collector = - SignaturesCollector::test_lazy_always_skip([TXToSign::new([E::e4()])]); - let outcome = collector.collect_signatures().await; - assert!(!outcome.successful()); - let signatures = outcome.all_signatures(); - assert!(signatures.is_empty()); - } - - async fn lazy_always_skip_user_e5() { - let collector = - SignaturesCollector::test_lazy_always_skip([TXToSign::new([E::e5()])]); - let outcome = collector.collect_signatures().await; - assert!(!outcome.successful()); - let signatures = outcome.all_signatures(); - assert!(signatures.is_empty()); - } - - async fn lazy_always_skip_user_e6() { - let collector = - SignaturesCollector::test_lazy_always_skip([TXToSign::new([E::e6()])]); - let outcome = collector.collect_signatures().await; - assert!(!outcome.successful()); - let signatures = outcome.all_signatures(); - assert!(signatures.is_empty()); - } - - async fn lazy_always_skip_user_e7() { - let collector = - SignaturesCollector::test_lazy_always_skip([TXToSign::new([E::e7()])]); - let outcome = collector.collect_signatures().await; - assert!(!outcome.successful()); - let signatures = outcome.all_signatures(); - assert!(signatures.is_empty()); - } - - async fn failure_e0() { - let collector = SignaturesCollector::test_prudent_with_failures( - [TXToSign::new([E::e0()])], - SimulatedFailures::with_simulated_failures([FactorSourceIDFromHash::fs0()]), - ); - let outcome = collector.collect_signatures().await; - assert!(!outcome.successful()); - assert_eq!( - outcome - .ids_of_neglected_factor_sources_failed() - .into_iter() - .collect_vec(), - vec![FactorSourceIDFromHash::fs0()] - ); - assert!(outcome - .ids_of_neglected_factor_sources_skipped_by_user() - .is_empty()) - } - - async fn failure_e5() { - let collector = SignaturesCollector::new_test( - SigningFinishEarlyStrategy::r#continue(), - HDFactorSource::all(), - [TXToSign::new([E::e5()])], - SimulatedUser::prudent_with_failures( - SimulatedFailures::with_simulated_failures([FactorSourceIDFromHash::fs4()]), - ), - ); - - let outcome = collector.collect_signatures().await; - assert!(outcome.successful()); - assert_eq!( - outcome - .ids_of_neglected_factor_sources_failed() - .into_iter() - .collect_vec(), - vec![FactorSourceIDFromHash::fs4()] - ); - assert!(outcome - .ids_of_neglected_factor_sources_skipped_by_user() - .is_empty()); - } - - async fn building_can_succeed_even_if_one_factor_source_fails_assert_ids_of_successful_tx_e4< - E: IsEntity, - >() { - let collector = SignaturesCollector::test_prudent_with_failures( - [TXToSign::new([E::e4()])], - SimulatedFailures::with_simulated_failures([FactorSourceIDFromHash::fs3()]), - ); - let outcome = collector.collect_signatures().await; - assert!(outcome.successful()); - assert_eq!( - outcome - .signatures_of_successful_transactions() - .into_iter() - .map(|f| f.factor_source_id()) - .collect::>(), - IndexSet::<_>::from_iter([ - FactorSourceIDFromHash::fs0(), - FactorSourceIDFromHash::fs5() - ]) - ); - } - - async fn building_can_succeed_even_if_one_factor_source_fails_assert_ids_of_failed_tx_e4< - E: IsEntity, - >() { - let collector = SignaturesCollector::test_prudent_with_failures( - [TXToSign::new([E::e4()])], - SimulatedFailures::with_simulated_failures([FactorSourceIDFromHash::fs3()]), - ); - let outcome = collector.collect_signatures().await; - assert!(outcome.successful()); - assert_eq!( - outcome.ids_of_neglected_factor_sources(), - IndexSet::<_>::just(FactorSourceIDFromHash::fs3()) - ); - } - - mod account { - use super::*; - type E = Account; - - #[actix_rt::test] - async fn prudent_user_single_tx_a0() { - prudent_user_single_tx_e0::().await - } - - #[actix_rt::test] - async fn prudent_user_single_tx_a0_assert_correct_intent_hash_is_signed() { - prudent_user_single_tx_e0_assert_correct_intent_hash_is_signed::().await - } - - #[actix_rt::test] - async fn prudent_user_single_tx_a0_assert_correct_owner_has_signed() { - prudent_user_single_tx_e0_assert_correct_owner_has_signed::().await - } - - #[actix_rt::test] - async fn prudent_user_single_tx_a0_assert_correct_owner_factor_instance_signed() { - prudent_user_single_tx_e0_assert_correct_owner_factor_instance_signed::() - .await - } - - #[actix_rt::test] - async fn prudent_user_single_tx_a1() { - prudent_user_single_tx_e1::().await - } - - #[actix_rt::test] - async fn prudent_user_single_tx_a2() { - prudent_user_single_tx_e2::().await - } - - #[actix_rt::test] - async fn prudent_user_single_tx_a3() { - prudent_user_single_tx_e3::().await - } - - #[actix_rt::test] - async fn prudent_user_single_tx_a4() { - prudent_user_single_tx_e4::().await - } - - #[actix_rt::test] - async fn prudent_user_single_tx_a5() { - prudent_user_single_tx_e5::().await - } - - #[actix_rt::test] - async fn prudent_user_single_tx_a6() { - prudent_user_single_tx_e6::().await - } - - #[actix_rt::test] - async fn prudent_user_single_tx_a7() { - prudent_user_single_tx_e7::().await - } - - #[actix_rt::test] - async fn lazy_sign_minimum_user_single_tx_a0() { - lazy_sign_minimum_user_single_tx_e0::().await - } - - #[actix_rt::test] - async fn lazy_sign_minimum_user_single_tx_a1() { - lazy_sign_minimum_user_single_tx_e1::().await - } - - #[actix_rt::test] - async fn lazy_sign_minimum_user_single_tx_a2() { - lazy_sign_minimum_user_single_tx_e2::().await - } - - #[actix_rt::test] - async fn lazy_sign_minimum_user_a3() { - lazy_sign_minimum_user_e3::().await - } - - #[actix_rt::test] - async fn lazy_sign_minimum_user_a4() { - lazy_sign_minimum_user_e4::().await - } - - #[actix_rt::test] - async fn lazy_sign_minimum_user_a5() { - lazy_sign_minimum_user_e5::().await - } - - #[actix_rt::test] - async fn lazy_sign_minimum_user_a6() { - lazy_sign_minimum_user_e6::().await - } - - #[actix_rt::test] - async fn lazy_sign_minimum_user_a7() { - lazy_sign_minimum_user_e7::().await - } - - #[actix_rt::test] - async fn lazy_sign_minimum_user_a5_last_factor_used() { - lazy_sign_minimum_user_e5_last_factor_used::().await - } - - #[actix_rt::test] - async fn lazy_sign_minimum_all_known_factors_used_as_override_factors_signed_with_device_for_account( - ) { - lazy_sign_minimum_all_known_factors_used_as_override_factors_signed_with_device_for_entity::().await - } - - #[actix_rt::test] - async fn lazy_always_skip_user_single_tx_a0() { - lazy_always_skip_user_single_tx_e0::().await - } - - #[actix_rt::test] - async fn fail_get_skipped_a0() { - fail_get_neglected_e0::().await - } - - #[actix_rt::test] - async fn lazy_always_skip_user_single_tx_a1() { - lazy_always_skip_user_single_tx_e1::().await - } - - #[actix_rt::test] - async fn lazy_always_skip_user_single_tx_a2() { - lazy_always_skip_user_single_tx_e2::().await - } - - #[actix_rt::test] - async fn lazy_always_skip_user_a3() { - lazy_always_skip_user_e3::().await - } - - #[actix_rt::test] - async fn lazy_always_skip_user_a4() { - lazy_always_skip_user_e4::().await - } - - #[actix_rt::test] - async fn lazy_always_skip_user_a5() { - lazy_always_skip_user_e5::().await - } - - #[actix_rt::test] - async fn lazy_always_skip_user_a6() { - lazy_always_skip_user_e6::().await - } - - #[actix_rt::test] - async fn lazy_always_skip_user_a7() { - lazy_always_skip_user_e7::().await - } - - #[actix_rt::test] - async fn failure_a0() { - failure_e0::().await - } - - #[actix_rt::test] - async fn failure_a5() { - failure_e5::().await - } - - #[actix_rt::test] - async fn building_can_succeed_even_if_one_factor_source_fails_assert_ids_of_successful_tx( - ) { - building_can_succeed_even_if_one_factor_source_fails_assert_ids_of_successful_tx_e4::() - .await - } - - #[actix_rt::test] - async fn building_can_succeed_even_if_one_factor_source_fails_assert_ids_of_failed_tx( - ) { - building_can_succeed_even_if_one_factor_source_fails_assert_ids_of_failed_tx_e4::().await - } - } - - mod persona { - use super::*; - type E = Persona; - - #[actix_rt::test] - async fn prudent_user_single_tx_p0() { - prudent_user_single_tx_e0::().await - } - - #[actix_rt::test] - async fn prudent_user_single_tx_p0_assert_correct_intent_hash_is_signed() { - prudent_user_single_tx_e0_assert_correct_intent_hash_is_signed::().await - } - - #[actix_rt::test] - async fn prudent_user_single_tx_p0_assert_correct_owner_has_signed() { - prudent_user_single_tx_e0_assert_correct_owner_has_signed::().await - } - - #[actix_rt::test] - async fn prudent_user_single_tx_p0_assert_correct_owner_factor_instance_signed() { - prudent_user_single_tx_e0_assert_correct_owner_factor_instance_signed::() - .await - } - - #[actix_rt::test] - async fn prudent_user_single_tx_p1() { - prudent_user_single_tx_e1::().await - } - - #[actix_rt::test] - async fn prudent_user_single_tx_p2() { - prudent_user_single_tx_e2::().await - } - - #[actix_rt::test] - async fn prudent_user_single_tx_p3() { - prudent_user_single_tx_e3::().await - } - - #[actix_rt::test] - async fn prudent_user_single_tx_p4() { - prudent_user_single_tx_e4::().await - } - - #[actix_rt::test] - async fn prudent_user_single_tx_p5() { - prudent_user_single_tx_e5::().await - } - - #[actix_rt::test] - async fn prudent_user_single_tx_p6() { - prudent_user_single_tx_e6::().await - } - - #[actix_rt::test] - async fn prudent_user_single_tx_p7() { - prudent_user_single_tx_e7::().await - } - - #[actix_rt::test] - async fn lazy_sign_minimum_user_single_tx_p0() { - lazy_sign_minimum_user_single_tx_e0::().await - } - - #[actix_rt::test] - async fn lazy_sign_minimum_user_single_tx_p1() { - lazy_sign_minimum_user_single_tx_e1::().await - } - - #[actix_rt::test] - async fn lazy_sign_minimum_user_single_tx_p2() { - lazy_sign_minimum_user_single_tx_e2::().await - } - - #[actix_rt::test] - async fn lazy_sign_minimum_user_p3() { - lazy_sign_minimum_user_e3::().await - } - - #[actix_rt::test] - async fn lazy_sign_minimum_user_p4() { - lazy_sign_minimum_user_e4::().await - } - - #[actix_rt::test] - async fn lazy_sign_minimum_user_p5() { - lazy_sign_minimum_user_e5::().await - } - - #[actix_rt::test] - async fn lazy_sign_minimum_user_p6() { - lazy_sign_minimum_user_e6::().await - } - - #[actix_rt::test] - async fn lazy_sign_minimum_user_p7() { - lazy_sign_minimum_user_e7::().await - } - - #[actix_rt::test] - async fn lazy_sign_minimum_user_p5_last_factor_used() { - lazy_sign_minimum_user_e5_last_factor_used::().await - } - - #[actix_rt::test] - async fn lazy_sign_minimum_all_known_factors_used_as_override_factors_signed_with_device_for_account( - ) { - lazy_sign_minimum_all_known_factors_used_as_override_factors_signed_with_device_for_entity::().await - } - - #[actix_rt::test] - async fn lazy_always_skip_user_single_tx_p0() { - lazy_always_skip_user_single_tx_e0::().await - } - - #[actix_rt::test] - async fn fail_get_skipped_p0() { - fail_get_neglected_e0::().await - } - - #[actix_rt::test] - async fn lazy_always_skip_user_single_tx_p1() { - lazy_always_skip_user_single_tx_e1::().await - } - - #[actix_rt::test] - async fn lazy_always_skip_user_single_tx_p2() { - lazy_always_skip_user_single_tx_e2::().await - } - - #[actix_rt::test] - async fn lazy_always_skip_user_p3() { - lazy_always_skip_user_e3::().await - } - - #[actix_rt::test] - async fn lazy_always_skip_user_p4() { - lazy_always_skip_user_e4::().await - } - - #[actix_rt::test] - async fn lazy_always_skip_user_p5() { - lazy_always_skip_user_e5::().await - } - - #[actix_rt::test] - async fn lazy_always_skip_user_p6() { - lazy_always_skip_user_e6::().await - } - - #[actix_rt::test] - async fn lazy_always_skip_user_p7() { - lazy_always_skip_user_e7::().await - } - - #[actix_rt::test] - async fn failure_p0() { - failure_e0::().await - } - - #[actix_rt::test] - async fn failure_p5() { - failure_e5::().await - } - - #[actix_rt::test] - async fn building_can_succeed_even_if_one_factor_source_fails_assert_ids_of_successful_tx( - ) { - building_can_succeed_even_if_one_factor_source_fails_assert_ids_of_successful_tx_e4::() - .await - } - - #[actix_rt::test] - async fn building_can_succeed_even_if_one_factor_source_fails_assert_ids_of_failed_tx( - ) { - building_can_succeed_even_if_one_factor_source_fails_assert_ids_of_failed_tx_e4::().await - } - } - } - } -} diff --git a/src/signing/tx_to_sign.rs b/src/signing/tx_to_sign.rs deleted file mode 100644 index 133c7211..00000000 --- a/src/signing/tx_to_sign.rs +++ /dev/null @@ -1,70 +0,0 @@ -use crate::prelude::*; - -#[derive(Clone, Debug, PartialEq, Eq, std::hash::Hash)] -pub(crate) struct TXToSign { - pub(crate) intent_hash: IntentHash, - entities_requiring_auth: Vec, // should be a set but Sets are not `Hash`. -} - -impl TXToSign { - pub(crate) fn with( - intent_hash: IntentHash, - entities_requiring_auth: impl IntoIterator>, - ) -> Self { - Self { - intent_hash, - entities_requiring_auth: entities_requiring_auth - .into_iter() - .map(|i| i.into()) - .collect_vec(), - } - } - - #[allow(unused)] - pub(crate) fn new( - entities_requiring_auth: impl IntoIterator>, - ) -> Self { - Self::with(IntentHash::generate(), entities_requiring_auth) - } - - pub(crate) fn entities_requiring_auth(&self) -> IndexSet { - self.entities_requiring_auth.clone().into_iter().collect() - } - - pub(crate) fn extracting_from_intent_and_profile( - intent: &TransactionIntent, - profile: &Profile, - ) -> Result { - let intent_hash = intent.intent_hash.clone(); - let summary = intent.manifest_summary(); - let mut entities_requiring_auth: IndexSet = IndexSet::new(); - - let accounts = summary - .addresses_of_accounts_requiring_auth - .iter() - .map(|a| profile.account_by_address(a)) - .collect::>>()?; - - entities_requiring_auth.extend( - accounts - .into_iter() - .map(AccountOrPersona::from) - .collect_vec(), - ); - - let personas = summary - .addresses_of_personas_requiring_auth - .into_iter() - .map(|a| profile.persona_by_address(a)) - .collect::>>()?; - - entities_requiring_auth.extend( - personas - .into_iter() - .map(AccountOrPersona::from) - .collect_vec(), - ); - - Ok(Self::with(intent_hash, entities_requiring_auth)) - } -} diff --git a/src/testing/derivation/mod.rs b/src/testing/derivation/mod.rs deleted file mode 100644 index 3dacb338..00000000 --- a/src/testing/derivation/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![cfg(test)] -#![allow(unused)] - -mod stateless_dummy_indices; -mod test_keys_collector; - -pub(crate) use stateless_dummy_indices::*; -pub(crate) use test_keys_collector::*; diff --git a/src/testing/derivation/stateless_dummy_indices.rs b/src/testing/derivation/stateless_dummy_indices.rs deleted file mode 100644 index f9b7f0c7..00000000 --- a/src/testing/derivation/stateless_dummy_indices.rs +++ /dev/null @@ -1,27 +0,0 @@ -#![cfg(test)] -#![allow(unused)] - -use crate::prelude::*; - -#[derive(Default, Clone, Debug)] -pub(crate) struct StatelessDummyIndices; - -impl StatelessDummyIndices { - pub(crate) fn next_derivation_index_for(&self, key_space: KeySpace) -> HDPathComponent { - match key_space { - KeySpace::Securified => HDPathComponent::securifying_base_index(0), - KeySpace::Unsecurified => HDPathComponent::unsecurified_hardening_base_index(0), - } - } - - pub(crate) fn next_derivation_path( - &self, - network_id: NetworkID, - key_kind: CAP26KeyKind, - entity_kind: CAP26EntityKind, - key_space: KeySpace, - ) -> DerivationPath { - let index = self.next_derivation_index_for(key_space); - DerivationPath::new(network_id, entity_kind, key_kind, index) - } -} diff --git a/src/testing/derivation/test_keys_collector.rs b/src/testing/derivation/test_keys_collector.rs deleted file mode 100644 index 06abc4ea..00000000 --- a/src/testing/derivation/test_keys_collector.rs +++ /dev/null @@ -1,190 +0,0 @@ -#![cfg(test)] -#![allow(unused)] - -use crate::prelude::*; - -pub(crate) struct TestDerivationInteractors { - pub(crate) poly: Arc, - pub(crate) mono: Arc, -} -impl TestDerivationInteractors { - pub(crate) fn new( - poly: impl PolyFactorKeyDerivationInteractor + Send + Sync + 'static, - mono: impl MonoFactorKeyDerivationInteractor + Send + Sync + 'static, - ) -> Self { - Self { - poly: Arc::new(poly), - mono: Arc::new(mono), - } - } -} - -impl TestDerivationInteractors { - pub(crate) fn fail() -> Self { - Self::new( - TestDerivationPolyInteractor::fail(), - TestDerivationMonoInteractor::fail(), - ) - } -} -impl Default for TestDerivationInteractors { - fn default() -> Self { - Self::new( - TestDerivationPolyInteractor::default(), - TestDerivationMonoInteractor::default(), - ) - } -} - -impl KeysDerivationInteractors for TestDerivationInteractors { - fn interactor_for(&self, kind: FactorSourceKind) -> KeyDerivationInteractor { - match kind { - FactorSourceKind::Device => KeyDerivationInteractor::poly(self.poly.clone()), - _ => KeyDerivationInteractor::mono(self.mono.clone()), - } - } -} - -pub(crate) struct TestDerivationPolyInteractor { - handle: fn( - MonoFactorKeyDerivationRequest, - ) -> Result>, -} -impl TestDerivationPolyInteractor { - pub(crate) fn new( - handle: fn( - MonoFactorKeyDerivationRequest, - ) -> Result>, - ) -> Self { - Self { handle } - } - pub(crate) fn fail() -> Self { - Self::new(|_| Err(CommonError::HardcodedFailureTestDerivationInteractor)) - } - fn derive( - &self, - request: MonoFactorKeyDerivationRequest, - ) -> Result> { - (self.handle)(request) - } -} -impl Default for TestDerivationPolyInteractor { - fn default() -> Self { - Self::new(do_derive_serially) - } -} - -fn do_derive_serially( - request: MonoFactorKeyDerivationRequest, -) -> Result> { - let factor_source_id = &request.factor_source_id; - let instances = request - .derivation_paths - .into_iter() - .map(|p| HierarchicalDeterministicFactorInstance::mocked_with(p, factor_source_id)) - .collect::>(); - - Ok(instances) -} - -#[async_trait::async_trait] -impl PolyFactorKeyDerivationInteractor for TestDerivationPolyInteractor { - async fn derive( - &self, - request: PolyFactorKeyDerivationRequest, - ) -> Result { - let pairs_result: Result< - IndexMap>, - > = request - .per_factor_source - .into_iter() - .map(|(k, r)| { - let instances = self.derive(r); - instances.map(|i| (k, i)) - }) - .collect(); - let pairs = pairs_result?; - Ok(KeyDerivationResponse::new(pairs)) - } -} - -pub(crate) struct TestDerivationMonoInteractor { - handle: fn( - MonoFactorKeyDerivationRequest, - ) -> Result>, -} -impl TestDerivationMonoInteractor { - pub(crate) fn new( - handle: fn( - MonoFactorKeyDerivationRequest, - ) -> Result>, - ) -> Self { - Self { handle } - } - pub(crate) fn fail() -> Self { - Self::new(|_| Err(CommonError::HardcodedFailureTestDerivationInteractor)) - } - fn derive( - &self, - request: MonoFactorKeyDerivationRequest, - ) -> Result> { - (self.handle)(request) - } -} -impl Default for TestDerivationMonoInteractor { - fn default() -> Self { - Self::new(do_derive_serially) - } -} - -#[async_trait::async_trait] -impl MonoFactorKeyDerivationInteractor for TestDerivationMonoInteractor { - async fn derive( - &self, - request: MonoFactorKeyDerivationRequest, - ) -> Result { - let instances = self.derive(request.clone())?; - Ok(KeyDerivationResponse::new(IndexMap::just(( - request.factor_source_id, - instances, - )))) - } -} - -impl KeysCollector { - pub(crate) fn new_test_with_factor_sources( - all_factor_sources_in_profile: impl IntoIterator, - derivation_paths: impl IntoIterator)>, - ) -> Self { - sensible_env_logger::safe_init!(); - Self::new( - all_factor_sources_in_profile, - derivation_paths - .into_iter() - .collect::>>(), - Arc::new(TestDerivationInteractors::default()), - ) - .unwrap() - } - - pub(crate) fn new_test( - derivation_paths: impl IntoIterator)>, - ) -> Self { - Self::new_test_with_factor_sources(HDFactorSource::all(), derivation_paths) - } - - pub(crate) fn with( - factor_source: &HDFactorSource, - network_id: NetworkID, - key_kind: CAP26KeyKind, - entity_kind: CAP26EntityKind, - key_space: KeySpace, - ) -> Self { - let indices = StatelessDummyIndices; - let path = indices.next_derivation_path(network_id, key_kind, entity_kind, key_space); - Self::new_test_with_factor_sources( - [factor_source.clone()], - [(factor_source.factor_source_id(), IndexSet::just(path))], - ) - } -} diff --git a/src/testing/mod.rs b/src/testing/mod.rs deleted file mode 100644 index 229dbdd7..00000000 --- a/src/testing/mod.rs +++ /dev/null @@ -1,38 +0,0 @@ -#![cfg(test)] -#![allow(unused)] - -mod derivation; -mod signing; - -pub(crate) use derivation::*; -pub(crate) use signing::*; - -#[cfg(test)] -mod common_tests { - - use crate::prelude::*; - - #[test] - fn factors_sources() { - assert_eq!(ALL_FACTOR_SOURCES.clone(), ALL_FACTOR_SOURCES.clone()); - } - - #[test] - fn factors_source_ids() { - assert_eq!(FactorSourceIDFromHash::fs0(), FactorSourceIDFromHash::fs0()); - assert_eq!(FactorSourceIDFromHash::fs1(), FactorSourceIDFromHash::fs1()); - assert_ne!(FactorSourceIDFromHash::fs0(), FactorSourceIDFromHash::fs1()); - } - - #[test] - fn factor_instance_in_accounts() { - assert_eq!( - Account::a0().security_state.all_factor_instances(), - Account::a0().security_state.all_factor_instances() - ); - assert_eq!( - Account::a6().security_state.all_factor_instances(), - Account::a6().security_state.all_factor_instances() - ); - } -} diff --git a/src/testing/signing/mod.rs b/src/testing/signing/mod.rs deleted file mode 100644 index 6e797cac..00000000 --- a/src/testing/signing/mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -#![cfg(test)] -#![allow(unused)] -#![allow(unused_imports)] - -mod simulated_user; -mod test_interactors; -mod test_signature_collecting_interactors; -mod test_signatures_collector; - -pub(crate) use simulated_user::*; -pub(crate) use test_interactors::*; -pub(crate) use test_signature_collecting_interactors::*; -pub(crate) use test_signatures_collector::*; diff --git a/src/testing/signing/simulated_user.rs b/src/testing/signing/simulated_user.rs deleted file mode 100644 index 51ed0989..00000000 --- a/src/testing/signing/simulated_user.rs +++ /dev/null @@ -1,179 +0,0 @@ -#![cfg(test)] -#![allow(unused)] - -use crate::prelude::*; - -#[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) enum SigningUserInput { - Sign, - Skip, -} - -#[derive(Clone, derive_more::Debug)] -#[debug("SimulatedUser(mode: {mode:?}, failures: {failures:?})")] -pub(crate) struct SimulatedUser { - spy_on_request: Arc)>, - mode: SimulatedUserMode, - /// `None` means never failures - failures: Option, -} - -impl SimulatedUser { - pub(crate) fn with_spy( - spy_on_request: impl Fn(FactorSourceKind, IndexSet) + 'static, - mode: SimulatedUserMode, - failures: impl Into>, - ) -> Self { - Self { - spy_on_request: Arc::new(spy_on_request), - mode, - failures: failures.into(), - } - } - pub(crate) fn new( - mode: SimulatedUserMode, - failures: impl Into>, - ) -> Self { - Self::with_spy(|_, _| {}, mode, failures) - } -} - -#[derive(Debug, Clone, Default)] -pub(crate) struct SimulatedFailures { - /// Set of FactorSources which should always fail. - simulated_failures: IndexSet, -} -impl SimulatedFailures { - pub(crate) fn with_details(simulated_failures: IndexSet) -> Self { - Self { simulated_failures } - } - - pub(crate) fn with_simulated_failures( - failures: impl IntoIterator, - ) -> Self { - Self::with_details(IndexSet::from_iter(failures)) - } - - /// If needed, simulates failure for ALL factor sources or NONE. - pub(crate) fn simulate_failure_if_needed( - &self, - factor_source_ids: IndexSet, - ) -> bool { - factor_source_ids - .into_iter() - .all(|id| self.simulated_failures.contains(&id)) - } -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) enum SimulatedUserMode { - /// Emulation of a "prudent" user, that signs with all factors sources, i.e. - /// she never ever "skips" a factor source - Prudent, - - /// Emulation of a "lazy" user, that skips signing with as many factor - /// sources as possible. - Lazy(Laziness), -} - -impl SimulatedUserMode { - pub(crate) fn lazy_always_skip() -> Self { - Self::Lazy(Laziness::AlwaysSkip) - } - - /// Skips only if `invalid_tx_if_skipped` is empty - pub(crate) fn lazy_sign_minimum() -> Self { - Self::Lazy(Laziness::SignMinimum) - } -} - -impl SimulatedUser { - pub(crate) fn prudent_no_fail() -> Self { - Self::new(SimulatedUserMode::Prudent, None) - } - - pub(crate) fn prudent_with_failures(simulated_failures: SimulatedFailures) -> Self { - Self::new(SimulatedUserMode::Prudent, simulated_failures) - } - - pub(crate) fn lazy_always_skip_no_fail() -> Self { - Self::new(SimulatedUserMode::lazy_always_skip(), None) - } - - /// Skips only if `invalid_tx_if_skipped` is empty - /// (or if simulated failure for that factor source) - pub(crate) fn lazy_sign_minimum( - simulated_failures: impl IntoIterator, - ) -> Self { - Self::new( - SimulatedUserMode::lazy_sign_minimum(), - SimulatedFailures::with_simulated_failures(simulated_failures), - ) - } -} - -unsafe impl Sync for SimulatedUser {} -unsafe impl Send for SimulatedUser {} - -/// A very lazy user that defers all boring work such as signing stuff for as long -/// as possible. Ironically, this sometimes leads to user signing more than she -/// actually needs. For example, if the user has a Securified Account with threshold -/// and override factors, she actually needs to sign with a single override -/// factor. But since user is so lazy, she defers signing with that override -/// factor if prompted for it first. -#[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) enum Laziness { - SignMinimum, - AlwaysSkip, -} - -impl SimulatedUser { - pub(crate) fn spy_on_request_before_handled( - &self, - factor_source_kind: FactorSourceKind, - invalid_tx_if_skipped: IndexSet, - ) { - (self.spy_on_request)(factor_source_kind, invalid_tx_if_skipped.clone()); - } - - pub(crate) fn sign_or_skip( - &self, - invalid_tx_if_skipped: impl IntoIterator, - ) -> SigningUserInput { - let invalid_tx_if_skipped = invalid_tx_if_skipped - .into_iter() - .collect::>(); - - if self.be_prudent(|| !invalid_tx_if_skipped.is_empty()) { - SigningUserInput::Sign - } else { - SigningUserInput::Skip - } - } - - pub(crate) fn simulate_failure_if_needed( - &self, - factor_source_ids: IndexSet, - ) -> bool { - if let Some(failures) = &self.failures { - failures.simulate_failure_if_needed(factor_source_ids) - } else { - false - } - } - - fn be_prudent(&self, is_prudent: F) -> bool - where - F: Fn() -> bool, - { - use rand::prelude::*; - - match &self.mode { - SimulatedUserMode::Prudent => true, - SimulatedUserMode::Lazy(laziness) => match laziness { - Laziness::AlwaysSkip => false, - Laziness::SignMinimum => is_prudent(), - }, - } - } -} diff --git a/src/testing/signing/test_interactors/mod.rs b/src/testing/signing/test_interactors/mod.rs deleted file mode 100644 index 4d2f81be..00000000 --- a/src/testing/signing/test_interactors/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![cfg(test)] -#![allow(unused)] - -mod test_interactor; -mod test_parallel_interactor; -mod test_serial_interactor; - -pub(crate) use test_interactor::*; -pub(crate) use test_parallel_interactor::*; -pub(crate) use test_serial_interactor::*; diff --git a/src/testing/signing/test_interactors/test_interactor.rs b/src/testing/signing/test_interactors/test_interactor.rs deleted file mode 100644 index 4f8a13b2..00000000 --- a/src/testing/signing/test_interactors/test_interactor.rs +++ /dev/null @@ -1,14 +0,0 @@ -#![cfg(test)] -#![allow(unused)] - -use crate::prelude::*; - -#[async_trait::async_trait] -pub(crate) trait IsTestInteractor: Sync { - fn simulated_user(&self) -> SimulatedUser; - - fn should_simulate_failure(&self, factor_source_ids: IndexSet) -> bool { - self.simulated_user() - .simulate_failure_if_needed(factor_source_ids) - } -} diff --git a/src/testing/signing/test_interactors/test_parallel_interactor.rs b/src/testing/signing/test_interactors/test_parallel_interactor.rs deleted file mode 100644 index cfd05ed9..00000000 --- a/src/testing/signing/test_interactors/test_parallel_interactor.rs +++ /dev/null @@ -1,77 +0,0 @@ -#![cfg(test)] -#![allow(unused)] - -use crate::prelude::*; - -pub(crate) struct TestSigningParallelInteractor { - simulated_user: SimulatedUser, -} - -impl TestSigningParallelInteractor { - pub(crate) fn new(simulated_user: SimulatedUser) -> Self { - Self { simulated_user } - } -} - -#[async_trait::async_trait] -impl IsTestInteractor for TestSigningParallelInteractor { - fn simulated_user(&self) -> SimulatedUser { - self.simulated_user.clone() - } -} - -#[async_trait::async_trait] -impl PolyFactorSignInteractor for TestSigningParallelInteractor { - async fn sign(&self, request: PolyFactorSignRequest) -> SignWithFactorsOutcome { - self.simulated_user.spy_on_request_before_handled( - request.clone().factor_source_kind(), - request.clone().invalid_transactions_if_neglected, - ); - let ids = request - .per_factor_source - .keys() - .cloned() - .collect::>(); - - if self.should_simulate_failure(ids.clone()) { - return SignWithFactorsOutcome::failure_with_factors(ids); - } - - match self - .simulated_user - .sign_or_skip(request.invalid_transactions_if_neglected) - { - SigningUserInput::Sign => { - let signatures = request - .per_factor_source - .iter() - .flat_map(|(_, v)| { - v.per_transaction - .iter() - .flat_map(|x| { - x.signature_inputs() - .iter() - .map(|y| HDSignature::produced_signing_with_input(y.clone())) - .collect_vec() - }) - .collect::>() - }) - .collect::>(); - - let signatures = signatures - .into_iter() - .into_group_map_by(|x| x.factor_source_id()); - let response = SignResponse::new( - signatures - .into_iter() - .map(|(k, v)| (k, IndexSet::from_iter(v))) - .collect(), - ); - - SignWithFactorsOutcome::signed(response) - } - - SigningUserInput::Skip => SignWithFactorsOutcome::user_skipped_factors(ids), - } - } -} diff --git a/src/testing/signing/test_interactors/test_serial_interactor.rs b/src/testing/signing/test_interactors/test_serial_interactor.rs deleted file mode 100644 index 5bc874bc..00000000 --- a/src/testing/signing/test_interactors/test_serial_interactor.rs +++ /dev/null @@ -1,59 +0,0 @@ -#![cfg(test)] -#![allow(unused)] - -use crate::prelude::*; - -pub(crate) struct TestSigningSerialInteractor { - simulated_user: SimulatedUser, -} - -impl TestSigningSerialInteractor { - pub(crate) fn new(simulated_user: SimulatedUser) -> Self { - Self { simulated_user } - } -} - -#[async_trait::async_trait] -impl IsTestInteractor for TestSigningSerialInteractor { - fn simulated_user(&self) -> SimulatedUser { - self.simulated_user.clone() - } -} - -#[async_trait::async_trait] -impl MonoFactorSignInteractor for TestSigningSerialInteractor { - async fn sign(&self, request: MonoFactorSignRequest) -> SignWithFactorsOutcome { - self.simulated_user.spy_on_request_before_handled( - request.clone().factor_source_kind(), - request.clone().invalid_transactions_if_neglected, - ); - let ids = IndexSet::from_iter([request.clone().input.factor_source_id]); - if self.should_simulate_failure(ids.clone()) { - return SignWithFactorsOutcome::failure_with_factors(ids); - } - let invalid_transactions_if_neglected = request.clone().invalid_transactions_if_neglected; - - match self - .simulated_user - .sign_or_skip(invalid_transactions_if_neglected) - { - SigningUserInput::Sign => { - let signatures = request - .input - .per_transaction - .into_iter() - .flat_map(|r| { - r.signature_inputs() - .iter() - .map(|x| HDSignature::produced_signing_with_input(x.clone())) - .collect::>() - }) - .collect::>(); - SignWithFactorsOutcome::signed(SignResponse::with_signatures(signatures)) - } - SigningUserInput::Skip => { - SignWithFactorsOutcome::user_skipped_factor(request.input.factor_source_id) - } - } - } -} diff --git a/src/testing/signing/test_signature_collecting_interactors.rs b/src/testing/signing/test_signature_collecting_interactors.rs deleted file mode 100644 index e74003ac..00000000 --- a/src/testing/signing/test_signature_collecting_interactors.rs +++ /dev/null @@ -1,27 +0,0 @@ -#![cfg(test)] -#![allow(unused)] - -use crate::prelude::*; - -pub(crate) struct TestSignatureCollectingInteractors { - pub(crate) simulated_user: SimulatedUser, -} - -impl TestSignatureCollectingInteractors { - pub(crate) fn new(simulated_user: SimulatedUser) -> Self { - Self { simulated_user } - } -} - -impl SignInteractors for TestSignatureCollectingInteractors { - fn interactor_for(&self, kind: FactorSourceKind) -> SignInteractor { - match kind { - FactorSourceKind::Device => SignInteractor::poly(Arc::new( - TestSigningParallelInteractor::new(self.simulated_user.clone()), - )), - _ => SignInteractor::mono(Arc::new(TestSigningSerialInteractor::new( - self.simulated_user.clone(), - ))), - } - } -} diff --git a/src/testing/signing/test_signatures_collector.rs b/src/testing/signing/test_signatures_collector.rs deleted file mode 100644 index d3aa6c8e..00000000 --- a/src/testing/signing/test_signatures_collector.rs +++ /dev/null @@ -1,110 +0,0 @@ -#![cfg(test)] -#![allow(unused)] - -use crate::prelude::*; - -impl SignaturesCollector { - /// Used by our tests. But Sargon will typically wanna use `SignaturesCollector::new` and passing - /// it a - pub(crate) fn new_test_with( - finish_early_strategy: SigningFinishEarlyStrategy, - all_factor_sources_in_profile: IndexSet, - transactions: IndexSet, - interactors: Arc, - ) -> Self { - sensible_env_logger::safe_init!(); - Self::with( - finish_early_strategy, - all_factor_sources_in_profile, - transactions, - interactors, - ) - } - pub(crate) fn new_test( - finish_early_strategy: SigningFinishEarlyStrategy, - all_factor_sources_in_profile: impl IntoIterator, - transactions: impl IntoIterator, - simulated_user: SimulatedUser, - ) -> Self { - Self::new_test_with( - finish_early_strategy, - all_factor_sources_in_profile.into_iter().collect(), - transactions.into_iter().collect(), - Arc::new(TestSignatureCollectingInteractors::new(simulated_user)), - ) - } - - pub(crate) fn test_prudent_with_factors_and_finish_early( - finish_early_strategy: SigningFinishEarlyStrategy, - all_factor_sources_in_profile: impl IntoIterator, - transactions: impl IntoIterator, - ) -> Self { - Self::new_test( - finish_early_strategy, - all_factor_sources_in_profile, - transactions, - SimulatedUser::prudent_no_fail(), - ) - } - - pub(crate) fn test_prudent_with_finish_early( - finish_early_strategy: SigningFinishEarlyStrategy, - transactions: impl IntoIterator, - ) -> Self { - Self::test_prudent_with_factors_and_finish_early( - finish_early_strategy, - HDFactorSource::all(), - transactions, - ) - } - - pub(crate) fn test_prudent(transactions: impl IntoIterator) -> Self { - Self::test_prudent_with_finish_early(SigningFinishEarlyStrategy::default(), transactions) - } - - pub(crate) fn test_prudent_with_failures( - transactions: impl IntoIterator, - simulated_failures: SimulatedFailures, - ) -> Self { - Self::new_test( - SigningFinishEarlyStrategy::default(), - HDFactorSource::all(), - transactions, - SimulatedUser::prudent_with_failures(simulated_failures), - ) - } - - pub(crate) fn test_lazy_sign_minimum_no_failures_with_factors( - all_factor_sources_in_profile: impl IntoIterator, - transactions: impl IntoIterator, - ) -> Self { - Self::new_test( - SigningFinishEarlyStrategy::default(), - all_factor_sources_in_profile, - transactions, - SimulatedUser::lazy_sign_minimum([]), - ) - } - - pub(crate) fn test_lazy_sign_minimum_no_failures( - transactions: impl IntoIterator, - ) -> Self { - Self::test_lazy_sign_minimum_no_failures_with_factors(HDFactorSource::all(), transactions) - } - - pub(crate) fn test_lazy_always_skip_with_factors( - all_factor_sources_in_profile: impl IntoIterator, - transactions: impl IntoIterator, - ) -> Self { - Self::new_test( - SigningFinishEarlyStrategy::default(), - all_factor_sources_in_profile, - transactions, - SimulatedUser::lazy_always_skip_no_fail(), - ) - } - - pub(crate) fn test_lazy_always_skip(transactions: impl IntoIterator) -> Self { - Self::test_lazy_always_skip_with_factors(HDFactorSource::all(), transactions) - } -} diff --git a/src/types/factor_sources_of_kind.rs b/src/types/factor_sources_of_kind.rs deleted file mode 100644 index 8c307790..00000000 --- a/src/types/factor_sources_of_kind.rs +++ /dev/null @@ -1,88 +0,0 @@ -use crate::prelude::*; - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct FactorSourcesOfKind { - pub(crate) kind: FactorSourceKind, - factor_sources: Vec, -} - -impl FactorSourcesOfKind { - pub(crate) fn new( - kind: FactorSourceKind, - factor_sources: impl IntoIterator, - ) -> Result { - let factor_sources = factor_sources.into_iter().collect::>(); - if factor_sources.is_empty() { - return Err(CommonError::FactorSourcesOfKindEmptyFactors); - } - if factor_sources - .iter() - .any(|f| f.factor_source_kind() != kind) - { - return Err(CommonError::InvalidFactorSourceKind); - } - Ok(Self { - kind, - factor_sources: factor_sources.into_iter().collect(), - }) - } - - pub(crate) fn factor_sources(&self) -> IndexSet { - self.factor_sources.clone().into_iter().collect() - } -} - -#[cfg(test)] -mod tests { - use super::*; - type Sut = FactorSourcesOfKind; - - #[test] - fn invalid_empty() { - assert_eq!( - Sut::new(FactorSourceKind::Device, []), - Err(CommonError::FactorSourcesOfKindEmptyFactors) - ); - } - - #[test] - fn invalid_single_element() { - assert_eq!( - Sut::new(FactorSourceKind::Device, [HDFactorSource::arculus()]), - Err(CommonError::InvalidFactorSourceKind) - ); - } - - #[test] - fn invalid_two_two() { - assert_eq!( - Sut::new( - FactorSourceKind::Device, - [ - HDFactorSource::arculus(), - HDFactorSource::device(), - HDFactorSource::arculus(), - HDFactorSource::device() - ] - ), - Err(CommonError::InvalidFactorSourceKind) - ); - } - - #[test] - fn valid_one() { - let sources = IndexSet::::just(HDFactorSource::device()); - let sut = Sut::new(FactorSourceKind::Device, sources.clone()).unwrap(); - assert_eq!(sut.factor_sources(), sources); - } - - #[test] - fn valid_two() { - let sources = IndexSet::::from_iter([ - HDFactorSource::ledger(), - HDFactorSource::ledger(), - ]); - let sut = Sut::new(FactorSourceKind::Ledger, sources.clone()).unwrap(); - assert_eq!(sut.factor_sources(), sources); - } -} diff --git a/src/types/hd_signature.rs b/src/types/hd_signature.rs deleted file mode 100644 index a895515d..00000000 --- a/src/types/hd_signature.rs +++ /dev/null @@ -1,93 +0,0 @@ -use crate::prelude::*; - -/// A signature of `intent_hash` by `entity` using `factor_source_id` and `derivation_path`, with `public_key` used for verification. -#[derive(Clone, PartialEq, Eq, Hash, derive_more::Debug)] -#[debug("HDSignature {{ input: {:#?} }}", input)] -pub struct HDSignature { - /// The input used to produce this `HDSignature` - pub input: HDSignatureInput, - - /// The ECDSA/EdDSA signature produced by the private key of the - /// `owned_hd_factor_instance.public_key`, - /// derived by the HDFactorSource identified by - /// `owned_hd_factor_instance.factor_source_id` and which - /// was derived at `owned_hd_factor_instance.derivation_path`. - pub signature: Signature, -} - -impl HDSignature { - pub fn produced_signing_with_input(input: HDSignatureInput) -> Self { - let signature = Signature::produced_by_input(&input); - Self::with_details(input, signature) - } - - /// Constructs a HDSignature from an already produced `Signature`. - fn with_details(input: HDSignatureInput, signature: Signature) -> Self { - Self { input, signature } - } - - pub fn intent_hash(&self) -> &IntentHash { - &self.input.intent_hash - } - - pub fn owned_factor_instance(&self) -> &OwnedFactorInstance { - &self.input.owned_factor_instance - } - - pub fn factor_source_id(&self) -> FactorSourceIDFromHash { - self.owned_factor_instance() - .factor_instance() - .factor_source_id - } - - pub fn derivation_path(&self) -> DerivationPath { - self.input - .owned_factor_instance - .factor_instance() - .derivation_path() - } -} - -impl HasSampleValues for HDSignature { - fn sample() -> Self { - let input = HDSignatureInput::sample(); - Self::produced_signing_with_input(input) - } - - fn sample_other() -> Self { - let input = HDSignatureInput::sample_other(); - Self::produced_signing_with_input(input) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - type Sut = HDSignature; - - #[test] - fn equality_of_samples() { - assert_eq!(Sut::sample(), Sut::sample()); - assert_eq!(Sut::sample_other(), Sut::sample_other()); - } - - #[test] - fn inequality_of_samples() { - assert_ne!(Sut::sample(), Sut::sample_other()); - } - - #[test] - fn hash_of_samples() { - assert_eq!( - IndexSet::::from_iter([ - Sut::sample(), - Sut::sample_other(), - Sut::sample(), - Sut::sample_other() - ]) - .len(), - 2 - ); - } -} diff --git a/src/types/hd_signature_input.rs b/src/types/hd_signature_input.rs deleted file mode 100644 index 006edbfb..00000000 --- a/src/types/hd_signature_input.rs +++ /dev/null @@ -1,72 +0,0 @@ -use crate::prelude::*; - -/// The input used to produce a `HDSignature`. Can be used to see two signatures -/// has the same signer, which would be a bug. -#[derive(Clone, PartialEq, Eq, Hash, derive_more::Debug)] -#[debug( - "HDSignatureInput {{ intent_hash: {:#?}, owned_factor_instance: {:#?} }}", - intent_hash, - owned_factor_instance -)] -pub struct HDSignatureInput { - /// Hash which was signed. - pub intent_hash: IntentHash, - - /// The account or identity address of the entity which signed the hash, - /// with expected public key and with derivation path to derive PrivateKey - /// with. - pub owned_factor_instance: OwnedFactorInstance, -} -impl HDSignatureInput { - /// Constructs a new `HDSignatureInput`. - pub fn new(intent_hash: IntentHash, owned_factor_instance: OwnedFactorInstance) -> Self { - Self { - intent_hash, - owned_factor_instance, - } - } -} - -impl HasSampleValues for HDSignatureInput { - fn sample() -> Self { - Self::new(IntentHash::sample(), OwnedFactorInstance::sample()) - } - fn sample_other() -> Self { - Self::new( - IntentHash::sample_other(), - OwnedFactorInstance::sample_other(), - ) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - type Sut = HDSignatureInput; - - #[test] - fn equality_of_samples() { - assert_eq!(Sut::sample(), Sut::sample()); - assert_eq!(Sut::sample_other(), Sut::sample_other()); - } - - #[test] - fn inequality_of_samples() { - assert_ne!(Sut::sample(), Sut::sample_other()); - } - - #[test] - fn hash_of_samples() { - assert_eq!( - IndexSet::::from_iter([ - Sut::sample(), - Sut::sample_other(), - Sut::sample(), - Sut::sample_other() - ]) - .len(), - 2 - ); - } -} diff --git a/src/types/hidden_constructor.rs b/src/types/hidden_constructor.rs deleted file mode 100644 index 963bb0a8..00000000 --- a/src/types/hidden_constructor.rs +++ /dev/null @@ -1,15 +0,0 @@ -/// A type used to hide a constructor for some other type, use -/// it like this: -/// -/// ```rust,ignore -/// pub struct ValidatedName { -/// hiding_ctor: HiddenConstructor, -/// pub name: String, -/// pub name_appended_to_name: String // validated! -/// } -/// ``` -/// -/// Making it impossible to create `ValidatedName` with invalid value! -/// -#[derive(Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct HiddenConstructor; diff --git a/src/types/invalid_transaction_if_neglected.rs b/src/types/invalid_transaction_if_neglected.rs deleted file mode 100644 index 6881ca29..00000000 --- a/src/types/invalid_transaction_if_neglected.rs +++ /dev/null @@ -1,91 +0,0 @@ -use crate::prelude::*; - -/// A list of entities which would fail in a transaction if we would -/// neglect certain factor source, either by user explicitly skipping -/// it or if implicitly neglected due to failure. -#[derive(Clone, Debug, PartialEq, Eq, std::hash::Hash)] -pub struct InvalidTransactionIfNeglected { - /// The intent hash of the transaction which would be invalid if a - /// certain factor source would be neglected, either if user - /// explicitly skipped it or implicitly neglected due to failure. - pub intent_hash: IntentHash, - - /// The entities in the transaction which would fail auth. - entities_which_would_fail_auth: Vec, -} - -impl InvalidTransactionIfNeglected { - /// Constructs a new `InvalidTransactionIfNeglected` from an IndexSet of - /// entities which would fail auth.. - /// - /// # Panics - /// Panics if `entities_which_would_fail_auth` is empty. - pub fn new( - intent_hash: IntentHash, - entities_which_would_fail_auth: impl IntoIterator, - ) -> Self { - let entities_which_would_fail_auth = - entities_which_would_fail_auth.into_iter().collect_vec(); - let len = entities_which_would_fail_auth.len(); - let entities_which_would_fail_auth = entities_which_would_fail_auth - .into_iter() - .collect::>(); - - assert!(!entities_which_would_fail_auth.is_empty(), "'entities_which_would_fail_auth' must not be empty, this type is not useful if it is empty."); - - assert!( - entities_which_would_fail_auth.len() == len, - "entities_which_would_fail_auth must not contain duplicates." - ); - - Self { - intent_hash, - entities_which_would_fail_auth: entities_which_would_fail_auth - .into_iter() - .collect_vec(), - } - } - - pub fn entities_which_would_fail_auth(&self) -> IndexSet { - IndexSet::from_iter(self.entities_which_would_fail_auth.clone()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - type Sut = InvalidTransactionIfNeglected; - - #[test] - #[should_panic( - expected = "'entities_which_would_fail_auth' must not be empty, this type is not useful if it is empty." - )] - fn panics_if_empty() { - Sut::new(IntentHash::sample(), IndexSet::new()); - } - - #[test] - #[should_panic(expected = "entities_which_would_fail_auth must not contain duplicates.")] - fn panics_if_duplicates() { - Sut::new( - IntentHash::sample(), - [ - AddressOfAccountOrPersona::sample(), - AddressOfAccountOrPersona::sample(), - ], - ); - } - - #[test] - fn new() { - let entities = [ - AddressOfAccountOrPersona::sample(), - AddressOfAccountOrPersona::sample_other(), - ]; - let sut = Sut::new(IntentHash::sample(), entities.clone()); - assert_eq!( - sut.entities_which_would_fail_auth(), - IndexSet::<_>::from_iter(entities.into_iter()) - ); - } -} diff --git a/src/types/mod.rs b/src/types/mod.rs deleted file mode 100644 index fe209f6e..00000000 --- a/src/types/mod.rs +++ /dev/null @@ -1,19 +0,0 @@ -mod factor_sources_of_kind; -mod hd_signature; -mod hd_signature_input; -mod hidden_constructor; -mod invalid_transaction_if_neglected; -mod new_methods_on_sargon_types; -mod new_types; -mod owned_types; -mod sargon_types; - -pub(crate) use factor_sources_of_kind::*; -pub use hd_signature::*; -pub use hd_signature_input::*; -pub use hidden_constructor::*; -pub use invalid_transaction_if_neglected::*; -pub use new_methods_on_sargon_types::*; -pub use new_types::*; -pub use owned_types::*; -pub use sargon_types::*; diff --git a/src/types/new_methods_on_sargon_types.rs b/src/types/new_methods_on_sargon_types.rs deleted file mode 100644 index 22bb7ba9..00000000 --- a/src/types/new_methods_on_sargon_types.rs +++ /dev/null @@ -1,53 +0,0 @@ -use crate::prelude::*; - -impl AccountOrPersona { - pub fn address(&self) -> AddressOfAccountOrPersona { - match self { - Self::AccountEntity(a) => a.address().clone(), - Self::PersonaEntity(p) => p.address().clone(), - } - } - - pub fn security_state(&self) -> EntitySecurityState { - match self { - Self::AccountEntity(a) => a.security_state.clone(), - Self::PersonaEntity(p) => p.security_state.clone(), - } - } -} - -impl TransactionIntent { - pub fn manifest_summary(&self) -> ManifestSummary { - self.manifest.summary() - } -} - -impl DerivationPath { - pub fn key_space(&self) -> KeySpace { - self.index.key_space() - } -} - -#[cfg(test)] -impl Profile { - pub fn accounts<'a>(accounts: impl IntoIterator) -> Self { - Self::new([], accounts, []) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn account_address() { - let account = AccountOrPersona::from(Account::sample()); - assert_eq!(account.address().to_string(), "acco_0_12f3a9fc") - } - - #[test] - fn persona_address() { - let persona = AccountOrPersona::from(Persona::sample()); - assert_eq!(persona.address().to_string(), "iden_0_2b0a4c3f") - } -} diff --git a/src/types/new_types/accounts.rs b/src/types/new_types/accounts.rs deleted file mode 100644 index 843eb50c..00000000 --- a/src/types/new_types/accounts.rs +++ /dev/null @@ -1,84 +0,0 @@ -use crate::prelude::*; - -pub type Accounts = Entities; -pub type Personas = Entities; - -/// A NonEmpty collection of Entities all on the SAME Network -/// but mixed if they are securified or unsecurified. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct Entities { - pub network_id: NetworkID, - entities: IndexSet, -} - -impl Entities { - pub fn new(network_id: NetworkID, entities: IndexSet) -> Result { - if entities.is_empty() { - return Err(CommonError::EmptyCollection); - } - if !entities.iter().all(|a| a.network_id() == network_id) { - return Err(CommonError::WrongNetwork); - } - Ok(Self { - network_id, - entities, - }) - } - - pub fn len(&self) -> usize { - self.entities.len() - } - - /// Should never be true, since we do not allow empty. - pub fn is_empty(&self) -> bool { - self.entities.is_empty() - } - - pub fn network_id(&self) -> NetworkID { - self.network_id - } -} - -impl IntoIterator for Entities { - type Item = E; - type IntoIter = as IntoIterator>::IntoIter; - fn into_iter(self) -> Self::IntoIter { - self.entities.clone().into_iter() - } -} - -#[cfg(test)] -mod tests { - use super::*; - type Sut = Accounts; - type Item = Account; - #[test] - fn empty_throws() { - assert!(matches!( - Sut::new(NetworkID::Mainnet, IndexSet::new()), - Err(CommonError::EmptyCollection) - )); - } - #[test] - fn wrong_network_single() { - assert!(matches!( - Sut::new(NetworkID::Stokenet, IndexSet::just(Item::sample())), - Err(CommonError::WrongNetwork) - )); - } - #[test] - fn wrong_network_two() { - assert!(matches!( - Sut::new( - NetworkID::Stokenet, - IndexSet::from_iter([Item::sample_other(), Item::sample(),]) - ), - Err(CommonError::WrongNetwork) - )); - } - #[test] - fn ok_new() { - let sut = Sut::new(NetworkID::Mainnet, IndexSet::just(Item::sample())).unwrap(); - assert!(!sut.is_empty()); - } -} diff --git a/src/types/new_types/appendable_collection.rs b/src/types/new_types/appendable_collection.rs deleted file mode 100644 index a65ff36f..00000000 --- a/src/types/new_types/appendable_collection.rs +++ /dev/null @@ -1,95 +0,0 @@ -use crate::prelude::*; -use std::borrow::Borrow; - -pub trait AppendableCollection: FromIterator { - type Element; - fn append>(&mut self, iter: T); -} -impl AppendableCollection for IndexSet { - type Element = V; - - fn append>(&mut self, iter: T) { - self.extend(iter) - } -} - -impl AppendableCollection for FactorInstances { - type Element = HierarchicalDeterministicFactorInstance; - - fn append>(&mut self, iter: T) { - self.extend(iter) - } -} - -pub trait AppendableMap { - type Key: Eq + std::hash::Hash + Clone; - type AC: AppendableCollection; - fn append_or_insert_to::Element>>( - &mut self, - key: impl Borrow, - items: I, - ); - - fn append_or_insert_element_to( - &mut self, - key: impl Borrow, - element: ::Element, - ) { - self.append_or_insert_to(key.borrow(), [element]); - } -} - -impl AppendableCollection for IndexMap -where - K: Eq + std::hash::Hash + Clone, -{ - type Element = (K, V); - - fn append>(&mut self, iter: T) { - self.extend(iter) - } -} - -impl AppendableMap for IndexMap -where - K: Eq + std::hash::Hash + Clone, - V: AppendableCollection, -{ - type Key = K; - type AC = V; - fn append_or_insert_to::Element>>( - &mut self, - key: impl Borrow, - items: I, - ) { - let key = key.borrow(); - if let Some(existing) = self.get_mut(key) { - existing.append(items); - } else { - self.insert(key.clone(), V::from_iter(items)); - } - } -} - -#[cfg(test)] -mod test_appendable_collection { - use super::*; - - #[test] - fn test_append_element() { - type Sut = IndexMap>; - let mut map = Sut::new(); - map.append_or_insert_element_to(-3, 5); - map.append_or_insert_element_to(-3, 6); - map.append_or_insert_element_to(-3, 6); - map.append_or_insert_to(-3, [42, 237]); - map.append_or_insert_to(-9, [64, 128]); - assert_eq!( - map, - Sut::from_iter([ - (-3, IndexSet::::from_iter([5, 6, 42, 237])), - (-9, IndexSet::::from_iter([64, 128])), - ]) - ); - } -} diff --git a/src/types/new_types/factor_instances.rs b/src/types/new_types/factor_instances.rs deleted file mode 100644 index 078a7cbc..00000000 --- a/src/types/new_types/factor_instances.rs +++ /dev/null @@ -1,133 +0,0 @@ -use crate::prelude::*; - -/// A collection of factor instances. -#[derive(Default, Clone, PartialEq, Eq, derive_more::Debug)] -#[debug("FIS[{:?}]", self.factor_instances)] -pub struct FactorInstances { - #[allow(dead_code)] - hidden: HiddenConstructor, - factor_instances: IndexSet, -} - -impl FactorInstances { - pub fn extend( - &mut self, - instances: impl IntoIterator, - ) { - let instances = instances.into_iter().collect::>(); // remove duplicates - self.factor_instances.extend(instances); - } - pub fn shift_remove_index(&mut self, index: usize) -> HierarchicalDeterministicFactorInstance { - self.factor_instances - .shift_remove_index(index) - .expect("correct index") - } - pub fn first(&self) -> Option { - self.factor_instances.first().cloned() - } - pub fn split_at(self, mid: usize) -> (Self, Self) { - let instances = self.factor_instances.into_iter().collect_vec(); - let (head, tail) = instances.split_at(mid); - (Self::from(head), Self::from(tail)) - } -} -impl From<&[HierarchicalDeterministicFactorInstance]> for FactorInstances { - fn from(value: &[HierarchicalDeterministicFactorInstance]) -> Self { - Self::from( - IndexSet::::from_iter(value.iter().cloned()), - ) - } -} -impl From> for FactorInstances { - fn from(instances: IndexSet) -> Self { - Self::new(instances) - } -} - -impl From for IndexSet { - fn from(value: FactorInstances) -> Self { - value.factor_instances() - } -} -impl FactorInstances { - pub fn append( - &mut self, - instances: impl Into>, - ) { - let to_append: IndexSet<_> = instances.into(); - self.factor_instances.extend(to_append); - } - - pub fn is_empty(&self) -> bool { - self.factor_instances.is_empty() - } - - pub fn len(&self) -> usize { - self.factor_instances.len() - } -} - -impl IntoIterator for FactorInstances { - type Item = HierarchicalDeterministicFactorInstance; - type IntoIter = as IntoIterator>::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.factor_instances().into_iter() - } -} - -impl FromIterator for FactorInstances { - fn from_iter>(iter: I) -> Self { - Self::new(iter.into_iter().collect()) - } -} - -impl FactorInstances { - pub fn new(factor_instances: IndexSet) -> Self { - Self { - hidden: HiddenConstructor, - factor_instances, - } - } - - pub fn just(factor_instance: HierarchicalDeterministicFactorInstance) -> Self { - Self::new(IndexSet::just(factor_instance)) - } - - pub fn factor_instances(&self) -> IndexSet { - self.factor_instances.clone() - } -} - -impl HasSampleValues for FactorInstances { - fn sample() -> Self { - Self::new(IndexSet::from_iter([ - HierarchicalDeterministicFactorInstance::sample(), - HierarchicalDeterministicFactorInstance::sample_other(), - ])) - } - - fn sample_other() -> Self { - Self::new(IndexSet::just( - HierarchicalDeterministicFactorInstance::sample_other(), - )) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - type Sut = FactorInstances; - - #[test] - fn equality() { - assert_eq!(Sut::sample(), Sut::sample()); - assert_eq!(Sut::sample_other(), Sut::sample_other()); - } - - #[test] - fn inequality() { - assert_ne!(Sut::sample(), Sut::sample_other()); - } -} diff --git a/src/types/new_types/is_securified_entity.rs b/src/types/new_types/is_securified_entity.rs deleted file mode 100644 index bd98327e..00000000 --- a/src/types/new_types/is_securified_entity.rs +++ /dev/null @@ -1,71 +0,0 @@ -use std::hash::Hash; - -use crate::prelude::*; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct AssertMatches { - pub network_id: NetworkID, - pub key_kind: CAP26KeyKind, - pub entity_kind: CAP26EntityKind, - pub key_space: KeySpace, -} -impl AssertMatches { - pub fn matches(&self, path: &DerivationPath) -> DerivationPath { - assert_eq!(self.entity_kind, path.entity_kind); - assert_eq!(self.network_id, path.network_id); - assert_eq!(self.entity_kind, path.entity_kind); - assert_eq!(self.key_space, path.key_space()); - path.clone() - } -} -impl MatrixOfFactorInstances { - fn highest_derivation_path_index( - &self, - factor_source_id: FactorSourceIDFromHash, - assert_matches: AssertMatches, - ) -> Option { - self.all_factors() - .into_iter() - .filter(|f| f.factor_source_id() == factor_source_id) - .map(|f| f.derivation_path()) - .map(|p| assert_matches.matches(&p)) - .map(|p| p.index) - .max() - } -} -impl SecurifiedEntityControl { - fn highest_derivation_path_index( - &self, - factor_source_id: FactorSourceIDFromHash, - assert_matches: AssertMatches, - ) -> Option { - self.matrix - .highest_derivation_path_index(factor_source_id, assert_matches) - } -} - -pub trait IsSecurifiedEntity: - Hash + Eq + Clone + IsNetworkAware + TryFrom + Into -{ - type BaseEntity: IsEntity + std::hash::Hash + Eq; - fn kind() -> CAP26EntityKind { - Self::BaseEntity::kind() - } - fn securified_entity_control(&self) -> SecurifiedEntityControl; - - fn new( - name: impl AsRef, - address: ::Address, - securified_entity_control: SecurifiedEntityControl, - third_party_deposit: impl Into>, - ) -> Self; - - fn highest_derivation_path_index( - &self, - factor_source_id: FactorSourceIDFromHash, - assert_matches: AssertMatches, - ) -> Option { - self.securified_entity_control() - .highest_derivation_path_index(factor_source_id, assert_matches) - } -} diff --git a/src/types/new_types/key_space.rs b/src/types/new_types/key_space.rs deleted file mode 100644 index aec97c4c..00000000 --- a/src/types/new_types/key_space.rs +++ /dev/null @@ -1,44 +0,0 @@ -use crate::prelude::*; - -/// We split the hardened derivation entity index "space" in -/// two halves. The first half is used for unsecurified entities, -/// and the second half is used for securified entities. -/// -/// The Unsecurified half works as it does today, with hardened -/// `u32` values, where hardened denotes addition of `2^31`. -/// -/// The Securified half is a new concept, where we offset the -/// `u32` value with half of the 2^31 space, i.e. `2^30`. -#[derive(Clone, Copy, PartialEq, Eq, Hash, derive_more::Display, derive_more::Debug)] -pub enum KeySpace { - /// Used by FactorInstances controlling - /// unsecurified entities, called "VECI"s - /// Virtual Entity Creating (Factor)Instances. - #[display("Unsecurified")] - #[debug("Unsecurified")] - Unsecurified, - - /// Used by FactorInstances in MatrixOfFactorInstances - /// for securified entities. - /// - /// This is the entity base index value, `u32` `+ 2^30`. - /// - /// We use `6^` notation to indicate: `6' + 2^30`, where `'`, - /// is the standard notation for hardened indices. - #[display("Securified")] - #[debug("Securified")] - Securified, -} - -impl KeySpace { - pub fn both() -> [Self; 2] { - [Self::Unsecurified, Self::Securified] - } - - pub fn indicator(&self) -> String { - match self { - Self::Unsecurified => "'".to_owned(), - Self::Securified => "^".to_owned(), - } - } -} diff --git a/src/types/new_types/mod.rs b/src/types/new_types/mod.rs deleted file mode 100644 index 88f30014..00000000 --- a/src/types/new_types/mod.rs +++ /dev/null @@ -1,23 +0,0 @@ -mod accounts; -mod appendable_collection; -mod factor_instances; -mod is_securified_entity; -mod key_space; -mod securified_account; -mod securified_accounts; -mod securified_persona; -mod u30; -mod unsecurified_entity; -mod veci; - -pub use accounts::*; -pub use appendable_collection::*; -pub use factor_instances::*; -pub use is_securified_entity::*; -pub use key_space::*; -pub use securified_account::*; -pub use securified_accounts::*; -pub use securified_persona::*; -pub use u30::*; -pub use unsecurified_entity::*; -pub use veci::*; diff --git a/src/types/new_types/securified_account.rs b/src/types/new_types/securified_account.rs deleted file mode 100644 index 23d052dd..00000000 --- a/src/types/new_types/securified_account.rs +++ /dev/null @@ -1,167 +0,0 @@ -use crate::prelude::*; - -/// The `SecurifiedEntityControl`, address and possibly third party deposit state of some -/// Securified entity. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct SecurifiedAccount { - name: String, - /// The address which is verified to match the `veci` - account_address: AccountAddress, - securified_entity_control: SecurifiedEntityControl, - /// If we found this UnsecurifiedEntity while scanning OnChain using - /// Gateway, we might have been able to read out the third party deposit - /// settings. - third_party_deposit: Option, -} -impl From for Account { - fn from(value: SecurifiedAccount) -> Account { - value.account() - } -} -impl IsSecurifiedEntity for SecurifiedAccount { - type BaseEntity = Account; - fn securified_entity_control(&self) -> SecurifiedEntityControl { - self.securified_entity_control() - } - - fn new( - name: impl AsRef, - address: AccountAddress, - securified_entity_control: SecurifiedEntityControl, - third_party_deposit: impl Into>, - ) -> Self { - Self { - name: name.as_ref().to_owned(), - account_address: address, - securified_entity_control, - third_party_deposit: third_party_deposit.into(), - } - } -} - -impl IsNetworkAware for SecurifiedAccount { - fn network_id(&self) -> NetworkID { - self.address().network_id() - } -} - -impl TryFrom for SecurifiedAccount { - type Error = CommonError; - fn try_from(value: Account) -> Result { - let securified_entity_control = value - .security_state() - .as_securified() - .cloned() - .ok_or(CommonError::AccountNotSecurified)?; - Ok(SecurifiedAccount::new( - value.name(), - value.entity_address(), - securified_entity_control, - value.third_party_deposit(), - )) - } -} - -impl TryFrom for SecurifiedAccount { - type Error = CommonError; - fn try_from(value: AccountOrPersona) -> Result { - Account::try_from(value).and_then(SecurifiedAccount::try_from) - } -} -impl From for Persona { - fn from(value: SecurifiedPersona) -> Persona { - value.persona() - } -} -impl TryFrom for SecurifiedPersona { - type Error = CommonError; - fn try_from(value: Persona) -> Result { - let securified_entity_control = value - .security_state() - .as_securified() - .cloned() - .ok_or(CommonError::PersonaNotSecurified)?; - Ok(SecurifiedPersona::new( - value.name(), - value.entity_address(), - securified_entity_control, - value.third_party_deposit(), - )) - } -} - -impl TryFrom for SecurifiedPersona { - type Error = CommonError; - fn try_from(value: AccountOrPersona) -> Result { - Persona::try_from(value).and_then(SecurifiedPersona::try_from) - } -} - -impl SecurifiedAccount { - pub fn account(&self) -> Account { - Account::new( - self.name.clone(), - self.address(), - EntitySecurityState::Securified(self.securified_entity_control()), - self.third_party_deposit, - ) - } - pub fn address(&self) -> AccountAddress { - self.account_address.clone() - } - pub fn securified_entity_control(&self) -> SecurifiedEntityControl { - self.securified_entity_control.clone() - } - pub fn third_party_deposit(&self) -> Option { - self.third_party_deposit - } -} - -impl HasSampleValues for SecurifiedAccount { - fn sample() -> Self { - Self::new( - "SecurifiedAccount", - AccountAddress::sample(), - SecurifiedEntityControl::sample(), - None, - ) - } - fn sample_other() -> Self { - Self::new( - "SecurifiedAccount Other", - AccountAddress::sample_other(), - SecurifiedEntityControl::sample_other(), - None, - ) - } -} - -#[cfg(test)] -mod tests { - use super::*; - type Sut = SecurifiedAccount; - #[test] - fn equality() { - assert_eq!(Sut::sample(), Sut::sample()); - assert_eq!(Sut::sample_other(), Sut::sample_other()); - } - #[test] - fn inequality() { - assert_ne!(Sut::sample(), Sut::sample_other()); - } - #[test] - fn third_party_dep() { - let test = |dep: ThirdPartyDepositPreference| { - let sut = Sut::new( - "name", - AccountAddress::sample_0(), - SecurifiedEntityControl::sample(), - dep, - ); - assert_eq!(sut.third_party_deposit(), Some(dep)); - }; - test(ThirdPartyDepositPreference::DenyAll); - test(ThirdPartyDepositPreference::AllowAll); - test(ThirdPartyDepositPreference::AllowKnown); - } -} diff --git a/src/types/new_types/securified_accounts.rs b/src/types/new_types/securified_accounts.rs deleted file mode 100644 index d53e687e..00000000 --- a/src/types/new_types/securified_accounts.rs +++ /dev/null @@ -1,44 +0,0 @@ -use crate::prelude::*; - -pub type SecurifiedAccounts = Entities; -pub type SecurifiedPersonas = Entities; - -#[cfg(test)] -mod tests { - use super::*; - type Sut = SecurifiedAccounts; - type Item = SecurifiedAccount; - #[test] - fn empty_throws() { - assert!(matches!( - Sut::new(NetworkID::Mainnet, IndexSet::new()), - Err(CommonError::EmptyCollection) - )); - } - #[test] - fn wrong_network_single() { - assert!(matches!( - Sut::new(NetworkID::Stokenet, IndexSet::just(Item::sample())), - Err(CommonError::WrongNetwork) - )); - } - #[test] - fn wrong_network_two() { - assert!(matches!( - Sut::new( - NetworkID::Stokenet, - IndexSet::from_iter([Item::sample_other(), Item::sample(),]) - ), - Err(CommonError::WrongNetwork) - )); - } - #[test] - fn ok_new() { - let network_id = NetworkID::Mainnet; - let sut = Sut::new(network_id, IndexSet::just(Item::sample())).unwrap(); - assert!(!sut.is_empty()); - assert_eq!(sut.len(), 1); - assert!(!sut.is_empty()); - assert_eq!(sut.network_id(), network_id); - } -} diff --git a/src/types/new_types/securified_persona.rs b/src/types/new_types/securified_persona.rs deleted file mode 100644 index d04c9b1a..00000000 --- a/src/types/new_types/securified_persona.rs +++ /dev/null @@ -1,92 +0,0 @@ -use crate::prelude::*; - -/// The `SecurifiedEntityControl`, address and possibly third party deposit state of some -/// Securified entity. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct SecurifiedPersona { - name: String, - /// The address which is verified to match the `veci` - identity_address: IdentityAddress, - securified_entity_control: SecurifiedEntityControl, -} -impl IsNetworkAware for SecurifiedPersona { - fn network_id(&self) -> NetworkID { - self.address().network_id() - } -} - -impl IsSecurifiedEntity for SecurifiedPersona { - type BaseEntity = Persona; - fn securified_entity_control(&self) -> SecurifiedEntityControl { - self.securified_entity_control() - } - - fn new( - name: impl AsRef, - address: IdentityAddress, - securified_entity_control: SecurifiedEntityControl, - _third_party_deposit: impl Into>, - ) -> Self { - Self { - name: name.as_ref().to_owned(), - identity_address: address, - securified_entity_control, - } - } -} - -impl SecurifiedPersona { - pub fn persona(&self) -> Persona { - Persona::new( - self.name.clone(), - self.address(), - EntitySecurityState::Securified(self.securified_entity_control()), - None, - ) - } - pub fn address(&self) -> IdentityAddress { - self.identity_address.clone() - } - pub fn securified_entity_control(&self) -> SecurifiedEntityControl { - self.securified_entity_control.clone() - } - pub fn third_party_deposit(&self) -> Option { - None - } -} -impl HasSampleValues for SecurifiedPersona { - fn sample() -> Self { - Self::new( - "SecurifiedPersona", - IdentityAddress::sample(), - SecurifiedEntityControl::sample(), - None, - ) - } - fn sample_other() -> Self { - Self::new( - "SecurifiedPersona Other", - IdentityAddress::sample_other(), - SecurifiedEntityControl::sample_other(), - None, - ) - } -} -#[cfg(test)] -mod tests { - - use super::*; - - type Sut = SecurifiedPersona; - - #[test] - fn equality() { - assert_eq!(Sut::sample(), Sut::sample()); - assert_eq!(Sut::sample_other(), Sut::sample_other()); - } - - #[test] - fn inequality() { - assert_ne!(Sut::sample(), Sut::sample_other()); - } -} diff --git a/src/types/new_types/u30.rs b/src/types/new_types/u30.rs deleted file mode 100644 index c78ff3ef..00000000 --- a/src/types/new_types/u30.rs +++ /dev/null @@ -1,56 +0,0 @@ -use crate::prelude::*; - -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, derive_more::Display, Ord, Hash)] -#[display("{inner}")] -pub struct U30 { - hidden_constructor: HiddenConstructor, - pub inner: u32, -} - -impl U30 { - pub const MAX: u32 = u32::MAX / 4; - pub fn new(inner: u32) -> Result { - if inner > Self::MAX { - return Err(CommonError::Invalid30 { bad_value: inner }); - } - Ok(Self { - hidden_constructor: HiddenConstructor, - inner, - }) - } -} - -#[cfg(test)] -mod tests { - - use super::*; - - #[allow(clippy::upper_case_acronyms)] - type SUT = U30; - - #[test] - fn invalid_too_large() { - assert_eq!( - SUT::new(U30::MAX + 1), - Err(CommonError::Invalid30 { - bad_value: U30::MAX + 1 - }) - ); - } - - #[test] - fn valid_max() { - assert!(SUT::new(U30::MAX).is_ok()) - } - - #[test] - fn inner() { - assert_eq!(SUT::new(1024).unwrap().inner, 1024); - } - - #[test] - fn ord() { - assert!(SUT::new(0).unwrap() < SUT::new(1).unwrap()); - assert!(SUT::new(U30::MAX).unwrap() > SUT::new(U30::MAX - 1).unwrap()); - } -} diff --git a/src/types/new_types/unsecurified_entity.rs b/src/types/new_types/unsecurified_entity.rs deleted file mode 100644 index 81f118ff..00000000 --- a/src/types/new_types/unsecurified_entity.rs +++ /dev/null @@ -1,135 +0,0 @@ -use crate::prelude::*; - -/// The HierarchicalDeterministicFactorInstance, address and possibly third party deposit state of some -/// unsecurified entity. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct UnsecurifiedEntity { - veci: VirtualEntityCreatingInstance, - - /// If we found this UnsecurifiedEntity while scanning OnChain using - /// Gateway, we might have been able to read out the third party deposit - /// settings. - third_party_deposit: Option, -} - -impl UnsecurifiedEntity { - /// # Panics - /// Panics if address does not match `factor_instance` - pub fn new( - address: AddressOfAccountOrPersona, - factor_instance: HierarchicalDeterministicFactorInstance, - third_party_deposit: impl Into>, - ) -> Self { - let veci = VirtualEntityCreatingInstance::new(factor_instance, address); - Self::with_veci(veci, third_party_deposit) - } - - pub fn network_id(&self) -> NetworkID { - self.address().network_id() - } - - pub fn with_veci( - veci: VirtualEntityCreatingInstance, - third_party_deposit: impl Into>, - ) -> Self { - Self { - veci, - third_party_deposit: third_party_deposit.into(), - } - } - - pub fn address(&self) -> AddressOfAccountOrPersona { - self.veci.clone().address() - } - - pub fn factor_instance(&self) -> HierarchicalDeterministicFactorInstance { - self.veci.factor_instance() - } - - pub fn veci(&self) -> VirtualEntityCreatingInstance { - self.veci.clone() - } - - pub fn third_party_deposit(&self) -> Option { - self.third_party_deposit - } -} - -impl From for AccountOrPersona { - fn from(value: UnsecurifiedEntity) -> Self { - let address = value.address(); - let name = "Recovered"; - let security_state = EntitySecurityState::Unsecured(value.factor_instance()); - - if let Ok(account_address) = address.clone().into_account() { - Account::new(name, account_address, security_state, None).into() - } else if let Ok(identity_address) = address.clone().into_identity() { - Persona::new(name, identity_address, security_state, None).into() - } else { - unreachable!("Either account or persona.") - } - } -} - -impl HasSampleValues for UnsecurifiedEntity { - fn sample() -> Self { - Self::with_veci( - VirtualEntityCreatingInstance::sample(), - ThirdPartyDepositPreference::sample(), - ) - } - fn sample_other() -> Self { - Self::with_veci( - VirtualEntityCreatingInstance::sample_other(), - ThirdPartyDepositPreference::sample_other(), - ) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - type Sut = UnsecurifiedEntity; - - #[test] - fn equality() { - assert_eq!(Sut::sample(), Sut::sample()); - assert_eq!(Sut::sample_other(), Sut::sample_other()); - } - - #[test] - fn inequality() { - assert_ne!(Sut::sample(), Sut::sample_other()); - } - - #[test] - fn unsecurified_persona_into_tagged_union() { - let sut = Sut::sample_other(); - assert!(AccountOrPersona::from(sut).is_persona_entity()); - } - - #[test] - fn unsecurified_account_into_tagged_union() { - let sut = Sut::sample(); - assert!(AccountOrPersona::from(sut).is_account_entity()); - } - - #[test] - fn network_id() { - assert_eq!(Sut::sample_other().network_id(), NetworkID::Stokenet); - } - - #[test] - fn third_party_dep() { - let test = |dep: ThirdPartyDepositPreference| { - let veci = HierarchicalDeterministicFactorInstance::sample(); - let address = AccountAddress::new(NetworkID::Mainnet, veci.public_key_hash()); - let sut = Sut::new(address.into(), veci, dep); - assert_eq!(sut.third_party_deposit(), Some(dep)); - }; - test(ThirdPartyDepositPreference::DenyAll); - test(ThirdPartyDepositPreference::AllowAll); - test(ThirdPartyDepositPreference::AllowKnown); - } -} diff --git a/src/types/new_types/veci.rs b/src/types/new_types/veci.rs deleted file mode 100644 index 20a9983a..00000000 --- a/src/types/new_types/veci.rs +++ /dev/null @@ -1,95 +0,0 @@ -use crate::prelude::*; - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct VirtualEntityCreatingInstance { - /// The instance which as known to have created `address` - factor_instance: HierarchicalDeterministicFactorInstance, - - /// The address of the entity. - address: AddressOfAccountOrPersona, -} -impl VirtualEntityCreatingInstance { - /// # Panics - /// Panics if factor_instance does not result in address. - /// - /// Panics if factor_instance is not in unsecurified space. - pub fn new( - factor_instance: HierarchicalDeterministicFactorInstance, - address: AddressOfAccountOrPersona, - ) -> Self { - assert_eq!( - factor_instance.key_space(), - KeySpace::Unsecurified, - "factor instance not in unsecurified space" - ); - assert_eq!( - address.public_key_hash(), - factor_instance.public_key_hash(), - "Discrepancy! PublicKeys does not match, this is a programmer error!" - ); - Self { - address, - factor_instance, - } - } - - pub fn address(&self) -> AddressOfAccountOrPersona { - self.address.clone() - } - - pub fn factor_instance(&self) -> HierarchicalDeterministicFactorInstance { - self.factor_instance.clone() - } - - fn with_factor_instance_on_network( - factor_instance: HierarchicalDeterministicFactorInstance, - entity_kind: CAP26EntityKind, - network_id: NetworkID, - ) -> Self { - let public_key_hash = factor_instance.public_key_hash(); - let address = match entity_kind { - CAP26EntityKind::Account => { - AddressOfAccountOrPersona::from(AccountAddress::new(network_id, public_key_hash)) - } - CAP26EntityKind::Identity => { - AddressOfAccountOrPersona::from(IdentityAddress::new(network_id, public_key_hash)) - } - }; - Self::new(factor_instance, address) - } -} - -impl HasSampleValues for VirtualEntityCreatingInstance { - fn sample() -> Self { - Self::with_factor_instance_on_network( - HierarchicalDeterministicFactorInstance::sample(), - CAP26EntityKind::Account, - NetworkID::Mainnet, - ) - } - fn sample_other() -> Self { - Self::with_factor_instance_on_network( - HierarchicalDeterministicFactorInstance::sample_other(), - CAP26EntityKind::Identity, - NetworkID::Stokenet, - ) - } -} - -#[cfg(test)] -mod test_instance { - use super::*; - - type Sut = VirtualEntityCreatingInstance; - - #[test] - fn equality() { - assert_eq!(Sut::sample(), Sut::sample()); - assert_eq!(Sut::sample_other(), Sut::sample_other()); - } - - #[test] - fn inequality() { - assert_ne!(Sut::sample(), Sut::sample_other()); - } -} diff --git a/src/types/owned_types/mod.rs b/src/types/owned_types/mod.rs deleted file mode 100644 index 2f9d954b..00000000 --- a/src/types/owned_types/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod owned; -mod owned_factor_instance; - -pub use owned::*; -pub use owned_factor_instance::*; diff --git a/src/types/owned_types/owned.rs b/src/types/owned_types/owned.rs deleted file mode 100644 index a369475a..00000000 --- a/src/types/owned_types/owned.rs +++ /dev/null @@ -1,26 +0,0 @@ -use crate::prelude::*; - -/// Some value with a known owner - an account or persona. -#[derive(Clone, PartialEq, Eq, std::hash::Hash, derive_more::Debug)] -#[debug("{:#?}: {:#?}", owner, value)] -pub struct Owned { - /// The known owner - an account or persona - of `value`. - pub owner: AddressOfAccountOrPersona, - /// Some value known to be owned by `owner` - an account or persona. - pub value: T, -} - -impl Owned { - pub fn new(owner: AddressOfAccountOrPersona, value: T) -> Self { - Self { owner, value } - } -} - -impl HasSampleValues for Owned { - fn sample() -> Self { - Self::new(AddressOfAccountOrPersona::sample(), T::sample()) - } - fn sample_other() -> Self { - Self::new(AddressOfAccountOrPersona::sample_other(), T::sample_other()) - } -} diff --git a/src/types/owned_types/owned_factor_instance.rs b/src/types/owned_types/owned_factor_instance.rs deleted file mode 100644 index 7589e46a..00000000 --- a/src/types/owned_types/owned_factor_instance.rs +++ /dev/null @@ -1,38 +0,0 @@ -use std::borrow::Borrow; - -use crate::prelude::*; - -/// A `HierarchicalDeterministicFactorInstance` with a known owner - an account or persona. -pub type OwnedFactorInstance = Owned; - -impl OwnedFactorInstance { - /// Constructs a new `OwnedFactorInstance`. - pub fn owned_factor_instance( - owner: AddressOfAccountOrPersona, - factor_instance: HierarchicalDeterministicFactorInstance, - ) -> Self { - Self::new(owner, factor_instance) - } - - /// The owned `HierarchicalDeterministicFactorInstance`, the value of this `OwnedFactorInstance`. - pub fn factor_instance(&self) -> &HierarchicalDeterministicFactorInstance { - &self.value - } - - pub fn factor_source_id(&self) -> FactorSourceIDFromHash { - self.factor_instance().factor_source_id() - } - - /// Checks if this `OwnedFactorInstance` was created from the factor source - /// with id `factor_source_id`. - pub fn by_factor_source(&self, factor_source_id: impl Borrow) -> bool { - let factor_source_id = factor_source_id.borrow(); - self.factor_source_id() == *factor_source_id - } -} - -impl From for HierarchicalDeterministicFactorInstance { - fn from(value: OwnedFactorInstance) -> Self { - value.value - } -} diff --git a/src/types/sargon_types.rs b/src/types/sargon_types.rs deleted file mode 100644 index ea75411e..00000000 --- a/src/types/sargon_types.rs +++ /dev/null @@ -1,2983 +0,0 @@ -use std::iter::Step; -use std::marker::PhantomData; -use std::ops::Add; - -use indexmap::map::Keys; - -use crate::prelude::*; - -use std::borrow::Borrow; -use std::borrow::BorrowMut; -use std::ops::AddAssign; -use std::sync::Mutex; - -/// An UNSAFE IDStepper, which `next` returns the consecutive next ID, -/// should only be used by tests and sample value creation. -pub struct IDStepper> { - ctr: Arc>, - phantom: PhantomData, -} -pub type UuidStepper = IDStepper; - -impl> IDStepper { - pub fn starting_at(ctr: u64) -> Self { - Self { - ctr: Arc::new(Mutex::new(ctr)), - phantom: PhantomData, - } - } - - #[allow(clippy::new_without_default)] - pub fn new() -> Self { - Self::starting_at(0) - } - - /// ONLY Use this in a test or when creating sample (preview) values. - /// - /// # Safety - /// This is completely unsafe, it does not generate a random UUID, it creates - /// the consecutive "next" ID. - pub fn _next(&self) -> T { - let n = Uuid::from_u64_pair(0, **self.ctr.lock().unwrap().borrow()); - self.ctr.lock().unwrap().borrow_mut().add_assign(1); - n.into() - } -} - -fn take_last_n(str: impl AsRef, n: usize) -> String { - let str = str.as_ref(); - if str.len() >= n { - str[str.len() - n..].to_owned() - } else { - "".to_owned() - } -} - -#[derive( - Clone, - Copy, - PartialEq, - Eq, - PartialOrd, - Ord, - std::hash::Hash, - derive_more::Display, - derive_more::Debug, -)] -#[display("{kind}:{}", take_last_n(self.id.to_string(), 2))] -#[debug("{}", self.to_string())] -pub struct FactorSourceIDFromHash { - pub kind: FactorSourceKind, - pub id: Uuid, -} - -impl FactorSourceIDFromHash { - fn with_details(kind: FactorSourceKind, id: Uuid) -> Self { - Self { kind, id } - } - pub fn new(kind: FactorSourceKind) -> Self { - Self::with_details(kind, IDStepper::next()) - } - pub fn to_bytes(&self) -> Vec { - self.id.as_bytes().to_vec() - } - - pub fn sample_third() -> Self { - Self::with_details(FactorSourceKind::Arculus, Uuid::from_bytes([0xaa; 16])) - } - - pub fn sample_fourth() -> Self { - Self::with_details( - FactorSourceKind::SecurityQuestions, - Uuid::from_bytes([0x5e; 16]), - ) - } -} - -impl HasSampleValues for FactorSourceIDFromHash { - fn sample() -> Self { - Self::with_details(FactorSourceKind::Device, Uuid::from_bytes([0xde; 16])) - } - fn sample_other() -> Self { - Self::with_details(FactorSourceKind::Ledger, Uuid::from_bytes([0x1e; 16])) - } -} - -#[derive(Clone, PartialEq, Eq, std::hash::Hash, derive_more::Debug)] -#[debug("{:#?}", id)] -pub struct HDFactorSource { - pub last_used: SystemTime, - id: FactorSourceIDFromHash, -} - -impl HasSampleValues for HDFactorSource { - fn sample() -> Self { - Self::device() - } - fn sample_other() -> Self { - Self::ledger() - } -} - -impl HDFactorSource { - pub fn is_olympia(&self) -> bool { - // TODO add support for Olympia and test! - false - } - pub fn factor_source_id(&self) -> FactorSourceIDFromHash { - self.id - } - pub fn factor_source_kind(&self) -> FactorSourceKind { - self.id.kind - } - pub fn new(kind: FactorSourceKind) -> Self { - Self { - id: FactorSourceIDFromHash::new(kind), - last_used: SystemTime::UNIX_EPOCH, - } - } - pub fn arculus() -> Self { - Self::new(FactorSourceKind::Arculus) - } - pub fn ledger() -> Self { - Self::new(FactorSourceKind::Ledger) - } - pub fn device() -> Self { - Self::new(FactorSourceKind::Device) - } - pub fn yubikey() -> Self { - Self::new(FactorSourceKind::Yubikey) - } - pub fn off_device() -> Self { - Self::new(FactorSourceKind::OffDeviceMnemonic) - } - pub fn security_question() -> Self { - Self::new(FactorSourceKind::SecurityQuestions) - } -} - -impl PartialOrd for HDFactorSource { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} -impl Ord for HDFactorSource { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - match self.factor_source_kind().cmp(&other.factor_source_kind()) { - core::cmp::Ordering::Equal => {} - ord => return ord, - } - match self.last_used.cmp(&other.last_used) { - core::cmp::Ordering::Equal => {} - ord => return ord, - } - core::cmp::Ordering::Equal - } -} - -pub trait Just { - fn just(item: Item) -> Self; -} -pub trait JustKV { - fn kv(key: Key, value: Value) -> Self; -} -impl Just for IndexSet { - fn just(item: T) -> Self { - Self::from_iter([item]) - } -} -impl Just for HashSet { - fn just(item: T) -> Self { - Self::from_iter([item]) - } -} -impl Just<(K, V)> for IndexMap { - fn just(item: (K, V)) -> Self { - Self::from_iter([item]) - } -} -impl JustKV for IndexMap { - fn kv(key: K, value: V) -> Self { - Self::from_iter([(key, value)]) - } -} -impl Just<(K, V)> for HashMap { - fn just(item: (K, V)) -> Self { - Self::from_iter([item]) - } -} -impl JustKV for HashMap { - fn kv(key: K, value: V) -> Self { - Self::from_iter([(key, value)]) - } -} - -#[repr(u32)] -#[derive(Clone, Copy, Debug, PartialEq, Eq, std::hash::Hash, PartialOrd, Ord, strum::Display)] -pub enum FactorSourceKind { - Ledger, - Arculus, - Yubikey, - SecurityQuestions, - OffDeviceMnemonic, - Device, -} -impl FactorSourceKind { - pub fn derivation_size( - &self, - key_space: KeySpace, - key_kind: CAP26KeyKind, - entity_kind: CAP26EntityKind, - ) -> Option { - match (key_kind, key_space, entity_kind) { - (CAP26KeyKind::TransactionSigning, KeySpace::Unsecurified, _) => { - self.derivation_size_t9n_unsecurified() - } - (CAP26KeyKind::TransactionSigning, KeySpace::Securified, _) => { - self.derivation_size_t9n_securified() - } - ( - CAP26KeyKind::AuthenticationSigning, - KeySpace::Securified, - CAP26EntityKind::Identity, - ) => self.derivation_size_rola(), - _ => { - warn!("Non-sensical derivation request: factor_source_kind: {}, key_space: {}, key_kind: {}, entity_kind: {}", self, key_space, key_kind, entity_kind); - None - } - } - } - - /// (KeyKind::AuthenticationSigning) - fn derivation_size_rola(&self) -> Option { - match self { - Self::Device => Some(1), - Self::Ledger - | Self::SecurityQuestions - | Self::OffDeviceMnemonic - | Self::Arculus - | Self::Yubikey => { - // only Device can be used for ROLA - None - } - } - } - - /// (KeyKind::TransactionSigning, KeySpace::Unsecurified) - fn derivation_size_t9n_unsecurified(&self) -> Option { - match self { - Self::Device => Some(50), // extra large since fast and most commonly used for unsecurified entities - Self::Ledger => Some(30), - Self::SecurityQuestions | Self::OffDeviceMnemonic | Self::Arculus | Self::Yubikey => { - // Virtual Entity creation not supported using these kinds - None - } - } - } - /// (KeyKind::TransactionSigning, KeySpace::Securified) - fn derivation_size_t9n_securified(&self) -> Option { - match self { - Self::Device | Self::SecurityQuestions | Self::OffDeviceMnemonic => Some(30), // - Self::Ledger | Self::Yubikey => Some(20), // Slow - Self::Arculus => Some(10), // Very slow - } - } -} -impl HasSampleValues for FactorSourceKind { - fn sample() -> Self { - FactorSourceKind::Device - } - fn sample_other() -> Self { - FactorSourceKind::Ledger - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, EnumAsInner, Default)] -pub enum ThirdPartyDepositPreference { - DenyAll, - #[default] - AllowAll, - AllowKnown, -} - -impl HasSampleValues for ThirdPartyDepositPreference { - fn sample() -> Self { - ThirdPartyDepositPreference::DenyAll - } - fn sample_other() -> Self { - ThirdPartyDepositPreference::AllowAll - } -} - -pub type HDPathValue = u32; - -#[derive( - Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, derive_more::Display, derive_more::Debug, -)] -#[display("{_0}")] -#[debug("{_0}")] -pub struct UnhardenedIndex(u32); -impl UnhardenedIndex { - /// # Panics - /// Panics if value is >= BIP32_HARDENED - pub fn new(value: u32) -> Self { - assert!(value < BIP32_HARDENED); - Self(value) - } - pub fn to_bytes(&self) -> Vec { - self.0.to_be_bytes().to_vec() - } - - pub fn add_n(&self, n: HDPathValue) -> Result { - let base_index = self.base_index(); - - if !(base_index as u64 + n as u64) < BIP32_HARDENED as u64 { - return Err(CommonError::EntityIndexWouldOverflowIfAddedTo); - } - - Ok(Self::new(self.0 + n)) - } - - pub(crate) fn base_index(&self) -> HDPathValue { - self.0 - } -} - -/// Hardened Unsecurified Index -#[derive( - Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, derive_more::Display, derive_more::Debug, -)] -#[display("{}{}", self.base_index(), KeySpace::Unsecurified.indicator())] -#[debug("{}{}", self.base_index(), KeySpace::Unsecurified.indicator())] -pub struct UnsecurifiedIndex(HDPathValue); -impl UnsecurifiedIndex { - /// # Panics - /// Panics if value < BIP32_HARDENED || >= BIP32_SECURIFIED_HALF - pub fn new(value: HDPathValue) -> Self { - assert!(value >= BIP32_HARDENED); - assert!(value < (BIP32_HARDENED + BIP32_SECURIFIED_HALF)); - Self(value) - } - pub fn unsecurified_hardening_base_index(base_index: HDPathValue) -> Self { - Self::new(base_index + BIP32_HARDENED) - } - pub fn to_bytes(&self) -> Vec { - self.0.to_be_bytes().to_vec() - } - - pub fn add_n(&self, n: HDPathValue) -> Result { - let base_index = self.base_index(); - if !(base_index as u64 + n as u64) < (BIP32_HARDENED + BIP32_SECURIFIED_HALF) as u64 { - return Err(CommonError::EntityIndexWouldOverflowIfAddedTo); - } - Ok(Self::new(self.0 + n)) - } - - pub(crate) fn base_index(&self) -> HDPathValue { - self.0 - BIP32_HARDENED - } -} - -/// Hardened Securified Index -#[derive( - Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, derive_more::Display, derive_more::Debug, -)] -#[display("{}{}", self.base_index(), KeySpace::Securified.indicator())] -#[debug("{}{}", self.base_index(), KeySpace::Securified.indicator())] -pub struct SecurifiedIndex(u32); -impl SecurifiedIndex { - /// # Panics - /// Panics if value < BIP32_HARDENED + BIP32_SECURIFIED_HALF - pub fn new(value: u32) -> Self { - assert!(value >= BIP32_HARDENED + BIP32_SECURIFIED_HALF); - Self(value) - } - - pub fn securifying_base_index(base_index: u32) -> Self { - Self::new(base_index + BIP32_HARDENED + BIP32_SECURIFIED_HALF) - } - - pub fn to_bytes(&self) -> Vec { - self.0.to_be_bytes().to_vec() - } - - pub fn add_n(&self, n: HDPathValue) -> Result { - let base_index = self.base_index(); - if !(base_index as u64 + n as u64) < HDPathValue::MAX as u64 { - return Err(CommonError::EntityIndexWouldOverflowIfAddedTo); - } - - Ok(Self::new(self.0 + n)) - } - - pub(crate) fn base_index(&self) -> HDPathValue { - self.0 - BIP32_HARDENED - BIP32_SECURIFIED_HALF - } -} - -#[derive( - Clone, - Copy, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - EnumAsInner, - derive_more::Display, - derive_more::Debug, -)] -pub enum HDPathComponentHardened { - #[display("{_0}")] - #[debug("{_0}")] - Unsecurified(UnsecurifiedIndex), - #[display("{_0}")] - #[debug("{_0}")] - Securified(SecurifiedIndex), -} - -impl From for HDPathComponentHardened { - fn from(u: UnsecurifiedIndex) -> Self { - Self::Unsecurified(u) - } -} -impl From for HDPathComponentHardened { - fn from(u: SecurifiedIndex) -> Self { - Self::Securified(u) - } -} -impl HDPathComponentHardened { - pub fn to_bytes(&self) -> Vec { - match self { - Self::Unsecurified(u) => u.to_bytes(), - Self::Securified(s) => s.to_bytes(), - } - } - - pub fn is_in_key_space(&self, key_space: KeySpace) -> bool { - match self { - Self::Unsecurified(_) => key_space == KeySpace::Unsecurified, - Self::Securified(_) => key_space == KeySpace::Securified, - } - } - - pub fn add_n(&self, n: HDPathValue) -> Result { - match self { - Self::Unsecurified(u) => u.add_n(n).map(Self::from), - Self::Securified(s) => s.add_n(n).map(Self::from), - } - } - - pub(crate) fn base_index(&self) -> HDPathValue { - match self { - Self::Unsecurified(u) => u.base_index(), - Self::Securified(s) => s.base_index(), - } - } -} - -#[derive( - Clone, - Copy, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - EnumAsInner, - derive_more::Display, - derive_more::Debug, -)] -pub enum HDPathComponent { - #[display("{_0}")] - #[debug("{_0}")] - Unhardened(UnhardenedIndex), - #[display("{_0}")] - #[debug("{_0}")] - Hardened(HDPathComponentHardened), -} - -impl From for HDPathComponent { - fn from(u: UnhardenedIndex) -> Self { - Self::Unhardened(u) - } -} -impl From for HDPathComponent { - fn from(u: HDPathComponentHardened) -> Self { - Self::Hardened(u) - } -} - -impl HDPathComponent { - pub fn to_bytes(&self) -> Vec { - match self { - Self::Unhardened(u) => u.to_bytes(), - Self::Hardened(h) => h.to_bytes(), - } - } -} - -pub const BIP32_SECURIFIED_HALF: u32 = 0x4000_0000; -pub(crate) const BIP32_HARDENED: u32 = 0x8000_0000; - -impl Step for HDPathComponent { - fn steps_between(start: &Self, end: &Self) -> Option { - Some((end.base_index() - start.base_index()) as usize) - } - - fn forward_checked(start: Self, count: usize) -> Option { - start.add_n(count as u32).ok() - } - - fn backward_checked(_start: Self, _count: usize) -> Option { - unreachable!("not needed, use (N..M) instead of (M..N) when M > N.") - } -} - -pub type HDBaseIndex = U30; - -impl HDPathComponent { - pub fn new_with_key_space_and_base_index(key_space: KeySpace, base_index: HDBaseIndex) -> Self { - match key_space { - KeySpace::Securified => Self::securifying_base_index(base_index.inner), - KeySpace::Unsecurified => Self::unsecurified_hardening_base_index(base_index.inner), - } - } - pub fn new_with_key_space_and_index(key_space: KeySpace, index: u32) -> Result { - HDBaseIndex::new(index) - .map(|base_index| Self::new_with_key_space_and_base_index(key_space, base_index)) - } - pub fn new_from_index(index: HDPathValue) -> Self { - if index < BIP32_HARDENED { - Self::Unhardened(UnhardenedIndex::new(index)) - } else if index < BIP32_SECURIFIED_HALF { - Self::Hardened(HDPathComponentHardened::Unsecurified( - UnsecurifiedIndex::new(index), - )) - } else { - Self::Hardened(HDPathComponentHardened::Securified(SecurifiedIndex::new( - index, - ))) - } - } - - /// Will harden `base_index` - pub fn unsecurified_hardening_base_index(value: HDPathValue) -> Self { - Self::Hardened(HDPathComponentHardened::Unsecurified( - UnsecurifiedIndex::unsecurified_hardening_base_index(value), - )) - } - - /// Will harden and add `BIP32_SECURIFIED_HALF` to `base_index` - /// Provide a value which is not yet hardened nor securified - pub fn securifying_base_index(base_index: HDPathValue) -> Self { - Self::Hardened(HDPathComponentHardened::Securified( - SecurifiedIndex::securifying_base_index(base_index), - )) - } -} - -impl HDPathComponent { - pub fn key_space(&self) -> KeySpace { - if self.is_securified() { - KeySpace::Securified - } else { - KeySpace::Unsecurified - } - } - pub fn is_in_key_space(&self, key_space: KeySpace) -> bool { - match self { - Self::Unhardened(_) => key_space == KeySpace::Unsecurified, - Self::Hardened(h) => h.is_in_key_space(key_space), - } - } - - /// # Panics - /// Panics if self would overflow within its key space. - pub fn add_n(&self, n: HDPathValue) -> Result { - match self { - Self::Hardened(h) => h.add_n(n).map(Self::from), - Self::Unhardened(u) => u.add_n(n).map(Self::from), - } - } - - /// # Panics - /// Panics if self would overflow within its keyspace. - pub fn add_one(&self) -> Result { - self.add_n(1) - } - - #[allow(unused)] - pub(crate) fn is_securified(&self) -> bool { - match self { - Self::Hardened(h) => h.is_securified(), - Self::Unhardened(_) => false, - } - } - - pub(crate) fn base_index(&self) -> HDPathValue { - match self { - Self::Hardened(h) => h.base_index(), - Self::Unhardened(u) => u.base_index(), - } - } - - #[allow(unused)] - pub(crate) fn securified_base_index(&self) -> Option { - match self { - Self::Hardened(h) => match h { - HDPathComponentHardened::Securified(s) => Some(s.base_index()), - _ => None, - }, - Self::Unhardened(_) => None, - } - } -} -impl HasSampleValues for HDPathComponent { - fn sample() -> Self { - Self::unsecurified_hardening_base_index(0) - } - fn sample_other() -> Self { - Self::securifying_base_index(1) - } -} - -#[cfg(test)] -mod tests_hdpathcomp { - - use super::*; - - type Sut = HDPathComponent; - - #[test] - fn add_one_successful() { - let t = |value: Sut, expected_base_index: HDPathValue| { - let actual = value.add_one().unwrap(); - assert_eq!(actual.base_index(), expected_base_index) - }; - t(Sut::unsecurified_hardening_base_index(0), 1); - t(Sut::unsecurified_hardening_base_index(5), 6); - t( - Sut::new_from_index(BIP32_SECURIFIED_HALF - 2), - BIP32_SECURIFIED_HALF - 1, - ); - - t(Sut::securifying_base_index(0), 1); - t(Sut::securifying_base_index(5), 6); - t( - Sut::securifying_base_index(BIP32_SECURIFIED_HALF - 3), - BIP32_SECURIFIED_HALF - 2, - ); - - t( - Sut::securifying_base_index(BIP32_SECURIFIED_HALF - 2), - BIP32_SECURIFIED_HALF - 1, - ); - } - - #[test] - #[should_panic] - fn add_one_unsecurified_max_panics() { - let sut = Sut::unsecurified_hardening_base_index(BIP32_SECURIFIED_HALF - 1); - _ = sut.add_one() - } - - #[test] - #[should_panic] - fn add_one_securified_max_panics() { - let sut = Sut::securifying_base_index(BIP32_SECURIFIED_HALF - 1); - _ = sut.add_one() - } - - #[test] - fn index_if_securified() { - let i = 5; - let sut = Sut::securifying_base_index(i); - assert_eq!(sut.base_index(), i); - assert_eq!(sut.securified_base_index(), Some(i)); - } -} - -#[repr(u16)] -#[derive(Clone, Copy, PartialEq, Eq, Hash, derive_more::Display, derive_more::Debug)] -pub enum CAP26KeyKind { - /// For a key to be used for signing transactions. - /// The value is the ascii sum of `"TRANSACTION_SIGNING"` - #[display("tx")] - #[debug("tx")] - TransactionSigning = 1460, - - /// For a key to be used for signing authentication.. - /// The value is the ascii sum of `"AUTHENTICATION_SIGNING"` - #[display("rola")] - #[debug("rola")] - AuthenticationSigning = 1678, -} - -impl CAP26KeyKind { - fn discriminant(&self) -> u16 { - core::intrinsics::discriminant_value(self) - } -} - -#[repr(u8)] -#[derive( - Clone, - Copy, - PartialEq, - Eq, - Hash, - derive_more::Display, - derive_more::Debug, - enum_iterator::Sequence, -)] -pub enum NetworkID { - #[display("Mainnet")] - #[debug("0")] - Mainnet, - - #[display("Stokenet")] - #[debug("1")] - Stokenet, - - #[display("Adapanet")] - #[debug("10")] - Adapanet, - - /// Nebunet (0x0b / 0d11 ) - /// - /// The first Betanet of Babylon - #[display("Nebunet")] - #[debug("11")] - Nebunet, - - /// Kisharnet (0x0c / 0d12) - /// - /// The first release candidate of Babylon (RCnet v1) - #[display("Kisharnet")] - #[debug("12")] - Kisharnet, - - /// Ansharnet (0x0d / 0d13) - /// - /// The second release candidate of Babylon (RCnet v2) - #[display("Ansharnet")] - #[debug("13")] - Ansharnet, -} - -impl NetworkID { - fn discriminant(&self) -> u8 { - core::intrinsics::discriminant_value(self) - } - pub fn all() -> IndexSet { - enum_iterator::all::().collect() - } -} - -#[repr(u8)] -#[derive(Clone, Copy, PartialEq, Eq, Hash, derive_more::Display, derive_more::Debug)] -pub enum CAP26EntityKind { - #[display("Account")] - #[debug("A")] - Account, - - #[display("Identity")] - #[debug("I")] - Identity, -} - -impl CAP26EntityKind { - fn discriminant(&self) -> u8 { - core::intrinsics::discriminant_value(self) - } -} - -#[derive(Clone, PartialEq, Eq, Hash, derive_more::Display, derive_more::Debug)] -#[display("{}/{}/{}/{}", network_id, entity_kind, key_kind, index)] -#[debug("{:?}/{:?}/{:?}/{:?}", network_id, entity_kind, key_kind, index)] -pub struct DerivationPath { - pub network_id: NetworkID, - pub entity_kind: CAP26EntityKind, - pub key_kind: CAP26KeyKind, - pub index: HDPathComponent, -} - -impl DerivationPath { - pub fn new( - network_id: NetworkID, - entity_kind: CAP26EntityKind, - key_kind: CAP26KeyKind, - index: HDPathComponent, - ) -> Self { - Self { - network_id, - entity_kind, - key_kind, - index, - } - } - - /// Will harden `base_index` - pub fn unsecurified_hardening_base_index( - network_id: NetworkID, - entity_kind: CAP26EntityKind, - key_kind: CAP26KeyKind, - base_index: HDPathValue, - ) -> Self { - Self::new( - network_id, - entity_kind, - key_kind, - HDPathComponent::unsecurified_hardening_base_index(base_index), - ) - } - pub fn account_tx(network_id: NetworkID, index: HDPathComponent) -> Self { - Self::new( - network_id, - CAP26EntityKind::Account, - CAP26KeyKind::TransactionSigning, - index, - ) - } - - pub fn to_bytes(&self) -> Vec { - let mut vec = Vec::new(); - vec.push(self.network_id.discriminant()); - vec.push(self.entity_kind.discriminant()); - vec.extend(self.key_kind.discriminant().to_be_bytes()); - vec.extend(self.index.to_bytes()); - vec - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct PublicKey { - /// this emulates the mnemonic - factor_source_id: FactorSourceIDFromHash, - /// this emulates the node in the HD tree - derivation_path: DerivationPath, -} -impl PublicKey { - pub fn new(factor_source_id: FactorSourceIDFromHash, derivation_path: DerivationPath) -> Self { - Self { - factor_source_id, - derivation_path, - } - } - pub fn to_bytes(&self) -> Vec { - let mut bytes = self.factor_source_id.to_bytes(); - bytes.extend(self.derivation_path.to_bytes()); - bytes - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct HierarchicalDeterministicPublicKey { - /// The expected public key of the private key derived at `derivationPath` - pub public_key: PublicKey, - - /// The HD derivation path for the key pair which produces virtual badges (signatures). - pub derivation_path: DerivationPath, -} -impl HierarchicalDeterministicPublicKey { - pub fn new(derivation_path: DerivationPath, public_key: PublicKey) -> Self { - Self { - derivation_path, - public_key, - } - } - - pub fn mocked_with( - derivation_path: DerivationPath, - factor_source_id: &FactorSourceIDFromHash, - ) -> Self { - Self::new( - derivation_path.clone(), - PublicKey::new(*factor_source_id, derivation_path), - ) - } - - pub fn to_bytes(&self) -> Vec { - [self.public_key.to_bytes(), self.derivation_path.to_bytes()].concat() - } -} - -#[derive(Clone, PartialEq, Eq, std::hash::Hash, derive_more::Debug)] -#[debug("{}", self.derivation_entity_index())] -pub struct HierarchicalDeterministicFactorInstance { - pub factor_source_id: FactorSourceIDFromHash, - pub public_key: HierarchicalDeterministicPublicKey, -} -impl HierarchicalDeterministicFactorInstance { - pub fn key_space(&self) -> KeySpace { - self.public_key.derivation_path.index.key_space() - } - pub fn derivation_entity_index(&self) -> HDPathComponent { - self.public_key.derivation_path.index - } - - pub fn derivation_entity_base_index(&self) -> HDPathValue { - self.derivation_entity_index().base_index() - } -} - -impl HierarchicalDeterministicFactorInstance { - #[allow(unused)] - fn debug_str(&self) -> String { - format!( - "factor_source_id: {:#?}, derivation_path: {:#?}", - self.factor_source_id, self.public_key.derivation_path - ) - } - - pub fn new( - public_key: HierarchicalDeterministicPublicKey, - factor_source_id: FactorSourceIDFromHash, - ) -> Self { - Self { - public_key, - factor_source_id, - } - } - - pub fn derivation_path(&self) -> DerivationPath { - self.public_key.derivation_path.clone() - } - - pub fn mocked_with( - derivation_path: DerivationPath, - factor_source_id: &FactorSourceIDFromHash, - ) -> Self { - Self::new( - HierarchicalDeterministicPublicKey::mocked_with(derivation_path, factor_source_id), - *factor_source_id, - ) - } - - pub fn tx_on_network( - entity_kind: CAP26EntityKind, - network_id: NetworkID, - index: HDPathComponent, - factor_source_id: FactorSourceIDFromHash, - ) -> Self { - let derivation_path = DerivationPath::new( - network_id, - entity_kind, - CAP26KeyKind::TransactionSigning, - index, - ); - let public_key = PublicKey::new(factor_source_id, derivation_path.clone()); - let hd_public_key = HierarchicalDeterministicPublicKey::new(derivation_path, public_key); - Self::new(hd_public_key, factor_source_id) - } - - pub fn mainnet_tx( - entity_kind: CAP26EntityKind, - index: HDPathComponent, - factor_source_id: FactorSourceIDFromHash, - ) -> Self { - Self::tx_on_network(entity_kind, NetworkID::Mainnet, index, factor_source_id) - } - - pub fn mainnet_tx_account( - index: HDPathComponent, - factor_source_id: FactorSourceIDFromHash, - ) -> Self { - Self::mainnet_tx(CAP26EntityKind::Account, index, factor_source_id) - } - - pub fn mainnet_tx_identity( - index: HDPathComponent, - factor_source_id: FactorSourceIDFromHash, - ) -> Self { - Self::mainnet_tx(CAP26EntityKind::Identity, index, factor_source_id) - } - - pub fn to_bytes(&self) -> Vec { - [self.public_key.to_bytes(), self.factor_source_id.to_bytes()].concat() - } -} - -impl HasSampleValues for HierarchicalDeterministicFactorInstance { - fn sample() -> Self { - Self::mainnet_tx_account( - HDPathComponent::unsecurified_hardening_base_index(0), - FactorSourceIDFromHash::sample(), - ) - } - fn sample_other() -> Self { - Self::mainnet_tx_account( - HDPathComponent::unsecurified_hardening_base_index(1), - FactorSourceIDFromHash::sample_other(), - ) - } -} - -#[derive(Clone, Debug, PartialEq, Eq, std::hash::Hash)] -pub struct Hash { - id: Uuid, -} -impl Hash { - pub fn to_bytes(&self) -> Vec { - self.id.as_bytes().to_vec() - } - fn new(id: Uuid) -> Self { - Self { id } - } - pub fn generate() -> Self { - Self::new(Uuid::new_v4()) - } - pub fn sample_third() -> Self { - Self::new(Uuid::from_bytes([0x11; 16])) - } - pub fn from_bytes(bytes: &[u8]) -> Self { - assert_eq!(bytes.len(), 16); // mock - Self::new(Uuid::from_slice(bytes).unwrap()) - } -} -impl HasSampleValues for Hash { - fn sample() -> Self { - Self::new(Uuid::from_bytes([0xde; 16])) - } - fn sample_other() -> Self { - Self::new(Uuid::from_bytes([0xab; 16])) - } -} - -#[derive(Clone, Debug, PartialEq, Eq, std::hash::Hash)] -pub struct SecurifiedEntityControl { - pub matrix: MatrixOfFactorInstances, - /// Virtual Entity Creation (Factor)Instance - pub veci: Option, - pub access_controller: AccessController, -} -impl SecurifiedEntityControl { - pub fn all_factor_instances(&self) -> IndexSet { - self.matrix.all_factors() - } - pub fn primary_role_instances(&self) -> FactorInstances { - self.matrix.primary_role_instances() - } - pub fn veci(&self) -> Option { - self.veci.clone() - } - - /// This is wrong... should be Role... - pub fn primary_role(&self) -> MatrixOfFactorInstances { - self.matrix.clone() - } - pub fn new( - matrix: MatrixOfFactorInstances, - access_controller: AccessController, - veci: impl Into>, - ) -> Self { - Self { - matrix, - access_controller, - veci: veci.into(), - } - } -} - -impl HasSampleValues for SecurifiedEntityControl { - fn sample() -> Self { - Self::new( - MatrixOfFactorInstances::sample(), - AccessController::sample(), - VirtualEntityCreatingInstance::sample(), - ) - } - fn sample_other() -> Self { - Self::new( - MatrixOfFactorInstances::sample_other(), - AccessController::sample_other(), - VirtualEntityCreatingInstance::sample_other(), - ) - } -} - -#[derive(Clone, Debug, PartialEq, Eq, std::hash::Hash, EnumAsInner)] -pub enum EntitySecurityState { - Unsecured(HierarchicalDeterministicFactorInstance), - Securified(SecurifiedEntityControl), -} -impl EntitySecurityState { - pub fn all_factor_instances(&self) -> IndexSet { - match self { - Self::Securified(sec) => { - let matrix = sec.matrix.clone(); - let mut set = IndexSet::new(); - set.extend(matrix.threshold_factors.clone()); - set.extend(matrix.override_factors.clone()); - set - } - Self::Unsecured(fi) => IndexSet::from_iter([fi.clone()]), - } - } -} - -#[derive(Clone, PartialEq, Eq, std::hash::Hash, derive_more::Display, derive_more::Debug)] -#[display("{}_{:?}_{:?}", self.kind(), network_id, public_key_hash)] -#[debug("{}_{:?}_{:?}", self.kind(), network_id, public_key_hash)] -pub struct AbstractAddress { - phantom: PhantomData, - pub network_id: NetworkID, - pub public_key_hash: PublicKeyHash, -} -impl AbstractAddress { - fn kind(&self) -> String { - T::entity_kind().to_string().to_lowercase()[0..4].to_owned() - } -} -impl IsEntityAddress for AbstractAddress { - fn new(network_id: NetworkID, public_key_hash: PublicKeyHash) -> Self { - Self { - phantom: PhantomData, - network_id, - public_key_hash, - } - } - fn network_id(&self) -> NetworkID { - self.network_id - } - fn public_key_hash(&self) -> PublicKeyHash { - self.public_key_hash.clone() - } -} -impl AbstractAddress { - pub fn entity_kind() -> CAP26EntityKind { - T::entity_kind() - } -} -impl AbstractAddress { - pub fn sample_0() -> Self { - Self::new(NetworkID::Mainnet, PublicKeyHash::sample_0()) - } - pub fn sample_1() -> Self { - Self::new(NetworkID::Mainnet, PublicKeyHash::sample_1()) - } - pub fn sample_2() -> Self { - Self::new(NetworkID::Mainnet, PublicKeyHash::sample_2()) - } - pub fn sample_3() -> Self { - Self::new(NetworkID::Mainnet, PublicKeyHash::sample_3()) - } - pub fn sample_4() -> Self { - Self::new(NetworkID::Mainnet, PublicKeyHash::sample_4()) - } - pub fn sample_5() -> Self { - Self::new(NetworkID::Mainnet, PublicKeyHash::sample_5()) - } - pub fn sample_6() -> Self { - Self::new(NetworkID::Mainnet, PublicKeyHash::sample_6()) - } - pub fn sample_7() -> Self { - Self::new(NetworkID::Mainnet, PublicKeyHash::sample_7()) - } - pub fn sample_8() -> Self { - Self::new(NetworkID::Mainnet, PublicKeyHash::sample_8()) - } - pub fn sample_9() -> Self { - Self::new(NetworkID::Mainnet, PublicKeyHash::sample_9()) - } -} -impl HasSampleValues for AbstractAddress { - fn sample() -> Self { - Self::sample_0() - } - fn sample_other() -> Self { - Self::sample_1() - } -} - -#[derive(Clone, Debug, PartialEq, Eq, std::hash::Hash)] -pub struct AccountAddressTag; - -#[derive(Clone, Debug, PartialEq, Eq, std::hash::Hash)] -pub struct IdentityAddressTag; - -pub trait EntityKindSpecifier { - fn entity_kind() -> CAP26EntityKind; -} -impl EntityKindSpecifier for AccountAddressTag { - fn entity_kind() -> CAP26EntityKind { - CAP26EntityKind::Account - } -} -impl EntityKindSpecifier for IdentityAddressTag { - fn entity_kind() -> CAP26EntityKind { - CAP26EntityKind::Identity - } -} - -impl EntityKindSpecifier for AbstractAddress { - fn entity_kind() -> CAP26EntityKind { - T::entity_kind() - } -} - -#[derive(Default, Clone, Debug, PartialEq, Eq, Hash)] -pub struct FactorSources(Vec); -impl FactorSources { - pub fn factor_sources(&self) -> IndexSet { - self.0.clone().into_iter().collect() - } - pub fn just(factor_source: HDFactorSource) -> Self { - Self(vec![factor_source]) - } - pub fn insert(&mut self, factor_source: HDFactorSource) { - assert!(!self.0.iter().any(|f| f == &factor_source)); - self.0.push(factor_source); - } -} -impl FromIterator for FactorSources { - fn from_iter>(iter: I) -> Self { - Self(iter.into_iter().collect()) - } -} -impl IntoIterator for FactorSources { - type Item = HDFactorSource; - type IntoIter = as IntoIterator>::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.factor_sources().into_iter() - } -} - -pub type AccountAddress = AbstractAddress; -pub type IdentityAddress = AbstractAddress; - -#[derive(Clone, PartialEq, Eq, std::hash::Hash, derive_more::Display, EnumAsInner)] -pub enum AddressOfAccountOrPersona { - Account(AccountAddress), - Identity(IdentityAddress), -} -impl AddressOfAccountOrPersona { - pub fn derived_from_factor_instance( - &self, - factor_instance: &HierarchicalDeterministicFactorInstance, - ) -> bool { - factor_instance.public_key_hash() == self.public_key_hash() - } - - pub fn new( - factor_instance: HierarchicalDeterministicFactorInstance, - network_id: NetworkID, - entity_kind: CAP26EntityKind, - ) -> Self { - match entity_kind { - CAP26EntityKind::Account => Self::Account(AccountAddress::new( - network_id, - factor_instance.public_key_hash(), - )), - CAP26EntityKind::Identity => Self::Identity(IdentityAddress::new( - network_id, - factor_instance.public_key_hash(), - )), - } - } - pub fn entity_kind(&self) -> CAP26EntityKind { - match self { - Self::Account(_) => CAP26EntityKind::Account, - Self::Identity(_) => CAP26EntityKind::Identity, - } - } - pub fn network_id(&self) -> NetworkID { - match self { - Self::Account(a) => a.network_id(), - Self::Identity(i) => i.network_id(), - } - } - pub fn public_key_hash(&self) -> PublicKeyHash { - match self { - Self::Account(a) => a.public_key_hash(), - Self::Identity(i) => i.public_key_hash(), - } - } -} -impl TryFrom for AccountAddress { - type Error = CommonError; - - fn try_from(value: AddressOfAccountOrPersona) -> Result { - match value { - AddressOfAccountOrPersona::Account(a) => Ok(a), - AddressOfAccountOrPersona::Identity(_) => Err(CommonError::AddressConversionError), - } - } -} -impl TryFrom for IdentityAddress { - type Error = CommonError; - - fn try_from(value: AddressOfAccountOrPersona) -> Result { - match value { - AddressOfAccountOrPersona::Identity(a) => Ok(a), - AddressOfAccountOrPersona::Account(_) => Err(CommonError::AddressConversionError), - } - } -} -impl std::fmt::Debug for AddressOfAccountOrPersona { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(&self.to_string()) - } -} -impl HasSampleValues for AddressOfAccountOrPersona { - fn sample() -> Self { - Self::Account(AccountAddress::sample()) - } - fn sample_other() -> Self { - Self::Identity(IdentityAddress::sample()) - } -} - -#[derive(Clone, Debug, PartialEq, Eq, std::hash::Hash, EnumAsInner)] -pub enum AccountOrPersona { - AccountEntity(Account), - PersonaEntity(Persona), -} -impl AccountOrPersona { - pub fn third_party_deposit_settings(&self) -> ThirdPartyDepositPreference { - ThirdPartyDepositPreference::default() // TODO let me stored field... - } - pub fn network_id(&self) -> NetworkID { - match self { - AccountOrPersona::AccountEntity(a) => a.network_id(), - AccountOrPersona::PersonaEntity(p) => p.network_id(), - } - } - - pub fn matches_key_space(&self, key_space: KeySpace) -> bool { - match key_space { - KeySpace::Securified => self.is_securified(), - KeySpace::Unsecurified => !self.is_securified(), - } - } - - pub fn is_securified(&self) -> bool { - self.security_state().is_securified() - } -} - -pub trait IsEntityAddress: Sized { - fn new(network_id: NetworkID, public_key_hash: PublicKeyHash) -> Self; - fn network_id(&self) -> NetworkID; - fn public_key_hash(&self) -> PublicKeyHash; - - fn by_hashing(network_id: NetworkID, key: impl Into) -> Self { - Self::new(network_id, key.into()) - } -} - -pub trait IsNetworkAware { - fn network_id(&self) -> NetworkID; -} - -pub trait IsEntity: - Into + TryFrom + Clone + IsNetworkAware -{ - type Address: IsEntityAddress - + HasSampleValues - + Clone - + Into - + TryFrom - + EntityKindSpecifier - + std::hash::Hash - + Eq - + std::fmt::Debug; - - fn new( - name: impl AsRef, - address: Self::Address, - security_state: impl Into, - third_party_deposit: impl Into>, - ) -> Self; - - fn as_unsecurified(&self) -> Result { - match self.security_state() { - EntitySecurityState::Unsecured(fi) => Ok(UnsecurifiedEntity::new( - self.address(), - fi, - ThirdPartyDepositPreference::default(), // TODO 3rd party - )), - EntitySecurityState::Securified(_) => Err(CommonError::EntityConversionError), - } - } - - fn unsecurified_on_network( - name: impl AsRef, - network_id: NetworkID, - genesis_factor_instance: HierarchicalDeterministicFactorInstance, - ) -> Self { - let address = Self::Address::new(network_id, genesis_factor_instance.public_key_hash()); - Self::new( - name, - address, - EntitySecurityState::Unsecured(genesis_factor_instance), - ThirdPartyDepositPreference::default(), - ) - } - - fn unsecurified_mainnet( - name: impl AsRef, - genesis_factor_instance: HierarchicalDeterministicFactorInstance, - ) -> Self { - Self::unsecurified_on_network(name, NetworkID::Mainnet, genesis_factor_instance) - } - - fn securified( - name: impl AsRef, - address: Self::Address, - make_matrix: impl Fn() -> MatrixOfFactorInstances, - ) -> Self { - let matrix = make_matrix(); - let access_controller = AccessController::new( - AccessControllerAddress::new(address.clone()), - ComponentMetadata::new(matrix.clone()), - ); - - Self::new( - name, - address, - EntitySecurityState::Securified(SecurifiedEntityControl::new( - matrix, - access_controller, - None, // TODO add this as a parameter to this ctor - )), - ThirdPartyDepositPreference::default(), - ) - } - - fn securified_mainnet( - name: impl AsRef, - address: Self::Address, - make_matrix: impl Fn() -> MatrixOfFactorInstances, - ) -> Self { - assert_eq!(address.network_id(), NetworkID::Mainnet); - let matrix = make_matrix(); - assert!(matrix - .clone() - .all_factors() - .into_iter() - .all(|f| f.derivation_path().network_id == NetworkID::Mainnet)); - Self::securified(name, address, || matrix.clone()) - } - - fn all_factor_instances(&self) -> HashSet { - self.security_state() - .all_factor_instances() - .into_iter() - .collect() - } - - fn is_securified(&self) -> bool { - match self.security_state() { - EntitySecurityState::Securified(_) => true, - EntitySecurityState::Unsecured(_) => false, - } - } - fn entity_address(&self) -> Self::Address; - - fn name(&self) -> String; - fn third_party_deposit(&self) -> ThirdPartyDepositPreference; - fn kind() -> CAP26EntityKind { - Self::Address::entity_kind() - } - fn security_state(&self) -> EntitySecurityState; - fn address(&self) -> AddressOfAccountOrPersona { - self.entity_address().clone().into() - } - fn e0() -> Self; - fn e1() -> Self; - fn e2() -> Self; - fn e3() -> Self; - fn e4() -> Self; - fn e5() -> Self; - fn e6() -> Self; - fn e7() -> Self; -} - -#[derive(Clone, PartialEq, Eq, std::hash::Hash, derive_more::Debug)] -#[debug("{}", self.address())] -pub struct AbstractEntity + EntityKindSpecifier> { - address: A, - pub name: String, - pub security_state: EntitySecurityState, - pub third_party_deposit: ThirdPartyDepositPreference, -} -pub type Account = AbstractEntity; -impl IsNetworkAware for Account { - fn network_id(&self) -> NetworkID { - self.address.network_id() - } -} -impl IsNetworkAware for Persona { - fn network_id(&self) -> NetworkID { - self.address.network_id() - } -} - -impl Persona { - pub fn as_securified(&self) -> Result { - SecurifiedPersona::try_from(self.clone()) - } -} - -impl Account { - pub fn set_name(&mut self, name: impl AsRef) { - self.name = name.as_ref().to_owned(); - } - pub fn as_securified(&self) -> Result { - SecurifiedAccount::try_from(self.clone()) - } -} - -impl IsEntity for Account { - fn new( - name: impl AsRef, - address: Self::Address, - security_state: impl Into, - third_party_deposit: impl Into>, - ) -> Self { - Self { - name: name.as_ref().to_owned(), - address, - security_state: security_state.into(), - third_party_deposit: third_party_deposit.into().unwrap_or_default(), - } - } - fn name(&self) -> String { - self.name.clone() - } - type Address = AccountAddress; - fn security_state(&self) -> EntitySecurityState { - self.security_state.clone() - } - fn entity_address(&self) -> Self::Address { - self.address.clone() - } - fn third_party_deposit(&self) -> ThirdPartyDepositPreference { - self.third_party_deposit - } - fn e0() -> Self { - Self::a0() - } - fn e1() -> Self { - Self::a1() - } - fn e2() -> Self { - Self::a2() - } - fn e3() -> Self { - Self::a3() - } - fn e4() -> Self { - Self::a4() - } - fn e5() -> Self { - Self::a5() - } - fn e6() -> Self { - Self::a6() - } - fn e7() -> Self { - Self::a7() - } -} - -pub type Persona = AbstractEntity; -impl IsEntity for Persona { - fn new( - name: impl AsRef, - address: IdentityAddress, - security_state: impl Into, - third_party_deposit: impl Into>, - ) -> Self { - Self { - name: name.as_ref().to_owned(), - address, - security_state: security_state.into(), - third_party_deposit: third_party_deposit.into().unwrap_or_default(), - } - } - type Address = IdentityAddress; - fn security_state(&self) -> EntitySecurityState { - self.security_state.clone() - } - fn name(&self) -> String { - self.name.clone() - } - fn third_party_deposit(&self) -> ThirdPartyDepositPreference { - self.third_party_deposit - } - fn entity_address(&self) -> Self::Address { - self.address.clone() - } - fn e0() -> Self { - Self::p0() - } - fn e1() -> Self { - Self::p1() - } - fn e2() -> Self { - Self::p2() - } - fn e3() -> Self { - Self::p3() - } - fn e4() -> Self { - Self::p4() - } - fn e5() -> Self { - Self::p5() - } - fn e6() -> Self { - Self::p6() - } - fn e7() -> Self { - Self::p7() - } -} - -impl + EntityKindSpecifier> EntityKindSpecifier - for AbstractEntity -{ - fn entity_kind() -> CAP26EntityKind { - T::entity_kind() - } -} - -impl + EntityKindSpecifier> AbstractEntity { - pub fn address(&self) -> AddressOfAccountOrPersona { - self.address.clone().into() - } -} - -impl From for AccountOrPersona { - fn from(value: Account) -> Self { - Self::AccountEntity(value) - } -} - -impl TryFrom for Account { - type Error = CommonError; - - fn try_from(value: AccountOrPersona) -> Result { - match value { - AccountOrPersona::AccountEntity(a) => Ok(a), - AccountOrPersona::PersonaEntity(_) => Err(CommonError::EntityConversionError), - } - } -} - -impl TryFrom for Persona { - type Error = CommonError; - - fn try_from(value: AccountOrPersona) -> Result { - match value { - AccountOrPersona::PersonaEntity(p) => Ok(p), - AccountOrPersona::AccountEntity(_) => Err(CommonError::EntityConversionError), - } - } -} - -impl From for AccountOrPersona { - fn from(value: Persona) -> Self { - Self::PersonaEntity(value) - } -} - -impl From for AddressOfAccountOrPersona { - fn from(value: AccountAddress) -> Self { - Self::Account(value) - } -} - -impl From for AddressOfAccountOrPersona { - fn from(value: IdentityAddress) -> Self { - Self::Identity(value) - } -} - -impl HasSampleValues for Account { - fn sample() -> Self { - Self::sample_unsecurified() - } - fn sample_other() -> Self { - Self::sample_securified() - } -} - -impl HasSampleValues for Persona { - fn sample() -> Self { - Self::sample_unsecurified() - } - fn sample_other() -> Self { - Self::sample_securified() - } -} - -impl< - T: IsEntityAddress - + Clone - + Into - + HasSampleValues - + EntityKindSpecifier, - > AbstractEntity -where - Self: IsEntity, -{ - /// mainnet - pub(crate) fn sample_unsecurified() -> Self { - ::unsecurified_mainnet( - "Sample Unsec", - HierarchicalDeterministicFactorInstance::fi0(T::entity_kind()), - ) - } - - /// mainnet - pub(crate) fn sample_securified() -> Self { - ::securified_mainnet( - "Grace", - as IsEntity>::Address::sample_other(), - || { - let idx = HDPathComponent::securifying_base_index(6); - MatrixOfFactorInstances::m6(HierarchicalDeterministicFactorInstance::f( - Self::entity_kind(), - idx, - )) - }, - ) - } -} - -#[derive(Clone, Debug, PartialEq, Eq, std::hash::Hash)] -pub struct MatrixOfFactors { - pub threshold_factors: Vec, - pub threshold: u8, - pub override_factors: Vec, -} - -impl MatrixOfFactors -where - F: std::hash::Hash + std::cmp::Eq + Clone, -{ - /// # Panics - /// Panics if threshold > threshold_factor.len() - /// - /// Panics if the same factor is present in both lists - pub fn new( - threshold_factors: impl IntoIterator, - threshold: u8, - override_factors: impl IntoIterator, - ) -> Self { - let threshold_factors = threshold_factors.into_iter().collect_vec(); - - assert!(threshold_factors.len() >= threshold as usize); - - let override_factors = override_factors.into_iter().collect_vec(); - - assert!( - HashSet::::from_iter(threshold_factors.clone()) - .intersection(&HashSet::::from_iter(override_factors.clone())) - .collect_vec() - .is_empty(), - "A factor MUST NOT be present in both threshold AND override list." - ); - - Self { - threshold_factors, - threshold, - override_factors: override_factors.into_iter().collect_vec(), - } - } - - pub fn override_only(factors: impl IntoIterator) -> Self { - Self::new([], 0, factors) - } - - pub fn single_override(factor: F) -> Self { - Self::override_only([factor]) - } - - pub fn threshold_only(factors: impl IntoIterator, threshold: u8) -> Self { - Self::new(factors, threshold, []) - } - - pub fn all_factors(&self) -> IndexSet { - let mut set = IndexSet::new(); - set.extend(self.threshold_factors.clone()); - set.extend(self.override_factors.clone()); - set - } - - pub fn single_threshold(factor: F) -> Self { - Self::threshold_only([factor], 1) - } -} - -pub type MatrixOfFactorInstances = MatrixOfFactors; - -impl MatrixOfFactorInstances { - pub fn primary_role_instances(&self) -> FactorInstances { - // this is completely incorrect. - FactorInstances::from(self.all_factors()) - } -} - -fn sample_for_matrix_of_instances_from_account(account: Account) -> MatrixOfFactorInstances { - account.security_state().into_securified().unwrap().matrix -} - -impl HasSampleValues for MatrixOfFactorInstances { - fn sample() -> Self { - sample_for_matrix_of_instances_from_account(Account::a5()) - } - - fn sample_other() -> Self { - sample_for_matrix_of_instances_from_account(Account::a6()) - } -} - -impl MatrixOfFactorInstances { - pub fn fulfilling_matrix_of_factor_sources_with_instances( - instances: &mut IndexMap, - matrix_of_factor_sources: MatrixOfFactorSources, - ) -> Result { - let mut get_factors = - |required: Vec| -> Result> { - required - .iter() - .map(|f| { - if let Some(existing) = instances - .get_mut(&f.factor_source_id()) { - assert!(!existing.is_empty()); - let instance = existing.shift_remove_index(0); - Ok(instance) - } else { - Err(CommonError::MissingFactorMappingInstancesIntoMatrix) - } - }) - .collect::>>() - }; - - let threshold_factors = get_factors(matrix_of_factor_sources.threshold_factors)?; - let override_factors = get_factors(matrix_of_factor_sources.override_factors)?; - - Ok(Self::new( - threshold_factors, - matrix_of_factor_sources.threshold, - override_factors, - )) - } -} - -pub type MatrixOfFactorSources = MatrixOfFactors; - -/// For unsecurified entities we map single factor -> single threshold factor. -/// Which is used by ROLA. -impl From for MatrixOfFactorInstances { - fn from(value: HierarchicalDeterministicFactorInstance) -> Self { - Self { - threshold: 1, - threshold_factors: vec![value], - override_factors: Vec::new(), - } - } -} - -pub trait HasSampleValues { - fn sample() -> Self; - fn sample_other() -> Self; -} - -#[derive(Clone, PartialEq, Eq, std::hash::Hash, Getters, derive_more::Debug)] -#[debug("TXID({:#?})", hash.id.to_string()[..6].to_owned())] -pub struct IntentHash { - hash: Hash, -} - -impl IntentHash { - fn new(hash: Hash) -> Self { - Self { hash } - } - pub fn generate() -> Self { - Self::new(Hash::generate()) - } - pub fn sample_third() -> Self { - Self::new(Hash::sample_third()) - } -} - -impl HasSampleValues for IntentHash { - fn sample() -> Self { - Self::new(Hash::sample()) - } - fn sample_other() -> Self { - Self::new(Hash::sample_other()) - } -} - -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub struct TransactionManifest { - addresses_of_accounts_requiring_auth: Vec, - addresses_of_personas_requiring_auth: Vec, -} - -impl TransactionManifest { - pub fn new( - addresses_of_accounts_requiring_auth: impl IntoIterator, - addresses_of_personas_requiring_auth: impl IntoIterator, - ) -> Self { - Self { - addresses_of_accounts_requiring_auth: addresses_of_accounts_requiring_auth - .into_iter() - .collect_vec(), - addresses_of_personas_requiring_auth: addresses_of_personas_requiring_auth - .into_iter() - .collect_vec(), - } - } - pub fn summary(&self) -> ManifestSummary { - ManifestSummary::new( - self.addresses_of_accounts_requiring_auth.clone(), - self.addresses_of_personas_requiring_auth.clone(), - ) - } -} - -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub struct TransactionIntent { - pub intent_hash: IntentHash, - pub(crate) manifest: TransactionManifest, -} - -impl TransactionIntent { - fn with(manifest: TransactionManifest) -> Self { - Self { - manifest, - intent_hash: IntentHash::generate(), - } - } - pub fn new( - addresses_of_accounts_requiring_auth: impl IntoIterator, - addresses_of_personas_requiring_auth: impl IntoIterator, - ) -> Self { - Self::with(TransactionManifest::new( - addresses_of_accounts_requiring_auth, - addresses_of_personas_requiring_auth, - )) - } - pub fn address_of<'a, 'p>( - accounts_requiring_auth: impl IntoIterator, - personas_requiring_auth: impl IntoIterator, - ) -> Self { - Self::new( - accounts_requiring_auth - .into_iter() - .map(|a| a.entity_address()) - .collect_vec(), - personas_requiring_auth - .into_iter() - .map(|a| a.entity_address()) - .collect_vec(), - ) - } -} - -pub struct ManifestSummary { - pub addresses_of_accounts_requiring_auth: Vec, - pub addresses_of_personas_requiring_auth: Vec, -} - -impl ManifestSummary { - pub fn new( - addresses_of_accounts_requiring_auth: impl IntoIterator, - addresses_of_personas_requiring_auth: impl IntoIterator, - ) -> Self { - Self { - addresses_of_accounts_requiring_auth: addresses_of_accounts_requiring_auth - .into_iter() - .collect_vec(), - addresses_of_personas_requiring_auth: addresses_of_personas_requiring_auth - .into_iter() - .collect_vec(), - } - } -} - -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct Profile { - pub factor_sources: IndexSet, - pub networks: IndexMap, - pub current_network: NetworkID, -} - -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct ProfileNetwork { - pub network_id: NetworkID, - pub accounts: IndexMap, - pub personas: IndexMap, -} - -impl Default for ProfileNetwork { - fn default() -> Self { - Self { - network_id: NetworkID::Mainnet, - accounts: IndexMap::new(), - personas: IndexMap::new(), - } - } -} - -impl ProfileNetwork { - pub fn contains_entity_by_address(&self, entity_address: &E::Address) -> bool { - self.get_entities_erased(E::kind()) - .into_iter() - .any(|e| e.address() == entity_address.clone().into()) - } - pub fn contains_account(&self, address: impl Into) -> bool { - let address = address.into(); - self.accounts.contains_key(&address) - } - - pub fn get_entities(&self) -> IndexSet { - self.get_entities_erased(E::kind()) - .into_iter() - .map(|e| E::try_from(e).ok().unwrap()) - .collect() - } - - pub fn get_entities_erased(&self, entity_kind: CAP26EntityKind) -> IndexSet { - match entity_kind { - CAP26EntityKind::Account => self - .accounts - .values() - .cloned() - .map(AccountOrPersona::from) - .collect::>(), - CAP26EntityKind::Identity => self - .personas - .values() - .cloned() - .map(AccountOrPersona::from) - .collect::>(), - } - } - - pub fn update_entity(&mut self, entity: E) { - match Into::::into(entity.clone()) { - AccountOrPersona::AccountEntity(a) => { - assert!(self.accounts.insert(a.entity_address(), a).is_some()); - } - AccountOrPersona::PersonaEntity(p) => { - assert!(self.personas.insert(p.entity_address(), p).is_some()); - } - } - } - - pub fn get_entities_of_kind_in_key_space( - &self, - entity_kind: CAP26EntityKind, - key_space: KeySpace, - ) -> IndexSet { - self.get_entities_erased(entity_kind) - .into_iter() - .filter(|e| e.matches_key_space(key_space)) - .collect() - } - - pub fn insert_accounts(&mut self, accounts: IndexSet) -> Result<()> { - if accounts.is_empty() { - return Ok(()); - } - - let count = self.accounts.len(); - let expected_after_insertion = count + accounts.len(); - for a in accounts.into_iter() { - let already_existed = self.accounts.insert(a.entity_address(), a); - assert!(already_existed.is_none()); - } - assert_eq!(self.accounts.len(), expected_after_insertion); - Ok(()) - } - - pub fn persona_by_address(&self, address: IdentityAddress) -> Result { - self.personas - .get(&address) - .ok_or(CommonError::UnknownPersona) - .cloned() - } - - pub fn insert_personas(&mut self, personas: IndexSet) -> Result<()> { - if personas.is_empty() { - return Ok(()); - } - - let count = self.personas.len(); - let expected_after_insertion = count + personas.len(); - for a in personas.into_iter() { - self.personas.insert(a.entity_address(), a); - } - assert_eq!(self.personas.len(), expected_after_insertion); - Ok(()) - } - - pub fn add_account(&mut self, account: &Account) -> Result<()> { - self.accounts - .insert(account.entity_address(), account.clone()); - Ok(()) - } - - pub fn update_account(&mut self, account: &Account) -> Result<()> { - assert!(self - .accounts - .insert(account.entity_address(), account.clone()) - .is_some()); - Ok(()) - } - - pub fn add_persona(&mut self, persona: &Persona) -> Result<()> { - self.personas - .insert(persona.entity_address(), persona.clone()); - Ok(()) - } -} - -impl Default for Profile { - fn default() -> Self { - Self { - factor_sources: IndexSet::new(), - networks: IndexMap::new(), - current_network: NetworkID::Mainnet, - } - } -} -impl From for AccountAddress { - fn from(value: Account) -> Self { - value.entity_address() - } -} -impl Profile { - pub fn contains_entity_by_address(&self, entity_address: &E::Address) -> bool { - self.networks - .values() - .any(|n: &ProfileNetwork| n.contains_entity_by_address::(entity_address)) - } - - /// # Panics if no BDFS was found - pub fn bdfs(&self) -> HDFactorSource { - self.factor_sources - .iter() - .find(|f| f.factor_source_kind() == FactorSourceKind::Device) - .expect("a Device FactorSource") - .clone() - } - - pub fn current_network(&self) -> NetworkID { - self.current_network - } - - pub fn contains_account(&self, address: impl Into) -> bool { - let address = address.into(); - self.networks - .values() - .any(|n| n.contains_account(address.clone())) - } - - pub fn get_entities_of_kind_on_network_in_key_space( - &self, - entity_kind: CAP26EntityKind, - network_id: NetworkID, - key_space: KeySpace, - ) -> IndexSet { - self.networks - .get(&network_id) - .map(|n| n.get_entities_of_kind_in_key_space(entity_kind, key_space)) - .unwrap_or_default() - } - - pub fn get_securified_entities_of_kind_on_network( - &self, - network_id: NetworkID, - ) -> IndexSet { - self.get_entities_of_kind_on_network_in_key_space( - E::kind(), - network_id, - KeySpace::Securified, - ) - .into_iter() - .flat_map(|x| E::try_from(x).ok()) - .collect() - } - - // pub fn get_securified_entities_of_kind_on_network( - // &self, - // entity_kind: CAP26EntityKind, - // network_id: NetworkID, - // ) -> IndexSet { - // self.get_entities_of_kind_on_network_in_key_space( - // entity_kind, - // network_id, - // KeySpace::Securified, - // ) - // .into_iter() - // .map(|e: AccountOrPersona| { - // let control = match e.security_state() { - // EntitySecurityState::Securified(control) => control, - // _ => unreachable!(), - // }; - // SecurifiedEntity::new(e.address(), control, e.third_party_deposit_settings()) - // }) - // .collect() - // } - - pub fn get_unsecurified_entities_of_kind_on_network( - &self, - entity_kind: CAP26EntityKind, - network_id: NetworkID, - ) -> IndexSet { - self.get_entities_of_kind_on_network_in_key_space( - entity_kind, - network_id, - KeySpace::Unsecurified, - ) - .into_iter() - .map(|e: AccountOrPersona| { - let factor_instance = match e.security_state() { - EntitySecurityState::Unsecured(factor_instance) => factor_instance, - _ => unreachable!(), - }; - UnsecurifiedEntity::new( - e.address(), - factor_instance, - e.third_party_deposit_settings(), - ) - }) - .collect() - } - - pub fn unsecurified_accounts_on_network( - &self, - network_id: NetworkID, - ) -> IndexSet { - self.get_unsecurified_entities_of_kind_on_network(CAP26EntityKind::Account, network_id) - } - - pub fn securified_accounts_on_network( - &self, - network_id: NetworkID, - ) -> IndexSet { - self.get_securified_entities_of_kind_on_network(network_id) - } - - pub fn unsecurified_identities_on_network( - &self, - network_id: NetworkID, - ) -> IndexSet { - self.get_unsecurified_entities_of_kind_on_network(CAP26EntityKind::Identity, network_id) - } - - pub fn securified_identities_on_network( - &self, - network_id: NetworkID, - ) -> IndexSet { - self.get_securified_entities_of_kind_on_network(network_id) - } - - pub fn accounts_on_network(&self, network_id: NetworkID) -> IndexSet { - self.get_accounts() - .into_iter() - .filter(|a| a.network_id() == network_id) - .collect() - } - pub fn personas_on_network(&self, network_id: NetworkID) -> IndexSet { - self.networks - .get(&network_id) - .map(|n| n.get_entities()) - .unwrap_or_default() - } - - pub fn get_entities(&self) -> IndexSet { - self.networks - .values() - .flat_map(|n| n.get_entities::()) - .collect() - } - - pub fn get_accounts(&self) -> IndexSet { - self.get_entities() - } - - pub fn get_personas(&self) -> IndexSet { - self.get_entities() - } - - /// assumes mainnet accounts and mainnet personas - pub fn new<'a, 'p>( - factor_sources: impl IntoIterator, - accounts: impl IntoIterator, - personas: impl IntoIterator, - ) -> Self { - let factor_sources = factor_sources.into_iter().collect::>(); - let accounts = accounts.into_iter().collect_vec(); - let personas = personas.into_iter().collect_vec(); - let network_id = NetworkID::Mainnet; - assert!(accounts.iter().all(|a| (*a).network_id() == network_id)); - assert!(personas.iter().all(|a| (*a).network_id() == network_id)); - Self { - factor_sources, - networks: IndexMap::kv( - network_id, - ProfileNetwork { - network_id, - accounts: accounts - .into_iter() - .map(|a| (a.entity_address(), a.clone())) - .collect::>(), - personas: personas - .into_iter() - .map(|p| (p.entity_address(), p.clone())) - .collect::>(), - }, - ), - current_network: NetworkID::Mainnet, - } - } - - pub fn account_by_address(&self, address: &AccountAddress) -> Result { - self.entity_by_address(address) - } - - pub fn entity_by_address( - &self, - address: &E::Address, - ) -> Result { - self.get_entities::() - .into_iter() - .find(|e| e.entity_address() == *address) - .ok_or(CommonError::UnknownEntity) - } - - pub fn update_entity(&mut self, entity: E) { - let account_or_persona = Into::::into(entity.clone()); - let network_id = account_or_persona.network_id(); - if let Some(existing) = self.networks.get_mut(&network_id) { - existing.update_entity(entity); - } else { - panic!("hmm what to do"); - } - } - - pub fn get_entity( - &self, - address: &E::Address, - ) -> Result { - self.get_entities::() - .into_iter() - .find(|e| e.entity_address() == *address) - .ok_or(CommonError::UnknownEntity) - } - - pub fn get_account(&self, address: &AccountAddress) -> Result { - self.get_accounts() - .into_iter() - .find(|a| a.entity_address() == *address) - .ok_or(CommonError::UnknownAccount) - } - - pub fn insert_accounts(&mut self, accounts: IndexSet) -> Result<()> { - if accounts.is_empty() { - return Ok(()); - } - let network_id = accounts.iter().next().unwrap().network_id(); - assert!(accounts.iter().all(|a| a.network_id() == network_id)); - - if let Some(existing) = self.networks.get_mut(&network_id) { - existing.insert_accounts(accounts) - } else { - self.networks.insert( - network_id, - ProfileNetwork { - network_id, - accounts: accounts - .into_iter() - .map(|a| (a.entity_address(), a)) - .collect(), - personas: IndexMap::new(), - }, - ); - Ok(()) - } - } - - pub fn insert_personas(&mut self, personas: IndexSet) -> Result<()> { - if personas.is_empty() { - return Ok(()); - } - let network_id = personas.iter().next().unwrap().network_id(); - assert!(personas.iter().all(|a| a.network_id() == network_id)); - - if let Some(existing) = self.networks.get_mut(&network_id) { - existing.insert_personas(personas) - } else { - self.networks.insert( - network_id, - ProfileNetwork { - network_id, - accounts: IndexMap::new(), - personas: personas - .into_iter() - .map(|a| (a.entity_address(), a)) - .collect(), - }, - ); - Ok(()) - } - } - - pub fn add_factor_source(&mut self, factor_source: HDFactorSource) -> Result<()> { - self.factor_sources.insert(factor_source); - Ok(()) - } - - pub fn add_account(&mut self, account: &Account) -> Result<()> { - self.insert_accounts(IndexSet::just(account.clone())) - } - - pub fn update_account(&mut self, account: &Account) -> Result<()> { - let network_id = account.network_id(); - let network = self.networks.get_mut(&network_id).unwrap(); - network.update_account(account) - } - - pub fn persona_by_address(&self, address: IdentityAddress) -> Result { - let network_id = address.network_id(); - let network = self - .networks - .get(&network_id) - .ok_or(CommonError::UnknownPersona)?; - network.persona_by_address(address) - } - - pub fn add_persona(&mut self, persona: &Persona) -> Result<()> { - self.insert_personas(IndexSet::just(persona.clone())) - } - - pub fn insert_entities(&mut self, entities: IndexSet) -> Result<()> { - for entity in entities { - if let Some(account) = entity.as_account_entity() { - self.add_account(account)?; - } else if let Some(persona) = entity.as_persona_entity() { - self.add_persona(persona)?; - } else { - panic!("Unknown entity kind"); - } - } - Ok(()) - } -} - -#[derive(Clone, Debug, PartialEq, Eq, std::hash::Hash)] -pub struct Signature([u8; 64]); -impl Signature { - pub fn new_with_hex(s: impl AsRef) -> Result { - hex::decode(s.as_ref()) - .map_err(|_| CommonError::StringNotHex) - .and_then(|b| b.try_into().map_err(|_| CommonError::BytesLengthError)) - .map(Self) - } -} -impl HasSampleValues for Signature { - fn sample() -> Self { - Self::new_with_hex("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef").unwrap() - } - fn sample_other() -> Self { - Self::new_with_hex("fadecafefadecafefadecafefadecafefadecafefadecafefadecafefadecafefadecafefadecafefadecafefadecafefadecafefadecafefadecafefadecafe").unwrap() - } -} - -#[cfg(test)] -mod signature_tests { - use super::*; - - type Sut = Signature; - - #[test] - fn eq() { - assert_eq!(Sut::sample(), Sut::sample()); - assert_eq!(Sut::sample_other(), Sut::sample_other()); - assert_ne!(Sut::sample(), Sut::sample_other()); - } -} - -impl Signature { - /// Emulates the signing of `intent_hash` with `factor_instance` - in a - /// deterministic manner. - pub fn produced_by( - intent_hash: IntentHash, - factor_instance: impl Into, - ) -> Self { - let factor_instance = factor_instance.into(); - - let intent_hash_bytes = intent_hash.hash().to_bytes(); - let factor_instance_bytes = factor_instance.to_bytes(); - let input_bytes = [intent_hash_bytes, factor_instance_bytes].concat(); - let mut hasher = sha2::Sha512::new(); - hasher.update(input_bytes); - Self(hasher.finalize().into()) - } - - /// Emulates signing using `input`. - pub fn produced_by_input(input: &HDSignatureInput) -> Self { - Self::produced_by( - input.intent_hash.clone(), - input.owned_factor_instance.clone(), - ) - } -} - -pub type Result = std::result::Result; - -#[derive(thiserror::Error, Clone, Debug, PartialEq, Eq)] -pub enum CommonError { - #[error("Unknown factor source")] - UnknownFactorSource, - - #[error("Invalid factor source kind")] - InvalidFactorSourceKind, - - #[error("Empty FactorSources list")] - FactorSourcesOfKindEmptyFactors, - - #[error("Unknown account")] - UnknownAccount, - - #[error("Unknown persona")] - UnknownPersona, - - #[error("Unknown entity")] - UnknownEntity, - - #[error("Failed To Acquire ReadGuard of KeysCache")] - KeysCacheReadGuard, - - #[error("Failed To Acquire WriteGuard of KeysCache")] - KeysCacheWriteGuard, - - #[error("KeysCache does not contain any references for key")] - KeysCacheUnknownKey, - - #[error("KeysCache empty list for key")] - KeysCacheEmptyForKey, - - #[error("FactorInstanceProvider failed to create genesis factor")] - InstanceProviderFailedToCreateGenesisFactor, - - #[error("Address conversion error")] - AddressConversionError, - - #[error("Entity conversion error")] - EntityConversionError, - - #[error("String not hex")] - StringNotHex, - - #[error("Bytes length error")] - BytesLengthError, - - #[error("Missing a FactorInstance while mapping FactorInstances and MatrixOfFactorSources into MatrixOfFactorInstances")] - MissingFactorMappingInstancesIntoMatrix, - - #[error("Matrix From ScryptoAccessRule Not Protected")] - MatrixFromRulesNotProtected, - - #[error("Matrix From ScryptoAccessRule Not AnyOf")] - MatrixFromRulesNotAnyOf, - - #[error("Matrix From ScryptoAccessRule Expected Two Any")] - MatrixFromRulesExpectedTwoAny, - - #[error("Matrix From ScryptoAccessRule Not ProofRule")] - MatrixFromRulesNotProofRule, - - #[error("Matrix From ScryptoAccessRule Not CountOf")] - MatrixFromRulesNotCountOf, - - #[error("Matrix From ScryptoAccessRule ResourceOrNonFungible not PublicKeyHash")] - MatrixFromRulesResourceOrNonFungibleNotKeyHash, - - #[error("TestDerivationInteractor hardcoded failure")] - HardcodedFailureTestDerivationInteractor, - - #[error("FactorInstances does not satisfy derivation requests")] - FactorInstancesDoesNotSatisfyDerivationRequests, - - #[error("Next Derivation Entity Index From Profile Analyser not present, but required")] - ProfileIndexAssignerNotPresent, - - #[error("Wrong network")] - WrongNetwork, - - #[error("Empty collection")] - EmptyCollection, - - #[error("Expected Veci")] - ExpectedVeci, - - #[error("Network Discrepancy")] - NetworkDiscrepancy, - - #[error("FactorSource Discrepancy")] - FactorSourceDiscrepancy, - - #[error("EntityKind Discrepancy")] - EntityKindDiscrepancy, - - #[error("KeySpace Discrepancy")] - KeySpaceDiscrepancy, - - #[error("KeyKind Discrepancy")] - KeyKindDiscrepancy, - - #[error("Invalid u30")] - Invalid30 { bad_value: u32 }, - - #[error("Account not securified")] - AccountNotSecurified, - - #[error("Persona not securified")] - PersonaNotSecurified, - - #[error("Unsupported Non Preset DerivationPath")] - NonStandardDerivationPath, - - #[error("Entity Index would overflow if added to")] - EntityIndexWouldOverflowIfAddedTo, - - #[error("Cache Already Contains FactorInstance with path: {derivation_path}")] - CacheAlreadyContainsFactorInstance { derivation_path: DerivationPath }, - - #[error("Too Few FactorInstances derived")] - FactorInstancesProviderDidNotDeriveEnoughFactors, -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct AccessControllerAddress(pub String); -impl AccessControllerAddress { - pub fn new(a: A) -> Self { - Self(format!( - "access_controller_{:?}_{:?}", - a.network_id(), - a.public_key_hash() - )) - } -} - -impl HasSampleValues for AccessControllerAddress { - fn sample() -> Self { - Self::new(AccountAddress::sample()) - } - - fn sample_other() -> Self { - Self::new(AccountAddress::sample_other()) - } -} - -#[derive(Clone, PartialEq, Eq, Hash, derive_more::Debug)] -#[debug("{}", hex::encode(&self.0[28..32]))] -pub struct PublicKeyHash([u8; 32]); - -impl PublicKeyHash { - pub fn new(bytes: [u8; 32]) -> Self { - Self(bytes) - } -} -impl HasSampleValues for PublicKeyHash { - fn sample() -> Self { - Self::sample_0() - } - fn sample_other() -> Self { - Self::sample_1() - } -} - -impl PublicKey { - pub fn hash(&self) -> PublicKeyHash { - let mut hasher = Sha256::new(); - hasher.update(self.to_bytes()); - let digest = hasher.finalize().into(); - PublicKeyHash(digest) - } -} - -impl HierarchicalDeterministicPublicKey { - pub fn hash(&self) -> PublicKeyHash { - self.public_key.hash() - } -} -impl HierarchicalDeterministicFactorInstance { - pub fn public_key_hash(&self) -> PublicKeyHash { - self.public_key.hash() - } -} -impl From for PublicKeyHash { - fn from(value: PublicKey) -> Self { - value.hash() - } -} -impl From for PublicKeyHash { - fn from(value: HierarchicalDeterministicPublicKey) -> Self { - value.hash() - } -} -impl From for PublicKeyHash { - fn from(value: HierarchicalDeterministicFactorInstance) -> Self { - value.public_key_hash() - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash, EnumAsInner)] -pub enum ScryptoResourceOrNonFungible { - PublicKeyHash(PublicKeyHash), -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash, EnumAsInner)] -pub enum ScryptoProofRule { - AnyOf(Vec), - CountOf(usize, Vec), - // AllOf - // Require - // AmountOf -} -impl ScryptoProofRule { - pub fn any_of(values: Vec) -> Self { - Self::AnyOf(values) - } - pub fn count_of(count: usize, values: Vec) -> Self { - Self::CountOf(count, values) - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash, EnumAsInner)] -pub enum ScryptoAccessRuleNode { - ProofRule(ScryptoProofRule), - AnyOf(Vec), - AllOf(Vec), -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash, EnumAsInner)] -pub enum ScryptoAccessRule { - Protected(ScryptoAccessRuleNode), - // AllowAll - // DenyAll -} -impl ScryptoAccessRule { - pub fn protected(rule: ScryptoAccessRuleNode) -> Self { - Self::Protected(rule) - } - pub fn with_threshold( - count: usize, - threshold_factors: impl IntoIterator>, - override_factors: impl IntoIterator>, - ) -> Self { - Self::protected(ScryptoAccessRuleNode::AnyOf(vec![ - ScryptoAccessRuleNode::ProofRule(ScryptoProofRule::CountOf( - count, - threshold_factors - .into_iter() - .map(Into::into) - .map(ScryptoResourceOrNonFungible::PublicKeyHash) - .collect_vec(), - )), - ScryptoAccessRuleNode::ProofRule(ScryptoProofRule::AnyOf( - override_factors - .into_iter() - .map(Into::into) - .map(ScryptoResourceOrNonFungible::PublicKeyHash) - .collect_vec(), - )), - ])) - } -} - -pub type MatrixOfKeyHashes = MatrixOfFactors; -impl From for ScryptoAccessRule { - fn from(value: MatrixOfFactorInstances) -> Self { - Self::with_threshold( - value.threshold as usize, - value.threshold_factors, - value.override_factors, - ) - } -} -impl From for ScryptoAccessRule { - fn from(value: MatrixOfKeyHashes) -> Self { - Self::with_threshold( - value.threshold as usize, - value.threshold_factors, - value.override_factors, - ) - } -} -impl TryFrom for MatrixOfKeyHashes { - type Error = CommonError; - - fn try_from(value: ScryptoAccessRule) -> Result { - let protected = value - .into_protected() - .map_err(|_| CommonError::MatrixFromRulesNotProtected)?; - let root_any_of = protected - .into_any_of() - .map_err(|_| CommonError::MatrixFromRulesNotAnyOf)?; - if root_any_of.len() != 2 { - return Err(CommonError::MatrixFromRulesExpectedTwoAny); - } - let rule_0 = root_any_of[0] - .clone() - .into_proof_rule() - .map_err(|_| CommonError::MatrixFromRulesNotProofRule)?; - - let rule_1 = root_any_of[1] - .clone() - .into_proof_rule() - .map_err(|_| CommonError::MatrixFromRulesNotProofRule)?; - - let threshold_rule = rule_0 - .into_count_of() - .map_err(|_| CommonError::MatrixFromRulesNotCountOf)?; - let override_rule = rule_1 - .into_any_of() - .map_err(|_| CommonError::MatrixFromRulesNotAnyOf)?; - - let threshold = threshold_rule.0; - let threshold_hashes = threshold_rule - .1 - .into_iter() - .map(|r| { - r.into_public_key_hash() - .map_err(|_| CommonError::MatrixFromRulesResourceOrNonFungibleNotKeyHash) - }) - .collect::>>()?; - - let override_hashes = override_rule - .into_iter() - .map(|r| { - r.into_public_key_hash() - .map_err(|_| CommonError::MatrixFromRulesResourceOrNonFungibleNotKeyHash) - }) - .collect::>>()?; - - Ok(Self::new( - threshold_hashes, - threshold as u8, - override_hashes, - )) - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct ComponentMetadata { - pub scrypto_access_rules: ScryptoAccessRule, -} - -impl ComponentMetadata { - pub fn new(scrypto_access_rules: impl Into) -> Self { - Self { - scrypto_access_rules: scrypto_access_rules.into(), - } - } -} - -impl HasSampleValues for ScryptoAccessRule { - fn sample() -> Self { - MatrixOfFactorInstances::sample().into() - } - - fn sample_other() -> Self { - MatrixOfFactorInstances::sample_other().into() - } -} - -impl HasSampleValues for ComponentMetadata { - fn sample() -> Self { - Self::new(ScryptoAccessRule::sample()) - } - - fn sample_other() -> Self { - Self::new(ScryptoAccessRule::sample_other()) - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct AccessController { - pub address: AccessControllerAddress, - pub metadata: Option, -} - -impl AccessController { - pub fn new( - address: AccessControllerAddress, - metadata: impl Into>, - ) -> Self { - Self { - address, - metadata: metadata.into(), - } - } - pub fn from_unsecurified_address(entity_address: E) -> Self { - Self::new(AccessControllerAddress::new(entity_address), None) - } -} - -impl HasSampleValues for AccessController { - fn sample() -> Self { - Self::new( - AccessControllerAddress::sample(), - ComponentMetadata::sample(), - ) - } - - fn sample_other() -> Self { - Self::new( - AccessControllerAddress::sample_other(), - ComponentMetadata::sample_other(), - ) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn sample_component_metadata() { - type Sut = ComponentMetadata; - assert_eq!(Sut::sample(), Sut::sample()); - assert_eq!(Sut::sample_other(), Sut::sample_other()); - assert_ne!(Sut::sample(), Sut::sample_other()); - } - - #[test] - fn sample_access_controller_address() { - type Sut = AccessControllerAddress; - assert_eq!(Sut::sample(), Sut::sample()); - assert_eq!(Sut::sample_other(), Sut::sample_other()); - assert_ne!(Sut::sample(), Sut::sample_other()); - } - - #[test] - fn sample_access_controller() { - type Sut = AccessController; - assert_eq!(Sut::sample(), Sut::sample()); - assert_eq!(Sut::sample_other(), Sut::sample_other()); - assert_ne!(Sut::sample(), Sut::sample_other()); - } - - #[test] - fn sample_scrypto_access_rule() { - type Sut = ScryptoAccessRule; - assert_eq!(Sut::sample(), Sut::sample()); - assert_eq!(Sut::sample_other(), Sut::sample_other()); - assert_ne!(Sut::sample(), Sut::sample_other()); - } -} diff --git a/tests/main.rs b/tests/main.rs deleted file mode 100644 index b76ef6b9..00000000 --- a/tests/main.rs +++ /dev/null @@ -1,305 +0,0 @@ -use use_factors::prelude::*; - -#[cfg(test)] -mod integration_test_derivation { - use std::sync::Arc; - - use indexmap::{IndexMap, IndexSet}; - - use super::*; - - struct TestDerivationInteractors; - struct TestDerivationInteractor; - - #[async_trait::async_trait] - impl PolyFactorKeyDerivationInteractor for TestDerivationInteractor { - async fn derive( - &self, - request: PolyFactorKeyDerivationRequest, - ) -> Result { - let mut keys = IndexMap::< - FactorSourceIDFromHash, - IndexSet, - >::new(); - for (f, req) in request.per_factor_source.into_iter() { - let resp = ::derive(self, req).await?; - - keys.insert(f, resp.per_factor_source.into_iter().next().unwrap().1); - } - Ok(KeyDerivationResponse::new(keys)) - } - } - - #[async_trait::async_trait] - impl MonoFactorKeyDerivationInteractor for TestDerivationInteractor { - async fn derive( - &self, - request: MonoFactorKeyDerivationRequest, - ) -> Result { - let factor_source_id = request.clone().factor_source_id; - Ok(KeyDerivationResponse::new(IndexMap::just(( - factor_source_id, - request - .derivation_paths - .clone() - .into_iter() - .map(|p| { - HierarchicalDeterministicFactorInstance::mocked_with(p, &factor_source_id) - }) - .collect(), - )))) - } - } - - impl KeysDerivationInteractors for TestDerivationInteractors { - fn interactor_for(&self, kind: FactorSourceKind) -> KeyDerivationInteractor { - match kind { - FactorSourceKind::Device => { - KeyDerivationInteractor::MonoFactor(Arc::new(TestDerivationInteractor)) - } - _ => KeyDerivationInteractor::PolyFactor(Arc::new(TestDerivationInteractor)), - } - } - } - - #[actix_rt::test] - async fn valid() { - let f0 = HDFactorSource::ledger(); - let f1 = HDFactorSource::device(); - let f2 = HDFactorSource::device(); - let f3 = HDFactorSource::arculus(); - - let paths = IndexMap::<_, _>::from_iter([ - ( - f0.factor_source_id(), - IndexSet::<_>::from_iter([ - DerivationPath::account_tx( - NetworkID::Mainnet, - HDPathComponent::securifying_base_index(0), - ), - DerivationPath::account_tx( - NetworkID::Mainnet, - HDPathComponent::securifying_base_index(1), - ), - DerivationPath::account_tx( - NetworkID::Stokenet, - HDPathComponent::unsecurified_hardening_base_index(2), - ), - ]), - ), - ( - f1.factor_source_id(), - IndexSet::<_>::just(DerivationPath::account_tx( - NetworkID::Stokenet, - HDPathComponent::unsecurified_hardening_base_index(3), - )), - ), - ( - f2.factor_source_id(), - IndexSet::<_>::just(DerivationPath::account_tx( - NetworkID::Mainnet, - HDPathComponent::unsecurified_hardening_base_index(4), - )), - ), - ( - f3.factor_source_id(), - IndexSet::<_>::just(DerivationPath::new( - NetworkID::Mainnet, - CAP26EntityKind::Identity, - CAP26KeyKind::AuthenticationSigning, - HDPathComponent::securifying_base_index(5), - )), - ), - ]); - - let collector = KeysCollector::new( - [f0, f1, f2, f3], - paths.clone(), - Arc::new(TestDerivationInteractors), - ) - .unwrap(); - - let outcome = collector.collect_keys().await; - let factors = outcome.all_factors().factor_instances(); - assert_eq!( - factors.len(), - paths - .clone() - .into_iter() - .flat_map(|(_, v)| v) - .collect::>() - .len(), - ); - } -} - -#[cfg(test)] -mod integration_test_signing { - use std::sync::Arc; - - use indexmap::IndexSet; - - use super::*; - - struct TestLazySignMinimumInteractors; - struct TestLazySignMinimumInteractor; - - #[async_trait::async_trait] - impl PolyFactorSignInteractor for TestLazySignMinimumInteractor { - async fn sign(&self, request: PolyFactorSignRequest) -> SignWithFactorsOutcome { - let mut signatures = IndexSet::::new(); - for (_, req) in request.per_factor_source.iter() { - let resp = ::sign( - self, - MonoFactorSignRequest::new( - req.clone(), - request.invalid_transactions_if_neglected.clone(), - ), - ) - .await; - - match resp { - SignWithFactorsOutcome::Signed { - produced_signatures, - } => { - signatures.extend( - produced_signatures - .signatures - .into_iter() - .flat_map(|(_, xs)| xs) - .collect::>(), - ); - } - SignWithFactorsOutcome::Neglected(_) => { - return SignWithFactorsOutcome::Neglected(NeglectedFactors::new( - NeglectFactorReason::UserExplicitlySkipped, - request.factor_source_ids(), - )); - } - } - } - SignWithFactorsOutcome::signed(SignResponse::with_signatures(signatures)) - } - } - - #[async_trait::async_trait] - impl MonoFactorSignInteractor for TestLazySignMinimumInteractor { - async fn sign(&self, request: MonoFactorSignRequest) -> SignWithFactorsOutcome { - if request.invalid_transactions_if_neglected.is_empty() { - return SignWithFactorsOutcome::Neglected(NeglectedFactors::new( - NeglectFactorReason::UserExplicitlySkipped, - IndexSet::just(request.input.factor_source_id), - )); - } - let signatures = request - .input - .per_transaction - .into_iter() - .flat_map(|r| { - r.signature_inputs() - .iter() - .map(|x| HDSignature::produced_signing_with_input(x.clone())) - .collect::>() - }) - .collect::>(); - SignWithFactorsOutcome::Signed { - produced_signatures: SignResponse::with_signatures(signatures), - } - } - } - - impl SignInteractors for TestLazySignMinimumInteractors { - fn interactor_for(&self, kind: FactorSourceKind) -> SignInteractor { - match kind { - FactorSourceKind::Device => { - SignInteractor::mono(Arc::new(TestLazySignMinimumInteractor)) - } - _ => SignInteractor::poly(Arc::new(TestLazySignMinimumInteractor)), - } - } - } - - #[actix_rt::test] - async fn valid() { - type FI = HierarchicalDeterministicFactorInstance; - - let f0 = HDFactorSource::ledger(); - let f1 = HDFactorSource::device(); - let f2 = HDFactorSource::device(); - let f3 = HDFactorSource::arculus(); - let f4 = HDFactorSource::off_device(); - - let alice = Account::securified_mainnet("Alice", AccountAddress::sample(), || { - let i = HDPathComponent::securifying_base_index(0); - MatrixOfFactorInstances::threshold_only( - [ - FI::mainnet_tx_account(i, f0.factor_source_id()), // SKIPPED - FI::mainnet_tx_account(i, f1.factor_source_id()), - FI::mainnet_tx_account(i, f2.factor_source_id()), - ], - 2, - ) - }); - - let bob = Account::securified_mainnet("Bob", AccountAddress::sample_2(), || { - let i = HDPathComponent::securifying_base_index(1); - MatrixOfFactorInstances::override_only([FI::mainnet_tx_account( - i, - f3.factor_source_id(), - )]) - }); - - let carol = Account::securified_mainnet("Carol", AccountAddress::sample_3(), || { - let i = HDPathComponent::securifying_base_index(2); - MatrixOfFactorInstances::new( - [FI::mainnet_tx_account(i, f2.factor_source_id())], - 1, - [FI::mainnet_tx_account(i, f4.factor_source_id())], - ) - }); - - let satoshi = Persona::unsecurified_mainnet( - "Satoshi", - HierarchicalDeterministicFactorInstance::mainnet_tx_identity( - HDPathComponent::unsecurified_hardening_base_index(0), - f4.factor_source_id(), - ), - ); - - let tx0 = TransactionIntent::new([alice.entity_address()], []); - let tx1 = TransactionIntent::new( - [ - alice.entity_address(), - bob.entity_address(), - carol.entity_address(), - ], - [satoshi.entity_address()], - ); - let tx2 = TransactionIntent::new([bob.entity_address()], [satoshi.entity_address()]); - - let transactions = [tx0, tx1, tx2]; - - let profile = Profile::new( - [f0.clone(), f1, f2, f3, f4], - [&alice, &bob, &carol], - [&satoshi], - ); - - let collector = SignaturesCollector::new( - SigningFinishEarlyStrategy::default(), - transactions, - Arc::new(TestLazySignMinimumInteractors), - &profile, - ) - .unwrap(); - - let outcome = collector.collect_signatures().await; - - assert!(outcome.successful()); - assert_eq!(outcome.signatures_of_successful_transactions().len(), 10); - assert_eq!( - outcome.ids_of_neglected_factor_sources(), - IndexSet::::just(f0.factor_source_id()) - ); - } -}