From c91f8f6b5f600ac34ede7f99598514d7d923f064 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Fri, 6 Dec 2024 15:21:23 +0100 Subject: [PATCH 01/60] Reintroduce `From> for ScryptoAccessRule` --- .../factor_instance_level/mod.rs | 2 ++ .../role_into_scrypto_access_rule.rs | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 crates/sargon/src/profile/mfa/security_structures/roles/factor_levels/factor_instance_level/role_into_scrypto_access_rule.rs diff --git a/crates/sargon/src/profile/mfa/security_structures/roles/factor_levels/factor_instance_level/mod.rs b/crates/sargon/src/profile/mfa/security_structures/roles/factor_levels/factor_instance_level/mod.rs index bb3e03464..5624c37f6 100644 --- a/crates/sargon/src/profile/mfa/security_structures/roles/factor_levels/factor_instance_level/mod.rs +++ b/crates/sargon/src/profile/mfa/security_structures/roles/factor_levels/factor_instance_level/mod.rs @@ -2,10 +2,12 @@ mod confirmation_role_with_factor_instances; mod general_role_with_hierarchical_deterministic_factor_instances; mod primary_role_with_factor_instances; mod recovery_role_with_factor_instances; +mod role_into_scrypto_access_rule; mod role_with_factor_instances; pub use confirmation_role_with_factor_instances::*; pub use general_role_with_hierarchical_deterministic_factor_instances::*; pub use primary_role_with_factor_instances::*; pub use recovery_role_with_factor_instances::*; +pub use role_into_scrypto_access_rule::*; pub use role_with_factor_instances::*; diff --git a/crates/sargon/src/profile/mfa/security_structures/roles/factor_levels/factor_instance_level/role_into_scrypto_access_rule.rs b/crates/sargon/src/profile/mfa/security_structures/roles/factor_levels/factor_instance_level/role_into_scrypto_access_rule.rs new file mode 100644 index 000000000..17bd5885b --- /dev/null +++ b/crates/sargon/src/profile/mfa/security_structures/roles/factor_levels/factor_instance_level/role_into_scrypto_access_rule.rs @@ -0,0 +1,27 @@ +use crate::prelude::*; + +impl From> for ScryptoAccessRule { + fn from(value: RoleWithFactorInstances) -> Self { + let from_factors = + |factors: &Vec| -> Vec { + factors + .iter() + .map(|instance| instance.badge.clone()) + .map(ScryptoResourceOrNonFungible::from) + .collect() + }; + ScryptoAccessRule::Protected(ScryptoCompositeRequirement::AnyOf(vec![ + ScryptoCompositeRequirement::BasicRequirement( + ScryptoBasicRequirement::CountOf( + value.get_threshold(), + from_factors(value.get_threshold_factors()), + ), + ), + ScryptoCompositeRequirement::BasicRequirement( + ScryptoBasicRequirement::AnyOf(from_factors( + value.get_override_factors(), + )), + ), + ])) + } +} From 2d3259e7b673a0bcdd18caeeee295beacb774894 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Mon, 9 Dec 2024 14:03:05 +0100 Subject: [PATCH 02/60] impl From for ScryptoRuleSet --- .../matrices/matrix_of_factor_instances.rs | 16 ++++ .../role_into_scrypto_access_rule.rs | 46 +++++++++++ .../security_structure_of_factors/mod.rs | 2 + .../security_structure_of_factor_instances.rs | 81 +++++++++++++++++++ ...security_structure_of_factor_source_ids.rs | 50 ------------ 5 files changed, 145 insertions(+), 50 deletions(-) create mode 100644 crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_instances.rs diff --git a/crates/sargon/src/profile/mfa/security_structures/matrices/matrix_of_factor_instances.rs b/crates/sargon/src/profile/mfa/security_structures/matrices/matrix_of_factor_instances.rs index 6a5b15e65..34192d394 100644 --- a/crates/sargon/src/profile/mfa/security_structures/matrices/matrix_of_factor_instances.rs +++ b/crates/sargon/src/profile/mfa/security_structures/matrices/matrix_of_factor_instances.rs @@ -2,6 +2,13 @@ use crate::prelude::*; pub type MatrixOfFactorInstances = AbstractMatrixBuilt; +impl MatrixOfFactorInstances { + pub fn timed_recovery_delay_in_minutes(&self) -> u32 { + let timed_recovery_in_days = + self.number_of_days_until_auto_confirm as u32; + MINUTES_PER_DAY * timed_recovery_in_days + } +} pub trait HasFactorInstances { fn unique_factor_instances(&self) -> IndexSet; } @@ -214,6 +221,15 @@ mod tests { assert_eq!(SUT::sample_other(), SUT::sample_other()); } + #[test] + fn timed_recovery_delay_in_minutes() { + let sut = SUT::sample(); + assert_eq!( + sut.timed_recovery_delay_in_minutes(), + SUT::DEFAULT_NUMBER_OF_DAYS_UNTIL_AUTO_CONFIRM as u32 * 24 * 60 + ); + } + #[test] fn inequality() { assert_ne!(SUT::sample(), SUT::sample_other()); diff --git a/crates/sargon/src/profile/mfa/security_structures/roles/factor_levels/factor_instance_level/role_into_scrypto_access_rule.rs b/crates/sargon/src/profile/mfa/security_structures/roles/factor_levels/factor_instance_level/role_into_scrypto_access_rule.rs index 17bd5885b..08fd51a2e 100644 --- a/crates/sargon/src/profile/mfa/security_structures/roles/factor_levels/factor_instance_level/role_into_scrypto_access_rule.rs +++ b/crates/sargon/src/profile/mfa/security_structures/roles/factor_levels/factor_instance_level/role_into_scrypto_access_rule.rs @@ -1,3 +1,7 @@ +use radix_engine_interface::blueprints::access_controller::{ + RecoveryProposal as ScryptoRecoveryProposal, RuleSet as ScryptoRuleSet, +}; + use crate::prelude::*; impl From> for ScryptoAccessRule { @@ -25,3 +29,45 @@ impl From> for ScryptoAccessRule { ])) } } + +impl From for ScryptoRuleSet { + fn from( + MatrixOfFactorInstances { + primary_role, + recovery_role, + confirmation_role, + .. + }: MatrixOfFactorInstances, + ) -> Self { + Self { + primary_role: primary_role.into(), + recovery_role: recovery_role.into(), + confirmation_role: confirmation_role.into(), + } + } +} + +pub const MINUTES_PER_DAY: u32 = 24 * 60; + +impl From for ScryptoRecoveryProposal { + fn from(value: SecurityStructureOfFactorInstances) -> Self { + let timed_recovery_delay_in_minutes = + value.timed_recovery_delay_in_minutes(); + Self { + rule_set: value.matrix_of_factors.into(), + timed_recovery_delay_in_minutes: Some( + timed_recovery_delay_in_minutes, + ), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn number_of_minutes_per_day() { + assert_eq!(MINUTES_PER_DAY, 1440); + } +} diff --git a/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/mod.rs b/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/mod.rs index 9e2b04e3b..7aa81f664 100644 --- a/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/mod.rs +++ b/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/mod.rs @@ -1,7 +1,9 @@ mod abstract_security_structure_of_factors; +mod security_structure_of_factor_instances; mod security_structure_of_factor_source_ids; mod security_structure_of_factor_sources; pub(crate) use abstract_security_structure_of_factors::*; +pub use security_structure_of_factor_instances::*; pub use security_structure_of_factor_source_ids::*; pub use security_structure_of_factor_sources::*; diff --git a/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_instances.rs b/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_instances.rs new file mode 100644 index 000000000..be1c79618 --- /dev/null +++ b/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_instances.rs @@ -0,0 +1,81 @@ +use crate::prelude::*; + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] +#[serde(rename_all = "camelCase")] +pub struct SecurityStructureOfFactorInstances { + /// The ID of the `SecurityStructureOfFactorSourceIDs` in + /// `profile.app_preferences.security.security_structures_of_factor_source_ids` + /// which was used to derive the factor instances in this structure. Or rather: + /// The id of `SecurityStructureOfFactorSources`. + pub security_structure_id: SecurityStructureID, + + /// The structure of factors to use for certain roles, Primary, Recovery + /// and Confirmation role. + pub matrix_of_factors: MatrixOfFactorInstances, +} + +impl SecurityStructureOfFactorInstances { + pub fn new( + security_structure_id: SecurityStructureID, + matrix_of_factors: MatrixOfFactorInstances, + ) -> Self { + Self { + security_structure_id, + matrix_of_factors, + } + } +} + +impl SecurityStructureOfFactorInstances { + pub fn timed_recovery_delay_in_minutes(&self) -> u32 { + self.matrix_of_factors.timed_recovery_delay_in_minutes() + } +} + +impl Identifiable for SecurityStructureOfFactorInstances { + type ID = ::ID; + + fn id(&self) -> Self::ID { + self.security_structure_id + } +} + +impl HasSampleValues for SecurityStructureOfFactorInstances { + fn sample() -> Self { + Self { + security_structure_id: SecurityStructureID::sample(), + matrix_of_factors: MatrixOfFactorInstances::sample(), + } + } + + fn sample_other() -> Self { + Self { + security_structure_id: SecurityStructureID::sample_other(), + matrix_of_factors: MatrixOfFactorInstances::sample_other(), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + #[allow(clippy::upper_case_acronyms)] + type SUT = SecurityStructureOfFactorInstances; + + #[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 timed_recovery_delay_in_minutes() { + let sut = SUT::sample(); + assert_eq!(sut.timed_recovery_delay_in_minutes(), 20160); + } +} diff --git a/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_source_ids.rs b/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_source_ids.rs index 0ae91a796..13d1bc790 100644 --- a/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_source_ids.rs +++ b/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_source_ids.rs @@ -3,56 +3,6 @@ use crate::prelude::*; pub type SecurityStructureOfFactorSourceIds = AbstractSecurityStructure; -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] -#[serde(rename_all = "camelCase")] -pub struct SecurityStructureOfFactorInstances { - /// The ID of the `SecurityStructureOfFactorSourceIDs` in - /// `profile.app_preferences.security.security_structures_of_factor_source_ids` - /// which was used to derive the factor instances in this structure. Or rather: - /// The id of `SecurityStructureOfFactorSources`. - pub security_structure_id: SecurityStructureID, - - /// The structure of factors to use for certain roles, Primary, Recovery - /// and Confirmation role. - pub matrix_of_factors: MatrixOfFactorInstances, -} - -impl SecurityStructureOfFactorInstances { - pub fn new( - security_structure_id: SecurityStructureID, - matrix_of_factors: MatrixOfFactorInstances, - ) -> Self { - Self { - security_structure_id, - matrix_of_factors, - } - } -} - -impl Identifiable for SecurityStructureOfFactorInstances { - type ID = ::ID; - - fn id(&self) -> Self::ID { - self.security_structure_id - } -} - -impl HasSampleValues for SecurityStructureOfFactorInstances { - fn sample() -> Self { - Self { - security_structure_id: SecurityStructureID::sample(), - matrix_of_factors: MatrixOfFactorInstances::sample(), - } - } - - fn sample_other() -> Self { - Self { - security_structure_id: SecurityStructureID::sample_other(), - matrix_of_factors: MatrixOfFactorInstances::sample_other(), - } - } -} - impl HasSampleValues for SecurityStructureOfFactorSourceIds { fn sample() -> Self { let metadata = SecurityStructureMetadata::sample(); From 7eb9e2daffd258c072aabdc57f60584f8f935685 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Thu, 12 Dec 2024 14:41:41 +0100 Subject: [PATCH 03/60] bump Scrypto and RET --- Cargo.lock | 775 +++++++++++++++++++++----------- crates/sargon-uniffi/Cargo.toml | 2 +- crates/sargon/Cargo.toml | 18 +- 3 files changed, 523 insertions(+), 272 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e4a1d85c9..d0ae80954 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9,7 +9,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.85", + "syn 2.0.90", ] [[package]] @@ -95,9 +95,9 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.18" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "android-tzdata" @@ -126,9 +126,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -141,43 +141,43 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.91" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c042108f3ed77fd83760a5fd79b53be043192bb3b9dba91d8c574c0ada7850c8" +checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" [[package]] name = "arrayvec" @@ -191,7 +191,7 @@ version = "2.0.2" source = "git+https://github.com/davidpdrsn/assert-json-diff/?rev=bca0d2c590808274298d939e0533da79cd09076d#bca0d2c590808274298d939e0533da79cd09076d" dependencies = [ "serde", - "serde_json 1.0.132", + "serde_json 1.0.133", ] [[package]] @@ -247,9 +247,9 @@ dependencies = [ [[package]] name = "async-io" -version = "2.3.4" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8" +checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" dependencies = [ "async-lock", "cfg-if", @@ -314,7 +314,7 @@ source = "git+https://github.com/dtolnay/async-trait?rev=1eb21ed8bd87029bf4dcbea dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.90", ] [[package]] @@ -499,9 +499,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "camino" @@ -519,9 +519,9 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" dependencies = [ "serde", ] @@ -536,7 +536,7 @@ dependencies = [ "cargo-platform", "semver", "serde", - "serde_json 1.0.132", + "serde_json 1.0.133", ] [[package]] @@ -549,8 +549,8 @@ dependencies = [ "cargo-platform", "semver", "serde", - "serde_json 1.0.132", - "thiserror 1.0.65", + "serde_json 1.0.133", + "thiserror 1.0.69", ] [[package]] @@ -574,9 +574,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.31" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" +checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d" dependencies = [ "shlex", ] @@ -589,9 +589,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" dependencies = [ "android-tzdata", "iana-time-zone", @@ -621,11 +621,11 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.20" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" dependencies = [ - "clap_builder 4.5.20", + "clap_builder 4.5.23", "clap_derive 4.5.18", ] @@ -640,13 +640,13 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.20" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" dependencies = [ "anstream", "anstyle", - "clap_lex 0.7.2", + "clap_lex 0.7.4", "strsim", ] @@ -658,7 +658,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.90", ] [[package]] @@ -670,7 +670,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.90", ] [[package]] @@ -680,15 +680,15 @@ source = "git+https://github.com/clap-rs/clap/?rev=8a7a13a5618cfdc4ff328624a5266 [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "colored" @@ -739,9 +739,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] @@ -826,7 +826,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.90", ] [[package]] @@ -850,7 +850,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.85", + "syn 2.0.90", ] [[package]] @@ -861,7 +861,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.85", + "syn 2.0.90", ] [[package]] @@ -871,7 +871,7 @@ source = "git+https://github.com/Kobzol/rust-delegate/?rev=ac852be64f3e4b5f9b58b dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.90", ] [[package]] @@ -917,7 +917,7 @@ source = "git+https://github.com/JelteF/derive_more?rev=1196b2dd7a366c06db621093 dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.90", "unicode-xid", ] @@ -928,7 +928,7 @@ source = "git+https://github.com/JelteF/derive_more?rev=d7f5b9e94d024790682f6fc4 dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.90", "unicode-xid", ] @@ -950,6 +950,17 @@ dependencies = [ "subtle", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "downcast-rs" version = "1.2.1" @@ -1042,7 +1053,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.90", ] [[package]] @@ -1060,7 +1071,7 @@ source = "git+https://github.com/stephaneyfx/enum-iterator/?rev=9d472a1237cfd03b dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.90", ] [[package]] @@ -1084,12 +1095,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1120,9 +1131,9 @@ dependencies = [ [[package]] name = "event-listener-strategy" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" dependencies = [ "event-listener 5.3.1", "pin-project-lite", @@ -1136,14 +1147,14 @@ checksum = "311a6d2f1f9d60bff73d2c78a0af97ed27f79672f15c238192a5bbb64db56d00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.90", ] [[package]] name = "fastrand" -version = "2.1.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "ff" @@ -1256,9 +1267,9 @@ checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" -version = "2.3.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +checksum = "cef40d21ae2c515b51041df9ed313ed21e572df340ea58a922a0aefe7e8891a1" dependencies = [ "fastrand", "futures-core", @@ -1275,7 +1286,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.90", ] [[package]] @@ -1321,9 +1332,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96512db27971c2c3eece70a1e106fbe6c87760234e31e8f7e5634912fe52794a" +checksum = "2cb8bc4c28d15ade99c7e90b219f30da4be5c88e586277e8cbe886beeb868ab2" dependencies = [ "typenum", ] @@ -1413,9 +1424,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "heck" @@ -1474,9 +1485,9 @@ dependencies = [ [[package]] name = "http" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" dependencies = [ "bytes", "fnv", @@ -1520,9 +1531,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" +checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f" dependencies = [ "bytes", "futures-channel", @@ -1555,9 +1566,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" dependencies = [ "bytes", "futures-channel", @@ -1595,6 +1606,124 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -1603,12 +1732,23 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", ] [[package]] @@ -1624,12 +1764,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown 0.15.0", + "hashbrown 0.15.2", "serde", ] @@ -1692,7 +1832,7 @@ name = "iso8601-timestamp" version = "0.2.17" source = "git+https://github.com/Lantern-chat/iso8601-timestamp/?rev=e5a3f2a5911759bc6b0d8100b032a6b4dd6e12c1#e5a3f2a5911759bc6b0d8100b032a6b4dd6e12c1" dependencies = [ - "generic-array 1.1.0", + "generic-array 1.1.1", "serde", "time", ] @@ -1716,16 +1856,17 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "js-sys" -version = "0.3.72" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" dependencies = [ + "once_cell 1.20.2", "wasm-bindgen", ] @@ -1786,15 +1927,15 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.161" +version = "0.2.168" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" +checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" [[package]] name = "libm" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "linux-raw-sys" @@ -1802,6 +1943,12 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +[[package]] +name = "litemap" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" + [[package]] name = "lock_api" version = "0.4.12" @@ -1860,11 +2007,10 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ - "hermit-abi 0.3.9", "libc", "wasi", "windows-sys 0.52.0", @@ -1887,7 +2033,7 @@ dependencies = [ "skeptic", "smallvec", "tagptr", - "thiserror 1.0.65", + "thiserror 1.0.69", "triomphe", "uuid 1.11.0", ] @@ -1941,17 +2087,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" -[[package]] -name = "num-derive" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.85", -] - [[package]] name = "num-integer" version = "0.1.46" @@ -2029,7 +2164,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.90", ] [[package]] @@ -2040,9 +2175,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-src" -version = "300.4.0+3.4.0" +version = "300.4.1+3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a709e02f2b4aca747929cca5ed248880847c650233cf8b8cdc48f40aaf4898a6" +checksum = "faa4eac4138c62414b5622d1b31c5c304f34b406b013c079c2bbc652fdd6678c" dependencies = [ "cc", ] @@ -2108,9 +2243,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -2153,9 +2288,9 @@ checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" [[package]] name = "polling" -version = "3.7.3" +version = "3.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" +checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" dependencies = [ "cfg-if", "concurrent-queue", @@ -2199,7 +2334,7 @@ version = "0.2.0" source = "git+https://github.com/dhedey/preinterpret?rev=6754b92bdead0ddd6f69fbee7d782180d6351605#6754b92bdead0ddd6f69fbee7d782180d6351605" dependencies = [ "proc-macro2", - "syn 2.0.85", + "syn 2.0.90", ] [[package]] @@ -2222,9 +2357,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.89" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -2251,8 +2386,8 @@ dependencies = [ [[package]] name = "radix-blueprint-schema-init" -version = "1.3.0-dev" -source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=423e26abcfbb631d8e7f64ae748cab6f57151bb3#423e26abcfbb631d8e7f64ae748cab6f57151bb3" +version = "1.4.0-dev" +source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=45bd94457e429ea65e954a7fab20dd4ddd987030#45bd94457e429ea65e954a7fab20dd4ddd987030" dependencies = [ "bitflags 1.3.2", "radix-common", @@ -2262,8 +2397,8 @@ dependencies = [ [[package]] name = "radix-common" -version = "1.3.0-dev" -source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=423e26abcfbb631d8e7f64ae748cab6f57151bb3#423e26abcfbb631d8e7f64ae748cab6f57151bb3" +version = "1.4.0-dev" +source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=45bd94457e429ea65e954a7fab20dd4ddd987030#45bd94457e429ea65e954a7fab20dd4ddd987030" dependencies = [ "bech32", "blake2", @@ -2288,8 +2423,8 @@ dependencies = [ [[package]] name = "radix-common-derive" -version = "1.3.0-dev" -source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=423e26abcfbb631d8e7f64ae748cab6f57151bb3#423e26abcfbb631d8e7f64ae748cab6f57151bb3" +version = "1.4.0-dev" +source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=45bd94457e429ea65e954a7fab20dd4ddd987030#45bd94457e429ea65e954a7fab20dd4ddd987030" dependencies = [ "paste 1.0.15", "proc-macro2", @@ -2300,8 +2435,8 @@ dependencies = [ [[package]] name = "radix-engine" -version = "1.3.0-dev" -source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=423e26abcfbb631d8e7f64ae748cab6f57151bb3#423e26abcfbb631d8e7f64ae748cab6f57151bb3" +version = "1.4.0-dev" +source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=45bd94457e429ea65e954a7fab20dd4ddd987030#45bd94457e429ea65e954a7fab20dd4ddd987030" dependencies = [ "bitflags 1.3.2", "colored", @@ -2331,8 +2466,8 @@ dependencies = [ [[package]] name = "radix-engine-interface" -version = "1.3.0-dev" -source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=423e26abcfbb631d8e7f64ae748cab6f57151bb3#423e26abcfbb631d8e7f64ae748cab6f57151bb3" +version = "1.4.0-dev" +source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=45bd94457e429ea65e954a7fab20dd4ddd987030#45bd94457e429ea65e954a7fab20dd4ddd987030" dependencies = [ "bitflags 1.3.2", "const-sha1", @@ -2346,22 +2481,22 @@ dependencies = [ "regex 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)", "sbor", "serde", - "serde_json 1.0.132", + "serde_json 1.0.133", "strum 0.24.1", ] [[package]] name = "radix-engine-profiling" -version = "1.3.0-dev" -source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=423e26abcfbb631d8e7f64ae748cab6f57151bb3#423e26abcfbb631d8e7f64ae748cab6f57151bb3" +version = "1.4.0-dev" +source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=45bd94457e429ea65e954a7fab20dd4ddd987030#45bd94457e429ea65e954a7fab20dd4ddd987030" dependencies = [ "fixedstr", ] [[package]] name = "radix-engine-profiling-derive" -version = "1.3.0-dev" -source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=423e26abcfbb631d8e7f64ae748cab6f57151bb3#423e26abcfbb631d8e7f64ae748cab6f57151bb3" +version = "1.4.0-dev" +source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=45bd94457e429ea65e954a7fab20dd4ddd987030#45bd94457e429ea65e954a7fab20dd4ddd987030" dependencies = [ "proc-macro2", "quote", @@ -2372,7 +2507,7 @@ dependencies = [ [[package]] name = "radix-engine-toolkit" version = "2.2.0-dev2" -source = "git+https://github.com/radixdlt/radix-engine-toolkit?rev=9f58ddfc6e0edb06cb35f8422044522bc0387d14#9f58ddfc6e0edb06cb35f8422044522bc0387d14" +source = "git+https://github.com/radixdlt/radix-engine-toolkit?rev=ca88bf19cd1ab7a22e9f637ff028c94dee39f500#ca88bf19cd1ab7a22e9f637ff028c94dee39f500" dependencies = [ "bech32", "cargo_toml 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2391,14 +2526,14 @@ dependencies = [ "sbor", "sbor-json", "scrypto", - "serde_json 1.0.132", + "serde_json 1.0.133", "serde_with 3.11.0", ] [[package]] name = "radix-engine-toolkit-common" -version = "1.3.0-dev" -source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=423e26abcfbb631d8e7f64ae748cab6f57151bb3#423e26abcfbb631d8e7f64ae748cab6f57151bb3" +version = "1.4.0-dev" +source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=45bd94457e429ea65e954a7fab20dd4ddd987030#45bd94457e429ea65e954a7fab20dd4ddd987030" dependencies = [ "radix-common", "radix-engine", @@ -2411,8 +2546,8 @@ dependencies = [ [[package]] name = "radix-native-sdk" -version = "1.3.0-dev" -source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=423e26abcfbb631d8e7f64ae748cab6f57151bb3#423e26abcfbb631d8e7f64ae748cab6f57151bb3" +version = "1.4.0-dev" +source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=45bd94457e429ea65e954a7fab20dd4ddd987030#45bd94457e429ea65e954a7fab20dd4ddd987030" dependencies = [ "radix-common", "radix-engine-interface", @@ -2422,17 +2557,17 @@ dependencies = [ [[package]] name = "radix-rust" -version = "1.3.0-dev" -source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=423e26abcfbb631d8e7f64ae748cab6f57151bb3#423e26abcfbb631d8e7f64ae748cab6f57151bb3" +version = "1.4.0-dev" +source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=45bd94457e429ea65e954a7fab20dd4ddd987030#45bd94457e429ea65e954a7fab20dd4ddd987030" dependencies = [ - "indexmap 2.6.0", + "indexmap 2.7.0", "serde", ] [[package]] name = "radix-sbor-derive" -version = "1.3.0-dev" -source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=423e26abcfbb631d8e7f64ae748cab6f57151bb3#423e26abcfbb631d8e7f64ae748cab6f57151bb3" +version = "1.4.0-dev" +source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=45bd94457e429ea65e954a7fab20dd4ddd987030#45bd94457e429ea65e954a7fab20dd4ddd987030" dependencies = [ "proc-macro2", "quote", @@ -2442,8 +2577,8 @@ dependencies = [ [[package]] name = "radix-substate-store-impls" -version = "1.3.0-dev" -source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=423e26abcfbb631d8e7f64ae748cab6f57151bb3#423e26abcfbb631d8e7f64ae748cab6f57151bb3" +version = "1.4.0-dev" +source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=45bd94457e429ea65e954a7fab20dd4ddd987030#45bd94457e429ea65e954a7fab20dd4ddd987030" dependencies = [ "hex 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.10.5", @@ -2455,8 +2590,8 @@ dependencies = [ [[package]] name = "radix-substate-store-interface" -version = "1.3.0-dev" -source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=423e26abcfbb631d8e7f64ae748cab6f57151bb3#423e26abcfbb631d8e7f64ae748cab6f57151bb3" +version = "1.4.0-dev" +source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=45bd94457e429ea65e954a7fab20dd4ddd987030#45bd94457e429ea65e954a7fab20dd4ddd987030" dependencies = [ "hex 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.10.5", @@ -2467,8 +2602,8 @@ dependencies = [ [[package]] name = "radix-substate-store-queries" -version = "1.3.0-dev" -source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=423e26abcfbb631d8e7f64ae748cab6f57151bb3#423e26abcfbb631d8e7f64ae748cab6f57151bb3" +version = "1.4.0-dev" +source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=45bd94457e429ea65e954a7fab20dd4ddd987030#45bd94457e429ea65e954a7fab20dd4ddd987030" dependencies = [ "hex 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.10.5", @@ -2484,8 +2619,8 @@ dependencies = [ [[package]] name = "radix-transactions" -version = "1.3.0-dev" -source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=423e26abcfbb631d8e7f64ae748cab6f57151bb3#423e26abcfbb631d8e7f64ae748cab6f57151bb3" +version = "1.4.0-dev" +source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=45bd94457e429ea65e954a7fab20dd4ddd987030#45bd94457e429ea65e954a7fab20dd4ddd987030" dependencies = [ "annotate-snippets", "bech32", @@ -2551,9 +2686,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ "bitflags 2.6.0", ] @@ -2638,7 +2773,7 @@ dependencies = [ "pin-project-lite", "rustls-pemfile", "serde", - "serde_json 1.0.132", + "serde_json 1.0.133", "serde_urlencoded", "sync_wrapper", "tokio", @@ -2686,7 +2821,7 @@ dependencies = [ "rinja_parser", "rustc-hash", "serde", - "syn 2.0.85", + "syn 2.0.90", ] [[package]] @@ -2723,15 +2858,15 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.37" +version = "0.38.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" dependencies = [ "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2869,13 +3004,13 @@ version = "0.1.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.90", ] [[package]] name = "sbor" -version = "1.3.0-dev" -source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=423e26abcfbb631d8e7f64ae748cab6f57151bb3#423e26abcfbb631d8e7f64ae748cab6f57151bb3" +version = "1.4.0-dev" +source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=45bd94457e429ea65e954a7fab20dd4ddd987030#45bd94457e429ea65e954a7fab20dd4ddd987030" dependencies = [ "const-sha1", "hex 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2888,8 +3023,8 @@ dependencies = [ [[package]] name = "sbor-derive" -version = "1.3.0-dev" -source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=423e26abcfbb631d8e7f64ae748cab6f57151bb3#423e26abcfbb631d8e7f64ae748cab6f57151bb3" +version = "1.4.0-dev" +source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=45bd94457e429ea65e954a7fab20dd4ddd987030#45bd94457e429ea65e954a7fab20dd4ddd987030" dependencies = [ "proc-macro2", "sbor-derive-common", @@ -2898,11 +3033,11 @@ dependencies = [ [[package]] name = "sbor-derive-common" -version = "1.3.0-dev" -source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=423e26abcfbb631d8e7f64ae748cab6f57151bb3#423e26abcfbb631d8e7f64ae748cab6f57151bb3" +version = "1.4.0-dev" +source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=45bd94457e429ea65e954a7fab20dd4ddd987030#45bd94457e429ea65e954a7fab20dd4ddd987030" dependencies = [ "const-sha1", - "indexmap 2.6.0", + "indexmap 2.7.0", "itertools 0.10.5", "proc-macro2", "quote", @@ -2912,7 +3047,7 @@ dependencies = [ [[package]] name = "sbor-json" version = "2.2.0-dev2" -source = "git+https://github.com/radixdlt/radix-engine-toolkit?rev=9f58ddfc6e0edb06cb35f8422044522bc0387d14#9f58ddfc6e0edb06cb35f8422044522bc0387d14" +source = "git+https://github.com/radixdlt/radix-engine-toolkit?rev=ca88bf19cd1ab7a22e9f637ff028c94dee39f500#ca88bf19cd1ab7a22e9f637ff028c94dee39f500" dependencies = [ "bech32", "radix-common", @@ -2920,15 +3055,15 @@ dependencies = [ "regex 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)", "sbor", "serde", - "serde_json 1.0.132", + "serde_json 1.0.133", "serde_with 3.11.0", ] [[package]] name = "schannel" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" dependencies = [ "windows-sys 0.59.0", ] @@ -2965,13 +3100,13 @@ checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.90", ] [[package]] name = "scrypto" -version = "1.3.0-dev" -source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=423e26abcfbb631d8e7f64ae748cab6f57151bb3#423e26abcfbb631d8e7f64ae748cab6f57151bb3" +version = "1.4.0-dev" +source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=45bd94457e429ea65e954a7fab20dd4ddd987030#45bd94457e429ea65e954a7fab20dd4ddd987030" dependencies = [ "bech32", "const-sha1", @@ -2991,8 +3126,8 @@ dependencies = [ [[package]] name = "scrypto-derive" -version = "1.3.0-dev" -source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=423e26abcfbb631d8e7f64ae748cab6f57151bb3#423e26abcfbb631d8e7f64ae748cab6f57151bb3" +version = "1.4.0-dev" +source = "git+https://github.com/radixdlt/radixdlt-scrypto?rev=45bd94457e429ea65e954a7fab20dd4ddd987030#45bd94457e429ea65e954a7fab20dd4ddd987030" dependencies = [ "proc-macro2", "quote", @@ -3001,7 +3136,7 @@ dependencies = [ "regex 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)", "sbor", "serde", - "serde_json 1.0.132", + "serde_json 1.0.133", "syn 1.0.109", ] @@ -3071,22 +3206,22 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.213" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ea7893ff5e2466df8d720bb615088341b295f849602c6956047f8f80f0e9bc1" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.213" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e85ad2009c50b58e87caa8cd6dac16bdf511bbfb7af6c33df902396aa480fa5" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.90", ] [[package]] @@ -3094,7 +3229,7 @@ name = "serde_json" version = "1.0.108" source = "git+https://github.com/serde-rs/json/?rev=4bc1eaa03a6160593575bc9bc60c94dba4cab1e3#4bc1eaa03a6160593575bc9bc60c94dba4cab1e3" dependencies = [ - "indexmap 2.6.0", + "indexmap 2.7.0", "itoa", "ryu", "serde", @@ -3102,11 +3237,11 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.132" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ - "indexmap 2.6.0", + "indexmap 2.7.0", "itoa", "memchr", "ryu", @@ -3120,7 +3255,7 @@ source = "git+https://github.com/dtolnay/serde-repr/?rev=94cce18a51bc169869f2cdc dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.90", ] [[package]] @@ -3153,9 +3288,9 @@ dependencies = [ "chrono", "hex 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "indexmap 1.9.3", - "indexmap 2.6.0", + "indexmap 2.7.0", "serde", - "serde_json 1.0.132", + "serde_json 1.0.133", "serde_with_macros 3.4.0", "time", ] @@ -3170,10 +3305,10 @@ dependencies = [ "chrono", "hex 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "indexmap 1.9.3", - "indexmap 2.6.0", + "indexmap 2.7.0", "serde", "serde_derive", - "serde_json 1.0.132", + "serde_json 1.0.133", "serde_with_macros 3.11.0", "time", ] @@ -3186,7 +3321,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.90", ] [[package]] @@ -3198,7 +3333,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.90", ] [[package]] @@ -3291,9 +3426,9 @@ checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", "windows-sys 0.52.0", @@ -3315,6 +3450,12 @@ dependencies = [ "der", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "static_assertions" version = "1.1.0" @@ -3377,7 +3518,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.85", + "syn 2.0.90", ] [[package]] @@ -3399,9 +3540,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.85" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -3414,6 +3555,17 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "tagptr" version = "0.2.0" @@ -3422,9 +3574,9 @@ checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" [[package]] name = "tempfile" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if", "fastrand", @@ -3461,11 +3613,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.65" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl 1.0.65", + "thiserror-impl 1.0.69", ] [[package]] @@ -3475,18 +3627,18 @@ source = "git+https://github.com/dtolnay/thiserror/?rev=a7d220d7915fb888413aa797 dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.90", ] [[package]] name = "thiserror-impl" -version = "1.0.65" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.90", ] [[package]] @@ -3500,9 +3652,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.36" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", "itoa", @@ -3521,14 +3673,24 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" dependencies = [ "num-conv", "time-core", ] +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tinyvec" version = "1.8.0" @@ -3546,9 +3708,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.41.0" +version = "1.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb" +checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" dependencies = [ "backtrace", "bytes", @@ -3607,7 +3769,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.6.0", + "indexmap 2.7.0", "serde", "serde_spanned", "toml_datetime", @@ -3622,9 +3784,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "pin-project-lite", "tracing-core", @@ -3632,9 +3794,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell 1.20.2", ] @@ -3663,17 +3825,11 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" -[[package]] -name = "unicode-bidi" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" - [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-normalization" @@ -3704,7 +3860,7 @@ dependencies = [ "anyhow", "camino 1.1.9", "cargo_metadata 0.15.4", - "clap 4.5.20", + "clap 4.5.23", "uniffi_bindgen", "uniffi_build", "uniffi_core", @@ -3750,7 +3906,7 @@ version = "0.28.3" source = "git+https://github.com/sajjon/uniffi-rs/?rev=fe40d992b32103876112713cb5e8303b54647183#fe40d992b32103876112713cb5e8303b54647183" dependencies = [ "quote", - "syn 2.0.85", + "syn 2.0.90", ] [[package]] @@ -3777,7 +3933,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.85", + "syn 2.0.90", "toml 0.5.11", "uniffi_meta", ] @@ -3828,9 +3984,9 @@ dependencies = [ [[package]] name = "url" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", @@ -3838,6 +3994,18 @@ dependencies = [ "serde", ] +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.2" @@ -3907,9 +4075,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" dependencies = [ "cfg-if", "once_cell 1.20.2", @@ -3918,36 +4086,36 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" dependencies = [ "bumpalo", "log", - "once_cell 1.20.2", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.90", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.45" +version = "0.4.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2" dependencies = [ "cfg-if", "js-sys", + "once_cell 1.20.2", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3955,22 +4123,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.90", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" [[package]] name = "wasm-encoder" @@ -3983,42 +4151,46 @@ dependencies = [ [[package]] name = "wasmi" -version = "0.35.0" +version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbaac6e702fa7b52258e5ac90d6e20a40afb37a1fbe7c645d0903ee42c5f85f4" +checksum = "fc7a1acc721dd73e4fff2dc3796cc3efda6e008369e859a20fdbe058bddeebc3" dependencies = [ "arrayvec", "multi-stash", - "num-derive", - "num-traits", "smallvec", "spin", "wasmi_collections", "wasmi_core", + "wasmi_ir", "wasmparser-nostd", ] [[package]] name = "wasmi_collections" -version = "0.35.0" +version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ff59e30e550a509cc689ec638e5042be4d78ec9f6dd8a71fd02ee28776a74fd" +checksum = "142fda775f9cda587681ff0ec63c7a7e5679dc95da75f3f9b7e3979ce3506a5b" dependencies = [ - "ahash", - "hashbrown 0.14.5", "string-interner", ] [[package]] name = "wasmi_core" -version = "0.35.0" +version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e10c674add0f92f47bf8ad57c55ee3ac1762a0d9baf07535e27e22b758a916" +checksum = "281a49ca3c12c8efa052cb67758454fc861d80ab5a03def352e04eb08c20beb2" dependencies = [ "downcast-rs", "libm", - "num-traits", - "paste 1.0.15", +] + +[[package]] +name = "wasmi_ir" +version = "0.39.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bbadcf529808086a74bacd3ce8aedece444a847292198a56dcde920d1fb213c" +dependencies = [ + "wasmi_core", ] [[package]] @@ -4038,7 +4210,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9dbe55c8f9d0dbd25d9447a5a889ff90c0cc3feaa7395310d3d826b2c703eaab" dependencies = [ "bitflags 2.6.0", - "indexmap 2.6.0", + "indexmap 2.7.0", "semver", ] @@ -4063,9 +4235,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.72" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" dependencies = [ "js-sys", "wasm-bindgen", @@ -4264,6 +4436,18 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + [[package]] name = "x25519-dalek" version = "2.0.1" @@ -4281,6 +4465,30 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", + "synstructure", +] + [[package]] name = "zerocopy" version = "0.7.35" @@ -4299,7 +4507,28 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.90", +] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", + "synstructure", ] [[package]] @@ -4327,7 +4556,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.90", ] [[package]] @@ -4337,5 +4566,27 @@ source = "git+https://github.com/RustCrypto/utils?rev=df6d2f48a5e8afe8eef04ba32e dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.90", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", ] diff --git a/crates/sargon-uniffi/Cargo.toml b/crates/sargon-uniffi/Cargo.toml index e1a3c3d74..8cbdc15ca 100644 --- a/crates/sargon-uniffi/Cargo.toml +++ b/crates/sargon-uniffi/Cargo.toml @@ -21,7 +21,7 @@ required-features = ["build-binary"] sargon = { path = "../sargon" } sargon-uniffi-conversion-macros = { path = "../sargon-uniffi-conversion-macros" } -radix-engine-toolkit = { git = "https://github.com/radixdlt/radix-engine-toolkit", rev = "9f58ddfc6e0edb06cb35f8422044522bc0387d14" } +radix-engine-toolkit = { git = "https://github.com/radixdlt/radix-engine-toolkit", rev = "ca88bf19cd1ab7a22e9f637ff028c94dee39f500" } # zeroize = "1.7.0" zeroize = { git = "https://github.com/RustCrypto/utils", rev = "df6d2f48a5e8afe8eef04ba32e2af55bacb41375", features = [ diff --git a/crates/sargon/Cargo.toml b/crates/sargon/Cargo.toml index 4b67ab8d8..2edd3a8c6 100644 --- a/crates/sargon/Cargo.toml +++ b/crates/sargon/Cargo.toml @@ -74,22 +74,22 @@ strum = { git = "https://github.com/Peternator7/strum/", rev = "f746c3699acf1501 "derive", ] } -sbor = { git = "https://github.com/radixdlt/radixdlt-scrypto", rev = "423e26abcfbb631d8e7f64ae748cab6f57151bb3" } -radix-rust = { git = "https://github.com/radixdlt/radixdlt-scrypto", rev = "423e26abcfbb631d8e7f64ae748cab6f57151bb3", features = [ +sbor = { git = "https://github.com/radixdlt/radixdlt-scrypto", rev = "45bd94457e429ea65e954a7fab20dd4ddd987030" } +radix-rust = { git = "https://github.com/radixdlt/radixdlt-scrypto", rev = "45bd94457e429ea65e954a7fab20dd4ddd987030", features = [ "serde", ] } -radix-engine = { git = "https://github.com/radixdlt/radixdlt-scrypto", rev = "423e26abcfbb631d8e7f64ae748cab6f57151bb3" } -radix-common = { git = "https://github.com/radixdlt/radixdlt-scrypto", rev = "423e26abcfbb631d8e7f64ae748cab6f57151bb3", features = [ +radix-engine = { git = "https://github.com/radixdlt/radixdlt-scrypto", rev = "45bd94457e429ea65e954a7fab20dd4ddd987030" } +radix-common = { git = "https://github.com/radixdlt/radixdlt-scrypto", rev = "45bd94457e429ea65e954a7fab20dd4ddd987030", features = [ "serde", "secp256k1_sign_and_validate", ] } -radix-common-derive = { git = "https://github.com/radixdlt/radixdlt-scrypto", rev = "423e26abcfbb631d8e7f64ae748cab6f57151bb3" } -radix-engine-interface = { git = "https://github.com/radixdlt/radixdlt-scrypto", rev = "423e26abcfbb631d8e7f64ae748cab6f57151bb3" } -radix-engine-toolkit-common = { git = "https://github.com/radixdlt/radixdlt-scrypto", rev = "423e26abcfbb631d8e7f64ae748cab6f57151bb3" } +radix-common-derive = { git = "https://github.com/radixdlt/radixdlt-scrypto", rev = "45bd94457e429ea65e954a7fab20dd4ddd987030" } +radix-engine-interface = { git = "https://github.com/radixdlt/radixdlt-scrypto", rev = "45bd94457e429ea65e954a7fab20dd4ddd987030" } +radix-engine-toolkit-common = { git = "https://github.com/radixdlt/radixdlt-scrypto", rev = "45bd94457e429ea65e954a7fab20dd4ddd987030" } -radix-transactions = { git = "https://github.com/radixdlt/radixdlt-scrypto", rev = "423e26abcfbb631d8e7f64ae748cab6f57151bb3" } +radix-transactions = { git = "https://github.com/radixdlt/radixdlt-scrypto", rev = "45bd94457e429ea65e954a7fab20dd4ddd987030" } -radix-engine-toolkit = { git = "https://github.com/radixdlt/radix-engine-toolkit", rev = "9f58ddfc6e0edb06cb35f8422044522bc0387d14" } +radix-engine-toolkit = { git = "https://github.com/radixdlt/radix-engine-toolkit", rev = "ca88bf19cd1ab7a22e9f637ff028c94dee39f500" } # enum-iterator = "1.4.1" enum-iterator = { git = "https://github.com/stephaneyfx/enum-iterator/", rev = "9d472a1237cfd03b1c7657fdcba74c8070bfb4ea" } From 4f3911765357b89289fa53985d452c914f9b159c Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Thu, 12 Dec 2024 15:01:22 +0100 Subject: [PATCH 04/60] [no ci] WIP --- .../high_level/manifest_building/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/mod.rs b/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/mod.rs index 68a211c81..d9e8cc0a8 100644 --- a/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/mod.rs +++ b/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/mod.rs @@ -6,6 +6,7 @@ mod delete_account; mod manifest_account_locker; mod manifest_assets_transfers; mod manifests; +mod manifests_access_controller; mod manifests_create_tokens; mod metadata; mod modify_manifest; @@ -19,6 +20,7 @@ pub use delete_account::*; pub use manifest_account_locker::*; pub use manifest_assets_transfers::*; pub use manifests::*; +pub use manifests_access_controller::*; pub use manifests_create_tokens::*; pub use metadata::*; pub use modify_manifest::*; From bf57732296fe1caa6ad6d72e415c16dbe3c468c4 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Thu, 12 Dec 2024 15:01:27 +0100 Subject: [PATCH 05/60] [no ci] WIP --- .../manifests_access_controller.rs | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/manifests_access_controller.rs diff --git a/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/manifests_access_controller.rs b/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/manifests_access_controller.rs new file mode 100644 index 000000000..ffe629d62 --- /dev/null +++ b/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/manifests_access_controller.rs @@ -0,0 +1,32 @@ +use crate::prelude::*; + +/* +pub const ACCESS_CONTROLLER_CREATE_IDENT: &str = "create"; + +#[derive(Debug, Eq, PartialEq, ScryptoSbor)] +pub struct AccessControllerCreateInput { + pub controlled_asset: Bucket, + pub rule_set: RuleSet, + pub timed_recovery_delay_in_minutes: Option, + pub address_reservation: Option, +} + +#[derive(Debug, Eq, PartialEq, ManifestSbor)] +pub struct AccessControllerCreateManifestInput { + pub controlled_asset: ManifestBucket, + pub rule_set: RuleSet, + pub timed_recovery_delay_in_minutes: Option, + pub address_reservation: Option, +} + +pub type AccessControllerCreateOutput = Global; +*/ + +impl TransactionManifest { + pub fn securify_unsecurified_entity( + entity: UnsecurifiedEntity, + security_structure_of_factor_instances: SecurityStructureOfFactorInstances, + ) -> Self { + todo!() + } +} From ed7f78dd4d1ca9a83559a35c4195cb28fc454b38 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Fri, 13 Dec 2024 08:50:57 +0100 Subject: [PATCH 06/60] [no ci] wip --- .../addresses_manifest_builder_support.rs | 13 ++++ .../manifests_access_controller.rs | 63 ++++++++++++++++++- 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/addresses_manifest_builder_support.rs b/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/addresses_manifest_builder_support.rs index 0ba27b566..6ed838691 100644 --- a/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/addresses_manifest_builder_support.rs +++ b/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/addresses_manifest_builder_support.rs @@ -95,6 +95,19 @@ macro_rules! is_dynamic_resource_address { }; } +impl TryInto for &Address { + type Error = crate::CommonError; + + fn try_into( + self, + ) -> Result { + match self { + Address::Account(value) => TryInto::::try_into(value), + _ => todo!() + } + } +} + is_dynamic_component_address!(AccountAddress); is_dynamic_component_address!(AccessControllerAddress); is_dynamic_component_address!(ComponentAddress); diff --git a/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/manifests_access_controller.rs b/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/manifests_access_controller.rs index ffe629d62..72572adc2 100644 --- a/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/manifests_access_controller.rs +++ b/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/manifests_access_controller.rs @@ -1,3 +1,9 @@ +use radix_engine_interface::blueprints::{ + access_controller::AccessControllerCreateManifestInput as ScryptoAccessControllerCreateManifestInput, + account::ACCOUNT_SECURIFY_IDENT as SCRYPTO_ACCOUNT_SECURIFY_IDENT, + identity::IDENTITY_SECURIFY_IDENT as SCRYPTO_IDENTITY_SECURIFY_IDENT, +}; + use crate::prelude::*; /* @@ -21,12 +27,67 @@ pub struct AccessControllerCreateManifestInput { pub type AccessControllerCreateOutput = Global; */ +impl From + for ScryptoAccessControllerCreateManifestInput +{ + fn from(value: SecurityStructureOfFactorInstances) -> Self { + todo!() + } +} + +impl From for Address { + fn from(value: AddressOfAccountOrPersona) -> Self { + todo!() + } +} impl TransactionManifest { pub fn securify_unsecurified_entity( entity: UnsecurifiedEntity, security_structure_of_factor_instances: SecurityStructureOfFactorInstances, ) -> Self { - todo!() + let entity_address = entity.address(); + let security_entity_identifier = if entity_address.is_identity() { + SCRYPTO_IDENTITY_SECURIFY_IDENT + } else { + SCRYPTO_ACCOUNT_SECURIFY_IDENT + }; + let entity_address = Address::from(entity_address); + + let mut builder = ScryptoTransactionManifestBuilder::new(); + let bucket_factory = BucketFactory::default(); + + // Securify the account which will return an account owner badge onto the worktop. + builder = + builder.call_method(entity_address, security_entity_identifier, ()); + + // Create a bucket out of the account owner badge. + let owner_badge = SCRYPTO_ACCOUNT_OWNER_BADGE; + let owner_badge_bucket = &bucket_factory.next(); + builder = + builder.take_all_from_worktop(owner_badge, owner_badge_bucket); + + // Create a proof from the account owner badge + let owner_badge_proof = "owner_badge_proof"; + builder = builder.create_proof_from_bucket_of_all( + owner_badge_bucket, + owner_badge_proof, + ); + + // Push the proof to the auth zone + builder = builder.push_to_auth_zone(owner_badge_proof); + + // We've changed the account deposit rules, so now we can drop all the proofs in the auth zone (which + // is pretty much a single proof of the account owner badge). + builder = builder.drop_auth_zone_proofs(); + + // We deposit the account's owner badge into it which locks it forever. + builder = builder.try_deposit_or_abort( + entity_address, + None, + owner_badge_bucket, + ); + + TransactionManifest::sargon_built(builder, entity_address.network_id()) } } From 9f7790dcb22c5164c02d7494cfe1def2347b56ac Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Fri, 13 Dec 2024 09:42:08 +0100 Subject: [PATCH 07/60] create_access_controller --- crates/sargon/src/lib.rs | 10 +- .../role_into_scrypto_access_rule.rs | 4 - .../addresses_manifest_builder_support.rs | 16 ++-- .../manifests_access_controller.rs | 92 ++++++------------- 4 files changed, 44 insertions(+), 78 deletions(-) diff --git a/crates/sargon/src/lib.rs b/crates/sargon/src/lib.rs index 7f9b7feaf..10ab0af31 100644 --- a/crates/sargon/src/lib.rs +++ b/crates/sargon/src/lib.rs @@ -146,7 +146,8 @@ pub mod prelude { NonFungibleGlobalId as ScryptoNonFungibleGlobalId, NonFungibleIdType as ScryptoNonFungibleIdType, UpperBound as ScryptoUpperBound, - ACCOUNT_OWNER_BADGE as SCRYPTO_ACCOUNT_OWNER_BADGE, XRD, + ACCOUNT_OWNER_BADGE as SCRYPTO_ACCOUNT_OWNER_BADGE, + IDENTITY_OWNER_BADGE as SCRYPTO_IDENTITY_OWNER_BADGE, XRD, }, types::{ ComponentAddress as ScryptoComponentAddress, @@ -156,11 +157,18 @@ pub mod prelude { }, ManifestSbor as ScryptoManifestSbor, ScryptoSbor, }; + pub(crate) use radix_engine_interface::blueprints::{ + access_controller::{ + RecoveryProposal as ScryptoRecoveryProposal, + RuleSet as ScryptoRuleSet, + }, account::{ DefaultDepositRule as ScryptoDefaultDepositRule, ResourcePreference as ScryptoResourcePreference, + ACCOUNT_SECURIFY_IDENT as SCRYPTO_ACCOUNT_SECURIFY_IDENT, }, + identity::IDENTITY_SECURIFY_IDENT as SCRYPTO_IDENTITY_SECURIFY_IDENT, resource::ResourceOrNonFungible as ScryptoResourceOrNonFungible, }; pub(crate) use radix_engine_interface::prelude::{ diff --git a/crates/sargon/src/profile/mfa/security_structures/roles/factor_levels/factor_instance_level/role_into_scrypto_access_rule.rs b/crates/sargon/src/profile/mfa/security_structures/roles/factor_levels/factor_instance_level/role_into_scrypto_access_rule.rs index 08fd51a2e..24acc5f40 100644 --- a/crates/sargon/src/profile/mfa/security_structures/roles/factor_levels/factor_instance_level/role_into_scrypto_access_rule.rs +++ b/crates/sargon/src/profile/mfa/security_structures/roles/factor_levels/factor_instance_level/role_into_scrypto_access_rule.rs @@ -1,7 +1,3 @@ -use radix_engine_interface::blueprints::access_controller::{ - RecoveryProposal as ScryptoRecoveryProposal, RuleSet as ScryptoRuleSet, -}; - use crate::prelude::*; impl From> for ScryptoAccessRule { diff --git a/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/addresses_manifest_builder_support.rs b/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/addresses_manifest_builder_support.rs index 6ed838691..4e8874b0a 100644 --- a/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/addresses_manifest_builder_support.rs +++ b/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/addresses_manifest_builder_support.rs @@ -95,19 +95,19 @@ macro_rules! is_dynamic_resource_address { }; } -impl TryInto for &Address { +impl TryInto for &AddressOfAccountOrPersona { type Error = crate::CommonError; - - fn try_into( - self, - ) -> Result { + fn try_into(self) -> Result { match self { - Address::Account(value) => TryInto::::try_into(value), - _ => todo!() + AddressOfAccountOrPersona::Account(value) => { + TryInto::::try_into(value) + } + AddressOfAccountOrPersona::Identity(value) => { + TryInto::::try_into(value) + } } } } - is_dynamic_component_address!(AccountAddress); is_dynamic_component_address!(AccessControllerAddress); is_dynamic_component_address!(ComponentAddress); diff --git a/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/manifests_access_controller.rs b/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/manifests_access_controller.rs index 72572adc2..29947114a 100644 --- a/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/manifests_access_controller.rs +++ b/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/manifests_access_controller.rs @@ -6,86 +6,48 @@ use radix_engine_interface::blueprints::{ use crate::prelude::*; -/* -pub const ACCESS_CONTROLLER_CREATE_IDENT: &str = "create"; - -#[derive(Debug, Eq, PartialEq, ScryptoSbor)] -pub struct AccessControllerCreateInput { - pub controlled_asset: Bucket, - pub rule_set: RuleSet, - pub timed_recovery_delay_in_minutes: Option, - pub address_reservation: Option, -} - -#[derive(Debug, Eq, PartialEq, ManifestSbor)] -pub struct AccessControllerCreateManifestInput { - pub controlled_asset: ManifestBucket, - pub rule_set: RuleSet, - pub timed_recovery_delay_in_minutes: Option, - pub address_reservation: Option, -} - -pub type AccessControllerCreateOutput = Global; -*/ -impl From - for ScryptoAccessControllerCreateManifestInput -{ - fn from(value: SecurityStructureOfFactorInstances) -> Self { - todo!() - } -} - -impl From for Address { - fn from(value: AddressOfAccountOrPersona) -> Self { - todo!() - } -} - impl TransactionManifest { pub fn securify_unsecurified_entity( entity: UnsecurifiedEntity, security_structure_of_factor_instances: SecurityStructureOfFactorInstances, ) -> Self { let entity_address = entity.address(); - let security_entity_identifier = if entity_address.is_identity() { - SCRYPTO_IDENTITY_SECURIFY_IDENT - } else { - SCRYPTO_ACCOUNT_SECURIFY_IDENT - }; - let entity_address = Address::from(entity_address); + let (security_entity_identifier, owner_badge) = + if entity_address.is_identity() { + ( + SCRYPTO_IDENTITY_SECURIFY_IDENT, + SCRYPTO_IDENTITY_OWNER_BADGE, + ) + } else { + (SCRYPTO_ACCOUNT_SECURIFY_IDENT, SCRYPTO_ACCOUNT_OWNER_BADGE) + }; let mut builder = ScryptoTransactionManifestBuilder::new(); let bucket_factory = BucketFactory::default(); - // Securify the account which will return an account owner badge onto the worktop. - builder = - builder.call_method(entity_address, security_entity_identifier, ()); + // Securify the entity which will return an entity owner badge onto the worktop. + builder = builder.call_method( + &entity_address, + security_entity_identifier, + (), + ); - // Create a bucket out of the account owner badge. - let owner_badge = SCRYPTO_ACCOUNT_OWNER_BADGE; + // Create a bucket out of the entity owner badge. let owner_badge_bucket = &bucket_factory.next(); - builder = - builder.take_all_from_worktop(owner_badge, owner_badge_bucket); + builder = builder.take_from_worktop(owner_badge, 1, owner_badge_bucket); - // Create a proof from the account owner badge - let owner_badge_proof = "owner_badge_proof"; - builder = builder.create_proof_from_bucket_of_all( - owner_badge_bucket, - owner_badge_proof, + let timed_recovery_delay_in_minutes = + security_structure_of_factor_instances + .timed_recovery_delay_in_minutes(); + let rule_set = ScryptoRuleSet::from( + security_structure_of_factor_instances.matrix_of_factors, ); - - // Push the proof to the auth zone - builder = builder.push_to_auth_zone(owner_badge_proof); - - // We've changed the account deposit rules, so now we can drop all the proofs in the auth zone (which - // is pretty much a single proof of the account owner badge). - builder = builder.drop_auth_zone_proofs(); - - // We deposit the account's owner badge into it which locks it forever. - builder = builder.try_deposit_or_abort( - entity_address, - None, + builder = builder.create_access_controller( owner_badge_bucket, + rule_set.primary_role, + rule_set.recovery_role, + rule_set.confirmation_role, + Some(timed_recovery_delay_in_minutes), ); TransactionManifest::sargon_built(builder, entity_address.network_id()) From 332c6a9d75b61b662cf1fa6e754b013856b0ba35 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Fri, 13 Dec 2024 14:03:09 +0100 Subject: [PATCH 08/60] [no ci] WIP --- .../src/core/error/common_error.rs | 13 + .../secured_entity_control.rs | 12 +- .../security_structure_of_factor_instances.rs | 12 + .../profile/v100/entity_security_state/mod.rs | 2 + .../provisional_securified_config.rs | 30 ++ .../unsecured_entity_control.rs | 4 +- crates/sargon/src/core/error/common_error.rs | 13 + .../profile_network_details.rs | 7 +- .../secured_entity_control.rs | 403 ++++++++++++++++- .../matrices/matrix_of_factor_instances.rs | 15 +- .../security_structure_of_factor_instances.rs | 410 +++++++++++++++++- .../profile/v100/entity/account/account.rs | 5 + .../profile/v100/entity/has_security_state.rs | 3 +- .../profile/v100/entity/persona/persona.rs | 6 +- .../entity_security_state.rs | 5 +- .../profile/v100/entity_security_state/mod.rs | 2 + .../provisional_securified_config.rs | 108 +++++ .../unsecured_entity_control.rs | 45 +- ...rarchical_deterministic_factor_instance.rs | 42 +- .../profile/v100/profile_legacy_state_bugs.rs | 44 -- .../authentication_signing_input.rs | 10 +- .../system/sargon_os/sargon_os_accounts.rs | 5 +- .../src/types/samples/account_samples.rs | 19 +- .../src/types/samples/persona_samples.rs | 85 +++- .../transaction_hashes/transaction_hashes.rs | 2 +- 25 files changed, 1165 insertions(+), 137 deletions(-) create mode 100644 crates/sargon-uniffi/src/profile/v100/entity_security_state/provisional_securified_config.rs create mode 100644 crates/sargon/src/profile/v100/entity_security_state/provisional_securified_config.rs diff --git a/crates/sargon-uniffi/src/core/error/common_error.rs b/crates/sargon-uniffi/src/core/error/common_error.rs index 7b43af923..76afec7c0 100644 --- a/crates/sargon-uniffi/src/core/error/common_error.rs +++ b/crates/sargon-uniffi/src/core/error/common_error.rs @@ -827,6 +827,19 @@ pub enum CommonError { #[error("Signing was rejected by the user")] SigningRejected = 10232, + + #[error("No Transaction Signing Factor")] + NoTransactionSigningFactorInstance = 10233, + + #[error("Authentication Signing FactorInstance not securified")] + AuthenticationSigningFactorInstanceNotSecurified = 10234, + + #[error("SecurityEntityControl has no QueuedTransaction, unable to mark it as cancelled")] + SecurityEntityControlHasNoProvisionallyQueuedTransaction = 10235, + + #[error("SecurityEntityControl has QueuedTransaction, unable override it, use `cancel_queued_transaction`")] + SecurityEntityControlCannotChangeProvisionalAlreadyHasQueuedTransaction = + 10236, } #[uniffi::export] diff --git a/crates/sargon-uniffi/src/profile/mfa/secured_entity_control/secured_entity_control.rs b/crates/sargon-uniffi/src/profile/mfa/secured_entity_control/secured_entity_control.rs index eb3565423..2582cdcd2 100644 --- a/crates/sargon-uniffi/src/profile/mfa/secured_entity_control/secured_entity_control.rs +++ b/crates/sargon-uniffi/src/profile/mfa/secured_entity_control/secured_entity_control.rs @@ -5,10 +5,16 @@ use crate::prelude::*; /// which user has created has been applied to it. #[derive(Clone, PartialEq, Eq, Hash, uniffi::Record)] pub struct SecuredEntityControl { + /// Virtual Entity Creation (Factor)Instance + /// + /// Optional since if we recovered this SecuredEntityControl part of + /// account recovery scan we might not know the veci + pub veci: Option, + /// The address of the access controller which controls this entity. /// /// Looking up the public key (hashes) set in the key-value store at - /// this address reveils the true factors (public keys) used to protect + /// this address reveals the true factors (public keys) used to protect /// this entity. It will be the same as the ones in `security_structure` /// if we have not changed them locally, which we should not do unless /// we are sure the Ledger corresponds to the values in `security_structure`. @@ -17,4 +23,8 @@ pub struct SecuredEntityControl { /// The believed-to-be-current security structure of FactorInstances which /// secures this entity. pub security_structure: SecurityStructureOfFactorInstances, + + /// A provisional new security structure configuration which user + /// is about to change to + pub provisional: Option, } diff --git a/crates/sargon-uniffi/src/profile/mfa/security_structures/security_structures/security_structure_of_factor_instances.rs b/crates/sargon-uniffi/src/profile/mfa/security_structures/security_structures/security_structure_of_factor_instances.rs index 8563e0846..85f5406e3 100644 --- a/crates/sargon-uniffi/src/profile/mfa/security_structures/security_structures/security_structure_of_factor_instances.rs +++ b/crates/sargon-uniffi/src/profile/mfa/security_structures/security_structures/security_structure_of_factor_instances.rs @@ -15,4 +15,16 @@ pub struct SecurityStructureOfFactorInstances { /// The structure of factors to use for certain roles, Primary, Recovery /// and Confirmation role. pub matrix_of_factors: MatrixOfFactorInstances, + + /// The authentication signing factor instance which is used to sign + /// proof of ownership - aka "True Rola Key". User can select which FactorSource + /// to use during Shield Building, but typically most users will user the + /// DeviceFactorSource which is default. DerivationPath is in securified + /// KeySpace of course. + /// + /// Non-optional since we can replace it with a new one for entities + /// we have recovered during Onboarding Account Recovery Scan for securified + /// entities + pub authentication_signing_factor_instance: + HierarchicalDeterministicFactorInstance, } diff --git a/crates/sargon-uniffi/src/profile/v100/entity_security_state/mod.rs b/crates/sargon-uniffi/src/profile/v100/entity_security_state/mod.rs index a7af15c95..644a39423 100644 --- a/crates/sargon-uniffi/src/profile/v100/entity_security_state/mod.rs +++ b/crates/sargon-uniffi/src/profile/v100/entity_security_state/mod.rs @@ -1,5 +1,7 @@ mod entity_security_state; +mod provisional_securified_config; mod unsecured_entity_control; pub use entity_security_state::*; +pub use provisional_securified_config::*; pub use unsecured_entity_control::*; diff --git a/crates/sargon-uniffi/src/profile/v100/entity_security_state/provisional_securified_config.rs b/crates/sargon-uniffi/src/profile/v100/entity_security_state/provisional_securified_config.rs new file mode 100644 index 000000000..ce62514b9 --- /dev/null +++ b/crates/sargon-uniffi/src/profile/v100/entity_security_state/provisional_securified_config.rs @@ -0,0 +1,30 @@ +use crate::prelude::*; +use sargon::{ + ProvisionalSecurifiedConfig as InternalProvisionalSecurifiedConfig, + ProvisionalSecurifiedTransactionQueued as InternalProvisionalSecurifiedTransactionQueued, +}; + +#[derive(Clone, PartialEq, Eq, Hash, InternalConversion, uniffi::Record)] +pub struct ProvisionalSecurifiedTransactionQueued { + pub factor_instances: SecurityStructureOfFactorInstances, + pub txid: TransactionIntentHash, +} + +#[derive(Clone, PartialEq, Eq, Hash, InternalConversion, uniffi::Enum)] +pub enum ProvisionalSecurifiedConfig { + /// User has selected which security shield to use for some entity, + /// but no FactorInstances has been provided yet. + ShieldSelected { value: SecurityStructureID }, + + /// User has fully prepared a `SecurityStructureOfFactorInstances` but + /// not made a transaction to apply it to the entity yet. + FactorInstancesDerived { + value: SecurityStructureOfFactorInstances, + }, + + /// User has made queued a transaction to apply a `SecurityStructureOfFactorInstances` + /// but it has not been submitted (confirmed) yet. + TransactionQueued { + value: ProvisionalSecurifiedTransactionQueued, + }, +} diff --git a/crates/sargon-uniffi/src/profile/v100/entity_security_state/unsecured_entity_control.rs b/crates/sargon-uniffi/src/profile/v100/entity_security_state/unsecured_entity_control.rs index f8e5486bd..d28e8f67a 100644 --- a/crates/sargon-uniffi/src/profile/v100/entity_security_state/unsecured_entity_control.rs +++ b/crates/sargon-uniffi/src/profile/v100/entity_security_state/unsecured_entity_control.rs @@ -11,8 +11,8 @@ pub struct UnsecuredEntityControl { // /// also controls this entity and is used for signing transactions. pub transaction_signing: HierarchicalDeterministicFactorInstance, - /// The factor instance which can be used for ROLA. - pub authentication_signing: Option, + /// The provisional security structure configuration + pub provisional: Option, } #[uniffi::export] diff --git a/crates/sargon/src/core/error/common_error.rs b/crates/sargon/src/core/error/common_error.rs index ee08859ff..5bb5eeba7 100644 --- a/crates/sargon/src/core/error/common_error.rs +++ b/crates/sargon/src/core/error/common_error.rs @@ -824,6 +824,19 @@ pub enum CommonError { #[error("Signing was rejected by the user")] SigningRejected = 10232, + + #[error("No Transaction Signing Factor")] + NoTransactionSigningFactorInstance = 10233, + + #[error("Authentication Signing FactorInstance not securified")] + AuthenticationSigningFactorInstanceNotSecurified = 10234, + + #[error("SecurityEntityControl has no QueuedTransaction, unable to mark it as cancelled")] + SecurityEntityControlHasNoProvisionallyQueuedTransaction = 10235, + + #[error("SecurityEntityControl has QueuedTransaction, unable override it, use `cancel_queued_transaction`")] + SecurityEntityControlCannotChangeProvisionalAlreadyHasQueuedTransaction = + 10236, } impl CommonError { diff --git a/crates/sargon/src/profile/logic/profile_network/profile_network_details.rs b/crates/sargon/src/profile/logic/profile_network/profile_network_details.rs index c74bbab18..1b7d3b8fe 100644 --- a/crates/sargon/src/profile/logic/profile_network/profile_network_details.rs +++ b/crates/sargon/src/profile/logic/profile_network/profile_network_details.rs @@ -118,12 +118,7 @@ impl AuthorizedPersonaSimple { let shared_accounts = self.accounts_for_display(non_hidden_accounts)?; - let has_auth_signing_key = match &persona.security_state { - EntitySecurityState::Unsecured { value: uec } => { - uec.authentication_signing.is_some() - } - _ => false, // TODO change that - }; + let has_auth_signing_key = persona.is_securified(); Ok(AuthorizedPersonaDetailed::new( persona.address, persona.display_name.clone(), diff --git a/crates/sargon/src/profile/mfa/secured_entity_control/secured_entity_control.rs b/crates/sargon/src/profile/mfa/secured_entity_control/secured_entity_control.rs index 4d7fa30e2..abc93ebfd 100644 --- a/crates/sargon/src/profile/mfa/secured_entity_control/secured_entity_control.rs +++ b/crates/sargon/src/profile/mfa/secured_entity_control/secured_entity_control.rs @@ -26,6 +26,11 @@ pub struct SecuredEntityControl { /// The believed-to-be-current security structure of FactorInstances which /// secures this entity. pub security_structure: SecurityStructureOfFactorInstances, + + /// A provisional new security structure configuration which user + /// is about to change to + #[serde(skip_serializing_if = "Option::is_none")] + pub provisional: Option, } impl HasFactorInstances for SecuredEntityControl { @@ -55,8 +60,59 @@ impl SecuredEntityControl { veci, access_controller_address, security_structure, + provisional: None, }) } + + /// # Throws + /// Throws if the provisional is already `Some(ProvisionalSecurifiedConfig::TransactionQueued)`, + /// you need to first cancel the transaction and then call the method `cancel_queued_transaction` on + /// this type + pub fn set_provisional( + &mut self, + provisional: Option, + ) -> Result<()> { + if let Some(ProvisionalSecurifiedConfig::TransactionQueued { + value: _, + }) = self.provisional.as_ref() + { + return Err(CommonError::SecurityEntityControlCannotChangeProvisionalAlreadyHasQueuedTransaction); + } else { + return self.set_provisional_unchecked(provisional); + } + } + + fn set_provisional_unchecked( + &mut self, + provisional: impl Into>, + ) -> Result<()> { + self.provisional = provisional.into(); + Ok(()) + } + + /// Call this once you have cancelled the queued transaction from the transaction queue, + /// this method will change the provisional state back to `Some(ProvisionalSecurifiedConfig::FactorInstancesDerived(_))` + pub fn cancel_queued_transaction(&mut self) -> Result<()> { + if let Some(ProvisionalSecurifiedConfig::TransactionQueued { value }) = + self.provisional.as_ref() + { + self.set_provisional_unchecked( + ProvisionalSecurifiedConfig::FactorInstancesDerived { + value: value.factor_instances.clone(), + }, + ) + } else { + Err(CommonError::SecurityEntityControlHasNoProvisionallyQueuedTransaction) + } + } + + pub fn authentication_signing_factor_instance( + &self, + ) -> HierarchicalDeterministicFactorInstance { + self.security_structure + .authentication_signing_factor_instance + .clone() + } } impl SecuredEntityControl { @@ -67,12 +123,14 @@ impl SecuredEntityControl { impl HasSampleValues for SecuredEntityControl { fn sample() -> Self { - Self::new( - None, + let mut sample = Self::new( + HierarchicalDeterministicFactorInstance::sample(), AccessControllerAddress::sample(), SecurityStructureOfFactorInstances::sample(), ) - .unwrap() + .unwrap(); + sample.provisional = Some(ProvisionalSecurifiedConfig::sample_other()); + sample } fn sample_other() -> Self { Self::new(HierarchicalDeterministicFactorInstance::sample_mainnet_account_device_factor_fs_10_unsecurified_at_index(0), AccessControllerAddress::sample_other(), SecurityStructureOfFactorInstances::sample_other()).unwrap() @@ -109,4 +167,343 @@ mod tests { SecurityStructureOfFactorInstances::sample(), ); } + + #[test] + fn json_roundtrip_sample() { + let model = SUT::sample(); + assert_eq_after_json_roundtrip( + &model, + r#" + { + "veci": { + "factorSourceID": { + "discriminator": "fromHash", + "fromHash": { + "kind": "device", + "body": "f1a93d324dd0f2bff89963ab81ed6e0c2ee7e18c0827dc1d3576b2d9f26bbd0a" + } + }, + "badge": { + "discriminator": "virtualSource", + "virtualSource": { + "discriminator": "hierarchicalDeterministicPublicKey", + "hierarchicalDeterministicPublicKey": { + "publicKey": { + "curve": "curve25519", + "compressedData": "c05f9fa53f203a01cbe43e89086cae29f6c7cdd5a435daa9e52b69e656739b36" + }, + "derivationPath": { + "scheme": "cap26", + "path": "m/44H/1022H/1H/525H/1460H/0H" + } + } + } + } + }, + "accessControllerAddress": "accesscontroller_rdx1c0duj4lq0dc3cpl8qd420fpn5eckh8ljeysvjm894lyl5ja5yq6y5a", + "securityStructure": { + "securityStructureId": "ffffffff-ffff-ffff-ffff-ffffffffffff", + "matrixOfFactors": { + "primaryRole": { + "threshold": 2, + "thresholdFactors": [ + { + "factorSourceID": { + "discriminator": "fromHash", + "fromHash": { + "kind": "device", + "body": "f1a93d324dd0f2bff89963ab81ed6e0c2ee7e18c0827dc1d3576b2d9f26bbd0a" + } + }, + "badge": { + "discriminator": "virtualSource", + "virtualSource": { + "discriminator": "hierarchicalDeterministicPublicKey", + "hierarchicalDeterministicPublicKey": { + "publicKey": { + "curve": "curve25519", + "compressedData": "427969814e15d74c3ff4d9971465cb709d210c8a7627af9466bdaa67bd0929b7" + }, + "derivationPath": { + "scheme": "cap26", + "path": "m/44H/1022H/1H/525H/1460H/0S" + } + } + } + } + }, + { + "factorSourceID": { + "discriminator": "fromHash", + "fromHash": { + "kind": "ledgerHQHardwareWallet", + "body": "ab59987eedd181fe98e512c1ba0f5ff059f11b5c7c56f15614dcc9fe03fec58b" + } + }, + "badge": { + "discriminator": "virtualSource", + "virtualSource": { + "discriminator": "hierarchicalDeterministicPublicKey", + "hierarchicalDeterministicPublicKey": { + "publicKey": { + "curve": "curve25519", + "compressedData": "92cd6838cd4e7b0523ed93d498e093f71139ffd5d632578189b39a26005be56b" + }, + "derivationPath": { + "scheme": "cap26", + "path": "m/44H/1022H/1H/525H/1460H/0S" + } + } + } + } + } + ], + "overrideFactors": [] + }, + "recoveryRole": { + "threshold": 0, + "thresholdFactors": [], + "overrideFactors": [ + { + "factorSourceID": { + "discriminator": "fromHash", + "fromHash": { + "kind": "device", + "body": "f1a93d324dd0f2bff89963ab81ed6e0c2ee7e18c0827dc1d3576b2d9f26bbd0a" + } + }, + "badge": { + "discriminator": "virtualSource", + "virtualSource": { + "discriminator": "hierarchicalDeterministicPublicKey", + "hierarchicalDeterministicPublicKey": { + "publicKey": { + "curve": "curve25519", + "compressedData": "427969814e15d74c3ff4d9971465cb709d210c8a7627af9466bdaa67bd0929b7" + }, + "derivationPath": { + "scheme": "cap26", + "path": "m/44H/1022H/1H/525H/1460H/0S" + } + } + } + } + }, + { + "factorSourceID": { + "discriminator": "fromHash", + "fromHash": { + "kind": "ledgerHQHardwareWallet", + "body": "ab59987eedd181fe98e512c1ba0f5ff059f11b5c7c56f15614dcc9fe03fec58b" + } + }, + "badge": { + "discriminator": "virtualSource", + "virtualSource": { + "discriminator": "hierarchicalDeterministicPublicKey", + "hierarchicalDeterministicPublicKey": { + "publicKey": { + "curve": "curve25519", + "compressedData": "92cd6838cd4e7b0523ed93d498e093f71139ffd5d632578189b39a26005be56b" + }, + "derivationPath": { + "scheme": "cap26", + "path": "m/44H/1022H/1H/525H/1460H/0S" + } + } + } + } + } + ] + }, + "confirmationRole": { + "threshold": 0, + "thresholdFactors": [], + "overrideFactors": [ + { + "factorSourceID": { + "discriminator": "fromHash", + "fromHash": { + "kind": "password", + "body": "181ab662e19fac3ad9f08d5c673b286d4a5ed9cd3762356dc9831dc42427c1b9" + } + }, + "badge": { + "discriminator": "virtualSource", + "virtualSource": { + "discriminator": "hierarchicalDeterministicPublicKey", + "hierarchicalDeterministicPublicKey": { + "publicKey": { + "curve": "curve25519", + "compressedData": "4af49eb56b1af579aaf03f1760ec526f56e2297651f7a067f4b362f685417a81" + }, + "derivationPath": { + "scheme": "cap26", + "path": "m/44H/1022H/1H/525H/1460H/0S" + } + } + } + } + } + ] + }, + "numberOfDaysUntilAutoConfirm": 14 + }, + "authenticationSigningFactorInstance": { + "factorSourceID": { + "discriminator": "fromHash", + "fromHash": { + "kind": "device", + "body": "f1a93d324dd0f2bff89963ab81ed6e0c2ee7e18c0827dc1d3576b2d9f26bbd0a" + } + }, + "badge": { + "discriminator": "virtualSource", + "virtualSource": { + "discriminator": "hierarchicalDeterministicPublicKey", + "hierarchicalDeterministicPublicKey": { + "publicKey": { + "curve": "curve25519", + "compressedData": "136b3a73595315517f921767bc49ae3ba43fc25d2e34e51fbff434a329176ee8" + }, + "derivationPath": { + "scheme": "cap26", + "path": "m/44H/1022H/1H/525H/1678H/0S" + } + } + } + } + } + }, + "provisional": { + "discriminator": "factorInstancesDerived", + "value": { + "securityStructureId": "dededede-dede-dede-dede-dededededede", + "matrixOfFactors": { + "primaryRole": { + "threshold": 1, + "thresholdFactors": [ + { + "factorSourceID": { + "discriminator": "fromHash", + "fromHash": { + "kind": "device", + "body": "f1a93d324dd0f2bff89963ab81ed6e0c2ee7e18c0827dc1d3576b2d9f26bbd0a" + } + }, + "badge": { + "discriminator": "virtualSource", + "virtualSource": { + "discriminator": "hierarchicalDeterministicPublicKey", + "hierarchicalDeterministicPublicKey": { + "publicKey": { + "curve": "curve25519", + "compressedData": "a40a1850ade79f5b24956b4abdb94624ba8189f68ad39fd2bb92ecdc2cbe17d2" + }, + "derivationPath": { + "scheme": "cap26", + "path": "m/44H/1022H/1H/618H/1460H/0S" + } + } + } + } + } + ], + "overrideFactors": [] + }, + "recoveryRole": { + "threshold": 0, + "thresholdFactors": [], + "overrideFactors": [ + { + "factorSourceID": { + "discriminator": "fromHash", + "fromHash": { + "kind": "ledgerHQHardwareWallet", + "body": "ab59987eedd181fe98e512c1ba0f5ff059f11b5c7c56f15614dcc9fe03fec58b" + } + }, + "badge": { + "discriminator": "virtualSource", + "virtualSource": { + "discriminator": "hierarchicalDeterministicPublicKey", + "hierarchicalDeterministicPublicKey": { + "publicKey": { + "curve": "curve25519", + "compressedData": "6f7ac7d9031e321d1762431941b672f164ebb5a6dd2ded9b0c8da2b278143c74" + }, + "derivationPath": { + "scheme": "cap26", + "path": "m/44H/1022H/1H/618H/1460H/0S" + } + } + } + } + } + ] + }, + "confirmationRole": { + "threshold": 0, + "thresholdFactors": [], + "overrideFactors": [ + { + "factorSourceID": { + "discriminator": "fromHash", + "fromHash": { + "kind": "ledgerHQHardwareWallet", + "body": "52ef052a0642a94279b296d6b3b17dedc035a7ae37b76c1d60f11f2725100077" + } + }, + "badge": { + "discriminator": "virtualSource", + "virtualSource": { + "discriminator": "hierarchicalDeterministicPublicKey", + "hierarchicalDeterministicPublicKey": { + "publicKey": { + "curve": "curve25519", + "compressedData": "e867cd64b70cccad642f47ee4acff014b982870cf5218fbd56da79b0eb6e9fba" + }, + "derivationPath": { + "scheme": "cap26", + "path": "m/44H/1022H/1H/618H/1460H/0S" + } + } + } + } + } + ] + }, + "numberOfDaysUntilAutoConfirm": 14 + }, + "authenticationSigningFactorInstance": { + "factorSourceID": { + "discriminator": "fromHash", + "fromHash": { + "kind": "device", + "body": "f1a93d324dd0f2bff89963ab81ed6e0c2ee7e18c0827dc1d3576b2d9f26bbd0a" + } + }, + "badge": { + "discriminator": "virtualSource", + "virtualSource": { + "discriminator": "hierarchicalDeterministicPublicKey", + "hierarchicalDeterministicPublicKey": { + "publicKey": { + "curve": "curve25519", + "compressedData": "d2343d84e7970224ad4f605782f78b096b750f03990c927492ba5308258c689a" + }, + "derivationPath": { + "scheme": "cap26", + "path": "m/44H/1022H/1H/618H/1678H/0S" + } + } + } + } + } + } + } + } + "#, + ); + } } diff --git a/crates/sargon/src/profile/mfa/security_structures/matrices/matrix_of_factor_instances.rs b/crates/sargon/src/profile/mfa/security_structures/matrices/matrix_of_factor_instances.rs index 34192d394..c048d8b37 100644 --- a/crates/sargon/src/profile/mfa/security_structures/matrices/matrix_of_factor_instances.rs +++ b/crates/sargon/src/profile/mfa/security_structures/matrices/matrix_of_factor_instances.rs @@ -105,12 +105,17 @@ impl MnemonicWithPassphrase { impl MatrixOfFactorInstances { fn sample_from_matrix_of_sources( matrix_of_sources: MatrixOfFactorSources, + entity_kind: CAP26EntityKind, ) -> Self { let mut consuming_instances = MnemonicWithPassphrase::derive_instances_for_factor_sources( NetworkID::Mainnet, 1, - [DerivationPreset::AccountMfa], + [if entity_kind == CAP26EntityKind::Account { + DerivationPreset::AccountMfa + } else { + DerivationPreset::IdentityMfa + }], matrix_of_sources.all_factors().into_iter().cloned(), ); @@ -123,13 +128,19 @@ impl MatrixOfFactorInstances { } impl HasSampleValues for MatrixOfFactorInstances { + /// Account fn sample() -> Self { - Self::sample_from_matrix_of_sources(MatrixOfFactorSources::sample()) + Self::sample_from_matrix_of_sources( + MatrixOfFactorSources::sample(), + CAP26EntityKind::Account, + ) } + /// Persona fn sample_other() -> Self { Self::sample_from_matrix_of_sources( MatrixOfFactorSources::sample_other(), + CAP26EntityKind::Identity, ) } } diff --git a/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_instances.rs b/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_instances.rs index be1c79618..06472dd05 100644 --- a/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_instances.rs +++ b/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_instances.rs @@ -1,3 +1,5 @@ +use indexmap::IndexSet; + use crate::prelude::*; #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] @@ -12,17 +14,79 @@ pub struct SecurityStructureOfFactorInstances { /// The structure of factors to use for certain roles, Primary, Recovery /// and Confirmation role. pub matrix_of_factors: MatrixOfFactorInstances, + + /// The authentication signing factor instance which is used to sign + /// proof of ownership - aka "True Rola Key". User can select which FactorSource + /// to use during Shield Building, but typically most users will user the + /// DeviceFactorSource which is default. DerivationPath is in securified + /// KeySpace of course. + /// + /// Non-optional since we can replace it with a new one for entities + /// we have recovered during Onboarding Account Recovery Scan for securified + /// entities + pub authentication_signing_factor_instance: + HierarchicalDeterministicFactorInstance, } impl SecurityStructureOfFactorInstances { pub fn new( security_structure_id: SecurityStructureID, matrix_of_factors: MatrixOfFactorInstances, - ) -> Self { - Self { + authentication_signing: HierarchicalDeterministicFactorInstance, + ) -> Result { + let tx_signing_factors = matrix_of_factors + .unique_factor_instances() + .into_iter() + .flat_map(|f| f.try_as_hd_factor_instances().ok()) + .collect::>(); + + if tx_signing_factors.is_empty() { + return Err(CommonError::NoTransactionSigningFactorInstance); + } + + if tx_signing_factors + .iter() + .any(|f| f.get_key_kind() != CAP26KeyKind::TransactionSigning) + { + return Err( + CommonError::WrongKeyKindOfTransactionSigningFactorInstance, + ); + } + + let tx_signing_factor = tx_signing_factors.iter().next().unwrap(); + + if tx_signing_factors + .iter() + .any(|f| f.get_entity_kind() != tx_signing_factor.get_entity_kind()) + { + return Err(CommonError::WrongEntityKindOfInFactorInstancesPath); + } + + if authentication_signing.get_key_kind() + != CAP26KeyKind::AuthenticationSigning + { + return Err( + CommonError::WrongKeyKindOfAuthenticationSigningFactorInstance, + ); + } + + if authentication_signing.get_entity_kind() + != tx_signing_factor.get_entity_kind() + { + return Err(CommonError::WrongEntityKindOfInFactorInstancesPath); + } + + if !authentication_signing.is_securified() { + return Err( + CommonError::AuthenticationSigningFactorInstanceNotSecurified, + ); + } + + Ok(Self { security_structure_id, matrix_of_factors, - } + authentication_signing_factor_instance: authentication_signing, + }) } } @@ -41,18 +105,24 @@ impl Identifiable for SecurityStructureOfFactorInstances { } impl HasSampleValues for SecurityStructureOfFactorInstances { + /// Account fn sample() -> Self { - Self { - security_structure_id: SecurityStructureID::sample(), - matrix_of_factors: MatrixOfFactorInstances::sample(), - } + Self::new( + SecurityStructureID::sample(), + MatrixOfFactorInstances::sample(), + HierarchicalDeterministicFactorInstance::sample_with_key_kind_entity_kind_on_network_and_hardened_index(NetworkID::Mainnet, CAP26KeyKind::AuthenticationSigning, CAP26EntityKind::Account, Hardened::Securified(SecurifiedU30::ZERO)) + ) + .unwrap() } + /// Persona fn sample_other() -> Self { - Self { - security_structure_id: SecurityStructureID::sample_other(), - matrix_of_factors: MatrixOfFactorInstances::sample_other(), - } + Self::new( + SecurityStructureID::sample_other(), + MatrixOfFactorInstances::sample_other(), + HierarchicalDeterministicFactorInstance::sample_with_key_kind_entity_kind_on_network_and_hardened_index(NetworkID::Mainnet, CAP26KeyKind::AuthenticationSigning, CAP26EntityKind::Identity, Hardened::Securified(SecurifiedU30::ZERO)) + ) + .unwrap() } } @@ -78,4 +148,322 @@ mod tests { let sut = SUT::sample(); assert_eq!(sut.timed_recovery_delay_in_minutes(), 20160); } + + #[test] + fn json_roundtrip_sample_other() { + let sut = SUT::sample_other(); + assert_eq_after_json_roundtrip( + &sut, + r#" + { + "securityStructureId": "dededede-dede-dede-dede-dededededede", + "matrixOfFactors": { + "primaryRole": { + "threshold": 1, + "thresholdFactors": [ + { + "factorSourceID": { + "discriminator": "fromHash", + "fromHash": { + "kind": "device", + "body": "f1a93d324dd0f2bff89963ab81ed6e0c2ee7e18c0827dc1d3576b2d9f26bbd0a" + } + }, + "badge": { + "discriminator": "virtualSource", + "virtualSource": { + "discriminator": "hierarchicalDeterministicPublicKey", + "hierarchicalDeterministicPublicKey": { + "publicKey": { + "curve": "curve25519", + "compressedData": "a40a1850ade79f5b24956b4abdb94624ba8189f68ad39fd2bb92ecdc2cbe17d2" + }, + "derivationPath": { + "scheme": "cap26", + "path": "m/44H/1022H/1H/618H/1460H/0S" + } + } + } + } + } + ], + "overrideFactors": [] + }, + "recoveryRole": { + "threshold": 0, + "thresholdFactors": [], + "overrideFactors": [ + { + "factorSourceID": { + "discriminator": "fromHash", + "fromHash": { + "kind": "ledgerHQHardwareWallet", + "body": "ab59987eedd181fe98e512c1ba0f5ff059f11b5c7c56f15614dcc9fe03fec58b" + } + }, + "badge": { + "discriminator": "virtualSource", + "virtualSource": { + "discriminator": "hierarchicalDeterministicPublicKey", + "hierarchicalDeterministicPublicKey": { + "publicKey": { + "curve": "curve25519", + "compressedData": "6f7ac7d9031e321d1762431941b672f164ebb5a6dd2ded9b0c8da2b278143c74" + }, + "derivationPath": { + "scheme": "cap26", + "path": "m/44H/1022H/1H/618H/1460H/0S" + } + } + } + } + } + ] + }, + "confirmationRole": { + "threshold": 0, + "thresholdFactors": [], + "overrideFactors": [ + { + "factorSourceID": { + "discriminator": "fromHash", + "fromHash": { + "kind": "ledgerHQHardwareWallet", + "body": "52ef052a0642a94279b296d6b3b17dedc035a7ae37b76c1d60f11f2725100077" + } + }, + "badge": { + "discriminator": "virtualSource", + "virtualSource": { + "discriminator": "hierarchicalDeterministicPublicKey", + "hierarchicalDeterministicPublicKey": { + "publicKey": { + "curve": "curve25519", + "compressedData": "e867cd64b70cccad642f47ee4acff014b982870cf5218fbd56da79b0eb6e9fba" + }, + "derivationPath": { + "scheme": "cap26", + "path": "m/44H/1022H/1H/618H/1460H/0S" + } + } + } + } + } + ] + }, + "numberOfDaysUntilAutoConfirm": 14 + }, + "authenticationSigningFactorInstance": { + "factorSourceID": { + "discriminator": "fromHash", + "fromHash": { + "kind": "device", + "body": "f1a93d324dd0f2bff89963ab81ed6e0c2ee7e18c0827dc1d3576b2d9f26bbd0a" + } + }, + "badge": { + "discriminator": "virtualSource", + "virtualSource": { + "discriminator": "hierarchicalDeterministicPublicKey", + "hierarchicalDeterministicPublicKey": { + "publicKey": { + "curve": "curve25519", + "compressedData": "d2343d84e7970224ad4f605782f78b096b750f03990c927492ba5308258c689a" + }, + "derivationPath": { + "scheme": "cap26", + "path": "m/44H/1022H/1H/618H/1678H/0S" + } + } + } + } + } + } + "#, + ); + } + + #[test] + fn json_roundtrip() { + let sut = SUT::sample(); + assert_eq_after_json_roundtrip( + &sut, + r#" + { + "securityStructureId": "ffffffff-ffff-ffff-ffff-ffffffffffff", + "matrixOfFactors": { + "primaryRole": { + "threshold": 2, + "thresholdFactors": [ + { + "factorSourceID": { + "discriminator": "fromHash", + "fromHash": { + "kind": "device", + "body": "f1a93d324dd0f2bff89963ab81ed6e0c2ee7e18c0827dc1d3576b2d9f26bbd0a" + } + }, + "badge": { + "discriminator": "virtualSource", + "virtualSource": { + "discriminator": "hierarchicalDeterministicPublicKey", + "hierarchicalDeterministicPublicKey": { + "publicKey": { + "curve": "curve25519", + "compressedData": "427969814e15d74c3ff4d9971465cb709d210c8a7627af9466bdaa67bd0929b7" + }, + "derivationPath": { + "scheme": "cap26", + "path": "m/44H/1022H/1H/525H/1460H/0S" + } + } + } + } + }, + { + "factorSourceID": { + "discriminator": "fromHash", + "fromHash": { + "kind": "ledgerHQHardwareWallet", + "body": "ab59987eedd181fe98e512c1ba0f5ff059f11b5c7c56f15614dcc9fe03fec58b" + } + }, + "badge": { + "discriminator": "virtualSource", + "virtualSource": { + "discriminator": "hierarchicalDeterministicPublicKey", + "hierarchicalDeterministicPublicKey": { + "publicKey": { + "curve": "curve25519", + "compressedData": "92cd6838cd4e7b0523ed93d498e093f71139ffd5d632578189b39a26005be56b" + }, + "derivationPath": { + "scheme": "cap26", + "path": "m/44H/1022H/1H/525H/1460H/0S" + } + } + } + } + } + ], + "overrideFactors": [] + }, + "recoveryRole": { + "threshold": 0, + "thresholdFactors": [], + "overrideFactors": [ + { + "factorSourceID": { + "discriminator": "fromHash", + "fromHash": { + "kind": "device", + "body": "f1a93d324dd0f2bff89963ab81ed6e0c2ee7e18c0827dc1d3576b2d9f26bbd0a" + } + }, + "badge": { + "discriminator": "virtualSource", + "virtualSource": { + "discriminator": "hierarchicalDeterministicPublicKey", + "hierarchicalDeterministicPublicKey": { + "publicKey": { + "curve": "curve25519", + "compressedData": "427969814e15d74c3ff4d9971465cb709d210c8a7627af9466bdaa67bd0929b7" + }, + "derivationPath": { + "scheme": "cap26", + "path": "m/44H/1022H/1H/525H/1460H/0S" + } + } + } + } + }, + { + "factorSourceID": { + "discriminator": "fromHash", + "fromHash": { + "kind": "ledgerHQHardwareWallet", + "body": "ab59987eedd181fe98e512c1ba0f5ff059f11b5c7c56f15614dcc9fe03fec58b" + } + }, + "badge": { + "discriminator": "virtualSource", + "virtualSource": { + "discriminator": "hierarchicalDeterministicPublicKey", + "hierarchicalDeterministicPublicKey": { + "publicKey": { + "curve": "curve25519", + "compressedData": "92cd6838cd4e7b0523ed93d498e093f71139ffd5d632578189b39a26005be56b" + }, + "derivationPath": { + "scheme": "cap26", + "path": "m/44H/1022H/1H/525H/1460H/0S" + } + } + } + } + } + ] + }, + "confirmationRole": { + "threshold": 0, + "thresholdFactors": [], + "overrideFactors": [ + { + "factorSourceID": { + "discriminator": "fromHash", + "fromHash": { + "kind": "password", + "body": "181ab662e19fac3ad9f08d5c673b286d4a5ed9cd3762356dc9831dc42427c1b9" + } + }, + "badge": { + "discriminator": "virtualSource", + "virtualSource": { + "discriminator": "hierarchicalDeterministicPublicKey", + "hierarchicalDeterministicPublicKey": { + "publicKey": { + "curve": "curve25519", + "compressedData": "4af49eb56b1af579aaf03f1760ec526f56e2297651f7a067f4b362f685417a81" + }, + "derivationPath": { + "scheme": "cap26", + "path": "m/44H/1022H/1H/525H/1460H/0S" + } + } + } + } + } + ] + }, + "numberOfDaysUntilAutoConfirm": 14 + }, + "authenticationSigningFactorInstance": { + "factorSourceID": { + "discriminator": "fromHash", + "fromHash": { + "kind": "device", + "body": "f1a93d324dd0f2bff89963ab81ed6e0c2ee7e18c0827dc1d3576b2d9f26bbd0a" + } + }, + "badge": { + "discriminator": "virtualSource", + "virtualSource": { + "discriminator": "hierarchicalDeterministicPublicKey", + "hierarchicalDeterministicPublicKey": { + "publicKey": { + "curve": "curve25519", + "compressedData": "136b3a73595315517f921767bc49ae3ba43fc25d2e34e51fbff434a329176ee8" + }, + "derivationPath": { + "scheme": "cap26", + "path": "m/44H/1022H/1H/525H/1678H/0S" + } + } + } + } + } + } + "#, + ); + } } diff --git a/crates/sargon/src/profile/v100/entity/account/account.rs b/crates/sargon/src/profile/v100/entity/account/account.rs index b30659157..09b268a67 100644 --- a/crates/sargon/src/profile/v100/entity/account/account.rs +++ b/crates/sargon/src/profile/v100/entity/account/account.rs @@ -84,6 +84,11 @@ impl HasSecurityState for Account { } } +impl IsSecurityStateAware for Account { + fn is_securified(&self) -> bool { + self.security_state().is_securified() + } +} impl IsBaseEntity for Account { type Address = AccountAddress; diff --git a/crates/sargon/src/profile/v100/entity/has_security_state.rs b/crates/sargon/src/profile/v100/entity/has_security_state.rs index 26fc26b05..8cb496c74 100644 --- a/crates/sargon/src/profile/v100/entity/has_security_state.rs +++ b/crates/sargon/src/profile/v100/entity/has_security_state.rs @@ -1,7 +1,8 @@ use crate::prelude::*; -pub trait HasSecurityState: HasFactorInstances { +pub trait HasSecurityState: HasFactorInstances + IsSecurityStateAware { fn security_state(&self) -> EntitySecurityState; + fn try_get_secured_control(&self) -> Result { self.security_state() .as_securified() diff --git a/crates/sargon/src/profile/v100/entity/persona/persona.rs b/crates/sargon/src/profile/v100/entity/persona/persona.rs index 000c40ac1..d59181548 100644 --- a/crates/sargon/src/profile/v100/entity/persona/persona.rs +++ b/crates/sargon/src/profile/v100/entity/persona/persona.rs @@ -66,7 +66,11 @@ impl HasEntityKind for Persona { CAP26EntityKind::Identity } } - +impl IsSecurityStateAware for Persona { + fn is_securified(&self) -> bool { + self.security_state().is_securified() + } +} impl HasSecurityState for Persona { fn security_state(&self) -> EntitySecurityState { self.security_state.clone() diff --git a/crates/sargon/src/profile/v100/entity_security_state/entity_security_state.rs b/crates/sargon/src/profile/v100/entity_security_state/entity_security_state.rs index 240992d17..15794f7ad 100644 --- a/crates/sargon/src/profile/v100/entity_security_state/entity_security_state.rs +++ b/crates/sargon/src/profile/v100/entity_security_state/entity_security_state.rs @@ -10,11 +10,14 @@ use crate::prelude::*; pub enum EntitySecurityState { /// The account is controlled by a single factor (private key) Unsecured { + /// The current state of the unsecured entity #[serde(rename = "unsecuredEntityControl")] value: UnsecuredEntityControl, }, + /// The account is controlled by multi-factor Securified { + /// The current state of the securified entity #[serde(rename = "securedEntityControl")] value: SecuredEntityControl, }, @@ -151,7 +154,7 @@ mod tests { let model = EntitySecurityState::Securified { value: secured_entity_control, }; - + print_json(&model); assert_eq_after_json_roundtrip( &model, r#" diff --git a/crates/sargon/src/profile/v100/entity_security_state/mod.rs b/crates/sargon/src/profile/v100/entity_security_state/mod.rs index a7af15c95..644a39423 100644 --- a/crates/sargon/src/profile/v100/entity_security_state/mod.rs +++ b/crates/sargon/src/profile/v100/entity_security_state/mod.rs @@ -1,5 +1,7 @@ mod entity_security_state; +mod provisional_securified_config; mod unsecured_entity_control; pub use entity_security_state::*; +pub use provisional_securified_config::*; pub use unsecured_entity_control::*; diff --git a/crates/sargon/src/profile/v100/entity_security_state/provisional_securified_config.rs b/crates/sargon/src/profile/v100/entity_security_state/provisional_securified_config.rs new file mode 100644 index 000000000..11fc7cd2b --- /dev/null +++ b/crates/sargon/src/profile/v100/entity_security_state/provisional_securified_config.rs @@ -0,0 +1,108 @@ +use crate::prelude::*; + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash)] +pub struct ProvisionalSecurifiedTransactionQueued { + pub factor_instances: SecurityStructureOfFactorInstances, + pub txid: TransactionIntentHash, +} + +impl ProvisionalSecurifiedTransactionQueued { + pub fn new( + factor_instances: SecurityStructureOfFactorInstances, + txid: TransactionIntentHash, + ) -> Self { + Self { + factor_instances, + txid, + } + } +} +impl HasSampleValues for ProvisionalSecurifiedTransactionQueued { + fn sample() -> Self { + Self::new( + SecurityStructureOfFactorInstances::sample(), + TransactionIntentHash::sample(), + ) + } + fn sample_other() -> Self { + Self::new( + SecurityStructureOfFactorInstances::sample_other(), + TransactionIntentHash::sample_other(), + ) + } +} +#[cfg(test)] +mod provisional_securified_transaction_queued_tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = ProvisionalSecurifiedTransactionQueued; + + #[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()); + } +} + +#[derive( + Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash, EnumAsInner, +)] +#[serde(tag = "discriminator")] +pub enum ProvisionalSecurifiedConfig { + /// User has selected which security shield to use for some entity, + /// but no FactorInstances has been provided yet. + #[serde(rename = "shieldSelected")] + ShieldSelected { value: SecurityStructureID }, + + /// User has fully prepared a `SecurityStructureOfFactorInstances` but + /// not made a transaction to apply it to the entity yet. + #[serde(rename = "factorInstancesDerived")] + FactorInstancesDerived { + value: SecurityStructureOfFactorInstances, + }, + + /// User has made queued a transaction to apply a `SecurityStructureOfFactorInstances` + /// but it has not been submitted (confirmed) yet. + #[serde(rename = "transactionQueued")] + TransactionQueued { + value: ProvisionalSecurifiedTransactionQueued, + }, +} + +impl HasSampleValues for ProvisionalSecurifiedConfig { + fn sample() -> Self { + Self::ShieldSelected { + value: SecurityStructureID::sample(), + } + } + fn sample_other() -> Self { + Self::FactorInstancesDerived { + value: SecurityStructureOfFactorInstances::sample_other(), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = ProvisionalSecurifiedConfig; + + #[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/crates/sargon/src/profile/v100/entity_security_state/unsecured_entity_control.rs b/crates/sargon/src/profile/v100/entity_security_state/unsecured_entity_control.rs index a9118e410..385897b53 100644 --- a/crates/sargon/src/profile/v100/entity_security_state/unsecured_entity_control.rs +++ b/crates/sargon/src/profile/v100/entity_security_state/unsecured_entity_control.rs @@ -7,25 +7,18 @@ use crate::prelude::*; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash)] #[serde(rename_all = "camelCase")] pub struct UnsecuredEntityControl { - // /// The factor instance which was used to create this unsecured entity, which - // /// also controls this entity and is used for signing transactions. + /// The factor instance which was used to create this unsecured entity, which + /// also controls this entity and is used for signing transactions. pub transaction_signing: HierarchicalDeterministicFactorInstance, - /// The factor instance which can be used for ROLA. + /// The provisional security structure configuration #[serde(skip_serializing_if = "Option::is_none")] - pub authentication_signing: Option, + pub provisional: Option, } impl HasFactorInstances for UnsecuredEntityControl { fn unique_factor_instances(&self) -> IndexSet { - let mut set = IndexSet::new(); - set.insert(self.transaction_signing.factor_instance()); - if let Some(authentication_signing) = - self.authentication_signing.as_ref() - { - set.insert(authentication_signing.factor_instance()); - } - set + IndexSet::just(self.transaction_signing.factor_instance()) } } @@ -38,28 +31,15 @@ impl UnsecuredEntityControl { { Self { transaction_signing: entity_creating_factor_instance.into(), - authentication_signing: None, + provisional: None, } } #[cfg(not(tarpaulin_include))] // false negative pub fn new( transaction_signing: HierarchicalDeterministicFactorInstance, - authentication_signing: Option, + provisional: impl Into>, ) -> Result { - let is_invalid_auth_signing_key = authentication_signing - .as_ref() - .map(|auth| { - auth.get_key_kind() != CAP26KeyKind::AuthenticationSigning - }) - .unwrap_or(false); - - if is_invalid_auth_signing_key { - return Err( - CommonError::WrongKeyKindOfAuthenticationSigningFactorInstance, - ); - } - let key_kind = transaction_signing.get_key_kind(); if key_kind != CAP26KeyKind::TransactionSigning { return Err( @@ -68,7 +48,7 @@ impl UnsecuredEntityControl { } Ok(Self { transaction_signing, - authentication_signing, + provisional: provisional.into(), }) } @@ -114,15 +94,6 @@ mod tests { assert_ne!(SUT::sample(), SUT::sample_other()); } - #[test] - fn with_auth_signing() { - let tx_sign = HierarchicalDeterministicFactorInstance::sample(); - let auth_sign = - HierarchicalDeterministicFactorInstance::sample_auth_signing(); - let control = SUT::new(tx_sign, Some(auth_sign.clone())).unwrap(); - assert_eq!(control.authentication_signing, Some(auth_sign)); - } - #[test] fn json_roundtrip() { let model = SUT::sample(); diff --git a/crates/sargon/src/profile/v100/factors/hierarchical_deterministic_factor_instance.rs b/crates/sargon/src/profile/v100/factors/hierarchical_deterministic_factor_instance.rs index f37b88963..74703f6be 100644 --- a/crates/sargon/src/profile/v100/factors/hierarchical_deterministic_factor_instance.rs +++ b/crates/sargon/src/profile/v100/factors/hierarchical_deterministic_factor_instance.rs @@ -6,6 +6,11 @@ pub struct HierarchicalDeterministicFactorInstance { pub public_key: HierarchicalDeterministicPublicKey, } +impl HasEntityKindObjectSafe for HierarchicalDeterministicFactorInstance { + fn get_entity_kind(&self) -> CAP26EntityKind { + self.public_key.derivation_path.get_entity_kind() + } +} impl IsKeySpaceAware for HierarchicalDeterministicFactorInstance { fn key_space(&self) -> KeySpace { self.public_key.key_space() @@ -89,7 +94,11 @@ impl HierarchicalDeterministicFactorInstance { let seed = factor_source_id.sample_associated_mnemonic().to_seed(); let hd_private_key = seed.derive_private_key(&derivation_path); - Self::new(factor_source_id, hd_private_key.public_key()) + assert_eq!(derivation_path.get_entity_kind(), entity_kind); + + let self_ = Self::new(factor_source_id, hd_private_key.public_key()); + assert_eq!(self_.get_entity_kind(), entity_kind); + self_ } /// Mainnet @@ -240,7 +249,7 @@ impl HierarchicalDeterministicFactorInstance { } /// A sample used to facilitate unit tests. - fn sample_with_key_kind_entity_kind( + pub(crate) fn sample_with_key_kind_entity_kind( key_kind: CAP26KeyKind, entity_kind: CAP26EntityKind, index: u32, @@ -260,19 +269,28 @@ impl HierarchicalDeterministicFactorInstance { entity_kind: CAP26EntityKind, index: u32, ) -> Self { + Self::sample_with_key_kind_entity_kind_on_network_and_hardened_index( + network_id, + key_kind, + entity_kind, + UnsecurifiedHardened::from_local_key_space(index).unwrap(), + ) + } + + pub(crate) fn sample_with_key_kind_entity_kind_on_network_and_hardened_index( + network_id: NetworkID, + key_kind: CAP26KeyKind, + entity_kind: CAP26EntityKind, + hardened: impl Into, + ) -> Self { + let hardened = hardened.into(); let path = match entity_kind { CAP26EntityKind::Account => DerivationPath::from(AccountPath::new( - network_id, - key_kind, - UnsecurifiedHardened::from_local_key_space(index).unwrap(), + network_id, key_kind, hardened, )), - CAP26EntityKind::Identity => { - DerivationPath::from(IdentityPath::new( - network_id, - key_kind, - UnsecurifiedHardened::from_local_key_space(index).unwrap(), - )) - } + CAP26EntityKind::Identity => DerivationPath::from( + IdentityPath::new(network_id, key_kind, hardened), + ), }; let mwp = MnemonicWithPassphrase::sample(); diff --git a/crates/sargon/src/profile/v100/profile_legacy_state_bugs.rs b/crates/sargon/src/profile/v100/profile_legacy_state_bugs.rs index dadac57c2..ca0adc825 100644 --- a/crates/sargon/src/profile/v100/profile_legacy_state_bugs.rs +++ b/crates/sargon/src/profile/v100/profile_legacy_state_bugs.rs @@ -116,39 +116,6 @@ impl Profile { sut } - fn with_instance_collision_authentication_signing_key_kind() -> Self { - let mwp = MnemonicWithPassphrase::sample_device(); - let mut sut = Profile::from_mnemonic_with_passphrase( - mwp.clone(), - HostId::sample(), - HostInfo::sample(), - ); - let mut account1 = Account::sample(); - let mut account2 = Account::sample_other(); - let mut uec1 = account1.try_get_unsecured_control().unwrap(); - uec1.authentication_signing = Some( - HierarchicalDeterministicFactorInstance::sample_auth_signing(), - ); - account1.security_state = - EntitySecurityState::Unsecured { value: uec1 }; - - let mut uec2 = account1.try_get_unsecured_control().unwrap(); - uec2.authentication_signing = Some( - HierarchicalDeterministicFactorInstance::sample_auth_signing(), - ); - account2.security_state = - EntitySecurityState::Unsecured { value: uec2 }; - - sut.networks = ProfileNetworks::just(ProfileNetwork::new( - NetworkID::Mainnet, - Accounts::from_iter([account1, account2]), - Personas::default(), - AuthorizedDapps::default(), - ResourcePreferences::default(), - )); - sut - } - fn with_instance_collision_securified() -> Self { let mwp = MnemonicWithPassphrase::sample_device(); let mut sut = Profile::from_mnemonic_with_passphrase( @@ -291,17 +258,6 @@ mod tests { instance_detection(sut, acc1, acc2) } - #[test] - fn instance_detection_auth_sign() { - let sut = - SUT::with_instance_collision_authentication_signing_key_kind(); - let accounts = sut.accounts_on_current_network().unwrap(); - let acc1 = accounts.clone().first().unwrap().clone(); - let acc2 = accounts.items().into_iter().next_back().unwrap(); - - instance_detection(sut, acc1, acc2) - } - #[test] fn instance_detection_both_personas() { let sut = SUT::with_instance_collision_both_personas(); diff --git a/crates/sargon/src/signing/authentication/authentication_signing_input.rs b/crates/sargon/src/signing/authentication/authentication_signing_input.rs index 2656ddb43..2596c1ce2 100644 --- a/crates/sargon/src/signing/authentication/authentication_signing_input.rs +++ b/crates/sargon/src/signing/authentication/authentication_signing_input.rs @@ -51,11 +51,11 @@ impl AuthenticationSigningInput { }?; let factor_instance = match security_state { - EntitySecurityState::Unsecured { value } => value - .authentication_signing - .unwrap_or(value.transaction_signing), - EntitySecurityState::Securified { value: _ } => { - panic!("Authentication signing not yet implemented for securified entities.") + EntitySecurityState::Unsecured { value } => { + value.transaction_signing + } + EntitySecurityState::Securified { value } => { + value.authentication_signing_factor_instance() } }; diff --git a/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs b/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs index 6e12aac3b..8ba4e4927 100644 --- a/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs +++ b/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs @@ -858,8 +858,9 @@ impl SargonOS { )?; SecurityStructureOfFactorInstances::new( security_structure_id, - matrix_of_factor_instances - ) + matrix_of_factor_instances, + HierarchicalDeterministicFactorInstance::sample_with_key_kind_entity_kind_on_network_and_hardened_index(entity_address.network_id(), CAP26KeyKind::AuthenticationSigning, A::entity_kind(), Hardened::Securified(SecurifiedU30::ZERO)), + )? }; Ok((entity_address, security_structure_of_factor_instances)) }).collect::>>()?; diff --git a/crates/sargon/src/types/samples/account_samples.rs b/crates/sargon/src/types/samples/account_samples.rs index 8c718a7ba..41e6a6fd2 100644 --- a/crates/sargon/src/types/samples/account_samples.rs +++ b/crates/sargon/src/types/samples/account_samples.rs @@ -174,6 +174,20 @@ impl Account { let network_id = NetworkID::Mainnet; let address = AccountAddress::new(veci.public_key(), NetworkID::Mainnet); + + let security_structure_of_factor_instances = + SecurityStructureOfFactorInstances::new( + SecurityStructureID::sample(), + matrix, + HierarchicalDeterministicFactorInstance::sample_with_key_kind_entity_kind_on_network_and_hardened_index( + NetworkID::Mainnet, + CAP26KeyKind::AuthenticationSigning, + CAP26EntityKind::Account, + SecurifiedU30::ZERO, + ),// TODO: Remove hard coding? + ) + .unwrap(); + Self { network_id, address, @@ -181,10 +195,7 @@ impl Account { security_state: SecuredEntityControl::new( Some(veci.clone()), AccessControllerAddress::sample_from_account_address(address), - SecurityStructureOfFactorInstances { - security_structure_id: SecurityStructureID::sample(), - matrix_of_factors: matrix, - }, + security_structure_of_factor_instances, ) .unwrap() .into(), diff --git a/crates/sargon/src/types/samples/persona_samples.rs b/crates/sargon/src/types/samples/persona_samples.rs index 278b7dd69..b9ceba1d5 100644 --- a/crates/sargon/src/types/samples/persona_samples.rs +++ b/crates/sargon/src/types/samples/persona_samples.rs @@ -93,6 +93,39 @@ static ALL_PERSONA_SAMPLES: Lazy<[Persona; 8]> = Lazy::new(|| { ] }); +impl DerivationPath { + /// # Safety + /// Crashes for Bip44LikePath, this is only meant to be used for tests + /// to map between IdentityPath -> IdentityPath + unsafe fn as_persona(&self) -> Self { + match self { + Self::Account { value } => { + IdentityPath::new(value.network_id, value.key_kind, value.index) + .into() + } + Self::Identity { value: _ } => self.clone(), + Self::Bip44Like { value: _ } => panic!("unsupported"), + } + } +} + +impl HierarchicalDeterministicFactorInstance { + /// # Safety + /// Completely unsafe, this is an invalid FactorInstance! It hardcodes + /// the derivation path as a persona, resulting in an invalid (DerivationPath, PublicKey) pair.! + unsafe fn invalid_hard_coding_derivation_path_as_persona(&self) -> Self { + unsafe { + Self::new( + self.factor_source_id(), + HierarchicalDeterministicPublicKey::new( + self.public_key(), + self.derivation_path().as_persona(), + ), + ) + } + } +} + impl Persona { pub fn sample_unsecurified_mainnet( name: impl AsRef, @@ -121,6 +154,7 @@ impl Persona { veci: HierarchicalDeterministicFactorInstance, make_role: impl Fn() -> GeneralRoleWithHierarchicalDeterministicFactorInstances, ) -> Self { + assert_eq!(veci.get_entity_kind(), CAP26EntityKind::Identity); let role = make_role(); assert_eq!(role.get_role_kind(), RoleKind::Primary, "If this tests fails you can update the code below to not be hardcoded to set the primary role..."); let mut matrix = MatrixOfFactorInstances::sample(); @@ -135,8 +169,54 @@ impl Persona { .map(FactorInstance::from) .collect_vec(), ); + unsafe { + matrix.recovery_role = + RecoveryRoleWithFactorInstances::with_factors( + 0, + [], + matrix + .recovery() + .get_override_factors() + .into_iter() + .filter_map(|f| f.try_as_hd_factor_instances().ok()) + .map(|f| { + f.invalid_hard_coding_derivation_path_as_persona() + }) + .map(FactorInstance::from) + .collect_vec(), + ); + matrix.confirmation_role = + ConfirmationRoleWithFactorInstances::with_factors( + 0, + [], + matrix + .confirmation() + .get_override_factors() + .into_iter() + .filter_map(|f| f.try_as_hd_factor_instances().ok()) + .map(|f| { + f.invalid_hard_coding_derivation_path_as_persona() + }) + .map(FactorInstance::from) + .collect_vec(), + ); + } let address = IdentityAddress::new(veci.public_key(), NetworkID::Mainnet); + + let security_structure_of_factor_instances = + SecurityStructureOfFactorInstances::new( + SecurityStructureID::sample(), + matrix, + HierarchicalDeterministicFactorInstance::sample_with_key_kind_entity_kind_on_network_and_hardened_index( + NetworkID::Mainnet, + CAP26KeyKind::AuthenticationSigning, + CAP26EntityKind::Identity, + SecurifiedU30::ZERO, + ), // TODO: Remove hard coding? + ) + .unwrap(); + Self { network_id: NetworkID::Mainnet, address, @@ -144,10 +224,7 @@ impl Persona { security_state: SecuredEntityControl::new( veci.clone(), AccessControllerAddress::sample_from_identity_address(address), - SecurityStructureOfFactorInstances { - security_structure_id: SecurityStructureID::sample(), - matrix_of_factors: matrix, - }, + security_structure_of_factor_instances, ) .unwrap() .into(), diff --git a/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/transaction_hashes/transaction_hashes.rs b/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/transaction_hashes/transaction_hashes.rs index b8e7ba793..76cab7a91 100644 --- a/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/transaction_hashes/transaction_hashes.rs +++ b/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/transaction_hashes/transaction_hashes.rs @@ -18,7 +18,7 @@ macro_rules! decl_tx_hash { #[doc = $expr] )* #[derive( - Clone, PartialEq, Eq, Hash, derive_more::Display, derive_more::Debug, + Clone, PartialEq, Eq, Hash, SerializeDisplay, DeserializeFromStr, derive_more::Display, derive_more::Debug, )] #[display("{}", self.bech32_encoded_tx_id)] #[debug("{}", self.bech32_encoded_tx_id)] From 9cded459d4f85e3ea176f7510b1a7dc877196679 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Fri, 13 Dec 2024 14:29:05 +0100 Subject: [PATCH 09/60] [no ci] wip --- .../high_level/manifest_building/manifests.rs | 37 +++++++- .../manifests_access_controller.rs | 92 +++++++++++++------ 2 files changed, 99 insertions(+), 30 deletions(-) diff --git a/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/manifests.rs b/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/manifests.rs index c0c24536a..3c2c04596 100644 --- a/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/manifests.rs +++ b/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/manifests.rs @@ -38,12 +38,29 @@ impl TransactionManifest { address_of_account_or_persona: &AddressOfAccountOrPersona, owner_key_hashes: Vec, ) -> Self { - Self::set_metadata( + let builder = Self::set_owner_keys_hashes_on_builder( + address_of_account_or_persona, + owner_key_hashes, + ScryptoTransactionManifestBuilder::new(), + ); + TransactionManifest::sargon_built( + builder, + address_of_account_or_persona.network_id(), + ) + } + + pub fn set_owner_keys_hashes_on_builder( + address_of_account_or_persona: &AddressOfAccountOrPersona, + owner_key_hashes: Vec, + builder: ScryptoTransactionManifestBuilder, + ) -> ScryptoTransactionManifestBuilder { + Self::set_metadata_on_builder( address_of_account_or_persona, MetadataKey::OwnerKeys, ScryptoMetadataValue::PublicKeyHashArray( owner_key_hashes.into_iter().map(|h| h.into()).collect_vec(), ), + builder, ) } @@ -126,14 +143,26 @@ impl TransactionManifest { where A: IntoScryptoAddress, { - let builder = ScryptoTransactionManifestBuilder::new().set_metadata( - address.scrypto(), + let builder = Self::set_metadata_on_builder( + address, key, value, + ScryptoTransactionManifestBuilder::new(), ); - TransactionManifest::sargon_built(builder, address.network_id()) } + + fn set_metadata_on_builder( + address: &A, + key: MetadataKey, + value: impl ScryptoToMetadataEntry, + builder: ScryptoTransactionManifestBuilder, + ) -> ScryptoTransactionManifestBuilder + where + A: IntoScryptoAddress, + { + builder.set_metadata(address.scrypto(), key, value) + } } #[cfg(test)] diff --git a/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/manifests_access_controller.rs b/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/manifests_access_controller.rs index 29947114a..505931f66 100644 --- a/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/manifests_access_controller.rs +++ b/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/manifests_access_controller.rs @@ -7,11 +7,28 @@ use radix_engine_interface::blueprints::{ use crate::prelude::*; impl TransactionManifest { - pub fn securify_unsecurified_entity( - entity: UnsecurifiedEntity, + pub fn securify_unsecurified_entity( + entity: E, + security_structure_of_factor_instances: SecurityStructureOfFactorInstances, + ) -> Result { + let Ok(unsecurified) = entity.security_state().into_unsecured() else { + return Err(CommonError::Unknown); + }; + + if unsecurified.provisional.is_some() { + return Err(CommonError::Unknown); + }; + + Ok(Self::_securify_unsecurified_entity( + Into::::into(entity.address()), + security_structure_of_factor_instances, + )) + } + + fn _securify_unsecurified_entity( + entity_address: AddressOfAccountOrPersona, security_structure_of_factor_instances: SecurityStructureOfFactorInstances, ) -> Self { - let entity_address = entity.address(); let (security_entity_identifier, owner_badge) = if entity_address.is_identity() { ( @@ -26,29 +43,52 @@ impl TransactionManifest { let bucket_factory = BucketFactory::default(); // Securify the entity which will return an entity owner badge onto the worktop. - builder = builder.call_method( - &entity_address, - security_entity_identifier, - (), - ); - - // Create a bucket out of the entity owner badge. - let owner_badge_bucket = &bucket_factory.next(); - builder = builder.take_from_worktop(owner_badge, 1, owner_badge_bucket); - - let timed_recovery_delay_in_minutes = - security_structure_of_factor_instances - .timed_recovery_delay_in_minutes(); - let rule_set = ScryptoRuleSet::from( - security_structure_of_factor_instances.matrix_of_factors, - ); - builder = builder.create_access_controller( - owner_badge_bucket, - rule_set.primary_role, - rule_set.recovery_role, - rule_set.confirmation_role, - Some(timed_recovery_delay_in_minutes), - ); + let owner_badge_bucket = &{ + builder = builder.call_method( + &entity_address, + security_entity_identifier, + (), + ); + + // Create a bucket out of the entity owner badge. + let owner_badge_bucket = bucket_factory.next(); + builder = + builder.take_from_worktop(owner_badge, 1, &owner_badge_bucket); + owner_badge_bucket + }; + + // Create an access controller for the entity. + { + let timed_recovery_delay_in_minutes = + security_structure_of_factor_instances + .timed_recovery_delay_in_minutes(); + let rule_set = ScryptoRuleSet::from( + security_structure_of_factor_instances.matrix_of_factors, + ); + + builder = builder.create_access_controller( + owner_badge_bucket, + rule_set.primary_role, + rule_set.recovery_role, + rule_set.confirmation_role, + Some(timed_recovery_delay_in_minutes), + ); + } + + // Set Rola Key + { + let rola_key_hash = PublicKeyHash::hash( + security_structure_of_factor_instances + .authentication_signing_factor_instance + .public_key(), + ); + let owner_key_hashes = vec![rola_key_hash]; + builder = Self::set_owner_keys_hashes_on_builder( + &entity_address, + owner_key_hashes, + builder, + ); + } TransactionManifest::sargon_built(builder, entity_address.network_id()) } From 5efcfffd1a10e80e82482ff673c310a8dd66cbe1 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Mon, 16 Dec 2024 10:45:19 +0100 Subject: [PATCH 10/60] [no ci] WIP --- .../secured_entity_control.rs | 3 +- .../entity_security_state.rs | 142 ++++++++++++++++++ .../unsecured_entity_control.rs | 14 ++ 3 files changed, 158 insertions(+), 1 deletion(-) diff --git a/crates/sargon/src/profile/mfa/secured_entity_control/secured_entity_control.rs b/crates/sargon/src/profile/mfa/secured_entity_control/secured_entity_control.rs index dca8af2fe..98da32d23 100644 --- a/crates/sargon/src/profile/mfa/secured_entity_control/secured_entity_control.rs +++ b/crates/sargon/src/profile/mfa/secured_entity_control/secured_entity_control.rs @@ -55,8 +55,9 @@ pub trait HasProvisionalSecurifiedConfig { /// this type fn set_provisional( &mut self, - provisional: Option, + provisional: impl Into>, ) -> Result<()> { + let provisional = provisional.into(); if let Some(ProvisionalSecurifiedConfig::TransactionQueued { value: _, }) = self.get_provisional().as_ref() diff --git a/crates/sargon/src/profile/v100/entity_security_state/entity_security_state.rs b/crates/sargon/src/profile/v100/entity_security_state/entity_security_state.rs index 4bcffaebe..5d4d7d431 100644 --- a/crates/sargon/src/profile/v100/entity_security_state/entity_security_state.rs +++ b/crates/sargon/src/profile/v100/entity_security_state/entity_security_state.rs @@ -24,6 +24,148 @@ pub enum EntitySecurityState { }, } +impl HasProvisionalSecurifiedConfig for EntitySecurityState { + fn get_provisional(&self) -> Option { + match self { + Self::Unsecured { value } => value.get_provisional(), + Self::Securified { value } => value.get_provisional(), + } + } + + fn set_provisional_unchecked( + &mut self, + provisional: impl Into>, + ) { + match self { + Self::Unsecured { value } => { + value.set_provisional_unchecked(provisional) + } + Self::Securified { value } => { + value.set_provisional_unchecked(provisional) + } + } + } +} + +#[cfg(test)] +mod has_provisional_securified_config_tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = EntitySecurityState; + + fn set_provisional_is_err_when_provisional_is_tx_queued(sut: SUT) { + let mut clone = sut.clone(); + let mut test = |x: ProvisionalSecurifiedConfig| { + assert!(clone.set_provisional(x).is_err()); + }; + + test(ProvisionalSecurifiedConfig::ShieldSelected { + value: SecurityStructureID::sample(), + }); + test(ProvisionalSecurifiedConfig::FactorInstancesDerived { + value: SecurityStructureOfFactorInstances::sample(), + }); + test(ProvisionalSecurifiedConfig::TransactionQueued { + value: ProvisionalSecurifiedTransactionQueued::sample_other(), + }); + + assert_eq!(clone, sut); // unchanged + } + + #[test] + fn set_provisional_is_err_when_provisional_is_tx_queued_unsecured() { + let mut sut = SUT::from(UnsecuredEntityControl::sample()); + sut.set_provisional(ProvisionalSecurifiedConfig::TransactionQueued { + value: ProvisionalSecurifiedTransactionQueued::sample(), + }) + .unwrap(); + set_provisional_is_err_when_provisional_is_tx_queued(sut); + } + + #[test] + fn set_provisional_is_err_when_provisional_is_tx_queued_secured() { + let mut sut = SUT::from(SecuredEntityControl::sample()); + sut.set_provisional(ProvisionalSecurifiedConfig::TransactionQueued { + value: ProvisionalSecurifiedTransactionQueued::sample(), + }) + .unwrap(); + set_provisional_is_err_when_provisional_is_tx_queued(sut); + } + + #[test] + fn cancel_works_unsecured() { + let mut sut = SUT::from(UnsecuredEntityControl::sample()); + sut.set_provisional(ProvisionalSecurifiedConfig::TransactionQueued { + value: ProvisionalSecurifiedTransactionQueued::sample(), + }) + .unwrap(); + assert!(sut.cancel_queued_transaction().is_ok()); + + assert!(sut.get_provisional().is_none()); // assert is cancelled + let new_state = ProvisionalSecurifiedConfig::ShieldSelected { + value: SecurityStructureID::sample(), + }; + sut.set_provisional(new_state.clone()).unwrap(); + assert_eq!(sut.get_provisional().unwrap(), new_state); // assert is set + } + + #[test] + fn cancel_works_secured() { + let mut sut = SUT::from(SecuredEntityControl::sample()); + sut.set_provisional(ProvisionalSecurifiedConfig::TransactionQueued { + value: ProvisionalSecurifiedTransactionQueued::sample(), + }) + .unwrap(); + assert!(sut.cancel_queued_transaction().is_ok()); + + assert!(sut.get_provisional().is_none()); // assert is cancelled + let new_state = ProvisionalSecurifiedConfig::ShieldSelected { + value: SecurityStructureID::sample(), + }; + sut.set_provisional(new_state.clone()).unwrap(); + assert_eq!(sut.get_provisional().unwrap(), new_state); // assert is set + } + + #[test] + fn cancel_when_no_tx_queued_is_err_unsecured() { + let test = |x: Option| { + let mut sut = SUT::from(UnsecuredEntityControl::sample()); + sut.set_provisional(x).unwrap(); + let clone = sut.clone(); + assert!(sut.cancel_queued_transaction().is_err()); + assert_eq!(clone, sut) // unchanged + }; + + test(None); + test(Some(ProvisionalSecurifiedConfig::ShieldSelected { + value: SecurityStructureID::sample(), + })); + test(Some(ProvisionalSecurifiedConfig::FactorInstancesDerived { + value: SecurityStructureOfFactorInstances::sample(), + })); + } + + #[test] + fn cancel_when_no_tx_queued_is_err_secured() { + let test = |x: Option| { + let mut sut = SUT::from(SecuredEntityControl::sample()); + sut.set_provisional(x).unwrap(); + let clone = sut.clone(); + assert!(sut.cancel_queued_transaction().is_err()); + assert_eq!(clone, sut) // unchanged + }; + + test(None); + test(Some(ProvisionalSecurifiedConfig::ShieldSelected { + value: SecurityStructureID::sample(), + })); + test(Some(ProvisionalSecurifiedConfig::FactorInstancesDerived { + value: SecurityStructureOfFactorInstances::sample(), + })); + } +} + impl<'de> Deserialize<'de> for EntitySecurityState { #[cfg(not(tarpaulin_include))] // false negative fn deserialize>( diff --git a/crates/sargon/src/profile/v100/entity_security_state/unsecured_entity_control.rs b/crates/sargon/src/profile/v100/entity_security_state/unsecured_entity_control.rs index 385897b53..5eec7b6ce 100644 --- a/crates/sargon/src/profile/v100/entity_security_state/unsecured_entity_control.rs +++ b/crates/sargon/src/profile/v100/entity_security_state/unsecured_entity_control.rs @@ -16,6 +16,20 @@ pub struct UnsecuredEntityControl { pub provisional: Option, } +impl HasProvisionalSecurifiedConfig for UnsecuredEntityControl { + fn get_provisional(&self) -> Option { + self.provisional.clone() + } + + fn set_provisional_unchecked( + &mut self, + provisional: impl Into>, + ) { + self.provisional = provisional.into(); + } +} + + impl HasFactorInstances for UnsecuredEntityControl { fn unique_factor_instances(&self) -> IndexSet { IndexSet::just(self.transaction_signing.factor_instance()) From 20fccd0f1091031272a0fe14978cf79878015615 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Mon, 16 Dec 2024 13:30:44 +0100 Subject: [PATCH 11/60] [no ci] wip --- .../src/core/error/common_error.rs | 5 +- crates/sargon/src/core/error/common_error.rs | 5 +- .../secured_entity_control.rs | 31 +++- .../entity_security_state.rs | 155 ++++++++++++------ .../unsecured_entity_control.rs | 1 - 5 files changed, 136 insertions(+), 61 deletions(-) diff --git a/crates/sargon-uniffi/src/core/error/common_error.rs b/crates/sargon-uniffi/src/core/error/common_error.rs index 4cf046aef..0df67ac4d 100644 --- a/crates/sargon-uniffi/src/core/error/common_error.rs +++ b/crates/sargon-uniffi/src/core/error/common_error.rs @@ -840,9 +840,12 @@ pub enum CommonError { #[error("SecurityEntityControl has no QueuedTransaction, unable to mark it as cancelled")] SecurityEntityControlHasNoProvisionallyQueuedTransaction = 10236, + #[error("SecurityEntityControl has derived instances, which would be lost if discarded. Implement a way to put them back in the cache.")] + SecurityEntityControlCannotChangeProvisionalAlreadyDerivedInstances = 10237, + #[error("SecurityEntityControl has QueuedTransaction, unable override it, use `cancel_queued_transaction`")] SecurityEntityControlCannotChangeProvisionalAlreadyHasQueuedTransaction = - 10237, + 10238, } #[uniffi::export] diff --git a/crates/sargon/src/core/error/common_error.rs b/crates/sargon/src/core/error/common_error.rs index 879b2bba7..0d3a46071 100644 --- a/crates/sargon/src/core/error/common_error.rs +++ b/crates/sargon/src/core/error/common_error.rs @@ -837,9 +837,12 @@ pub enum CommonError { #[error("SecurityEntityControl has no QueuedTransaction, unable to mark it as cancelled")] SecurityEntityControlHasNoProvisionallyQueuedTransaction = 10236, + #[error("SecurityEntityControl has derived instances, which would be lost if discarded. Implement a way to put them back in the cache.")] + SecurityEntityControlCannotChangeProvisionalAlreadyDerivedInstances = 10237, + #[error("SecurityEntityControl has QueuedTransaction, unable override it, use `cancel_queued_transaction`")] SecurityEntityControlCannotChangeProvisionalAlreadyHasQueuedTransaction = - 102367, + 10238, } impl CommonError { diff --git a/crates/sargon/src/profile/mfa/secured_entity_control/secured_entity_control.rs b/crates/sargon/src/profile/mfa/secured_entity_control/secured_entity_control.rs index 98da32d23..14dfe687e 100644 --- a/crates/sargon/src/profile/mfa/secured_entity_control/secured_entity_control.rs +++ b/crates/sargon/src/profile/mfa/secured_entity_control/secured_entity_control.rs @@ -58,13 +58,30 @@ pub trait HasProvisionalSecurifiedConfig { provisional: impl Into>, ) -> Result<()> { let provisional = provisional.into(); - if let Some(ProvisionalSecurifiedConfig::TransactionQueued { - value: _, - }) = self.get_provisional().as_ref() - { - Err(CommonError::SecurityEntityControlCannotChangeProvisionalAlreadyHasQueuedTransaction) - } else { - self.set_provisional_unchecked_ok(provisional) + let maybe_existing = self.get_provisional(); + let Some(existing) = maybe_existing.as_ref() else { + return self.set_provisional_unchecked_ok(provisional); + }; + match existing { + ProvisionalSecurifiedConfig::FactorInstancesDerived { value: _ } => { + if let Some(new) = provisional.as_ref() { + if new.is_transaction_queued() { + // We allow `FactorInstancesDerived` -> `TransactionQueued` transition ofc... + return self.set_provisional_unchecked_ok(provisional); + } + } + // We have already consumed FactorInstances from the FactorInstancesCache. + // We currently do not have a way of putting these back. We don't want to + // create gaps if we can. Wallet Features might change, to REQUIRE us to + // allow this, if so we can change this - allowing transition from + // `FactorInstancesDerived` to Non-TransactionQueued state. + Err( + CommonError::SecurityEntityControlCannotChangeProvisionalAlreadyDerivedInstances, + )}, + ProvisionalSecurifiedConfig::TransactionQueued { value: _ } => { + Err(CommonError::SecurityEntityControlCannotChangeProvisionalAlreadyHasQueuedTransaction) + } + _ => self.set_provisional_unchecked_ok(provisional), } } /// Call this once you have cancelled the queued transaction from the transaction queue, diff --git a/crates/sargon/src/profile/v100/entity_security_state/entity_security_state.rs b/crates/sargon/src/profile/v100/entity_security_state/entity_security_state.rs index 5d4d7d431..e910eed65 100644 --- a/crates/sargon/src/profile/v100/entity_security_state/entity_security_state.rs +++ b/crates/sargon/src/profile/v100/entity_security_state/entity_security_state.rs @@ -55,6 +55,11 @@ mod has_provisional_securified_config_tests { type SUT = EntitySecurityState; fn set_provisional_is_err_when_provisional_is_tx_queued(sut: SUT) { + let mut sut = sut; + sut.set_provisional(ProvisionalSecurifiedConfig::TransactionQueued { + value: ProvisionalSecurifiedTransactionQueued::sample(), + }) + .unwrap(); let mut clone = sut.clone(); let mut test = |x: ProvisionalSecurifiedConfig| { assert!(clone.set_provisional(x).is_err()); @@ -73,64 +78,117 @@ mod has_provisional_securified_config_tests { assert_eq!(clone, sut); // unchanged } + fn can_change_shield(sut: SUT) { + let mut sut = sut; + let id1 = ProvisionalSecurifiedConfig::ShieldSelected { + value: SecurityStructureID::sample(), + }; + let id2 = ProvisionalSecurifiedConfig::ShieldSelected { + value: SecurityStructureID::sample_other(), + }; + sut.set_provisional(id1.clone()).unwrap(); + assert_eq!(sut.get_provisional().unwrap(), id1); + assert!(sut.set_provisional(id2.clone()).is_ok()); + assert_eq!(sut.get_provisional().unwrap(), id2); + } + #[test] - fn set_provisional_is_err_when_provisional_is_tx_queued_unsecured() { - let mut sut = SUT::from(UnsecuredEntityControl::sample()); - sut.set_provisional(ProvisionalSecurifiedConfig::TransactionQueued { - value: ProvisionalSecurifiedTransactionQueued::sample(), - }) - .unwrap(); - set_provisional_is_err_when_provisional_is_tx_queued(sut); + fn can_change_shield_id_unsecured() { + can_change_shield(SUT::from(UnsecuredEntityControl::sample())); } #[test] - fn set_provisional_is_err_when_provisional_is_tx_queued_secured() { - let mut sut = SUT::from(SecuredEntityControl::sample()); - sut.set_provisional(ProvisionalSecurifiedConfig::TransactionQueued { - value: ProvisionalSecurifiedTransactionQueued::sample(), - }) + fn can_change_shield_id_secured() { + can_change_shield(SUT::from(SecuredEntityControl::sample_other())); + } + + fn set_provisional_to_non_tx_queued_is_err_when_provisional_is_instances_derived( + sut: SUT, + ) { + let mut sut = sut; + sut.set_provisional( + ProvisionalSecurifiedConfig::FactorInstancesDerived { + value: SecurityStructureOfFactorInstances::sample(), + }, + ) .unwrap(); - set_provisional_is_err_when_provisional_is_tx_queued(sut); + let mut clone = sut.clone(); + let mut test = |x: Option| { + assert!(clone.set_provisional(x).is_err()); + }; + test(None); + test(Some(ProvisionalSecurifiedConfig::ShieldSelected { + value: SecurityStructureID::sample(), + })); + test(Some(ProvisionalSecurifiedConfig::FactorInstancesDerived { + value: SecurityStructureOfFactorInstances::sample(), + })); + + assert_eq!(clone, sut); // unchanged } #[test] - fn cancel_works_unsecured() { - let mut sut = SUT::from(UnsecuredEntityControl::sample()); + fn set_provisional_to_non_tx_queued_is_err_when_provisional_is_instances_derived_unsecure( + ) { + set_provisional_to_non_tx_queued_is_err_when_provisional_is_instances_derived(SUT::from(UnsecuredEntityControl::sample())); + } + + #[test] + fn set_provisional_to_non_tx_queued_is_err_when_provisional_is_instances_derived_secure( + ) { + set_provisional_to_non_tx_queued_is_err_when_provisional_is_instances_derived(SUT::from(SecuredEntityControl::sample_other())); + } + + #[test] + fn set_provisional_is_err_when_provisional_is_tx_queued_unsecured() { + set_provisional_is_err_when_provisional_is_tx_queued(SUT::from( + UnsecuredEntityControl::sample(), + )); + } + + #[test] + fn set_provisional_is_err_when_provisional_is_tx_queued_secured() { + set_provisional_is_err_when_provisional_is_tx_queued(SUT::from( + SecuredEntityControl::sample_other(), + )); + } + + fn cancel_works(sut: SUT) { + let mut sut = sut; + let tx_queued = ProvisionalSecurifiedTransactionQueued::sample(); sut.set_provisional(ProvisionalSecurifiedConfig::TransactionQueued { - value: ProvisionalSecurifiedTransactionQueued::sample(), + value: tx_queued.clone(), }) .unwrap(); assert!(sut.cancel_queued_transaction().is_ok()); - assert!(sut.get_provisional().is_none()); // assert is cancelled - let new_state = ProvisionalSecurifiedConfig::ShieldSelected { - value: SecurityStructureID::sample(), - }; - sut.set_provisional(new_state.clone()).unwrap(); - assert_eq!(sut.get_provisional().unwrap(), new_state); // assert is set - } + assert_eq!( + sut.get_provisional().unwrap(), + ProvisionalSecurifiedConfig::FactorInstancesDerived { + value: tx_queued.clone().factor_instances + } + ); // assert is cancelled - #[test] - fn cancel_works_secured() { - let mut sut = SUT::from(SecuredEntityControl::sample()); + // can re-queue tx sut.set_provisional(ProvisionalSecurifiedConfig::TransactionQueued { - value: ProvisionalSecurifiedTransactionQueued::sample(), + value: tx_queued.clone(), }) .unwrap(); - assert!(sut.cancel_queued_transaction().is_ok()); + } - assert!(sut.get_provisional().is_none()); // assert is cancelled - let new_state = ProvisionalSecurifiedConfig::ShieldSelected { - value: SecurityStructureID::sample(), - }; - sut.set_provisional(new_state.clone()).unwrap(); - assert_eq!(sut.get_provisional().unwrap(), new_state); // assert is set + #[test] + fn cancel_works_unsecured() { + cancel_works(SUT::from(UnsecuredEntityControl::sample())); } #[test] - fn cancel_when_no_tx_queued_is_err_unsecured() { + fn cancel_works_secured() { + cancel_works(SUT::from(SecuredEntityControl::sample_other())); + } + + fn cancel_when_no_tx_queued_is_err(val: SUT) { let test = |x: Option| { - let mut sut = SUT::from(UnsecuredEntityControl::sample()); + let mut sut = val.clone(); sut.set_provisional(x).unwrap(); let clone = sut.clone(); assert!(sut.cancel_queued_transaction().is_err()); @@ -147,22 +205,17 @@ mod has_provisional_securified_config_tests { } #[test] - fn cancel_when_no_tx_queued_is_err_secured() { - let test = |x: Option| { - let mut sut = SUT::from(SecuredEntityControl::sample()); - sut.set_provisional(x).unwrap(); - let clone = sut.clone(); - assert!(sut.cancel_queued_transaction().is_err()); - assert_eq!(clone, sut) // unchanged - }; + fn cancel_when_no_tx_queued_is_err_unsecured() { + cancel_when_no_tx_queued_is_err(SUT::from( + UnsecuredEntityControl::sample(), + )) + } - test(None); - test(Some(ProvisionalSecurifiedConfig::ShieldSelected { - value: SecurityStructureID::sample(), - })); - test(Some(ProvisionalSecurifiedConfig::FactorInstancesDerived { - value: SecurityStructureOfFactorInstances::sample(), - })); + #[test] + fn cancel_when_no_tx_queued_is_err_secured() { + cancel_when_no_tx_queued_is_err(SUT::from( + SecuredEntityControl::sample_other(), + )) } } diff --git a/crates/sargon/src/profile/v100/entity_security_state/unsecured_entity_control.rs b/crates/sargon/src/profile/v100/entity_security_state/unsecured_entity_control.rs index 5eec7b6ce..5b6e95f9a 100644 --- a/crates/sargon/src/profile/v100/entity_security_state/unsecured_entity_control.rs +++ b/crates/sargon/src/profile/v100/entity_security_state/unsecured_entity_control.rs @@ -29,7 +29,6 @@ impl HasProvisionalSecurifiedConfig for UnsecuredEntityControl { } } - impl HasFactorInstances for UnsecuredEntityControl { fn unique_factor_instances(&self) -> IndexSet { IndexSet::just(self.transaction_signing.factor_instance()) From 642c9cc7d60a9d83b46ba812dd363fff59270c45 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Mon, 16 Dec 2024 14:53:43 +0100 Subject: [PATCH 12/60] [no ci] WIP --- .../src/core/error/common_error.rs | 8 ++ .../create_access_controller_for_account.rtm | 98 +++++++++++++++++++ .../create_access_controller_for_persona.rtm | 92 +++++++++++++++++ crates/sargon/src/core/error/common_error.rs | 8 ++ .../secured_entity_control.rs | 8 +- .../matrices/matrix_of_factor_instances.rs | 71 +++++++++++++- .../security_structure_of_factor_instances.rs | 48 ++++----- .../profile/v100/entity/has_security_state.rs | 11 +-- .../entity_security_state.rs | 26 +++-- .../unsecured_entity_control.rs | 2 +- crates/sargon/src/profile/v100/profile.rs | 4 +- .../profile/v100/profile_legacy_state_bugs.rs | 16 +-- .../manifests_access_controller.rs | 74 ++++++++++++-- 13 files changed, 392 insertions(+), 74 deletions(-) create mode 100644 crates/sargon/fixtures/transaction/create_access_controller_for_account.rtm create mode 100644 crates/sargon/fixtures/transaction/create_access_controller_for_persona.rtm diff --git a/crates/sargon-uniffi/src/core/error/common_error.rs b/crates/sargon-uniffi/src/core/error/common_error.rs index 0df67ac4d..3758b41c8 100644 --- a/crates/sargon-uniffi/src/core/error/common_error.rs +++ b/crates/sargon-uniffi/src/core/error/common_error.rs @@ -846,6 +846,14 @@ pub enum CommonError { #[error("SecurityEntityControl has QueuedTransaction, unable override it, use `cancel_queued_transaction`")] SecurityEntityControlCannotChangeProvisionalAlreadyHasQueuedTransaction = 10238, + + #[error( + "Entity kind of FactorInstances does not match EntityKind of entity" + )] + SecurityStructureOfFactorInstancesEntityDiscrepancyInEntityKind { + entity_kind_of_entity: CAP26EntityKind, + entity_kind_of_factor_instances: CAP26EntityKind, + } = 10239, } #[uniffi::export] diff --git a/crates/sargon/fixtures/transaction/create_access_controller_for_account.rtm b/crates/sargon/fixtures/transaction/create_access_controller_for_account.rtm new file mode 100644 index 000000000..feecabe59 --- /dev/null +++ b/crates/sargon/fixtures/transaction/create_access_controller_for_account.rtm @@ -0,0 +1,98 @@ +CALL_METHOD + Address("account_rdx128dtethfy8ujrsfdztemyjk0kvhnah6dafr57frz85dcw2c8z0td87") + "securify" +; +TAKE_FROM_WORKTOP + Address("resource_rdx1nfxxxxxxxxxxaccwnrxxxxxxxxx006664022062xxxxxxxxxaccwnr") + Decimal("1") + Bucket("bucket1") +; +CREATE_ACCESS_CONTROLLER + Bucket("bucket1") + Tuple( + Enum<2u8>( + Enum<1u8>( + Array( + Enum<0u8>( + Enum<2u8>( + 2u8, + Array( + Enum<0u8>( + NonFungibleGlobalId("resource_rdx1nfxxxxxxxxxxed25sgxxxxxxxxx002236757237xxxxxxxxxed25sg:[2dabcc6872c45a625bccc21be9e666bfbc62b1f87a16f3848dd877ba22]") + ), + Enum<0u8>( + NonFungibleGlobalId("resource_rdx1nfxxxxxxxxxxed25sgxxxxxxxxx002236757237xxxxxxxxxed25sg:[7225b29de13d7d06e0e9f406fe15165677573c9106ee036ad52bee2864]") + ) + ) + ) + ), + Enum<0u8>( + Enum<4u8>( + Array() + ) + ) + ) + ) + ), + Enum<2u8>( + Enum<1u8>( + Array( + Enum<0u8>( + Enum<2u8>( + 0u8, + Array() + ) + ), + Enum<0u8>( + Enum<4u8>( + Array( + Enum<0u8>( + NonFungibleGlobalId("resource_rdx1nfxxxxxxxxxxed25sgxxxxxxxxx002236757237xxxxxxxxxed25sg:[2dabcc6872c45a625bccc21be9e666bfbc62b1f87a16f3848dd877ba22]") + ), + Enum<0u8>( + NonFungibleGlobalId("resource_rdx1nfxxxxxxxxxxed25sgxxxxxxxxx002236757237xxxxxxxxxed25sg:[7225b29de13d7d06e0e9f406fe15165677573c9106ee036ad52bee2864]") + ) + ) + ) + ) + ) + ) + ), + Enum<2u8>( + Enum<1u8>( + Array( + Enum<0u8>( + Enum<2u8>( + 0u8, + Array() + ) + ), + Enum<0u8>( + Enum<4u8>( + Array( + Enum<0u8>( + NonFungibleGlobalId("resource_rdx1nfxxxxxxxxxxed25sgxxxxxxxxx002236757237xxxxxxxxxed25sg:[31262cc8dc5e9a49d1fe0ea8e60a17ef36d1ea857db94cca3e1e2a52dd]") + ) + ) + ) + ) + ) + ) + ) + ) + Enum<1u8>( + 20160u32 + ) + Enum<0u8>() +; +SET_METADATA + Address("account_rdx128dtethfy8ujrsfdztemyjk0kvhnah6dafr57frz85dcw2c8z0td87") + "owner_keys" + Enum<143u8>( + Array( + Enum<1u8>( + Bytes("cb3f6086cd08a1d0ab10139a9c6d191783edb534059f7b4716dc5d239e") + ) + ) + ) +; \ No newline at end of file diff --git a/crates/sargon/fixtures/transaction/create_access_controller_for_persona.rtm b/crates/sargon/fixtures/transaction/create_access_controller_for_persona.rtm new file mode 100644 index 000000000..c4809655d --- /dev/null +++ b/crates/sargon/fixtures/transaction/create_access_controller_for_persona.rtm @@ -0,0 +1,92 @@ +CALL_METHOD + Address("identity_rdx12tw6rt9c4l56rz6p866e35tmzp556nymxmpj8hagfewq82kspctdyw") + "securify" +; +TAKE_FROM_WORKTOP + Address("resource_rdx1nfxxxxxxxxxxdntwnrxxxxxxxxx002876444928xxxxxxxxxdntwnr") + Decimal("1") + Bucket("bucket1") +; +CREATE_ACCESS_CONTROLLER + Bucket("bucket1") + Tuple( + Enum<2u8>( + Enum<1u8>( + Array( + Enum<0u8>( + Enum<2u8>( + 1u8, + Array( + Enum<0u8>( + NonFungibleGlobalId("resource_rdx1nfxxxxxxxxxxed25sgxxxxxxxxx002236757237xxxxxxxxxed25sg:[99b417749d9022e73a6d2e025648a928ffbc499be8dc9e55eda900b11f]") + ) + ) + ) + ), + Enum<0u8>( + Enum<4u8>( + Array() + ) + ) + ) + ) + ), + Enum<2u8>( + Enum<1u8>( + Array( + Enum<0u8>( + Enum<2u8>( + 0u8, + Array() + ) + ), + Enum<0u8>( + Enum<4u8>( + Array( + Enum<0u8>( + NonFungibleGlobalId("resource_rdx1nfxxxxxxxxxxed25sgxxxxxxxxx002236757237xxxxxxxxxed25sg:[97d5d7196e49781708520322aaf5872214d854122600dd0125c837aefe]") + ) + ) + ) + ) + ) + ) + ), + Enum<2u8>( + Enum<1u8>( + Array( + Enum<0u8>( + Enum<2u8>( + 0u8, + Array() + ) + ), + Enum<0u8>( + Enum<4u8>( + Array( + Enum<0u8>( + NonFungibleGlobalId("resource_rdx1nfxxxxxxxxxxed25sgxxxxxxxxx002236757237xxxxxxxxxed25sg:[0b9bdb05d848b70041d7ed45c28dd9d6743a19eb129524d1c623b31784]") + ) + ) + ) + ) + ) + ) + ) + ) + Enum<1u8>( + 20160u32 + ) + Enum<0u8>() +; +SET_METADATA + Address("identity_rdx12tw6rt9c4l56rz6p866e35tmzp556nymxmpj8hagfewq82kspctdyw") + "owner_keys" + Enum<143u8>( + Array( + Enum<1u8>( + Bytes("675506ad8d7ce4c602cb06c593c0f10e1cc4dcdf2c4144360ef33ebeef") + ) + ) + ) +; \ No newline at end of file diff --git a/crates/sargon/src/core/error/common_error.rs b/crates/sargon/src/core/error/common_error.rs index 0d3a46071..33649ecf8 100644 --- a/crates/sargon/src/core/error/common_error.rs +++ b/crates/sargon/src/core/error/common_error.rs @@ -843,6 +843,14 @@ pub enum CommonError { #[error("SecurityEntityControl has QueuedTransaction, unable override it, use `cancel_queued_transaction`")] SecurityEntityControlCannotChangeProvisionalAlreadyHasQueuedTransaction = 10238, + + #[error( + "Entity kind of FactorInstances does not match EntityKind of entity" + )] + SecurityStructureOfFactorInstancesEntityDiscrepancyInEntityKind { + entity_kind_of_entity: CAP26EntityKind, + entity_kind_of_factor_instances: CAP26EntityKind, + } = 10239, } impl CommonError { diff --git a/crates/sargon/src/profile/mfa/secured_entity_control/secured_entity_control.rs b/crates/sargon/src/profile/mfa/secured_entity_control/secured_entity_control.rs index 14dfe687e..4762d028c 100644 --- a/crates/sargon/src/profile/mfa/secured_entity_control/secured_entity_control.rs +++ b/crates/sargon/src/profile/mfa/secured_entity_control/secured_entity_control.rs @@ -115,10 +115,14 @@ pub trait HasProvisionalSecurifiedConfig { } impl HasFactorInstances for SecuredEntityControl { - fn unique_factor_instances(&self) -> IndexSet { + fn unique_all_factor_instances(&self) -> IndexSet { + self.security_structure.unique_all_factor_instances() + } + + fn unique_tx_signing_factor_instances(&self) -> IndexSet { self.security_structure .matrix_of_factors - .unique_factor_instances() + .unique_tx_signing_factor_instances() } } diff --git a/crates/sargon/src/profile/mfa/security_structures/matrices/matrix_of_factor_instances.rs b/crates/sargon/src/profile/mfa/security_structures/matrices/matrix_of_factor_instances.rs index 3ff0cc87e..cc71081ec 100644 --- a/crates/sargon/src/profile/mfa/security_structures/matrices/matrix_of_factor_instances.rs +++ b/crates/sargon/src/profile/mfa/security_structures/matrices/matrix_of_factor_instances.rs @@ -10,11 +10,72 @@ impl MatrixOfFactorInstances { } } pub trait HasFactorInstances { - fn unique_factor_instances(&self) -> IndexSet; + fn assert_has_entity_kind( + &self, + entity_kind_of_entity: CAP26EntityKind, + ) -> Result<()> { + let entity_kind_of_factor_instances = + self.entity_kind_of_all_factors()?; + + if entity_kind_of_entity != entity_kind_of_factor_instances { + return Err(CommonError::SecurityStructureOfFactorInstancesEntityDiscrepancyInEntityKind { entity_kind_of_entity, entity_kind_of_factor_instances }); + } + + Ok(()) + } + + fn entity_kind_of_all_factors(&self) -> Result { + let index_agnostic_path = + self.index_agnostic_path_of_all_tx_signing_factor_instances()?; + Ok(index_agnostic_path.entity_kind) + } + + fn index_agnostic_path_of_all_tx_signing_factor_instances( + &self, + ) -> Result { + let factors = self + .unique_tx_signing_factor_instances() + .into_iter() + .filter_map(|f| f.try_as_hd_factor_instances().ok()) + .collect_vec(); + + if factors.is_empty() { + return Err(CommonError::NoTransactionSigningFactorInstance); + } + + let index_agnostic_path = + factors.iter().next().unwrap().derivation_path().agnostic(); + + if factors + .iter() + .any(|f| f.get_entity_kind() != index_agnostic_path.entity_kind) + { + return Err(CommonError::WrongEntityKindOfInFactorInstancesPath); + } + + if factors + .iter() + .any(|f| f.get_key_kind() != CAP26KeyKind::TransactionSigning) + { + return Err( + CommonError::WrongKeyKindOfTransactionSigningFactorInstance, + ); + } + + Ok(index_agnostic_path) + } + + fn unique_tx_signing_factor_instances(&self) -> IndexSet; + + /// Override this method for types which has an authentication signing factor + /// instance, e.g. `SecurityStructureOfFactorInstances`. + fn unique_all_factor_instances(&self) -> IndexSet { + self.unique_tx_signing_factor_instances() + } /// Returns whether the entity is linked to the given factor source. fn is_linked_to_factor_source(&self, factor_source: FactorSource) -> bool { - self.unique_factor_instances().iter().any(|factor| { + self.unique_all_factor_instances().iter().any(|factor| { factor.factor_source_id == factor_source.factor_source_id() }) } @@ -33,7 +94,7 @@ impl HasFactorSourceKindObjectSafe for FactorSourceID { } impl HasFactorInstances for MatrixOfFactorInstances { - fn unique_factor_instances(&self) -> IndexSet { + fn unique_tx_signing_factor_instances(&self) -> IndexSet { let mut set = IndexSet::new(); set.extend(self.primary_role.all_factors().into_iter().cloned()); set.extend(self.recovery_role.all_factors().into_iter().cloned()); @@ -252,8 +313,8 @@ mod tests { fn inequality() { assert_ne!(SUT::sample(), SUT::sample_other()); assert_ne!( - SUT::sample().unique_factor_instances(), - SUT::sample_other().unique_factor_instances() + SUT::sample().unique_tx_signing_factor_instances(), + SUT::sample_other().unique_tx_signing_factor_instances() ); } diff --git a/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_instances.rs b/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_instances.rs index 06472dd05..fd624d18e 100644 --- a/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_instances.rs +++ b/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_instances.rs @@ -28,39 +28,29 @@ pub struct SecurityStructureOfFactorInstances { HierarchicalDeterministicFactorInstance, } +impl HasFactorInstances for SecurityStructureOfFactorInstances { + fn unique_tx_signing_factor_instances(&self) -> IndexSet { + self.matrix_of_factors.unique_tx_signing_factor_instances() + } + + fn unique_all_factor_instances(&self) -> IndexSet { + let mut instances = self.unique_tx_signing_factor_instances(); + instances + .insert(self.authentication_signing_factor_instance.clone().into()); + instances + } +} + impl SecurityStructureOfFactorInstances { pub fn new( security_structure_id: SecurityStructureID, matrix_of_factors: MatrixOfFactorInstances, authentication_signing: HierarchicalDeterministicFactorInstance, ) -> Result { - let tx_signing_factors = matrix_of_factors - .unique_factor_instances() - .into_iter() - .flat_map(|f| f.try_as_hd_factor_instances().ok()) - .collect::>(); - - if tx_signing_factors.is_empty() { - return Err(CommonError::NoTransactionSigningFactorInstance); - } - - if tx_signing_factors - .iter() - .any(|f| f.get_key_kind() != CAP26KeyKind::TransactionSigning) - { - return Err( - CommonError::WrongKeyKindOfTransactionSigningFactorInstance, - ); - } - - let tx_signing_factor = tx_signing_factors.iter().next().unwrap(); - - if tx_signing_factors - .iter() - .any(|f| f.get_entity_kind() != tx_signing_factor.get_entity_kind()) - { - return Err(CommonError::WrongEntityKindOfInFactorInstancesPath); - } + let index_agnostic_path = matrix_of_factors + .index_agnostic_path_of_all_tx_signing_factor_instances()?; + let entity_kind = index_agnostic_path.entity_kind; + matrix_of_factors.assert_has_entity_kind(entity_kind)?; if authentication_signing.get_key_kind() != CAP26KeyKind::AuthenticationSigning @@ -70,9 +60,7 @@ impl SecurityStructureOfFactorInstances { ); } - if authentication_signing.get_entity_kind() - != tx_signing_factor.get_entity_kind() - { + if authentication_signing.get_entity_kind() != entity_kind { return Err(CommonError::WrongEntityKindOfInFactorInstancesPath); } diff --git a/crates/sargon/src/profile/v100/entity/has_security_state.rs b/crates/sargon/src/profile/v100/entity/has_security_state.rs index 8cb496c74..389977716 100644 --- a/crates/sargon/src/profile/v100/entity/has_security_state.rs +++ b/crates/sargon/src/profile/v100/entity/has_security_state.rs @@ -19,14 +19,7 @@ pub trait HasSecurityState: HasFactorInstances + IsSecurityStateAware { } impl HasFactorInstances for T { - fn unique_factor_instances(&self) -> IndexSet { - match self.security_state() { - EntitySecurityState::Securified { value } => { - value.unique_factor_instances() - } - EntitySecurityState::Unsecured { value } => { - value.unique_factor_instances() - } - } + fn unique_tx_signing_factor_instances(&self) -> IndexSet { + self.security_state().unique_tx_signing_factor_instances() } } diff --git a/crates/sargon/src/profile/v100/entity_security_state/entity_security_state.rs b/crates/sargon/src/profile/v100/entity_security_state/entity_security_state.rs index 67f3d3630..4ce6af7d9 100644 --- a/crates/sargon/src/profile/v100/entity_security_state/entity_security_state.rs +++ b/crates/sargon/src/profile/v100/entity_security_state/entity_security_state.rs @@ -285,13 +285,23 @@ impl HasSampleValues for EntitySecurityState { } impl HasFactorInstances for EntitySecurityState { - fn unique_factor_instances(&self) -> IndexSet { + fn unique_tx_signing_factor_instances(&self) -> IndexSet { match self { EntitySecurityState::Unsecured { value } => { - value.unique_factor_instances() + value.unique_tx_signing_factor_instances() } EntitySecurityState::Securified { value } => { - value.unique_factor_instances() + value.unique_tx_signing_factor_instances() + } + } + } + fn unique_all_factor_instances(&self) -> IndexSet { + match self { + EntitySecurityState::Unsecured { value } => { + value.unique_all_factor_instances() + } + EntitySecurityState::Securified { value } => { + value.unique_all_factor_instances() } } } @@ -703,14 +713,14 @@ mod tests { } #[test] - fn unique_factor_instances() { + fn unique_tx_signing_factor_instances() { let unsecured = UnsecuredEntityControl::sample(); let sut = SUT::Unsecured { value: unsecured.clone(), }; assert_eq!( - sut.unique_factor_instances(), - unsecured.unique_factor_instances() + sut.unique_tx_signing_factor_instances(), + unsecured.unique_tx_signing_factor_instances() ); let secured = SecuredEntityControl::sample(); @@ -718,8 +728,8 @@ mod tests { value: secured.clone(), }; assert_eq!( - sut.unique_factor_instances(), - secured.unique_factor_instances() + sut.unique_tx_signing_factor_instances(), + secured.unique_tx_signing_factor_instances() ); } } diff --git a/crates/sargon/src/profile/v100/entity_security_state/unsecured_entity_control.rs b/crates/sargon/src/profile/v100/entity_security_state/unsecured_entity_control.rs index 5b6e95f9a..1acdba6df 100644 --- a/crates/sargon/src/profile/v100/entity_security_state/unsecured_entity_control.rs +++ b/crates/sargon/src/profile/v100/entity_security_state/unsecured_entity_control.rs @@ -30,7 +30,7 @@ impl HasProvisionalSecurifiedConfig for UnsecuredEntityControl { } impl HasFactorInstances for UnsecuredEntityControl { - fn unique_factor_instances(&self) -> IndexSet { + fn unique_tx_signing_factor_instances(&self) -> IndexSet { IndexSet::just(self.transaction_signing.factor_instance()) } } diff --git a/crates/sargon/src/profile/v100/profile.rs b/crates/sargon/src/profile/v100/profile.rs index 1b8dde339..97737fe2a 100644 --- a/crates/sargon/src/profile/v100/profile.rs +++ b/crates/sargon/src/profile/v100/profile.rs @@ -294,7 +294,7 @@ impl Profile { .items() .into_iter() .map(Into::::into) - .map(|e| (e.clone(), e.unique_factor_instances())) + .map(|e| (e.clone(), e.unique_tx_signing_factor_instances())) .collect::>>(); let Some(duplicate_instances) = self @@ -331,7 +331,7 @@ impl Profile { ) -> IndexMap> { self.all_entities_on_all_networks() .into_iter() - .map(|e| (e.clone(), e.unique_factor_instances())) + .map(|e| (e.clone(), e.unique_tx_signing_factor_instances())) .collect() } diff --git a/crates/sargon/src/profile/v100/profile_legacy_state_bugs.rs b/crates/sargon/src/profile/v100/profile_legacy_state_bugs.rs index ca0adc825..ea3fa8367 100644 --- a/crates/sargon/src/profile/v100/profile_legacy_state_bugs.rs +++ b/crates/sargon/src/profile/v100/profile_legacy_state_bugs.rs @@ -60,8 +60,8 @@ impl Profile { value: UnsecuredEntityControl::new(hd_fi, None).unwrap(), }; assert_eq!( - account.unique_factor_instances(), - persona.unique_factor_instances() + account.unique_tx_signing_factor_instances(), + persona.unique_tx_signing_factor_instances() ); sut.networks = ProfileNetworks::just(ProfileNetwork::new( NetworkID::Mainnet, @@ -103,8 +103,8 @@ impl Profile { }; assert_eq!( - account.unique_factor_instances(), - account2.unique_factor_instances() + account.unique_tx_signing_factor_instances(), + account2.unique_tx_signing_factor_instances() ); sut.networks = ProfileNetworks::just(ProfileNetwork::new( NetworkID::Mainnet, @@ -175,8 +175,8 @@ impl Profile { }; assert_eq!( - persona1.unique_factor_instances(), - persona2.unique_factor_instances() + persona1.unique_tx_signing_factor_instances(), + persona2.unique_tx_signing_factor_instances() ); sut.networks = ProfileNetworks::just(ProfileNetwork::new( NetworkID::Mainnet, @@ -212,7 +212,7 @@ mod tests { let accounts = sut.accounts_on_current_network().unwrap(); let acc = accounts.first().unwrap(); let factor_instance = acc - .unique_factor_instances() + .unique_tx_signing_factor_instances() .into_iter() .next() .clone() @@ -286,7 +286,7 @@ mod tests { let e1 = e1.into(); let factor_instance = e1 - .unique_factor_instances() + .unique_tx_signing_factor_instances() .into_iter() .next() .clone() diff --git a/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/manifests_access_controller.rs b/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/manifests_access_controller.rs index 505931f66..d7c64c27f 100644 --- a/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/manifests_access_controller.rs +++ b/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/manifests_access_controller.rs @@ -1,8 +1,4 @@ -use radix_engine_interface::blueprints::{ - access_controller::AccessControllerCreateManifestInput as ScryptoAccessControllerCreateManifestInput, - account::ACCOUNT_SECURIFY_IDENT as SCRYPTO_ACCOUNT_SECURIFY_IDENT, - identity::IDENTITY_SECURIFY_IDENT as SCRYPTO_IDENTITY_SECURIFY_IDENT, -}; +use radix_engine_interface::blueprints::access_controller::AccessControllerCreateManifestInput as ScryptoAccessControllerCreateManifestInput; use crate::prelude::*; @@ -19,16 +15,19 @@ impl TransactionManifest { return Err(CommonError::Unknown); }; - Ok(Self::_securify_unsecurified_entity( + Self::_securify_unsecurified_entity( Into::::into(entity.address()), security_structure_of_factor_instances, - )) + ) } fn _securify_unsecurified_entity( entity_address: AddressOfAccountOrPersona, security_structure_of_factor_instances: SecurityStructureOfFactorInstances, - ) -> Self { + ) -> Result { + security_structure_of_factor_instances + .assert_has_entity_kind(entity_address.get_entity_kind())?; + let (security_entity_identifier, owner_badge) = if entity_address.is_identity() { ( @@ -90,6 +89,63 @@ impl TransactionManifest { ); } - TransactionManifest::sargon_built(builder, entity_address.network_id()) + let manifest = TransactionManifest::sargon_built( + builder, + entity_address.network_id(), + ); + + Ok(manifest) + } +} + +#[cfg(test)] +mod tests { + + use super::*; + + #[test] + fn test_securify_unsecurified_account() { + let expected_manifest = include_str!(concat!( + env!("FIXTURES_TX"), + "create_access_controller_for_account.rtm" + )); + let manifest = TransactionManifest::securify_unsecurified_entity( + Account::sample(), + SecurityStructureOfFactorInstances::sample(), + ) + .unwrap(); + manifest_eq(manifest, expected_manifest); + } + + #[test] + fn test_securify_unsecurified_persona() { + let expected_manifest = include_str!(concat!( + env!("FIXTURES_TX"), + "create_access_controller_for_persona.rtm" + )); + let manifest = TransactionManifest::securify_unsecurified_entity( + Persona::sample_other(), + SecurityStructureOfFactorInstances::sample_other(), + ) + .unwrap(); + manifest_eq(manifest, expected_manifest); + } + + #[test] + fn test_mismatch_entity_kind_account_persona() { + let manifest = TransactionManifest::securify_unsecurified_entity( + Account::sample_other(), + SecurityStructureOfFactorInstances::sample_other(), + ); + assert_eq!(manifest, Err(CommonError::SecurityStructureOfFactorInstancesEntityDiscrepancyInEntityKind { entity_kind_of_entity: CAP26EntityKind::Account, entity_kind_of_factor_instances: CAP26EntityKind::Identity })); + } + + #[test] + fn test_mismatch_entity_kind_persona_account() { + let manifest = TransactionManifest::securify_unsecurified_entity( + Persona::sample_other(), + SecurityStructureOfFactorInstances::sample(), + ); + assert_eq!(manifest, Err(CommonError::SecurityStructureOfFactorInstancesEntityDiscrepancyInEntityKind { entity_kind_of_entity: CAP26EntityKind::Identity, entity_kind_of_factor_instances: CAP26EntityKind::Account })); } } From d68c5971b33508151d65fbb66434f59d8e3ba828 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Mon, 16 Dec 2024 14:55:46 +0100 Subject: [PATCH 13/60] update readme --- README.md | 270 ++++++++++-------- .../matrices/matrix_of_factor_instances.rs | 2 +- ...gon_os_entities_linked_to_factor_source.rs | 1 + 3 files changed, 150 insertions(+), 123 deletions(-) diff --git a/README.md b/README.md index b1a777725..46e436f91 100644 --- a/README.md +++ b/README.md @@ -37,11 +37,14 @@ xcode-select --install Or install `Xcode` from App Store After installing, you should run the following command to verify the SDK path is set to the Xcode app under `Applications`. + ```sh $ xcrun --show-sdk-path /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk ``` + If it doesn't point to the expected path (and instead points to something like `/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk`), make sure you have the PATH exported on your profile (e.g. `.zshrc`): + ``` export PATH="/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin" ``` @@ -161,131 +164,138 @@ Alternatively if you wanna skip code cove ## Android ### Prerequisites +
MacOs -* #### Install `jenv` - ```sh - brew install jenv - ``` - Dont forget to add to eval to zsh - ```sh - export PATH="$HOME/.jenv/bin:$PATH" - eval "$(jenv init -)" - ``` - -* #### Install Java (openjdk@17) - ```sh - brew install openjdk@17 - ``` - #### Add `openjdk` version to `jenv` - ```sh - jenv add /opt/homebrew/Cellar/openjdk@17/17.0.10/libexec/openjdk.jdk/Contents/Home/ - ``` -* #### `cargo-ndk` - ```sh - cargo install cargo-ndk - ``` -* Download the Command Line tools [here](https://developer.android.com/studio#command-tools) and unzip - ```sh - mkdir -p ~/Library/Android/sdk/cmdline-tools - mv /cmdline-tools ~/Library/Android/sdk/cmdline-tools/latest - ``` - ```sh - ## In your profile (like .zshrc) - export ANDROID_HOME=$HOME/Library/Android/sdk - export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin - export PATH=$PATH:$ANDROID_HOME/platform-tools - # Make sure to also include the SDK ROOT in order to build the mac os desktop binaries - export SDKROOT="`xcrun --show-sdk-path` - ``` - ```sh - ## Source your profile - source ~/.zshrc - ``` - ```sh - ## Assert that it works with - sdkmanager --version - ``` -* Download the latest ndk - ```sh - ## Print the list of available ANDKs - sdkmanager --list | grep ndk - ``` - ```sh - ## Install the latest ndk like ndk;27.1.12297006 - sdkmanager --install "ndk;" - ``` - ```sh - ## Export ndk - ## In your profile (like .bashrc, or .zshrc etc) - export ANDROID_NDK_HOME=$ANDROID_HOME/ndk - ``` -
+- #### Install `jenv` + + ```sh + brew install jenv + ``` + + Dont forget to add to eval to zsh + + ```sh + export PATH="$HOME/.jenv/bin:$PATH" + eval "$(jenv init -)" + ``` + +- #### Install Java (openjdk@17) + ```sh + brew install openjdk@17 + ``` + #### Add `openjdk` version to `jenv` + ```sh + jenv add /opt/homebrew/Cellar/openjdk@17/17.0.10/libexec/openjdk.jdk/Contents/Home/ + ``` +- #### `cargo-ndk` + ```sh + cargo install cargo-ndk + ``` +- Download the Command Line tools [here](https://developer.android.com/studio#command-tools) and unzip + ```sh + mkdir -p ~/Library/Android/sdk/cmdline-tools + mv /cmdline-tools ~/Library/Android/sdk/cmdline-tools/latest + ``` + ```sh + ## In your profile (like .zshrc) + export ANDROID_HOME=$HOME/Library/Android/sdk + export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin + export PATH=$PATH:$ANDROID_HOME/platform-tools + # Make sure to also include the SDK ROOT in order to build the mac os desktop binaries + export SDKROOT="`xcrun --show-sdk-path` + ``` + ```sh + ## Source your profile + source ~/.zshrc + ``` + ```sh + ## Assert that it works with + sdkmanager --version + ``` +- Download the latest ndk + ```sh + ## Print the list of available ANDKs + sdkmanager --list | grep ndk + ``` + ```sh + ## Install the latest ndk like ndk;27.1.12297006 + sdkmanager --install "ndk;" + ``` + ```sh + ## Export ndk + ## In your profile (like .bashrc, or .zshrc etc) + export ANDROID_NDK_HOME=$ANDROID_HOME/ndk + ``` +
Linux -* #### (Optional) Install build essentials - ```sh - apt-get install build-essential - apt-get install cmake - ``` -* #### Install Java (openjdk-17) - ```sh - apt-get install openjdk-17-jre - ``` -* #### `cargo-ndk` - ```sh - cargo install cargo-ndk - ``` -* Download the Command Line tools [here](https://developer.android.com/studio#command-tools) and unzip - ```sh - mkdir -p ~/Library/Android/sdk/cmdline-tools - mv /cmdline-tools ~/Library/Android/sdk/cmdline-tools/latest - ``` - ```sh - ## In your profile (like .zshrc) - export ANDROID_HOME=$HOME/Library/Android/sdk - export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin - export PATH=$PATH:$ANDROID_HOME/platform-tools - ``` - ```sh - ## Source your profile - source ~/.bashrc - ``` - ```sh - ## Assert that it works with - sdkmanager --version - ``` -* Download the latest ndk - ```sh - ## Print the list of available ANDKs - sdkmanager --list | grep ndk - ``` - ```sh - ## Install the latest ndk like ndk;27.1.12297006 - sdkmanager --install "ndk;" - ``` - ```sh - ## Export ndk - ## In your profile (like .bashrc, or .zshrc etc) - export ANDROID_NDK_HOME=$ANDROID_HOME/ndk - ``` -
+- #### (Optional) Install build essentials + ```sh + apt-get install build-essential + apt-get install cmake + ``` +- #### Install Java (openjdk-17) + ```sh + apt-get install openjdk-17-jre + ``` +- #### `cargo-ndk` + ```sh + cargo install cargo-ndk + ``` +- Download the Command Line tools [here](https://developer.android.com/studio#command-tools) and unzip + ```sh + mkdir -p ~/Library/Android/sdk/cmdline-tools + mv /cmdline-tools ~/Library/Android/sdk/cmdline-tools/latest + ``` + ```sh + ## In your profile (like .zshrc) + export ANDROID_HOME=$HOME/Library/Android/sdk + export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin + export PATH=$PATH:$ANDROID_HOME/platform-tools + ``` + ```sh + ## Source your profile + source ~/.bashrc + ``` + ```sh + ## Assert that it works with + sdkmanager --version + ``` +- Download the latest ndk + ```sh + ## Print the list of available ANDKs + sdkmanager --list | grep ndk + ``` + ```sh + ## Install the latest ndk like ndk;27.1.12297006 + sdkmanager --install "ndk;" + ``` + ```sh + ## Export ndk + ## In your profile (like .bashrc, or .zshrc etc) + export ANDROID_NDK_HOME=$ANDROID_HOME/ndk + ``` + ### Install Rust targets (Android) + ```sh rustup target add aarch64-linux-android armv7-linux-androideabi ``` ### Install Rust targets (Desktop Binaries) +
MacOs ```sh rustup target add aarch64-apple-darwin ``` +
@@ -294,9 +304,11 @@ rustup target add aarch64-apple-darwin ```sh rustup target add x86_64-unknown-linux-gnu ``` +
### Build + ```sh cd jvm # (Debug) @@ -306,10 +318,13 @@ cd jvm ``` ### Unit Tests (Running locally) + ```sh ./gradlew sargon-android:testDebugUnitTest ``` + ### Instrumentation Tests (Running on a device) + ```sh # Make sure you have a device or emulator is connected to ADB ./gradlew sargon-android:connectedDebugAndroidTest @@ -321,6 +336,9 @@ cd jvm ### Locally +> [!TIP] +> We really recommend you release using CD. + #### Prerequisites > [!IMPORTANT] @@ -379,22 +397,28 @@ See [`.github/workflows/release.yml`](.github/workflows/release.yml) ## Android ### Locally -In order to build sargon for local development we will leverage the local maven repository. Instead of publishing the package in a maven server, we can publish it locally. -In order to publish both android and desktop binaries with a simple command run +In order to build sargon for local development we will leverage the local maven repository. Instead of publishing the package in a maven server, we can publish it locally. + +In order to publish both android and desktop binaries with a simple command run + ```sh cd jvm/ ./gradlew sargon-android:buildForLocalDev // This builds both sargon-android and sargon-desktop-bins ``` + This will produce the following message when successfully finished + ```txt > Task :sargon-android:buildForLocalDev ✅ Library is published in maven local with version: 1.1.19-c74d9cbf-SNAPSHOT ``` + Note that such local maven builds are in debug mode and have a `-SNAPSHOT` suffix. -Copy the version name to your project but make sure that `mavenLocal()` is included in your project's `settings.gradle` +Copy the version name to your project but make sure that `mavenLocal()` is included in your project's `settings.gradle` + ```gradle dependencyResolutionManagement { ... @@ -404,8 +428,10 @@ dependencyResolutionManagement { } } ``` + > [!TIP] > The libraries that are published in local maven will reside in: +> > ``` > $HOME/.m2/repository/com/radixdlt/sargon > ``` @@ -414,29 +440,29 @@ dependencyResolutionManagement { Two modules are published in [Github's maven](https://github.com/radixdlt/sargon/packages/). -- `sargon-android` +- `sargon-android` - (See [`.github/workflows/release-android.yml`](.github/workflows/release-android.yml)) + (See [`.github/workflows/release-android.yml`](.github/workflows/release-android.yml)) - Contains the generated UniFFi Kotlin code and the runtime sargon binaries, in different architectures. It also contains the JNA dependency. + Contains the generated UniFFi Kotlin code and the runtime sargon binaries, in different architectures. It also contains the JNA dependency. - Import with: + Import with: - ``` - implementation("com.radixdlt.sargon:sargon-android:") - ``` + ``` + implementation("com.radixdlt.sargon:sargon-android:") + ``` -- `sargon-desktop-bins` +- `sargon-desktop-bins` - (See [`.github/workflows/release-desktop-bins.yml`](.github/workflows/release-desktop.yml)) + (See [`.github/workflows/release-desktop-bins.yml`](.github/workflows/release-desktop.yml)) - Contains only the runtime sargon binaries, built for desktop. Used when running Unit tests. + Contains only the runtime sargon binaries, built for desktop. Used when running Unit tests. - Import with: + Import with: - ``` - testRuntimeOnly("com.radixdlt.sargon:sargon-desktop-bins:") - ``` + ``` + testRuntimeOnly("com.radixdlt.sargon:sargon-desktop-bins:") + ``` > [!IMPORTANT] > Currently only supporting `aarch64-apple-darwin` (apple silicon) and `x86_64-unknown-linux-gnu`. So when running Unit tests for your client app, make sure to run them on an apple silicon or linux machine. We can add more architectures in the future, if requested. diff --git a/crates/sargon/src/profile/mfa/security_structures/matrices/matrix_of_factor_instances.rs b/crates/sargon/src/profile/mfa/security_structures/matrices/matrix_of_factor_instances.rs index cc71081ec..035a6656e 100644 --- a/crates/sargon/src/profile/mfa/security_structures/matrices/matrix_of_factor_instances.rs +++ b/crates/sargon/src/profile/mfa/security_structures/matrices/matrix_of_factor_instances.rs @@ -44,7 +44,7 @@ pub trait HasFactorInstances { } let index_agnostic_path = - factors.iter().next().unwrap().derivation_path().agnostic(); + factors.first().unwrap().derivation_path().agnostic(); if factors .iter() diff --git a/crates/sargon/src/system/sargon_os/sargon_os_entities_linked_to_factor_source.rs b/crates/sargon/src/system/sargon_os/sargon_os_entities_linked_to_factor_source.rs index 2563786d2..dff0497a5 100644 --- a/crates/sargon/src/system/sargon_os/sargon_os_entities_linked_to_factor_source.rs +++ b/crates/sargon/src/system/sargon_os/sargon_os_entities_linked_to_factor_source.rs @@ -232,6 +232,7 @@ mod tests { /// - 1 visible Account (sample_stokenet_nadia) /// - 1 hidden Account (sample_stokenet_olivia) /// - 1 visible Persona (sample_stokenet_leia_skywalker) + /// /// And the corresponding mocked secure/unsafe storages. async fn boot_with_entities( device_mnemonic_in_secure_storage: bool, From 9c8e7bcdb3a400744925f902af75da22a7fbfbc1 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Mon, 16 Dec 2024 16:23:19 +0100 Subject: [PATCH 14/60] fix swift --- .../Sargon/Protocols/EntityProtocol.swift | 19 ++---- .../Profile/Account/AccountTests.swift | 6 -- .../security_structure_of_factor_instances.rs | 43 +++++++++++++ .../profile/v100/entity_security_state/mod.rs | 2 + .../provisional_securified_config.rs | 60 +++---------------- ...ovisional_securified_transaction_queued.rs | 58 ++++++++++++++++++ 6 files changed, 117 insertions(+), 71 deletions(-) create mode 100644 crates/sargon/src/profile/v100/entity_security_state/provisional_securified_transaction_queued.rs diff --git a/apple/Sources/Sargon/Protocols/EntityProtocol.swift b/apple/Sources/Sargon/Protocols/EntityProtocol.swift index 507df188f..8d5efe427 100644 --- a/apple/Sources/Sargon/Protocols/EntityProtocol.swift +++ b/apple/Sources/Sargon/Protocols/EntityProtocol.swift @@ -41,31 +41,25 @@ extension EntityBaseProtocol { flags.contains(.hiddenByUser) } + // TODO: MOVE TO SARGON public var virtualHierarchicalDeterministicFactorInstances: Set { var factorInstances = Set() switch securityState { case let .unsecured(unsecuredEntityControl): factorInstances.insert(unsecuredEntityControl.transactionSigning) - if let authSigning = unsecuredEntityControl.authenticationSigning { - factorInstances.insert(authSigning) - } return factorInstances - // TODO: Handle when MFA is integrated -// case .securified(value: let value): -// return [] } } + // TODO: MOVE TO SARGON public var hasAuthenticationSigningKey: Bool { switch securityState { case let .unsecured(unsecuredEntityControl): - unsecuredEntityControl.authenticationSigning != nil - // TODO: Handle when MFA is integrated -// case .securified(value: let value): -// false // TODO handle that in the future + false } } + // TODO: MOVE TO SARGON public var deviceFactorSourceID: FactorSourceIDFromHash? { switch self.securityState { case let .unsecured(control): @@ -75,9 +69,6 @@ extension EntityBaseProtocol { } return factorSourceID - // TODO: Handle when MFA is integrated -// case .securified(value: _): -// return nil // TODO handle that in the future } } } @@ -155,7 +146,7 @@ extension EntityProtocol { self.init( networkID: networkID, address: address, - securityState: .unsecured(value: .init(transactionSigning: factorInstance, authenticationSigning: nil)), + securityState: .unsecured(value: .init(transactionSigning: factorInstance, provisional: nil)), displayName: displayName, extraProperties: extraProperties ) diff --git a/apple/Tests/TestCases/Profile/Account/AccountTests.swift b/apple/Tests/TestCases/Profile/Account/AccountTests.swift index a98dc0e20..2b56e5962 100644 --- a/apple/Tests/TestCases/Profile/Account/AccountTests.swift +++ b/apple/Tests/TestCases/Profile/Account/AccountTests.swift @@ -43,12 +43,6 @@ final class AccountTests: EntityProtocolTest { XCTAssertNil(sut.deviceFactorSourceID) } - func test_virtual_hd_deterministic_factor_instances_includes_auth_signing_if_set() { - var sut = SUT.sample - sut.securityState = .unsecured(value: .init(transactionSigning: .sample, authenticationSigning: .sampleOther)) - XCTAssertEqual(sut.virtualHierarchicalDeterministicFactorInstances.count, 2) - } - func test_new() { let fi: HierarchicalDeterministicFactorInstance = .sample let sut = SUT(networkID: .sample, factorInstance: fi, displayName: .sample, extraProperties: .sample) diff --git a/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_instances.rs b/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_instances.rs index fd624d18e..feb247c91 100644 --- a/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_instances.rs +++ b/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_instances.rs @@ -126,6 +126,17 @@ mod tests { assert_eq!(SUT::sample_other(), SUT::sample_other()); } + #[test] + fn unique_all_factor_instances() { + let sut = SUT::sample(); + assert!(sut + .unique_all_factor_instances() + .into_iter() + .map(|f| f.try_as_hd_factor_instances().unwrap()) + .any(|f| f.derivation_path().get_key_kind() + == CAP26KeyKind::AuthenticationSigning)); + } + #[test] fn inequality() { assert_ne!(SUT::sample(), SUT::sample_other()); @@ -137,6 +148,38 @@ mod tests { assert_eq!(sut.timed_recovery_delay_in_minutes(), 20160); } + #[test] + fn wrong_entity_kind_of_auth_signing_factor() { + let res = SUT::new(SecurityStructureID::sample(), MatrixOfFactorInstances::sample(), HierarchicalDeterministicFactorInstance::sample_with_key_kind_entity_kind_on_network_and_hardened_index(NetworkID::Mainnet, CAP26KeyKind::AuthenticationSigning, CAP26EntityKind::Identity, Hardened::Securified(SecurifiedU30::ZERO))); + assert!(matches!( + res, + Err(CommonError::WrongEntityKindOfInFactorInstancesPath) + )); + } + + #[test] + fn id() { + assert_eq!(SUT::sample().id(), SUT::sample().security_structure_id); + } + + #[test] + fn wrong_key_kind_of_auth_signing_factor() { + let res = SUT::new(SecurityStructureID::sample(), MatrixOfFactorInstances::sample(), HierarchicalDeterministicFactorInstance::sample_with_key_kind_entity_kind_on_network_and_hardened_index(NetworkID::Mainnet, CAP26KeyKind::TransactionSigning, CAP26EntityKind::Account, Hardened::Securified(SecurifiedU30::ZERO))); + assert!(matches!( + res, + Err(CommonError::WrongKeyKindOfAuthenticationSigningFactorInstance) + )); + } + + #[test] + fn auth_signing_factor_not_signing() { + let res = SUT::new(SecurityStructureID::sample(), MatrixOfFactorInstances::sample(), HierarchicalDeterministicFactorInstance::sample_with_key_kind_entity_kind_on_network_and_hardened_index(NetworkID::Mainnet, CAP26KeyKind::AuthenticationSigning, CAP26EntityKind::Account, Hardened::Unsecurified(UnsecurifiedHardened::ZERO))); + assert!(matches!( + res, + Err(CommonError::AuthenticationSigningFactorInstanceNotSecurified) + )); + } + #[test] fn json_roundtrip_sample_other() { let sut = SUT::sample_other(); diff --git a/crates/sargon/src/profile/v100/entity_security_state/mod.rs b/crates/sargon/src/profile/v100/entity_security_state/mod.rs index 644a39423..48ba2abb0 100644 --- a/crates/sargon/src/profile/v100/entity_security_state/mod.rs +++ b/crates/sargon/src/profile/v100/entity_security_state/mod.rs @@ -1,7 +1,9 @@ mod entity_security_state; mod provisional_securified_config; +mod provisional_securified_transaction_queued; mod unsecured_entity_control; pub use entity_security_state::*; pub use provisional_securified_config::*; +pub use provisional_securified_transaction_queued::*; pub use unsecured_entity_control::*; diff --git a/crates/sargon/src/profile/v100/entity_security_state/provisional_securified_config.rs b/crates/sargon/src/profile/v100/entity_security_state/provisional_securified_config.rs index 11fc7cd2b..34226de58 100644 --- a/crates/sargon/src/profile/v100/entity_security_state/provisional_securified_config.rs +++ b/crates/sargon/src/profile/v100/entity_security_state/provisional_securified_config.rs @@ -1,55 +1,13 @@ use crate::prelude::*; -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash)] -pub struct ProvisionalSecurifiedTransactionQueued { - pub factor_instances: SecurityStructureOfFactorInstances, - pub txid: TransactionIntentHash, -} - -impl ProvisionalSecurifiedTransactionQueued { - pub fn new( - factor_instances: SecurityStructureOfFactorInstances, - txid: TransactionIntentHash, - ) -> Self { - Self { - factor_instances, - txid, - } - } -} -impl HasSampleValues for ProvisionalSecurifiedTransactionQueued { - fn sample() -> Self { - Self::new( - SecurityStructureOfFactorInstances::sample(), - TransactionIntentHash::sample(), - ) - } - fn sample_other() -> Self { - Self::new( - SecurityStructureOfFactorInstances::sample_other(), - TransactionIntentHash::sample_other(), - ) - } -} -#[cfg(test)] -mod provisional_securified_transaction_queued_tests { - use super::*; - - #[allow(clippy::upper_case_acronyms)] - type SUT = ProvisionalSecurifiedTransactionQueued; - - #[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()); - } -} - +/// The different intermediary states of changing the security structure of an entity. +/// This type is put in an `Option` on either `UnsecuredEntityControl` or `SecurifiedEntityControl`, +/// and if `None` it means user has no provisionally changed security structure. If set, it contains +/// these different variants: +/// * `ShieldSelected` - User has selected which security shield to use for some entity, +/// * `FactorInstancesDerived` - Sargon has provided a `SecurityStructureOfFactorInstances` but +/// user has not made a transaction to apply it to the entity yet. +/// * `TransactionQueued` - User has signed and queued a transaction changing to `SecurityStructureOfFactorInstances` #[derive( Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash, EnumAsInner, )] @@ -67,7 +25,7 @@ pub enum ProvisionalSecurifiedConfig { value: SecurityStructureOfFactorInstances, }, - /// User has made queued a transaction to apply a `SecurityStructureOfFactorInstances` + /// User has signed and queued a transaction to apply a `SecurityStructureOfFactorInstances` /// but it has not been submitted (confirmed) yet. #[serde(rename = "transactionQueued")] TransactionQueued { diff --git a/crates/sargon/src/profile/v100/entity_security_state/provisional_securified_transaction_queued.rs b/crates/sargon/src/profile/v100/entity_security_state/provisional_securified_transaction_queued.rs new file mode 100644 index 000000000..18f296f89 --- /dev/null +++ b/crates/sargon/src/profile/v100/entity_security_state/provisional_securified_transaction_queued.rs @@ -0,0 +1,58 @@ +use crate::prelude::*; + +/// A tuple of a `SecurityStructureOfFactorInstances` and a `TransactionIntentHash` +/// which represents a queued transaction to which is changing the security structure +/// if some entity. Since this provisional state is set on the entity itself, no +/// need to store the entity address here. +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash)] +pub struct ProvisionalSecurifiedTransactionQueued { + /// The FactorInstances we are changing to. + pub factor_instances: SecurityStructureOfFactorInstances, + /// The ID of the queued transaction which is changing the security structure + /// to `factor_instances`. + pub txid: TransactionIntentHash, +} + +impl ProvisionalSecurifiedTransactionQueued { + pub fn new( + factor_instances: SecurityStructureOfFactorInstances, + txid: TransactionIntentHash, + ) -> Self { + Self { + factor_instances, + txid, + } + } +} +impl HasSampleValues for ProvisionalSecurifiedTransactionQueued { + fn sample() -> Self { + Self::new( + SecurityStructureOfFactorInstances::sample(), + TransactionIntentHash::sample(), + ) + } + fn sample_other() -> Self { + Self::new( + SecurityStructureOfFactorInstances::sample_other(), + TransactionIntentHash::sample_other(), + ) + } +} +#[cfg(test)] +mod provisional_securified_transaction_queued_tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = ProvisionalSecurifiedTransactionQueued; + + #[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()); + } +} From 6e56fa2be2e13b86f7a95d873230a1c36f44f6ff Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Mon, 16 Dec 2024 16:58:22 +0100 Subject: [PATCH 15/60] doc --- .../provisional_securified_config.rs | 16 ++ .../entity_security_state.rs | 208 +++++++++--------- ...ovisional_securified_transaction_queued.rs | 1 + 3 files changed, 117 insertions(+), 108 deletions(-) diff --git a/crates/sargon-uniffi/src/profile/v100/entity_security_state/provisional_securified_config.rs b/crates/sargon-uniffi/src/profile/v100/entity_security_state/provisional_securified_config.rs index ce62514b9..ebf499462 100644 --- a/crates/sargon-uniffi/src/profile/v100/entity_security_state/provisional_securified_config.rs +++ b/crates/sargon-uniffi/src/profile/v100/entity_security_state/provisional_securified_config.rs @@ -4,12 +4,28 @@ use sargon::{ ProvisionalSecurifiedTransactionQueued as InternalProvisionalSecurifiedTransactionQueued, }; +/// A tuple of a `SecurityStructureOfFactorInstances` and a `TransactionIntentHash` +/// which represents a queued transaction to which is changing the security structure +/// if some entity. Since this provisional state is set on the entity itself, no +/// need to store the entity address here. #[derive(Clone, PartialEq, Eq, Hash, InternalConversion, uniffi::Record)] pub struct ProvisionalSecurifiedTransactionQueued { + /// The FactorInstances we are changing to. pub factor_instances: SecurityStructureOfFactorInstances, + + /// The ID of the queued transaction which is changing the security structure + /// to `factor_instances`. pub txid: TransactionIntentHash, } +/// The different intermediary states of changing the security structure of an entity. +/// This type is put in an `Option` on either `UnsecuredEntityControl` or `SecurifiedEntityControl`, +/// and if `None` it means user has no provisionally changed security structure. If set, it contains +/// these different variants: +/// * `ShieldSelected` - User has selected which security shield to use for some entity, +/// * `FactorInstancesDerived` - Sargon has provided a `SecurityStructureOfFactorInstances` but +/// user has not made a transaction to apply it to the entity yet. +/// * `TransactionQueued` - User has signed and queued a transaction changing to `SecurityStructureOfFactorInstances` #[derive(Clone, PartialEq, Eq, Hash, InternalConversion, uniffi::Enum)] pub enum ProvisionalSecurifiedConfig { /// User has selected which security shield to use for some entity, diff --git a/crates/sargon/src/profile/v100/entity_security_state/entity_security_state.rs b/crates/sargon/src/profile/v100/entity_security_state/entity_security_state.rs index 4ce6af7d9..05434c5d7 100644 --- a/crates/sargon/src/profile/v100/entity_security_state/entity_security_state.rs +++ b/crates/sargon/src/profile/v100/entity_security_state/entity_security_state.rs @@ -47,13 +47,112 @@ impl HasProvisionalSecurifiedConfig for EntitySecurityState { } } +impl<'de> Deserialize<'de> for EntitySecurityState { + #[cfg(not(tarpaulin_include))] // false negative + fn deserialize>( + deserializer: D, + ) -> Result { + // https://github.com/serde-rs/serde/issues/1343#issuecomment-409698470 + #[derive(Deserialize, Serialize)] + struct Wrapper { + #[serde(flatten, with = "EntitySecurityState")] + value: EntitySecurityState, + } + Wrapper::deserialize(deserializer).map(|w| w.value) + } +} + +impl Serialize for EntitySecurityState { + #[cfg(not(tarpaulin_include))] // false negative + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut state = + serializer.serialize_struct("EntitySecurityState", 2)?; + match self { + EntitySecurityState::Unsecured { value } => { + state.serialize_field("discriminator", "unsecured")?; + state.serialize_field("unsecuredEntityControl", value)?; + } + EntitySecurityState::Securified { value } => { + state.serialize_field("discriminator", "securified")?; + state.serialize_field("securedEntityControl", value)?; + } + } + state.end() + } +} + +impl From for EntitySecurityState { + fn from(value: UnsecuredEntityControl) -> Self { + Self::Unsecured { value } + } +} + +impl From for EntitySecurityState { + fn from(value: SecuredEntityControl) -> Self { + Self::Securified { value } + } +} + +impl HasSampleValues for EntitySecurityState { + /// A sample used to facilitate unit tests. + fn sample() -> Self { + Self::Unsecured { + value: UnsecuredEntityControl::sample(), + } + } + + /// A sample used to facilitate unit tests. + fn sample_other() -> Self { + Self::Unsecured { + value: UnsecuredEntityControl::sample_other(), + } + } +} + +impl HasFactorInstances for EntitySecurityState { + fn unique_tx_signing_factor_instances(&self) -> IndexSet { + match self { + EntitySecurityState::Unsecured { value } => { + value.unique_tx_signing_factor_instances() + } + EntitySecurityState::Securified { value } => { + value.unique_tx_signing_factor_instances() + } + } + } + fn unique_all_factor_instances(&self) -> IndexSet { + match self { + EntitySecurityState::Unsecured { value } => { + value.unique_all_factor_instances() + } + EntitySecurityState::Securified { value } => { + value.unique_all_factor_instances() + } + } + } +} + #[cfg(test)] -mod has_provisional_securified_config_tests { +mod tests { use super::*; #[allow(clippy::upper_case_acronyms)] type SUT = EntitySecurityState; + #[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()); + } + fn set_provisional_is_err_when_provisional_is_tx_queued(sut: SUT) { let mut sut = sut; sut.set_provisional(ProvisionalSecurifiedConfig::TransactionQueued { @@ -217,113 +316,6 @@ mod has_provisional_securified_config_tests { SecuredEntityControl::sample_other(), )) } -} - -impl<'de> Deserialize<'de> for EntitySecurityState { - #[cfg(not(tarpaulin_include))] // false negative - fn deserialize>( - deserializer: D, - ) -> Result { - // https://github.com/serde-rs/serde/issues/1343#issuecomment-409698470 - #[derive(Deserialize, Serialize)] - struct Wrapper { - #[serde(flatten, with = "EntitySecurityState")] - value: EntitySecurityState, - } - Wrapper::deserialize(deserializer).map(|w| w.value) - } -} - -impl Serialize for EntitySecurityState { - #[cfg(not(tarpaulin_include))] // false negative - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut state = - serializer.serialize_struct("EntitySecurityState", 2)?; - match self { - EntitySecurityState::Unsecured { value } => { - state.serialize_field("discriminator", "unsecured")?; - state.serialize_field("unsecuredEntityControl", value)?; - } - EntitySecurityState::Securified { value } => { - state.serialize_field("discriminator", "securified")?; - state.serialize_field("securedEntityControl", value)?; - } - } - state.end() - } -} - -impl From for EntitySecurityState { - fn from(value: UnsecuredEntityControl) -> Self { - Self::Unsecured { value } - } -} - -impl From for EntitySecurityState { - fn from(value: SecuredEntityControl) -> Self { - Self::Securified { value } - } -} - -impl HasSampleValues for EntitySecurityState { - /// A sample used to facilitate unit tests. - fn sample() -> Self { - Self::Unsecured { - value: UnsecuredEntityControl::sample(), - } - } - - /// A sample used to facilitate unit tests. - fn sample_other() -> Self { - Self::Unsecured { - value: UnsecuredEntityControl::sample_other(), - } - } -} - -impl HasFactorInstances for EntitySecurityState { - fn unique_tx_signing_factor_instances(&self) -> IndexSet { - match self { - EntitySecurityState::Unsecured { value } => { - value.unique_tx_signing_factor_instances() - } - EntitySecurityState::Securified { value } => { - value.unique_tx_signing_factor_instances() - } - } - } - fn unique_all_factor_instances(&self) -> IndexSet { - match self { - EntitySecurityState::Unsecured { value } => { - value.unique_all_factor_instances() - } - EntitySecurityState::Securified { value } => { - value.unique_all_factor_instances() - } - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[allow(clippy::upper_case_acronyms)] - type SUT = EntitySecurityState; - - #[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 json_roundtrip_unsecurified() { diff --git a/crates/sargon/src/profile/v100/entity_security_state/provisional_securified_transaction_queued.rs b/crates/sargon/src/profile/v100/entity_security_state/provisional_securified_transaction_queued.rs index 18f296f89..14c8851d2 100644 --- a/crates/sargon/src/profile/v100/entity_security_state/provisional_securified_transaction_queued.rs +++ b/crates/sargon/src/profile/v100/entity_security_state/provisional_securified_transaction_queued.rs @@ -8,6 +8,7 @@ use crate::prelude::*; pub struct ProvisionalSecurifiedTransactionQueued { /// The FactorInstances we are changing to. pub factor_instances: SecurityStructureOfFactorInstances, + /// The ID of the queued transaction which is changing the security structure /// to `factor_instances`. pub txid: TransactionIntentHash, From a0f3e6a7973cb2b0e7ea219f48e2886cce29ac05 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Mon, 16 Dec 2024 17:54:52 +0100 Subject: [PATCH 16/60] removed unused code --- .../role_into_scrypto_access_rule.rs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/crates/sargon/src/profile/mfa/security_structures/roles/factor_levels/factor_instance_level/role_into_scrypto_access_rule.rs b/crates/sargon/src/profile/mfa/security_structures/roles/factor_levels/factor_instance_level/role_into_scrypto_access_rule.rs index 24acc5f40..9d977beca 100644 --- a/crates/sargon/src/profile/mfa/security_structures/roles/factor_levels/factor_instance_level/role_into_scrypto_access_rule.rs +++ b/crates/sargon/src/profile/mfa/security_structures/roles/factor_levels/factor_instance_level/role_into_scrypto_access_rule.rs @@ -45,19 +45,6 @@ impl From for ScryptoRuleSet { pub const MINUTES_PER_DAY: u32 = 24 * 60; -impl From for ScryptoRecoveryProposal { - fn from(value: SecurityStructureOfFactorInstances) -> Self { - let timed_recovery_delay_in_minutes = - value.timed_recovery_delay_in_minutes(); - Self { - rule_set: value.matrix_of_factors.into(), - timed_recovery_delay_in_minutes: Some( - timed_recovery_delay_in_minutes, - ), - } - } -} - #[cfg(test)] mod tests { use super::*; From 15200f5965f5374e8c7a1e49153521a0c5d43669 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Mon, 16 Dec 2024 20:20:45 +0100 Subject: [PATCH 17/60] more tests --- .../src/core/error/common_error.rs | 8 ++ crates/sargon/src/core/error/common_error.rs | 8 ++ .../secured_entity_control.rs | 11 +++ .../matrices/matrix_of_factor_instances.rs | 95 +++++++++++++++++++ ...rarchical_deterministic_factor_instance.rs | 5 +- crates/sargon/src/profile/v100/profile.rs | 2 +- .../authentication/authentication_signer.rs | 2 +- .../src/types/samples/account_samples.rs | 8 +- .../src/types/samples/persona_samples.rs | 8 +- .../manifests_access_controller.rs | 94 ++++++++++++++++-- .../low_level/public_key_hash.rs | 11 ++- 11 files changed, 234 insertions(+), 18 deletions(-) diff --git a/crates/sargon-uniffi/src/core/error/common_error.rs b/crates/sargon-uniffi/src/core/error/common_error.rs index 3758b41c8..759c67792 100644 --- a/crates/sargon-uniffi/src/core/error/common_error.rs +++ b/crates/sargon-uniffi/src/core/error/common_error.rs @@ -854,6 +854,14 @@ pub enum CommonError { entity_kind_of_entity: CAP26EntityKind, entity_kind_of_factor_instances: CAP26EntityKind, } = 10239, + + #[error( + "Cannot securify entity it is already securified according to profile" + )] + CannotSecurifyEntityItIsAlreadySecurifiedAccordingToProfile = 10240, + + #[error("Cannot securify entity that has provisional security config")] + CannotSecurifyEntityHasProvisionalSecurityConfig = 10241, } #[uniffi::export] diff --git a/crates/sargon/src/core/error/common_error.rs b/crates/sargon/src/core/error/common_error.rs index 33649ecf8..48a760836 100644 --- a/crates/sargon/src/core/error/common_error.rs +++ b/crates/sargon/src/core/error/common_error.rs @@ -851,6 +851,14 @@ pub enum CommonError { entity_kind_of_entity: CAP26EntityKind, entity_kind_of_factor_instances: CAP26EntityKind, } = 10239, + + #[error( + "Cannot securify entity it is already securified according to profile" + )] + CannotSecurifyEntityItIsAlreadySecurifiedAccordingToProfile = 10240, + + #[error("Cannot securify entity that has provisional security config")] + CannotSecurifyEntityHasProvisionalSecurityConfig = 10241, } impl CommonError { diff --git a/crates/sargon/src/profile/mfa/secured_entity_control/secured_entity_control.rs b/crates/sargon/src/profile/mfa/secured_entity_control/secured_entity_control.rs index 4762d028c..2d1e15dcf 100644 --- a/crates/sargon/src/profile/mfa/secured_entity_control/secured_entity_control.rs +++ b/crates/sargon/src/profile/mfa/secured_entity_control/secured_entity_control.rs @@ -194,6 +194,17 @@ mod tests { assert_eq!(SUT::sample_other(), SUT::sample_other()); } + #[test] + fn unique_all_factor_instances_includes_rola() { + let sut = SUT::sample(); + assert!(sut + .unique_all_factor_instances() + .into_iter() + .map(|f| f.try_as_hd_factor_instances().unwrap()) + .any(|f| f.derivation_path().get_key_kind() + == CAP26KeyKind::AuthenticationSigning)); + } + #[test] fn inequality() { assert_ne!(SUT::sample(), SUT::sample_other()); diff --git a/crates/sargon/src/profile/mfa/security_structures/matrices/matrix_of_factor_instances.rs b/crates/sargon/src/profile/mfa/security_structures/matrices/matrix_of_factor_instances.rs index 035a6656e..7c1fde0a2 100644 --- a/crates/sargon/src/profile/mfa/security_structures/matrices/matrix_of_factor_instances.rs +++ b/crates/sargon/src/profile/mfa/security_structures/matrices/matrix_of_factor_instances.rs @@ -329,6 +329,101 @@ mod tests { )); } + #[test] + fn empty_is_err() { + let invalid = unsafe { + SUT::unbuilt_with_roles_and_days( + PrimaryRoleWithFactorInstances::unbuilt_with_factors(0, [], []), + RecoveryRoleWithFactorInstances::unbuilt_with_factors( + 0, + [], + [], + ), + ConfirmationRoleWithFactorInstances::unbuilt_with_factors( + 0, + [], + [], + ), + 1, + ) + }; + let res = + invalid.index_agnostic_path_of_all_tx_signing_factor_instances(); + assert!(matches!( + res, + Err(CommonError::NoTransactionSigningFactorInstance) + )); + } + + #[test] + fn wrong_entity_kind() { + let invalid = unsafe { + SUT::unbuilt_with_roles_and_days( + PrimaryRoleWithFactorInstances::unbuilt_with_factors(0, [ + HierarchicalDeterministicFactorInstance::sample_mainnet_entity_device_factor_fs_0_securified_at_index( + CAP26EntityKind::Account, + 0, + ).into(), HierarchicalDeterministicFactorInstance::sample_mainnet_entity_device_factor_fs_0_securified_at_index( + CAP26EntityKind::Identity, // <--- Wrong entity kind + 1, + ).into()], []), + RecoveryRoleWithFactorInstances::unbuilt_with_factors( + 0, + [], + [], + ), + ConfirmationRoleWithFactorInstances::unbuilt_with_factors( + 0, + [], + [], + ), + 1, + ) + }; + let res = + invalid.index_agnostic_path_of_all_tx_signing_factor_instances(); + assert!(matches!( + res, + Err(CommonError::WrongEntityKindOfInFactorInstancesPath) + )); + } + + #[test] + fn wrong_key_kind() { + let invalid = unsafe { + SUT::unbuilt_with_roles_and_days( + PrimaryRoleWithFactorInstances::unbuilt_with_factors(0, [ + HierarchicalDeterministicFactorInstance::sample_mainnet_entity_device_factor_fs_0_securified_at_index( + CAP26EntityKind::Account, + 0, + ).into(), + HierarchicalDeterministicFactorInstance::sample_with_key_kind_entity_kind_on_network_and_hardened_index( + NetworkID::Mainnet, + CAP26KeyKind::AuthenticationSigning, // <-- Wrong key kind + CAP26EntityKind::Account, + SecurifiedU30::ZERO + ).into()], []), + RecoveryRoleWithFactorInstances::unbuilt_with_factors( + 0, + [], + [], + ), + ConfirmationRoleWithFactorInstances::unbuilt_with_factors( + 0, + [], + [], + ), + 1, + ) + }; + let res = + invalid.index_agnostic_path_of_all_tx_signing_factor_instances(); + assert!(matches!( + res, + Err(CommonError::WrongKeyKindOfTransactionSigningFactorInstance) + )); + } + #[test] fn err_if_empty_instance_found_for_factor_source() { assert!(matches!( diff --git a/crates/sargon/src/profile/v100/factors/hierarchical_deterministic_factor_instance.rs b/crates/sargon/src/profile/v100/factors/hierarchical_deterministic_factor_instance.rs index 74703f6be..bfedeacd3 100644 --- a/crates/sargon/src/profile/v100/factors/hierarchical_deterministic_factor_instance.rs +++ b/crates/sargon/src/profile/v100/factors/hierarchical_deterministic_factor_instance.rs @@ -227,7 +227,10 @@ impl HierarchicalDeterministicFactorInstance { /// Account | Mainnet /// A sample used to facilitate unit tests. - fn sample_with_key_kind(key_kind: CAP26KeyKind, index: u32) -> Self { + pub(crate) fn sample_with_key_kind( + key_kind: CAP26KeyKind, + index: u32, + ) -> Self { Self::sample_with_key_kind_entity_kind( key_kind, CAP26EntityKind::Account, diff --git a/crates/sargon/src/profile/v100/profile.rs b/crates/sargon/src/profile/v100/profile.rs index 97737fe2a..9d49a343d 100644 --- a/crates/sargon/src/profile/v100/profile.rs +++ b/crates/sargon/src/profile/v100/profile.rs @@ -331,7 +331,7 @@ impl Profile { ) -> IndexMap> { self.all_entities_on_all_networks() .into_iter() - .map(|e| (e.clone(), e.unique_tx_signing_factor_instances())) + .map(|e| (e.clone(), e.unique_all_factor_instances())) .collect() } diff --git a/crates/sargon/src/signing/authentication/authentication_signer.rs b/crates/sargon/src/signing/authentication/authentication_signer.rs index 7fffe81f2..d623be2e7 100644 --- a/crates/sargon/src/signing/authentication/authentication_signer.rs +++ b/crates/sargon/src/signing/authentication/authentication_signer.rs @@ -155,7 +155,7 @@ mod test { result, WalletToDappInteractionAuthProof::new( factor_instance.clone().public_key.public_key, - "9c0745dbfb85926a18936a3d7fde45b21fc9915f2361bde8f4149468f2cc857a6c8dca0bf202cd2d037eeb21ce57cbd5a52440bfdc73a8b5d70284f5cb64fc03".parse::().unwrap() + "be359ca8edf8dccb2155e841952e88591fe42903da7e9a1560e863fe2fea94ed412d9eed282d201d48e5602fcde9a1dc201f440e86cb5f919b493bafc0ba2002".parse::().unwrap() ) ); } diff --git a/crates/sargon/src/types/samples/account_samples.rs b/crates/sargon/src/types/samples/account_samples.rs index 41e6a6fd2..3d3c44d1f 100644 --- a/crates/sargon/src/types/samples/account_samples.rs +++ b/crates/sargon/src/types/samples/account_samples.rs @@ -171,6 +171,10 @@ impl Account { .collect_vec(), ); + let rola_index = u32::from( + veci.derivation_entity_index().index_in_local_key_space(), + ); + let network_id = NetworkID::Mainnet; let address = AccountAddress::new(veci.public_key(), NetworkID::Mainnet); @@ -183,8 +187,8 @@ impl Account { NetworkID::Mainnet, CAP26KeyKind::AuthenticationSigning, CAP26EntityKind::Account, - SecurifiedU30::ZERO, - ),// TODO: Remove hard coding? + SecurifiedU30::try_from(rola_index).unwrap(), + ), ) .unwrap(); diff --git a/crates/sargon/src/types/samples/persona_samples.rs b/crates/sargon/src/types/samples/persona_samples.rs index f0c545254..c4f50722c 100644 --- a/crates/sargon/src/types/samples/persona_samples.rs +++ b/crates/sargon/src/types/samples/persona_samples.rs @@ -204,6 +204,10 @@ impl Persona { let address = IdentityAddress::new(veci.public_key(), NetworkID::Mainnet); + let rola_index = u32::from( + veci.derivation_entity_index().index_in_local_key_space(), + ); + let security_structure_of_factor_instances = SecurityStructureOfFactorInstances::new( SecurityStructureID::sample(), @@ -212,8 +216,8 @@ impl Persona { NetworkID::Mainnet, CAP26KeyKind::AuthenticationSigning, CAP26EntityKind::Identity, - SecurifiedU30::ZERO, - ), // TODO: Remove hard coding? + SecurifiedU30::try_from(rola_index).unwrap(), + ), ) .unwrap(); diff --git a/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/manifests_access_controller.rs b/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/manifests_access_controller.rs index d7c64c27f..92850721f 100644 --- a/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/manifests_access_controller.rs +++ b/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/manifests_access_controller.rs @@ -8,11 +8,13 @@ impl TransactionManifest { security_structure_of_factor_instances: SecurityStructureOfFactorInstances, ) -> Result { let Ok(unsecurified) = entity.security_state().into_unsecured() else { - return Err(CommonError::Unknown); + return Err(CommonError::CannotSecurifyEntityItIsAlreadySecurifiedAccordingToProfile); }; if unsecurified.provisional.is_some() { - return Err(CommonError::Unknown); + return Err( + CommonError::CannotSecurifyEntityHasProvisionalSecurityConfig, + ); }; Self::_securify_unsecurified_entity( @@ -103,32 +105,104 @@ mod tests { use super::*; + #[test] + fn cannot_securify_entity_it_is_already_securified_according_to_profile() { + let account = Account::sample_at(2); + assert!(account.is_securified()); + let res = TransactionManifest::securify_unsecurified_entity( + account, + SecurityStructureOfFactorInstances::sample(), + ); + assert_eq!(res, Err(CommonError::CannotSecurifyEntityItIsAlreadySecurifiedAccordingToProfile)); + } + + #[test] + fn cannot_securify_entity_with_provisional() { + let mut account = Account::sample_alice(); + assert!(!account.is_securified()); + account + .security_state + .set_provisional(ProvisionalSecurifiedConfig::ShieldSelected { + value: SecurityStructureID::sample(), + }) + .unwrap(); + let res = TransactionManifest::securify_unsecurified_entity( + account, + SecurityStructureOfFactorInstances::sample(), + ); + assert_eq!( + res, + Err(CommonError::CannotSecurifyEntityHasProvisionalSecurityConfig) + ); + } + #[test] fn test_securify_unsecurified_account() { - let expected_manifest = include_str!(concat!( + let expected_manifest_str = include_str!(concat!( env!("FIXTURES_TX"), "create_access_controller_for_account.rtm" )); + let entity = Account::sample(); + let security_structure_of_factor_instances = + SecurityStructureOfFactorInstances::sample(); let manifest = TransactionManifest::securify_unsecurified_entity( - Account::sample(), - SecurityStructureOfFactorInstances::sample(), + entity.clone(), + security_structure_of_factor_instances.clone(), ) .unwrap(); - manifest_eq(manifest, expected_manifest); + manifest_eq(manifest, expected_manifest_str); + assert!(expected_manifest_str.contains("securify")); + assert!(expected_manifest_str.contains( + &security_structure_of_factor_instances + .timed_recovery_delay_in_minutes() + .to_string() + )); + + for fi in security_structure_of_factor_instances + .unique_all_factor_instances() + .into_iter() + .filter_map(|f| f.try_as_hd_factor_instances().ok()) + { + assert!(expected_manifest_str + .contains(&PublicKeyHash::hash(fi.public_key()).to_string())); + } + + assert!(expected_manifest_str.contains(&entity.address.to_string())); } #[test] fn test_securify_unsecurified_persona() { - let expected_manifest = include_str!(concat!( + let expected_manifest_str = include_str!(concat!( env!("FIXTURES_TX"), "create_access_controller_for_persona.rtm" )); + let entity = Persona::sample_other(); + let security_structure_of_factor_instances = + SecurityStructureOfFactorInstances::sample_other(); let manifest = TransactionManifest::securify_unsecurified_entity( - Persona::sample_other(), - SecurityStructureOfFactorInstances::sample_other(), + entity.clone(), + security_structure_of_factor_instances.clone(), ) .unwrap(); - manifest_eq(manifest, expected_manifest); + manifest_eq(manifest, expected_manifest_str); + + assert!(expected_manifest_str.contains("securify")); + assert!(expected_manifest_str.contains( + &security_structure_of_factor_instances + .timed_recovery_delay_in_minutes() + .to_string() + )); + + for fi in security_structure_of_factor_instances + .unique_all_factor_instances() + .into_iter() + .filter_map(|f| f.try_as_hd_factor_instances().ok()) + { + assert!(expected_manifest_str + .contains(&PublicKeyHash::hash(fi.public_key()).to_string())); + } + + assert!(expected_manifest_str.contains(&entity.address.to_string())); } #[test] diff --git a/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/public_key_hash.rs b/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/public_key_hash.rs index 67c31a4c4..a49854fdd 100644 --- a/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/public_key_hash.rs +++ b/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/public_key_hash.rs @@ -2,7 +2,16 @@ use crate::prelude::*; /// Hashes of public keys, either Ed25519PublicKey or Secp256k1PublicKey #[derive( - Clone, Copy, Debug, PartialEq, PartialOrd, Ord, EnumAsInner, Eq, Hash, + Clone, + Copy, + Debug, + PartialEq, + PartialOrd, + Ord, + EnumAsInner, + Eq, + Hash, + derive_more::Display, )] pub enum PublicKeyHash { Ed25519 { value: Exactly29Bytes }, From 67bc3862ccc9e014d72aa9ec8ff7d1c1920d0c62 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Tue, 17 Dec 2024 09:50:10 +0100 Subject: [PATCH 18/60] [no ci] WIP --- .../quantified_derivation_preset.rs | 7 + .../agnostic_paths/quantities.rs | 24 +++ .../factor_instances_cache.rs | 182 ++++++++++++------ .../provider/factor_instances_provider.rs | 125 +++++++----- ...ernal_factor_instances_provider_outcome.rs | 12 +- .../types/appendable_collection.rs | 2 +- .../client/factor_instances_cache_client.rs | 38 +++- 7 files changed, 278 insertions(+), 112 deletions(-) diff --git a/crates/sargon/src/factor_instances_provider/agnostic_paths/quantified_derivation_preset.rs b/crates/sargon/src/factor_instances_provider/agnostic_paths/quantified_derivation_preset.rs index 250ef7c82..09f55b73b 100644 --- a/crates/sargon/src/factor_instances_provider/agnostic_paths/quantified_derivation_preset.rs +++ b/crates/sargon/src/factor_instances_provider/agnostic_paths/quantified_derivation_preset.rs @@ -7,6 +7,13 @@ pub struct QuantifiedDerivationPreset { pub quantity: usize, } +impl Identifiable for QuantifiedDerivationPreset { + type ID = DerivationPreset; + fn id(&self) -> DerivationPreset { + self.derivation_preset.clone() + } +} + impl QuantifiedDerivationPreset { pub fn new(derivation_preset: DerivationPreset, quantity: usize) -> Self { Self { diff --git a/crates/sargon/src/factor_instances_provider/agnostic_paths/quantities.rs b/crates/sargon/src/factor_instances_provider/agnostic_paths/quantities.rs index e6349fbff..5c27bc320 100644 --- a/crates/sargon/src/factor_instances_provider/agnostic_paths/quantities.rs +++ b/crates/sargon/src/factor_instances_provider/agnostic_paths/quantities.rs @@ -2,3 +2,27 @@ use crate::prelude::*; /// The quantity of DerivationPreset's to fill cache with. pub const CACHE_FILLING_QUANTITY: usize = 30; + +/// The quantity of DerivationPreset's to fill cache with for `DerivationPreset::AccountVeci`. +pub const CACHE_FILLING_QUANTITY_ACCOUNT_VECI: usize = CACHE_FILLING_QUANTITY; + +/// The quantity of DerivationPreset's to fill cache with for `DerivationPreset::AccountMfa`. +pub const CACHE_FILLING_QUANTITY_ACCOUNT_MFA: usize = CACHE_FILLING_QUANTITY; + +/// The quantity of DerivationPreset's to fill cache with for `DerivationPreset::PersonaVeci`. +pub const CACHE_FILLING_QUANTITY_PERSONA_VECI: usize = CACHE_FILLING_QUANTITY; + +/// The quantity of DerivationPreset's to fill cache with for `DerivationPreset::PersonaMfa`. +pub const CACHE_FILLING_QUANTITY_PERSONA_MFA: usize = CACHE_FILLING_QUANTITY; + +impl DerivationPreset { + /// The quantity of DerivationPreset's to fill cache with. + pub fn cache_filling_quantity(&self) -> usize { + match self { + Self::AccountVeci => CACHE_FILLING_QUANTITY_ACCOUNT_VECI, + Self::AccountMfa => CACHE_FILLING_QUANTITY_ACCOUNT_MFA, + Self::PersonaVeci => CACHE_FILLING_QUANTITY_PERSONA_VECI, + Self::PersonaMfa => CACHE_FILLING_QUANTITY_PERSONA_MFA, + } + } +} diff --git a/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs b/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs index 85705106a..aee90eac8 100644 --- a/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs +++ b/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs @@ -220,108 +220,176 @@ impl FactorInstancesCache { .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( + /// Loads cached factor instances for the given network and factor source and + /// per derivation preset. The outcome is either a load from cache failure or + /// a `CachedInstancesWithQuantitiesOutcome` which is either a + /// `Satisfied` or `NotSatisfied` outcome. + /// + /// Satisfied means *fully satisfied*, i.e. all requested instances were + /// found in the cache. + /// + /// NotSatisfied means that the cache did not contain all the requested + /// instances, but it might have contained some of the quantity specified + /// per quantified derivation preset, and the rest must be derived, so + /// NotSatisfied contains the instances that were found in the cache and + /// the quantities to derive. + pub fn get_poly_factor_with_quantified_preset( &self, factor_source_ids: &IndexSet, - originally_requested_quantified_derivation_preset: &QuantifiedDerivationPreset, + quantified_derivation_presets: &IdentifiedVecOf< + 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::< + let mut pf_pdp = IndexMap::< FactorSourceIDFromHash, - IndexMap, + IndexMap< + DerivationPreset, + CacheInstancesAndRemainingQuantityToDerive, + >, >::new(); - let mut is_quantity_satisfied_for_all_factor_sources = true; for factor_source_id in factor_source_ids { + let mut pdp = IndexMap::< + DerivationPreset, + CacheInstancesAndRemainingQuantityToDerive, + >::new(); + for preset in DerivationPreset::all() { + let cache_filling_quantity = preset.cache_filling_quantity(); + 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 val = if let Some(quantified_derivation_preset) = + quantified_derivation_presets.get_id(preset) { - let satisfies_requested_quantity = + // The `preset` was part of the originally requested preset + // with a target quantity. + let target_quantity = quantified_derivation_preset.quantity; + + let is_quantity_satisfied = count_in_cache >= target_quantity; - if satisfies_requested_quantity { + + if is_quantity_satisfied { // 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, + Some(CacheInstancesAndRemainingQuantityToDerive { // 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, - ); + instances_to_use_from_cache: for_preset + .split_at(target_quantity) + .0, + quantity_to_derive: 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 + 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(), - ); + + Some(CacheInstancesAndRemainingQuantityToDerive { + instances_to_use_from_cache: for_preset.clone(), + quantity_to_derive, + }) } - } else { - // Not originally requested derivation preset, calculate number + } else if count_in_cache < cache_filling_quantity { + // Not 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 quantity_to_derive = + cache_filling_quantity - count_in_cache; + + Some(CacheInstancesAndRemainingQuantityToDerive { + instances_to_use_from_cache: FactorInstances::default(), + quantity_to_derive, + }) + } else { + None + }; + if let Some(val) = val { + pdp.insert(preset, val); + } + + if pdp.is_empty() { + continue; } + pf_pdp.insert(factor_source_id, pdp); } } - let outcome = if is_quantity_satisfied_for_all_factor_sources { - CachedInstancesWithQuantitiesOutcome::Satisfied(pf_instances) + + // The instances in the cache cannot satisfy the requested quantity + // we must derive more! + let is_quantity_satisfied_for_all = pf_pdp.iter().any(|(_, pdp)| { + pdp.iter() + .any(|(_, ci)| ci.remaining_quantity_to_derive > 0) + }); + + let outcome = if is_quantity_satisfied_for_all { + CachedInstancesWithQuantitiesOutcome::Satisfied(CacheSatisfied { + cached_and_quantities_to_derive: pf_pdp + .into_iter() + .map(|(k, v)| { + ( + k, + v.into_iter() + .map(|x| x.instances_to_use_from_cache) + .collect(), + ) + }) + .collect(), + }) } else { - CachedInstancesWithQuantitiesOutcome::NotSatisfied { - partial_instances: pf_instances, - quantities_to_derive: pf_pdp_qty_to_derive, - } + CachedInstancesWithQuantitiesOutcome::NotSatisfied( + CacheNotSatisfied { + cached_and_quantities_to_derive: pf_pdp, + }, + ) }; Ok(outcome) } } +#[derive(Debug, PartialEq, Eq)] +pub struct CacheNotSatisfied { + /// PER FactorSourceID => PER DerivationPreset => CacheInstancesAndRemainingQuantityToDerive + pub cached_and_quantities_to_derive: IndexMap< + FactorSourceIDFromHash, + IndexMap, + >, +} + +#[derive(Debug, PartialEq, Eq)] +pub struct CacheSatisfied { + /// PER FactorSourceID => PER DerivationPreset => FactorInstances + pub cached_and_quantities_to_derive: IndexMap< + FactorSourceIDFromHash, + IndexMap, + >, +} + +#[derive(Debug, PartialEq, Eq)] +pub struct CacheInstancesAndRemainingQuantityToDerive { + pub instances_to_use_from_cache: FactorInstances, // if empty then this was not a requested derivation preset, but we are cache filling and found `quantity_to_derive` needed to fill cache. + pub quantity_to_derive: usize, +} + #[derive(Debug, PartialEq, Eq, enum_as_inner::EnumAsInner)] pub enum CachedInstancesWithQuantitiesOutcome { - Satisfied(IndexMap), - NotSatisfied { - partial_instances: IndexMap, - quantities_to_derive: - IndexMap>, - }, + Satisfied(CacheSatisfied), + NotSatisfied(CacheNotSatisfied), } impl FactorInstancesCache { diff --git a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs index 0592a85a3..f68436b6e 100644 --- a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs @@ -53,11 +53,25 @@ impl FactorInstancesProvider { ) -> Result<( InstancesInCacheConsumer, InternalFactorInstancesProviderOutcome, + )> { + self.provide_for_presets( + IdentifiedVecOf::just(quantified_derivation_preset), + derivation_purpose, + ).await + } + + pub async fn provide_for_presets( + self, + quantified_derivation_presets: IdentifiedVecOf, + derivation_purpose: DerivationPurpose, + ) -> Result<( + InstancesInCacheConsumer, + InternalFactorInstancesProviderOutcome, )> { let mut _self = self; _self - ._provide(quantified_derivation_preset, derivation_purpose) + ._provide_for_presets(quantified_derivation_presets, derivation_purpose) .await } } @@ -84,9 +98,9 @@ impl FactorInstancesProvider { }) } - async fn _provide( + async fn _provide_for_presets( &mut self, - quantified_derivation_preset: QuantifiedDerivationPreset, + quantified_derivation_presets: IdentifiedVecOf, derivation_purpose: DerivationPurpose, ) -> Result<( InstancesInCacheConsumer, @@ -96,9 +110,9 @@ impl FactorInstancesProvider { let network_id = self.network_id; let cached = self .cache_client - .get_poly_factor_with_quantities( + .get_poly_factor_with_quantified_presets( &factor_sources.iter().map(|f| f.id_from_hash()).collect(), - &quantified_derivation_preset, + quantified_derivation_presets.clone(), network_id, ) .await?; @@ -119,15 +133,16 @@ impl FactorInstancesProvider { ), )) } - CachedInstancesWithQuantitiesOutcome::NotSatisfied { - quantities_to_derive, - partial_instances, - } => { - warn!("NotSatisfied, quantities_to_derive: {:?}, partial_instances: {:?}", quantities_to_derive, partial_instances); + CachedInstancesWithQuantitiesOutcome::NotSatisfied( + // quantities_to_derive, + // partial_instances, + unsatisfied + ) => { self.derive_more_and_cache( - quantified_derivation_preset, - partial_instances, - quantities_to_derive, + // quantified_derivation_preset, + // partial_instances, + // quantities_to_derive, + unsatisfied, derivation_purpose, ) .await @@ -137,48 +152,53 @@ impl FactorInstancesProvider { async fn derive_more_and_cache( &mut self, - quantified_derivation_preset: QuantifiedDerivationPreset, - pf_found_in_cache_leq_requested: IndexMap< - FactorSourceIDFromHash, - FactorInstances, - >, - pf_pdp_qty_to_derive: IndexMap< - FactorSourceIDFromHash, - IndexMap, - >, + // quantified_derivation_preset: QuantifiedDerivationPreset, + // pf_found_in_cache_leq_requested: IndexMap< + // FactorSourceIDFromHash, + // FactorInstances, + // >, + // pf_pdp_qty_to_derive: IndexMap< + // FactorSourceIDFromHash, + // IndexMap, + // >, + not_satisfied: IndexMap, derivation_purpose: DerivationPurpose, ) -> Result<( InstancesInCacheConsumer, InternalFactorInstancesProviderOutcome, )> { let pf_newly_derived = self - .derive_more(pf_pdp_qty_to_derive, derivation_purpose) + .derive_more + // (pf_pdp_qty_to_derive, + not_satisfied, + derivation_purpose) .await?; - let Split { - pf_to_use_directly, - pf_to_cache, - } = self.split( - &quantified_derivation_preset, - &pf_found_in_cache_leq_requested, - &pf_newly_derived, - ); + // let Split { + // pf_to_use_directly, + // pf_to_cache, + // } = self.split( + // &quantified_derivation_preset, + // &pf_found_in_cache_leq_requested, + // &pf_newly_derived, + // ); - let instances_in_cache_consumer = self - .make_instances_in_cache_consumer( - pf_found_in_cache_leq_requested.clone(), - ); + // let instances_in_cache_consumer = self + // .make_instances_in_cache_consumer( + // pf_found_in_cache_leq_requested.clone(), + // ); - self.cache_client.insert_all(&pf_to_cache).await?; + // self.cache_client.insert_all(&pf_to_cache).await?; - let outcome = InternalFactorInstancesProviderOutcome::transpose( - pf_to_cache, - pf_to_use_directly, - pf_found_in_cache_leq_requested, - pf_newly_derived, - ); - let outcome = outcome; - Ok((instances_in_cache_consumer, outcome)) + // let outcome = InternalFactorInstancesProviderOutcome::transpose( + // pf_to_cache, + // pf_to_use_directly, + // pf_found_in_cache_leq_requested, + // pf_newly_derived, + // ); + // let outcome = outcome; + // Ok((instances_in_cache_consumer, outcome)) + todo!() } /// Per factor, split the instances into those to use directly and those to cache. @@ -261,10 +281,11 @@ impl FactorInstancesProvider { pub(super) async fn derive_more( &self, - pf_pdp_quantity_to_derive: IndexMap< - FactorSourceIDFromHash, - IndexMap, - >, + // pf_pdp_quantity_to_derive: IndexMap< + // FactorSourceIDFromHash, + // IndexMap, + // >, + not_satisfied: IndexMap, derivation_purpose: DerivationPurpose, ) -> Result> { let factor_sources = self.factor_sources.clone(); @@ -277,8 +298,11 @@ impl FactorInstancesProvider { cache_snapshot, ); - let pf_paths = pf_pdp_quantity_to_derive - .into_iter() + let pf_paths = + not_satisfied.into_iter().flat_map(|(quantified_derivation_preset, not_satisfied)| { + // pf_pdp_quantity_to_derive + // .into_iter() + not_satisfied.quantities_to_derive.into_iter() .map(|(factor_source_id, pdp_quantity_to_derive)| { let paths = pdp_quantity_to_derive .into_iter() @@ -307,6 +331,7 @@ impl FactorInstancesProvider { Ok((factor_source_id, paths)) }) + }) .collect::>, >>()?; diff --git a/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs b/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs index d9a414d30..382d2829d 100644 --- a/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs +++ b/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs @@ -2,13 +2,21 @@ use crate::prelude::*; #[derive(Clone, Debug)] pub struct InternalFactorInstancesProviderOutcome { + pub per_derivation_preset: IndexMap< + DerivationPreset, + InternalFactorInstancesProviderOutcomePerFactor, + >, +} + +#[derive(Clone, Debug)] +pub struct InternalFactorInstancesProviderOutcomePerFactor { pub per_factor: IndexMap< FactorSourceIDFromHash, InternalFactorInstancesProviderOutcomeForFactor, >, } -impl InternalFactorInstancesProviderOutcome { +impl InternalFactorInstancesProviderOutcomePerFactor { pub fn new( per_factor: IndexMap< FactorSourceIDFromHash, @@ -144,7 +152,7 @@ mod tests { use super::*; #[allow(clippy::upper_case_acronyms)] - type SUT = InternalFactorInstancesProviderOutcome; + type SUT = InternalFactorInstancesProviderOutcomePerFactor; #[test] fn only_to_cache() { diff --git a/crates/sargon/src/factor_instances_provider/types/appendable_collection.rs b/crates/sargon/src/factor_instances_provider/types/appendable_collection.rs index c690578c6..117169660 100644 --- a/crates/sargon/src/factor_instances_provider/types/appendable_collection.rs +++ b/crates/sargon/src/factor_instances_provider/types/appendable_collection.rs @@ -34,7 +34,7 @@ pub trait AppendableMap { } } -/// A collection which we can append to, primlary used as a generic +/// A collection which we can append to, primarily used as a generic /// constraint for `AppendableMap`. pub trait AppendableCollection: FromIterator { type Element; diff --git a/crates/sargon/src/system/clients/client/factor_instances_cache_client.rs b/crates/sargon/src/system/clients/client/factor_instances_cache_client.rs index 9e21213b7..07fb76010 100644 --- a/crates/sargon/src/system/clients/client/factor_instances_cache_client.rs +++ b/crates/sargon/src/system/clients/client/factor_instances_cache_client.rs @@ -158,11 +158,45 @@ impl FactorInstancesCacheClient { .await } + pub async fn get_poly_factor_with_quantified_presets( + &self, + factor_source_ids: impl Borrow>, + quantified_derivation_presets: IdentifiedVecOf< + QuantifiedDerivationPreset, + >, + network_id: NetworkID, + ) -> Result { + let mut unaggregated = IndexMap::new(); + let mut is_satisfied = true; + for quantified_preset in quantified_derivation_presets.items() { + let part = self + .get_poly_factor_with_quantities( + factor_source_ids.borrow(), + quantified_preset, + network_id, + ) + .await?; + is_satisfied &= part.is_satisfied(); + unaggregated.insert(quantified_preset, part); + } + if is_satisfied { + let aggregated = IndexMap::new(); + todo!("impl me"); + Ok(CachedInstancesWithQuantitiesOutcome::Satisfied(aggregated)) + } else { + let aggregated = IndexMap::new(); + todo!("impl me"); + Ok(CachedInstancesWithQuantitiesOutcome::NotSatisfied( + unaggregated, + )) + } + } + /// 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 async fn get_poly_factor_with_quantities( + async fn get_poly_factor_with_quantities( &self, factor_source_ids: impl Borrow>, originally_requested_quantified_derivation_preset: impl Borrow< @@ -171,7 +205,7 @@ impl FactorInstancesCacheClient { network_id: NetworkID, ) -> Result { self.access_cache_init_if_needed(|cache| { - cache.get_poly_factor_with_quantities( + cache.get_poly_factor_with_quantified_preset( factor_source_ids.borrow(), originally_requested_quantified_derivation_preset.borrow(), network_id, From e54a5d322dad9783dba565bad0dd71feb48c2d3a Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Tue, 17 Dec 2024 10:15:03 +0100 Subject: [PATCH 19/60] polish --- .../Sargon/Protocols/EntityProtocol.swift | 11 ++++-- .../secured_entity_control.rs | 2 +- .../security_structure_of_factor_instances.rs | 3 ++ .../unsecured_entity_control.rs | 2 +- crates/sargon/src/core/utils/constants.rs | 3 ++ .../secured_entity_control.rs | 34 ++++++++++++------- .../role_into_scrypto_access_rule.rs | 2 -- .../security_structure_of_factor_instances.rs | 13 +++++-- .../entity_security_state.rs | 10 +++--- .../unsecured_entity_control.rs | 19 +++++++---- crates/sargon/src/profile/v100/profile.rs | 2 +- .../manifests_access_controller.rs | 2 +- 12 files changed, 68 insertions(+), 35 deletions(-) diff --git a/apple/Sources/Sargon/Protocols/EntityProtocol.swift b/apple/Sources/Sargon/Protocols/EntityProtocol.swift index 8d5efe427..8c151dda3 100644 --- a/apple/Sources/Sargon/Protocols/EntityProtocol.swift +++ b/apple/Sources/Sargon/Protocols/EntityProtocol.swift @@ -9,7 +9,9 @@ public protocol BaseBaseEntityProtocol: SargonModel {} #endif // DEBUG // MARK: - EntityBaseProtocol -public protocol EntityBaseProtocol: BaseBaseEntityProtocol, CustomStringConvertible, Identifiable where ID == EntityAddress { +public protocol EntityBaseProtocol: BaseBaseEntityProtocol, CustomStringConvertible, Identifiable + where ID == EntityAddress +{ associatedtype EntityAddress: BaseEntityAddressProtocol var networkId: NetworkID { get } var displayName: DisplayName { get } @@ -42,7 +44,9 @@ extension EntityBaseProtocol { } // TODO: MOVE TO SARGON - public var virtualHierarchicalDeterministicFactorInstances: Set { + public var virtualHierarchicalDeterministicFactorInstances: + Set + { var factorInstances = Set() switch securityState { case let .unsecured(unsecuredEntityControl): @@ -146,7 +150,8 @@ extension EntityProtocol { self.init( networkID: networkID, address: address, - securityState: .unsecured(value: .init(transactionSigning: factorInstance, provisional: nil)), + securityState: .unsecured( + value: .init(transactionSigning: factorInstance, provisionalSecurifiedConfig: nil)), displayName: displayName, extraProperties: extraProperties ) diff --git a/crates/sargon-uniffi/src/profile/mfa/secured_entity_control/secured_entity_control.rs b/crates/sargon-uniffi/src/profile/mfa/secured_entity_control/secured_entity_control.rs index 2582cdcd2..84874d88e 100644 --- a/crates/sargon-uniffi/src/profile/mfa/secured_entity_control/secured_entity_control.rs +++ b/crates/sargon-uniffi/src/profile/mfa/secured_entity_control/secured_entity_control.rs @@ -26,5 +26,5 @@ pub struct SecuredEntityControl { /// A provisional new security structure configuration which user /// is about to change to - pub provisional: Option, + pub provisional_securified_config: Option, } diff --git a/crates/sargon-uniffi/src/profile/mfa/security_structures/security_structures/security_structure_of_factor_instances.rs b/crates/sargon-uniffi/src/profile/mfa/security_structures/security_structures/security_structure_of_factor_instances.rs index 85f5406e3..fe1c1bdaf 100644 --- a/crates/sargon-uniffi/src/profile/mfa/security_structures/security_structures/security_structure_of_factor_instances.rs +++ b/crates/sargon-uniffi/src/profile/mfa/security_structures/security_structures/security_structure_of_factor_instances.rs @@ -4,6 +4,9 @@ use sargon::SecurityStructureOfFactorInstances as InternalSecurityStructureOfFac /// A MatrixOfFactorInstances and an ID which identifies it, this is /// the Profile data structure representation of the owner key hashes which /// have been uploaded as Scrypto AccessRules on the AccessController on-ledger. +/// +/// Also contains an authentication signing factor instance which is used for +/// Rola. #[derive(Clone, PartialEq, Eq, Hash, InternalConversion, uniffi::Record)] pub struct SecurityStructureOfFactorInstances { /// The ID of the `SecurityStructureOfFactorSourceIDs` in diff --git a/crates/sargon-uniffi/src/profile/v100/entity_security_state/unsecured_entity_control.rs b/crates/sargon-uniffi/src/profile/v100/entity_security_state/unsecured_entity_control.rs index d28e8f67a..faa951d6f 100644 --- a/crates/sargon-uniffi/src/profile/v100/entity_security_state/unsecured_entity_control.rs +++ b/crates/sargon-uniffi/src/profile/v100/entity_security_state/unsecured_entity_control.rs @@ -12,7 +12,7 @@ pub struct UnsecuredEntityControl { pub transaction_signing: HierarchicalDeterministicFactorInstance, /// The provisional security structure configuration - pub provisional: Option, + pub provisional_securified_config: Option, } #[uniffi::export] diff --git a/crates/sargon/src/core/utils/constants.rs b/crates/sargon/src/core/utils/constants.rs index b5aeba374..649fe36b5 100644 --- a/crates/sargon/src/core/utils/constants.rs +++ b/crates/sargon/src/core/utils/constants.rs @@ -27,3 +27,6 @@ pub const MIN_REQUIRED_XRD_FOR_ACCOUNT_DELETION: f64 = 4.0; /// The delay increment among polling requests is set to 1 second. /// This means that there will be a 2s delay after first call, a 3s delay after second call, 4s after third and so on. pub const POLLING_DELAY_INCREMENT_IN_SECONDS: u64 = 1; + +/// Number of minutes per day. +pub const MINUTES_PER_DAY: u32 = 24 * 60; diff --git a/crates/sargon/src/profile/mfa/secured_entity_control/secured_entity_control.rs b/crates/sargon/src/profile/mfa/secured_entity_control/secured_entity_control.rs index 2d1e15dcf..d25425ee2 100644 --- a/crates/sargon/src/profile/mfa/secured_entity_control/secured_entity_control.rs +++ b/crates/sargon/src/profile/mfa/secured_entity_control/secured_entity_control.rs @@ -30,19 +30,22 @@ pub struct SecuredEntityControl { /// A provisional new security structure configuration which user /// is about to change to #[serde(skip_serializing_if = "Option::is_none")] - pub provisional: Option, + pub provisional_securified_config: Option, } impl HasProvisionalSecurifiedConfig for SecuredEntityControl { fn get_provisional(&self) -> Option { - self.provisional.clone() + self.provisional_securified_config.clone() } fn set_provisional_unchecked( &mut self, - provisional: impl Into>, + provisional_securified_config: impl Into< + Option, + >, ) { - self.provisional = provisional.into(); + self.provisional_securified_config = + provisional_securified_config.into(); } } @@ -55,9 +58,11 @@ pub trait HasProvisionalSecurifiedConfig { /// this type fn set_provisional( &mut self, - provisional: impl Into>, + provisional_securified_config: impl Into< + Option, + >, ) -> Result<()> { - let provisional = provisional.into(); + let provisional = provisional_securified_config.into(); let maybe_existing = self.get_provisional(); let Some(existing) = maybe_existing.as_ref() else { return self.set_provisional_unchecked_ok(provisional); @@ -102,15 +107,19 @@ pub trait HasProvisionalSecurifiedConfig { fn set_provisional_unchecked_ok( &mut self, - provisional: impl Into>, + provisional_securified_config: impl Into< + Option, + >, ) -> Result<()> { - self.set_provisional_unchecked(provisional); + self.set_provisional_unchecked(provisional_securified_config); Ok(()) } fn set_provisional_unchecked( &mut self, - provisional: impl Into>, + provisional_securified_config: impl Into< + Option, + >, ); } @@ -145,7 +154,7 @@ impl SecuredEntityControl { veci, access_controller_address, security_structure, - provisional: None, + provisional_securified_config: None, }) } @@ -172,7 +181,8 @@ impl HasSampleValues for SecuredEntityControl { SecurityStructureOfFactorInstances::sample(), ) .unwrap(); - sample.provisional = Some(ProvisionalSecurifiedConfig::sample_other()); + sample.provisional_securified_config = + Some(ProvisionalSecurifiedConfig::sample_other()); sample } @@ -430,7 +440,7 @@ mod tests { } } }, - "provisional": { + "provisionalSecurifiedConfig": { "discriminator": "factorInstancesDerived", "value": { "securityStructureId": "dededede-dede-dede-dede-dededededede", diff --git a/crates/sargon/src/profile/mfa/security_structures/roles/factor_levels/factor_instance_level/role_into_scrypto_access_rule.rs b/crates/sargon/src/profile/mfa/security_structures/roles/factor_levels/factor_instance_level/role_into_scrypto_access_rule.rs index 9d977beca..99c0e1330 100644 --- a/crates/sargon/src/profile/mfa/security_structures/roles/factor_levels/factor_instance_level/role_into_scrypto_access_rule.rs +++ b/crates/sargon/src/profile/mfa/security_structures/roles/factor_levels/factor_instance_level/role_into_scrypto_access_rule.rs @@ -43,8 +43,6 @@ impl From for ScryptoRuleSet { } } -pub const MINUTES_PER_DAY: u32 = 24 * 60; - #[cfg(test)] mod tests { use super::*; diff --git a/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_instances.rs b/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_instances.rs index feb247c91..e1f4c205c 100644 --- a/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_instances.rs +++ b/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_instances.rs @@ -2,6 +2,13 @@ use indexmap::IndexSet; use crate::prelude::*; +/// A structure of factors to use for certain roles, Primary, Recovery and +/// Confirmation, as well as an authentication signing factor instance which is +/// used for Rola. +/// +/// This structure is identified by the `security_structure_id` which is the ID +/// of the `SecurityStructureOfFactorSourceIDs` which was used to derive the +/// instances in this structure. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] #[serde(rename_all = "camelCase")] pub struct SecurityStructureOfFactorInstances { @@ -49,8 +56,6 @@ impl SecurityStructureOfFactorInstances { ) -> Result { let index_agnostic_path = matrix_of_factors .index_agnostic_path_of_all_tx_signing_factor_instances()?; - let entity_kind = index_agnostic_path.entity_kind; - matrix_of_factors.assert_has_entity_kind(entity_kind)?; if authentication_signing.get_key_kind() != CAP26KeyKind::AuthenticationSigning @@ -60,7 +65,9 @@ impl SecurityStructureOfFactorInstances { ); } - if authentication_signing.get_entity_kind() != entity_kind { + if authentication_signing.get_entity_kind() + != index_agnostic_path.entity_kind + { return Err(CommonError::WrongEntityKindOfInFactorInstancesPath); } diff --git a/crates/sargon/src/profile/v100/entity_security_state/entity_security_state.rs b/crates/sargon/src/profile/v100/entity_security_state/entity_security_state.rs index 05434c5d7..1bab332e7 100644 --- a/crates/sargon/src/profile/v100/entity_security_state/entity_security_state.rs +++ b/crates/sargon/src/profile/v100/entity_security_state/entity_security_state.rs @@ -34,14 +34,16 @@ impl HasProvisionalSecurifiedConfig for EntitySecurityState { fn set_provisional_unchecked( &mut self, - provisional: impl Into>, + provisional_securified_config: impl Into< + Option, + >, ) { match self { Self::Unsecured { value } => { - value.set_provisional_unchecked(provisional) + value.set_provisional_unchecked(provisional_securified_config) } Self::Securified { value } => { - value.set_provisional_unchecked(provisional) + value.set_provisional_unchecked(provisional_securified_config) } } } @@ -571,7 +573,7 @@ mod tests { } } }, - "provisional": { + "provisionalSecurifiedConfig": { "discriminator": "factorInstancesDerived", "value": { "securityStructureId": "dededede-dede-dede-dede-dededededede", diff --git a/crates/sargon/src/profile/v100/entity_security_state/unsecured_entity_control.rs b/crates/sargon/src/profile/v100/entity_security_state/unsecured_entity_control.rs index 1acdba6df..481ac357b 100644 --- a/crates/sargon/src/profile/v100/entity_security_state/unsecured_entity_control.rs +++ b/crates/sargon/src/profile/v100/entity_security_state/unsecured_entity_control.rs @@ -13,19 +13,22 @@ pub struct UnsecuredEntityControl { /// The provisional security structure configuration #[serde(skip_serializing_if = "Option::is_none")] - pub provisional: Option, + pub provisional_securified_config: Option, } impl HasProvisionalSecurifiedConfig for UnsecuredEntityControl { fn get_provisional(&self) -> Option { - self.provisional.clone() + self.provisional_securified_config.clone() } fn set_provisional_unchecked( &mut self, - provisional: impl Into>, + provisional_securified_config: impl Into< + Option, + >, ) { - self.provisional = provisional.into(); + self.provisional_securified_config = + provisional_securified_config.into(); } } @@ -44,14 +47,16 @@ impl UnsecuredEntityControl { { Self { transaction_signing: entity_creating_factor_instance.into(), - provisional: None, + provisional_securified_config: None, } } #[cfg(not(tarpaulin_include))] // false negative pub fn new( transaction_signing: HierarchicalDeterministicFactorInstance, - provisional: impl Into>, + provisional_securified_config: impl Into< + Option, + >, ) -> Result { let key_kind = transaction_signing.get_key_kind(); if key_kind != CAP26KeyKind::TransactionSigning { @@ -61,7 +66,7 @@ impl UnsecuredEntityControl { } Ok(Self { transaction_signing, - provisional: provisional.into(), + provisional_securified_config: provisional_securified_config.into(), }) } diff --git a/crates/sargon/src/profile/v100/profile.rs b/crates/sargon/src/profile/v100/profile.rs index 9d49a343d..1644a7450 100644 --- a/crates/sargon/src/profile/v100/profile.rs +++ b/crates/sargon/src/profile/v100/profile.rs @@ -294,7 +294,7 @@ impl Profile { .items() .into_iter() .map(Into::::into) - .map(|e| (e.clone(), e.unique_tx_signing_factor_instances())) + .map(|e| (e.clone(), e.unique_all_factor_instances())) .collect::>>(); let Some(duplicate_instances) = self diff --git a/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/manifests_access_controller.rs b/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/manifests_access_controller.rs index 92850721f..ce39dcf24 100644 --- a/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/manifests_access_controller.rs +++ b/crates/sargon/src/wrapped_radix_engine_toolkit/high_level/manifest_building/manifests_access_controller.rs @@ -11,7 +11,7 @@ impl TransactionManifest { return Err(CommonError::CannotSecurifyEntityItIsAlreadySecurifiedAccordingToProfile); }; - if unsecurified.provisional.is_some() { + if unsecurified.provisional_securified_config.is_some() { return Err( CommonError::CannotSecurifyEntityHasProvisionalSecurityConfig, ); From 3ba71d3dd682de2a2e0e97e8d678711fa7d8b3d2 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Tue, 17 Dec 2024 10:29:55 +0100 Subject: [PATCH 20/60] fix typo --- .../security_structure_of_factor_instances.rs | 2 +- .../security_structure_of_factor_instances.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/sargon-uniffi/src/profile/mfa/security_structures/security_structures/security_structure_of_factor_instances.rs b/crates/sargon-uniffi/src/profile/mfa/security_structures/security_structures/security_structure_of_factor_instances.rs index fe1c1bdaf..78c7806b1 100644 --- a/crates/sargon-uniffi/src/profile/mfa/security_structures/security_structures/security_structure_of_factor_instances.rs +++ b/crates/sargon-uniffi/src/profile/mfa/security_structures/security_structures/security_structure_of_factor_instances.rs @@ -21,7 +21,7 @@ pub struct SecurityStructureOfFactorInstances { /// The authentication signing factor instance which is used to sign /// proof of ownership - aka "True Rola Key". User can select which FactorSource - /// to use during Shield Building, but typically most users will user the + /// to use during Shield Building, but typically most users will use the /// DeviceFactorSource which is default. DerivationPath is in securified /// KeySpace of course. /// diff --git a/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_instances.rs b/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_instances.rs index e1f4c205c..62794519a 100644 --- a/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_instances.rs +++ b/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_instances.rs @@ -24,7 +24,7 @@ pub struct SecurityStructureOfFactorInstances { /// The authentication signing factor instance which is used to sign /// proof of ownership - aka "True Rola Key". User can select which FactorSource - /// to use during Shield Building, but typically most users will user the + /// to use during Shield Building, but typically most users will use the /// DeviceFactorSource which is default. DerivationPath is in securified /// KeySpace of course. /// From a2f77c8e9ee645031573d872d3f494d6bf7c05c3 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Tue, 17 Dec 2024 11:47:59 +0100 Subject: [PATCH 21/60] [no ci] WIP --- .../agnostic_paths/quantities.rs | 12 +-- .../factor_instances_cache.rs | 87 ++++++++++++------- .../provider/factor_instances_provider.rs | 68 +++++++++------ 3 files changed, 103 insertions(+), 64 deletions(-) diff --git a/crates/sargon/src/factor_instances_provider/agnostic_paths/quantities.rs b/crates/sargon/src/factor_instances_provider/agnostic_paths/quantities.rs index 5c27bc320..e9971d99c 100644 --- a/crates/sargon/src/factor_instances_provider/agnostic_paths/quantities.rs +++ b/crates/sargon/src/factor_instances_provider/agnostic_paths/quantities.rs @@ -9,11 +9,11 @@ pub const CACHE_FILLING_QUANTITY_ACCOUNT_VECI: usize = CACHE_FILLING_QUANTITY; /// The quantity of DerivationPreset's to fill cache with for `DerivationPreset::AccountMfa`. pub const CACHE_FILLING_QUANTITY_ACCOUNT_MFA: usize = CACHE_FILLING_QUANTITY; -/// The quantity of DerivationPreset's to fill cache with for `DerivationPreset::PersonaVeci`. -pub const CACHE_FILLING_QUANTITY_PERSONA_VECI: usize = CACHE_FILLING_QUANTITY; +/// The quantity of DerivationPreset's to fill cache with for `DerivationPreset::IdentityVeci`. +pub const CACHE_FILLING_QUANTITY_IDENTITY_VECI: usize = CACHE_FILLING_QUANTITY; -/// The quantity of DerivationPreset's to fill cache with for `DerivationPreset::PersonaMfa`. -pub const CACHE_FILLING_QUANTITY_PERSONA_MFA: usize = CACHE_FILLING_QUANTITY; +/// The quantity of DerivationPreset's to fill cache with for `DerivationPreset::IdentityMfa`. +pub const CACHE_FILLING_QUANTITY_IDENTITY_MFA: usize = CACHE_FILLING_QUANTITY; impl DerivationPreset { /// The quantity of DerivationPreset's to fill cache with. @@ -21,8 +21,8 @@ impl DerivationPreset { match self { Self::AccountVeci => CACHE_FILLING_QUANTITY_ACCOUNT_VECI, Self::AccountMfa => CACHE_FILLING_QUANTITY_ACCOUNT_MFA, - Self::PersonaVeci => CACHE_FILLING_QUANTITY_PERSONA_VECI, - Self::PersonaMfa => CACHE_FILLING_QUANTITY_PERSONA_MFA, + Self::IdentityVeci => CACHE_FILLING_QUANTITY_IDENTITY_VECI, + Self::IdentityMfa => CACHE_FILLING_QUANTITY_IDENTITY_MFA, } } } diff --git a/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs b/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs index aee90eac8..d2855a298 100644 --- a/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs +++ b/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs @@ -322,19 +322,17 @@ impl FactorInstancesCache { if let Some(val) = val { pdp.insert(preset, val); } - - if pdp.is_empty() { - continue; - } - pf_pdp.insert(factor_source_id, pdp); } + if pdp.is_empty() { + continue; + } + pf_pdp.insert(*factor_source_id, pdp); } // The instances in the cache cannot satisfy the requested quantity // we must derive more! let is_quantity_satisfied_for_all = pf_pdp.iter().any(|(_, pdp)| { - pdp.iter() - .any(|(_, ci)| ci.remaining_quantity_to_derive > 0) + pdp.iter().any(|(_, ci)| ci.quantity_to_derive > 0) }); let outcome = if is_quantity_satisfied_for_all { @@ -343,13 +341,25 @@ impl FactorInstancesCache { .into_iter() .map(|(k, v)| { ( - k, - v.into_iter() - .map(|x| x.instances_to_use_from_cache) - .collect(), - ) + k, + v.into_iter() + .map(|(preset, x)| { + ( + preset, + x.instances_to_use_from_cache, + ) + }) + .collect::>( + ), + ) }) - .collect(), + .collect::, + >>(), }) } else { CachedInstancesWithQuantitiesOutcome::NotSatisfied( @@ -505,6 +515,19 @@ impl FactorInstancesCache { #[cfg(test)] impl FactorInstancesCache { + pub fn get_poly_factor_with_quantities( + &self, + factor_source_ids: &IndexSet, + quantified_derivation_preset: &QuantifiedDerivationPreset, + network_id: NetworkID, + ) -> Result { + self.get_poly_factor_with_quantified_preset( + factor_source_ids, + &IdentifiedVecOf::just(*quantified_derivation_preset), + network_id, + ) + } + /// Queries the cache to see if the cache is full for factor_source_id for /// each DerivationPreset pub fn is_full( @@ -512,24 +535,26 @@ impl FactorInstancesCache { 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(_)) - ) - }) + // get_poly_factor_with_quantified_preset. + // 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(_)) + // ) + // }) + todo!() } pub fn assert_is_full( diff --git a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs index f68436b6e..242ad8f09 100644 --- a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs @@ -57,12 +57,15 @@ impl FactorInstancesProvider { self.provide_for_presets( IdentifiedVecOf::just(quantified_derivation_preset), derivation_purpose, - ).await + ) + .await } pub async fn provide_for_presets( self, - quantified_derivation_presets: IdentifiedVecOf, + quantified_derivation_presets: IdentifiedVecOf< + QuantifiedDerivationPreset, + >, derivation_purpose: DerivationPurpose, ) -> Result<( InstancesInCacheConsumer, @@ -71,7 +74,10 @@ impl FactorInstancesProvider { let mut _self = self; _self - ._provide_for_presets(quantified_derivation_presets, derivation_purpose) + ._provide_for_presets( + quantified_derivation_presets, + derivation_purpose, + ) .await } } @@ -100,7 +106,9 @@ impl FactorInstancesProvider { async fn _provide_for_presets( &mut self, - quantified_derivation_presets: IdentifiedVecOf, + quantified_derivation_presets: IdentifiedVecOf< + QuantifiedDerivationPreset, + >, derivation_purpose: DerivationPurpose, ) -> Result<( InstancesInCacheConsumer, @@ -136,7 +144,7 @@ impl FactorInstancesProvider { CachedInstancesWithQuantitiesOutcome::NotSatisfied( // quantities_to_derive, // partial_instances, - unsatisfied + unsatisfied, ) => { self.derive_more_and_cache( // quantified_derivation_preset, @@ -168,10 +176,11 @@ impl FactorInstancesProvider { InternalFactorInstancesProviderOutcome, )> { let pf_newly_derived = self - .derive_more - // (pf_pdp_qty_to_derive, - not_satisfied, - derivation_purpose) + .derive_more( + // (pf_pdp_qty_to_derive, + not_satisfied, + derivation_purpose, + ) .await?; // let Split { @@ -298,17 +307,18 @@ impl FactorInstancesProvider { cache_snapshot, ); - let pf_paths = - not_satisfied.into_iter().flat_map(|(quantified_derivation_preset, not_satisfied)| { - // pf_pdp_quantity_to_derive - // .into_iter() - not_satisfied.quantities_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 - (0..qty) + let pf_paths = not_satisfied + .into_iter() + .flat_map(|(quantified_derivation_preset, not_satisfied)| { + // pf_pdp_quantity_to_derive + // .into_iter() + not_satisfied.quantities_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 + (0..qty) .map(|_| { let index_agnostic_path = derivation_preset .index_agnostic_path_on_network(network_id); @@ -322,16 +332,20 @@ impl FactorInstancesProvider { }) }) .collect::>>() - }) - .collect::>>>()?; + }) + .collect::>>>( + )?; - // flatten (I was unable to use `flat_map` above combined with `Result`...) - let paths = - paths.into_iter().flatten().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)) + Ok((factor_source_id, paths)) + }, + ) }) - }) .collect::>, >>()?; From ce3e9fdace3f8172375668d003e01be9214c1687 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Tue, 17 Dec 2024 13:11:05 +0100 Subject: [PATCH 22/60] [no ci] WIP --- .../factor_instances_cache.rs | 119 ++++++++------- .../provider/factor_instances_provider.rs | 135 +++++++++++------- .../factor_instances_provider_outcome.rs | 43 ++++-- ...ernal_factor_instances_provider_outcome.rs | 62 +++++--- .../provider_adopters/cache_filler.rs | 50 ++++--- ...rtual_entity_creating_instance_provider.rs | 12 +- .../client/factor_instances_cache_client.rs | 131 +++++++++-------- 7 files changed, 334 insertions(+), 218 deletions(-) diff --git a/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs b/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs index d2855a298..a04e41039 100644 --- a/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs +++ b/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs @@ -233,7 +233,7 @@ impl FactorInstancesCache { /// per quantified derivation preset, and the rest must be derived, so /// NotSatisfied contains the instances that were found in the cache and /// the quantities to derive. - pub fn get_poly_factor_with_quantified_preset( + pub fn get( &self, factor_source_ids: &IndexSet, quantified_derivation_presets: &IdentifiedVecOf< @@ -241,26 +241,26 @@ impl FactorInstancesCache { >, network_id: NetworkID, ) -> Result { - let mut pf_pdp = IndexMap::< - FactorSourceIDFromHash, + let mut per_derivation_preset = IndexMap::< + DerivationPreset, IndexMap< - DerivationPreset, + FactorSourceIDFromHash, CacheInstancesAndRemainingQuantityToDerive, >, >::new(); - for factor_source_id in factor_source_ids { - let mut pdp = IndexMap::< - DerivationPreset, + for preset in DerivationPreset::all() { + let mut per_factor_source = IndexMap::< + FactorSourceIDFromHash, CacheInstancesAndRemainingQuantityToDerive, >::new(); - for preset in DerivationPreset::all() { - let cache_filling_quantity = preset.cache_filling_quantity(); + let cache_filling_quantity = preset.cache_filling_quantity(); - let index_agnostic_path = - preset.index_agnostic_path_on_network(network_id); + let index_agnostic_path = + preset.index_agnostic_path_on_network(network_id); + for factor_source_id in factor_source_ids { let for_preset = self .get_mono_factor(factor_source_id, index_agnostic_path) .unwrap_or_default(); @@ -320,51 +320,61 @@ impl FactorInstancesCache { None }; if let Some(val) = val { - pdp.insert(preset, val); + per_factor_source.insert(*factor_source_id, val); } } - if pdp.is_empty() { + if per_factor_source.is_empty() { continue; } - pf_pdp.insert(*factor_source_id, pdp); + per_derivation_preset.insert(preset, per_factor_source); } // The instances in the cache cannot satisfy the requested quantity // we must derive more! - let is_quantity_satisfied_for_all = pf_pdp.iter().any(|(_, pdp)| { - pdp.iter().any(|(_, ci)| ci.quantity_to_derive > 0) - }); + let is_quantity_satisfied_for_all = per_derivation_preset + .iter() + .any(|(_, pf)| pf.iter().any(|(_, ci)| ci.quantity_to_derive > 0)); let outcome = if is_quantity_satisfied_for_all { CachedInstancesWithQuantitiesOutcome::Satisfied(CacheSatisfied { - cached_and_quantities_to_derive: pf_pdp + cached: per_derivation_preset .into_iter() - .map(|(k, v)| { + .map(|(preset, v)| { ( - k, - v.into_iter() - .map(|(preset, x)| { - ( - preset, - x.instances_to_use_from_cache, - ) - }) - .collect::>( - ), - ) + preset, + v.into_iter() + .map(|(fsid, x)| { + assert_eq!(x.quantity_to_derive, 0); + let instances = + x.instances_to_use_from_cache; + assert!(instances.clone().into_iter().all( + |fi| { + fi.factor_source_id() == fsid + && DerivationPreset::try_from( + fi.derivation_path() + .agnostic(), + ) + .unwrap() + == preset + } + )); + (fsid, instances) + }) + .collect::>(), + ) }) .collect::, + DerivationPreset, + IndexMap, >>(), }) } else { CachedInstancesWithQuantitiesOutcome::NotSatisfied( CacheNotSatisfied { - cached_and_quantities_to_derive: pf_pdp, + cached_and_quantities_to_derive: per_derivation_preset, }, ) }; @@ -372,30 +382,33 @@ impl FactorInstancesCache { } } -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct CacheInstancesAndRemainingQuantityToDerive { + pub instances_to_use_from_cache: FactorInstances, // if empty then this was not a requested derivation preset, but we are cache filling and found `quantity_to_derive` needed to fill cache. + pub quantity_to_derive: usize, +} + +#[derive(Debug, Clone, PartialEq, Eq)] pub struct CacheNotSatisfied { - /// PER FactorSourceID => PER DerivationPreset => CacheInstancesAndRemainingQuantityToDerive + /// PER DerivationPreset => PER FactorSourceID => CacheInstancesAndRemainingQuantityToDerive pub cached_and_quantities_to_derive: IndexMap< - FactorSourceIDFromHash, - IndexMap, + DerivationPreset, + IndexMap< + FactorSourceIDFromHash, + CacheInstancesAndRemainingQuantityToDerive, + >, >, } -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct CacheSatisfied { - /// PER FactorSourceID => PER DerivationPreset => FactorInstances - pub cached_and_quantities_to_derive: IndexMap< - FactorSourceIDFromHash, - IndexMap, + /// PER DerivationPreset => PER FactorSourceID => FactorInstances + pub cached: IndexMap< + DerivationPreset, + IndexMap, >, } -#[derive(Debug, PartialEq, Eq)] -pub struct CacheInstancesAndRemainingQuantityToDerive { - pub instances_to_use_from_cache: FactorInstances, // if empty then this was not a requested derivation preset, but we are cache filling and found `quantity_to_derive` needed to fill cache. - pub quantity_to_derive: usize, -} - #[derive(Debug, PartialEq, Eq, enum_as_inner::EnumAsInner)] pub enum CachedInstancesWithQuantitiesOutcome { Satisfied(CacheSatisfied), @@ -521,7 +534,7 @@ impl FactorInstancesCache { quantified_derivation_preset: &QuantifiedDerivationPreset, network_id: NetworkID, ) -> Result { - self.get_poly_factor_with_quantified_preset( + self.get( factor_source_ids, &IdentifiedVecOf::just(*quantified_derivation_preset), network_id, @@ -535,7 +548,7 @@ impl FactorInstancesCache { network_id: NetworkID, factor_source_id: FactorSourceIDFromHash, ) -> bool { - // get_poly_factor_with_quantified_preset. + // get. // DerivationPreset::all() // .into_iter() // .map(|preset| { diff --git a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs index 242ad8f09..97a91316d 100644 --- a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs @@ -88,20 +88,25 @@ impl FactorInstancesProvider { impl FactorInstancesProvider { fn make_instances_in_cache_consumer( &self, - instances_per_factor_sources_to_delete: IndexMap< - FactorSourceIDFromHash, - FactorInstances, - >, + // instances_per_factor_sources_to_delete: IndexMap< + // FactorSourceIDFromHash, + // FactorInstances, + // >, + instances_to_delete: IndexMap< + DerivationPreset, + IndexMap, + > ) -> InstancesInCacheConsumer { - let instances_clone = instances_per_factor_sources_to_delete.clone(); - let cache_client_clone = self.cache_client.clone(); - InstancesInCacheConsumer::new(move || { - let cache_client_clone_clone = cache_client_clone.clone(); - let instances_clone_clone = instances_clone.clone(); - async move { - cache_client_clone_clone.delete(instances_clone_clone).await - } - }) + // let instances_clone = instances_per_factor_sources_to_delete.clone(); + // let cache_client_clone = self.cache_client.clone(); + // InstancesInCacheConsumer::new(move || { + // let cache_client_clone_clone = cache_client_clone.clone(); + // let instances_clone_clone = instances_clone.clone(); + // async move { + // cache_client_clone_clone.delete(instances_clone_clone).await + // } + // }) + todo!() } async fn _provide_for_presets( @@ -118,7 +123,7 @@ impl FactorInstancesProvider { let network_id = self.network_id; let cached = self .cache_client - .get_poly_factor_with_quantified_presets( + .gets( &factor_sources.iter().map(|f| f.id_from_hash()).collect(), quantified_derivation_presets.clone(), network_id, @@ -133,7 +138,7 @@ impl FactorInstancesProvider { // will be deleted from the cache, they are still present in the cache now // and will continue to be present until the `consume()` is called. let instances_in_cache_consumer = self - .make_instances_in_cache_consumer(enough_instances.clone()); + .make_instances_in_cache_consumer(enough_instances.clone().cached); Ok(( instances_in_cache_consumer, InternalFactorInstancesProviderOutcome::satisfied_by_cache( @@ -169,7 +174,7 @@ impl FactorInstancesProvider { // FactorSourceIDFromHash, // IndexMap, // >, - not_satisfied: IndexMap, + not_satisfied: CacheNotSatisfied, derivation_purpose: DerivationPurpose, ) -> Result<( InstancesInCacheConsumer, @@ -294,9 +299,14 @@ impl FactorInstancesProvider { // FactorSourceIDFromHash, // IndexMap, // >, - not_satisfied: IndexMap, + not_satisfied: CacheNotSatisfied, derivation_purpose: DerivationPurpose, - ) -> Result> { + ) -> Result< + IndexMap< + DerivationPreset, + IndexMap, + >, + > { let factor_sources = self.factor_sources.clone(); let network_id = self.network_id; @@ -307,63 +317,86 @@ impl FactorInstancesProvider { cache_snapshot, ); - let pf_paths = not_satisfied + let per_preset_per_factor_paths = not_satisfied + .cached_and_quantities_to_derive .into_iter() - .flat_map(|(quantified_derivation_preset, not_satisfied)| { - // pf_pdp_quantity_to_derive - // .into_iter() - not_satisfied.quantities_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 - (0..qty) + // .flat_map(|(derivation_preset, instances_and_qty_to_derive)| { + // // pf_pdp_quantity_to_derive + // // .into_iter() + // not_satisfied.quantities_to_derive.into_iter() + .map(|(derivation_preset, per_factor_source)| { + let per_factor_paths = per_factor_source + .into_iter() + .map(|(factor_source_id, instances_and_qty_to_derive)| { + let qty = + instances_and_qty_to_derive.quantity_to_derive; + // `qty` many paths + let paths = (0..qty) .map(|_| { let index_agnostic_path = derivation_preset .index_agnostic_path_on_network(network_id); - next_index_assigner + let path = next_index_assigner .next(factor_source_id, index_agnostic_path) .map(|index| { DerivationPath::from(( index_agnostic_path, index, )) - }) - }) - .collect::>>() + })?; + Ok(path) }) - .collect::>>>( - )?; - - // flatten (I was unable to use `flat_map` above combined with `Result`...) - let paths = paths - .into_iter() - .flatten() - .collect::>(); + .collect::>>()?; Ok((factor_source_id, paths)) - }, - ) + }) + .collect::, + >, + >>()?; + + Ok((derivation_preset, per_factor_paths)) }) .collect::>, + // IndexMap>, + IndexMap< + DerivationPreset, + IndexMap>, + >, >>()?; let interactor = self.interactor.clone(); let collector = KeysCollector::new( factor_sources, - pf_paths.clone(), + per_preset_per_factor_paths.clone().into_iter().flat_map( + |(_, pf_paths)| { + pf_paths + .into_iter() + .map(|(fs, paths)| (fs, paths)) + + } + ) + .collect::, + >>(), interactor, derivation_purpose, )?; let pf_derived = collector.collect_keys().await.factors_by_source; - let mut pf_instances = - IndexMap::::new(); + let mut pdp_pf_instances = + IndexMap::< + DerivationPreset, + IndexMap, + >::new(); - for (factor_source_id, paths) in pf_paths { + for (preset, per_factor) in per_preset_per_factor_paths { + let mut pf_instances = + IndexMap::::new(); + for (factor_source_id, paths) in per_factor { let derived_for_factor = pf_derived .get(&factor_source_id) .cloned() @@ -375,9 +408,11 @@ impl FactorInstancesProvider { factor_source_id, derived_for_factor.into_iter().collect::(), ); - } + }; + pdp_pf_instances.insert(preset, pf_instances); + } - Ok(pf_instances) + Ok(pdp_pf_instances) } } diff --git a/crates/sargon/src/factor_instances_provider/provider/outcome/factor_instances_provider_outcome.rs b/crates/sargon/src/factor_instances_provider/provider/outcome/factor_instances_provider_outcome.rs index 3a23f32d3..724455a32 100644 --- a/crates/sargon/src/factor_instances_provider/provider/outcome/factor_instances_provider_outcome.rs +++ b/crates/sargon/src/factor_instances_provider/provider/outcome/factor_instances_provider_outcome.rs @@ -4,6 +4,16 @@ use crate::prelude::*; /// 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< + // FactorSourceIDFromHash, + // FactorInstancesProviderOutcomeForFactor, + // >, + pub per_derivation_preset: + IndexMap, +} + +#[derive(Clone, Debug)] +pub struct FactorInstancesProviderOutcomePerFactor { pub per_factor: IndexMap< FactorSourceIDFromHash, FactorInstancesProviderOutcomeForFactor, @@ -14,13 +24,14 @@ impl From for FactorInstancesProviderOutcome { fn from(value: InternalFactorInstancesProviderOutcome) -> Self { - Self { - per_factor: value - .per_factor - .into_iter() - .map(|(k, v)| (k, v.into())) - .collect(), - } + // Self { + // per_factor: value + // .per_factor + // .into_iter() + // .map(|(k, v)| (k, v.into())) + // .collect(), + // } + todo!() } } @@ -29,10 +40,11 @@ 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() + // self.per_factor + // .values() + // .flat_map(|x| x.debug_was_derived.factor_instances()) + // .collect() + todo!() } pub fn total_number_of_newly_derived_instances(&self) -> usize { @@ -46,10 +58,11 @@ impl FactorInstancesProviderOutcome { 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() + // self.per_factor + // .values() + // .flat_map(|x| x.debug_found_in_cache.factor_instances()) + // .collect() + todo!() } pub fn total_number_of_instances_found_in_cache(&self) -> usize { diff --git a/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs b/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs index 382d2829d..2936153c2 100644 --- a/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs +++ b/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs @@ -8,6 +8,51 @@ pub struct InternalFactorInstancesProviderOutcome { >, } +impl InternalFactorInstancesProviderOutcome { + /// Outcome of FactorInstances just from cache, none have been derived. + pub fn satisfied_by_cache(satisfied: CacheSatisfied) -> Self { + // Self::new( + // pf_found_in_cache + // .into_iter() + // .map(|(k, v)| { + // ( + // k, + // InternalFactorInstancesProviderOutcomeForFactor::satisfied_by_cache(k, v), + // ) + // }) + // .collect(), + // ) + todo!() + } + + pub fn get_for_derivation_preset( + &self, + preset: DerivationPreset, + ) -> Option<&InternalFactorInstancesProviderOutcomePerFactor> { + self.per_derivation_preset.get(&preset) + } + + pub fn get_for_derivation_preset_for_factor( + &self, + preset: DerivationPreset, + factor_source_id: FactorSourceIDFromHash, + ) -> Option<&InternalFactorInstancesProviderOutcomeForFactor> { + self.get_for_derivation_preset(preset) + .and_then(|x| x.per_factor.get(&factor_source_id)) + } + + #[cfg(test)] + pub(crate) fn get( + &self, + preset: DerivationPreset, + factor_source_id: FactorSourceIDFromHash, + ) -> InternalFactorInstancesProviderOutcomeForFactor { + self.get_for_derivation_preset_for_factor(preset, factor_source_id) + .cloned() + .expect("Expected to find factor source") + } +} + #[derive(Clone, Debug)] pub struct InternalFactorInstancesProviderOutcomePerFactor { pub per_factor: IndexMap< @@ -26,23 +71,6 @@ impl InternalFactorInstancesProviderOutcomePerFactor { 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, diff --git a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/cache_filler.rs b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/cache_filler.rs index d55d49c17..80e00ce89 100644 --- a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/cache_filler.rs +++ b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/cache_filler.rs @@ -21,28 +21,44 @@ impl CacheFiller { cache_client.clone(), interactor, ); - let quantities = IndexMap::kv( - factor_source.id_from_hash(), - DerivationPreset::all() + + let not_satisfied = CacheNotSatisfied { + cached_and_quantities_to_derive: DerivationPreset::all() .into_iter() - .map(|dp| (dp, CACHE_FILLING_QUANTITY)) - .collect::>(), - ); + .map(|preset| { + ( + preset, + IndexMap::kv( + factor_source.id_from_hash(), + CacheInstancesAndRemainingQuantityToDerive { + instances_to_use_from_cache: + FactorInstances::default(), // TODO improve surrounding code. should not have to create CacheInstancesAndRemainingQuantityToDerive... + quantity_to_derive: preset + .cache_filling_quantity(), + }, + ), + ) + }) + .collect::>(), + }; + let derived = provider - .derive_more(quantities, DerivationPurpose::pre_deriving_keys()) + .derive_more(not_satisfied, DerivationPurpose::pre_deriving_keys()) .await?; cache_client.insert_all(&derived).await?; - let derived = - derived.get(&factor_source.id_from_hash()).unwrap().clone(); - let outcome = InternalFactorInstancesProviderOutcomeForFactor::new( - factor_source.id_from_hash(), - derived.clone(), - FactorInstances::default(), - FactorInstances::default(), - derived, - ); - Ok(outcome.into()) + todo!("migrate me") + + // let derived = + // derived.get(&factor_source.id_from_hash()).unwrap().clone(); + // let outcome = InternalFactorInstancesProviderOutcomeForFactor::new( + // factor_source.id_from_hash(), + // derived.clone(), + // FactorInstances::default(), + // FactorInstances::default(), + // derived, + // ); + // Ok(outcome.into()) } } diff --git a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs index 2d9895f1d..595108e2f 100644 --- a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs @@ -131,19 +131,19 @@ impl VirtualEntityCreatingInstanceProvider { cache_client, interactor, ); + let derivation_preset = DerivationPreset::veci_entity_kind(entity_kind); let (instances_in_cache_consumer, outcome) = provider .provide( - QuantifiedDerivationPreset::new( - DerivationPreset::veci_entity_kind(entity_kind), - count, - ), + QuantifiedDerivationPreset::new(derivation_preset, count), DerivationPurpose::creation_of_new_virtual_entity(entity_kind), ) .await?; let outcome = outcome - .per_factor - .get(&factor_source.id_from_hash()) + .get_for_derivation_preset_for_factor( + derivation_preset, + factor_source.id_from_hash(), + ) .cloned() .expect("Expected to have instances for the factor source"); diff --git a/crates/sargon/src/system/clients/client/factor_instances_cache_client.rs b/crates/sargon/src/system/clients/client/factor_instances_cache_client.rs index 07fb76010..4f2707c4b 100644 --- a/crates/sargon/src/system/clients/client/factor_instances_cache_client.rs +++ b/crates/sargon/src/system/clients/client/factor_instances_cache_client.rs @@ -138,12 +138,17 @@ impl FactorInstancesCacheClient { /// Inserts all instance in `per_factor`. pub async fn insert_all( &self, - per_factor: impl Borrow>, + // per_factor: impl Borrow>, + per_derivation_preset_per_factor: &IndexMap< + DerivationPreset, + IndexMap, + >, ) -> Result<()> { - self.update_and_persist_cache(|cache| { - cache.insert_all(per_factor.borrow()) - }) - .await + // self.update_and_persist_cache(|cache| { + // cache.insert_all(per_factor.borrow()) + // }) + // .await + todo!() } /// Returns the max derivation entity index for the given `factor_source_id` and `index_agnostic_path`. @@ -158,7 +163,7 @@ impl FactorInstancesCacheClient { .await } - pub async fn get_poly_factor_with_quantified_presets( + pub async fn gets( &self, factor_source_ids: impl Borrow>, quantified_derivation_presets: IdentifiedVecOf< @@ -179,17 +184,18 @@ impl FactorInstancesCacheClient { is_satisfied &= part.is_satisfied(); unaggregated.insert(quantified_preset, part); } - if is_satisfied { - let aggregated = IndexMap::new(); - todo!("impl me"); - Ok(CachedInstancesWithQuantitiesOutcome::Satisfied(aggregated)) - } else { - let aggregated = IndexMap::new(); - todo!("impl me"); - Ok(CachedInstancesWithQuantitiesOutcome::NotSatisfied( - unaggregated, - )) - } + todo!("migrate me") + // if is_satisfied { + // let aggregated = IndexMap::new(); + // todo!("impl me"); + // Ok(CachedInstancesWithQuantitiesOutcome::Satisfied(aggregated)) + // } else { + // let aggregated = IndexMap::new(); + // todo!("impl me"); + // Ok(CachedInstancesWithQuantitiesOutcome::NotSatisfied( + // unaggregated, + // )) + // } } /// Returns enough instances to satisfy the requested quantity for each factor source, @@ -205,9 +211,11 @@ impl FactorInstancesCacheClient { network_id: NetworkID, ) -> Result { self.access_cache_init_if_needed(|cache| { - cache.get_poly_factor_with_quantified_preset( + cache.get( factor_source_ids.borrow(), - originally_requested_quantified_derivation_preset.borrow(), + &IdentifiedVecOf::just( + *originally_requested_quantified_derivation_preset.borrow(), + ), network_id, ) }) @@ -350,50 +358,53 @@ mod tests { let max_higher_sut1 = sut1.max_index_for(fsid, path).await.unwrap(); assert_eq!(max_higher_sut1, Some(one)); - // test get_poly_factor_with_quantities - let poly = sut1 - .get_poly_factor_with_quantities( - IndexSet::just(fsid), - QuantifiedDerivationPreset::new(derivation_preset, 2), - network, - ) - .await - .unwrap(); - let satisfied = IndexMap::kv(fsid, instances); - assert_eq!( - poly, - CachedInstancesWithQuantitiesOutcome::Satisfied(satisfied) - ); - - let snap_1 = sut1.snapshot().await.unwrap(); - let snap_2 = sut2.snapshot().await.unwrap(); - assert_eq!( - snap_1.serializable_snapshot(), - snap_2.serializable_snapshot(), - ); + todo!("migrate me") + + // // test get_poly_factor_with_quantities + // let poly = sut1 + // .get_poly_factor_with_quantities( + // IndexSet::just(fsid), + // QuantifiedDerivationPreset::new(derivation_preset, 2), + // network, + // ) + // .await + // .unwrap(); + // let satisfied = IndexMap::kv(fsid, instances); + // assert_eq!( + // poly, + // CachedInstancesWithQuantitiesOutcome::Satisfied(satisfied) + // ); + + // let snap_1 = sut1.snapshot().await.unwrap(); + // let snap_2 = sut2.snapshot().await.unwrap(); + // assert_eq!( + // snap_1.serializable_snapshot(), + // snap_2.serializable_snapshot(), + // ); } #[actix_rt::test] async fn test_insert_all() { - let file_system = Arc::new(FileSystemClient::in_memory()); - let sut = SUT::new(file_system); - - let fs = FactorSourceIDFromHash::sample_at(0); - sut.insert_all(IndexMap::kv(fs, FactorInstances::sample())) - .await - .unwrap(); - - let max = sut - .max_index_for( - fs, - DerivationPreset::AccountMfa - .index_agnostic_path_on_network(NetworkID::Mainnet), - ) - .await - .unwrap(); - assert_eq!( - max.unwrap(), - HDPathComponent::Securified(SecurifiedU30::ONE) - ); + // let file_system = Arc::new(FileSystemClient::in_memory()); + // let sut = SUT::new(file_system); + + // let fs = FactorSourceIDFromHash::sample_at(0); + // sut.insert_all(IndexMap::kv(fs, FactorInstances::sample())) + // .await + // .unwrap(); + + // let max = sut + // .max_index_for( + // fs, + // DerivationPreset::AccountMfa + // .index_agnostic_path_on_network(NetworkID::Mainnet), + // ) + // .await + // .unwrap(); + // assert_eq!( + // max.unwrap(), + // HDPathComponent::Securified(SecurifiedU30::ONE) + // ); + todo!("migrate me") } } From 01288fafe94a075526a656edc42829692f2c10cb Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Tue, 17 Dec 2024 13:40:47 +0100 Subject: [PATCH 23/60] [no ci] WIP --- .../quantified_derivation_preset.rs | 35 +++++++ .../factor_instances_provider_outcome.rs | 18 ++++ ...curify_entity_factor_instances_provider.rs | 92 ++++++++++++------- .../collector/derivation_purpose.rs | 47 +++++++--- .../profile_network_get_entities.rs | 11 +-- .../src/profile/logic/profile_networks.rs | 6 +- .../system/sargon_os/sargon_os_accounts.rs | 24 +++-- 7 files changed, 165 insertions(+), 68 deletions(-) diff --git a/crates/sargon/src/factor_instances_provider/agnostic_paths/quantified_derivation_preset.rs b/crates/sargon/src/factor_instances_provider/agnostic_paths/quantified_derivation_preset.rs index 09f55b73b..cdd5e74d6 100644 --- a/crates/sargon/src/factor_instances_provider/agnostic_paths/quantified_derivation_preset.rs +++ b/crates/sargon/src/factor_instances_provider/agnostic_paths/quantified_derivation_preset.rs @@ -21,4 +21,39 @@ impl QuantifiedDerivationPreset { quantity, } } + + pub fn mfa_for_entities( + addresses_of_entities: &IndexSet, + ) -> IdentifiedVecOf { + let account_addresses = addresses_of_entities + .iter() + .filter(|a| a.is_account()) + .collect_vec(); + let identity_addresses = addresses_of_entities + .iter() + .filter(|a| a.is_identity()) + .collect_vec(); + + match (account_addresses.is_empty(), identity_addresses.is_empty()) { + (true, true) => IdentifiedVecOf::new(), // weird! + (true, false) => IdentifiedVecOf::just(Self::new( + DerivationPreset::IdentityMfa, + identity_addresses.len(), + )), + (false, false) => IdentifiedVecOf::from_iter([ + Self::new( + DerivationPreset::AccountMfa, + account_addresses.len(), + ), + Self::new( + DerivationPreset::IdentityMfa, + identity_addresses.len(), + ), + ]), + (false, true) => IdentifiedVecOf::just(Self::new( + DerivationPreset::AccountMfa, + account_addresses.len(), + )), + } + } } diff --git a/crates/sargon/src/factor_instances_provider/provider/outcome/factor_instances_provider_outcome.rs b/crates/sargon/src/factor_instances_provider/provider/outcome/factor_instances_provider_outcome.rs index 724455a32..c6e995861 100644 --- a/crates/sargon/src/factor_instances_provider/provider/outcome/factor_instances_provider_outcome.rs +++ b/crates/sargon/src/factor_instances_provider/provider/outcome/factor_instances_provider_outcome.rs @@ -12,6 +12,24 @@ pub struct FactorInstancesProviderOutcome { IndexMap, } +impl FactorInstancesProviderOutcome { + pub fn get_derivation_preset( + &self, + preset: DerivationPreset, + ) -> Option<&FactorInstancesProviderOutcomePerFactor> { + self.per_derivation_preset.get(&preset) + } + + pub fn get_derivation_preset_for_factor( + &self, + preset: DerivationPreset, + factor_source_id: &FactorSourceIDFromHash, + ) -> Option<&FactorInstancesProviderOutcomeForFactor> { + self.get_derivation_preset(preset) + .and_then(|x| x.per_factor.get(factor_source_id)) + } +} + #[derive(Clone, Debug)] pub struct FactorInstancesProviderOutcomePerFactor { pub per_factor: IndexMap< diff --git a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/securify_entity_factor_instances_provider.rs b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/securify_entity_factor_instances_provider.rs index 661a45b88..668f40ad1 100644 --- a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/securify_entity_factor_instances_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/securify_entity_factor_instances_provider.rs @@ -23,11 +23,11 @@ impl SecurifyEntityFactorInstancesProvider { interactor: Arc, ) -> Result<(InstancesInCacheConsumer, FactorInstancesProviderOutcome)> { - Self::for_entity_mfa::( + Self::for_entity_mfa( cache_client, profile, matrix_of_factor_sources, - account_addresses, + account_addresses.into_iter().map(Into::into).collect(), interactor, ) .await @@ -52,11 +52,11 @@ impl SecurifyEntityFactorInstancesProvider { interactor: Arc, ) -> Result<(InstancesInCacheConsumer, FactorInstancesProviderOutcome)> { - Self::for_entity_mfa::( + Self::for_entity_mfa( cache_client, profile, matrix_of_factor_sources, - persona_addresses, + persona_addresses.into_iter().map(Into::into).collect(), interactor, ) .await @@ -73,11 +73,11 @@ impl SecurifyEntityFactorInstancesProvider { /// /// 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( + pub async fn for_entity_mfa( cache_client: Arc, profile: Arc, matrix_of_factor_sources: MatrixOfFactorSources, - addresses_of_entities: IndexSet
, + addresses_of_entities: IndexSet, interactor: Arc, ) -> Result<(InstancesInCacheConsumer, FactorInstancesProviderOutcome)> { @@ -107,7 +107,7 @@ impl SecurifyEntityFactorInstancesProvider { assert!( addresses_of_entities .iter() - .all(|a| profile.contains_entity_by_address::(a)), + .all(|a| profile.contains_entity_by_address(a)), "unknown entity" ); @@ -119,8 +119,6 @@ impl SecurifyEntityFactorInstancesProvider { "wrong network" ); - let entity_kind = A::entity_kind(); - let provider = FactorInstancesProvider::new( network_id, factor_sources_to_use, @@ -129,13 +127,23 @@ impl SecurifyEntityFactorInstancesProvider { interactor, ); + let purpose = DerivationPurpose::for_securifying_or_updating( + &addresses_of_entities, + ); + + let quantified_derivation_presets = + QuantifiedDerivationPreset::mfa_for_entities( + &addresses_of_entities, + ); + let (instances_in_cache_consumer, outcome) = provider - .provide( - QuantifiedDerivationPreset::new( - DerivationPreset::mfa_entity_kind(entity_kind), - addresses_of_entities.len(), - ), - DerivationPurpose::for_securifying_or_updating(entity_kind), + .provide_for_presets( + // QuantifiedDerivationPreset::new( + // DerivationPreset::mfa_entity_kind(entity_kind), + // addresses_of_entities.len(), + // ), + quantified_derivation_presets, + purpose, ) .await?; @@ -310,35 +318,51 @@ mod tests { let profile = Arc::new(os.profile().unwrap()); let derivation_interactors = os.keys_derivation_interactor(); - let (instances_in_cache_consumer, outcome) = SUT::for_account_mfa( + let (instances_in_cache_consumer, outcome) = SUT::for_entity_mfa( cache_client.clone(), profile, matrix_0.clone(), - IndexSet::just(alice.address()), + IndexSet::from_iter([ + AddressOfAccountOrPersona::from(alice.address()), + AddressOfAccountOrPersona::from(batman.address()), + ]), derivation_interactors.clone(), ) .await .unwrap(); - // don't forget to consume - instances_in_cache_consumer.consume().await.unwrap(); - let outcome = outcome.per_factor.get(&bdfs.id_from_hash()).unwrap(); - assert_eq!(outcome.to_use_directly.len(), 1); - - let profile = Arc::new(os.profile().unwrap()); - let (instances_in_cache_consumer, outcome) = SUT::for_persona_mfa( - cache_client.clone(), - profile, - matrix_0.clone(), - IndexSet::just(batman.address()), - derivation_interactors.clone(), - ) - .await - .unwrap(); + assert_eq!(outcome.per_derivation_preset.len(), 2); // don't forget to consume instances_in_cache_consumer.consume().await.unwrap(); - let outcome = outcome.per_factor.get(&bdfs.id_from_hash()).unwrap(); - assert_eq!(outcome.to_use_directly.len(), 1); + let account_outcome = outcome + .get_derivation_preset_for_factor( + DerivationPreset::AccountMfa, + &bdfs.id_from_hash(), + ) + .unwrap(); + assert_eq!(account_outcome.len(), 1); + + // let profile = Arc::new(os.profile().unwrap()); + // let (instances_in_cache_consumer, outcome) = SUT::for_persona_mfa( + // cache_client.clone(), + // profile, + // matrix_0.clone(), + // IndexSet::just(batman.address()), + // derivation_interactors.clone(), + // ) + // .await + // .unwrap(); + + // // don't forget to consume + // instances_in_cache_consumer.consume().await.unwrap(); + // // let outcome = outcome.per_factor.get(&bdfs.id_from_hash()).unwrap(); + let persona_outcome = outcome + .get_derivation_preset_for_factor( + DerivationPreset::AccountMfa, + &bdfs.id_from_hash(), + ) + .unwrap(); + assert_eq!(persona_outcome.len(), 1); } } diff --git a/crates/sargon/src/keys_collector/collector/derivation_purpose.rs b/crates/sargon/src/keys_collector/collector/derivation_purpose.rs index 74c3576bd..fd5bf8c7a 100644 --- a/crates/sargon/src/keys_collector/collector/derivation_purpose.rs +++ b/crates/sargon/src/keys_collector/collector/derivation_purpose.rs @@ -12,11 +12,15 @@ pub enum DerivationPurpose { /// for identity VECIs CreatingNewPersona, - /// When applying a security shield to an account, initiates keys collection + /// When applying a security shield to accounts and personas mixed, initiates keys collection + /// for account MFA + SecurifyingAccountsAndPersonas, + + /// When applying a security shield to only accounts, initiates keys collection /// for account MFA SecurifyingAccount, - /// When applying a security shield to a persona, initiates keys collection + /// When applying a security shield to only personas, initiates keys collection /// for identity MFA SecurifyingPersona, @@ -35,10 +39,23 @@ impl DerivationPurpose { } } - pub fn for_securifying_or_updating(entity_kind: CAP26EntityKind) -> Self { - match entity_kind { - CAP26EntityKind::Account => Self::SecurifyingAccount, - CAP26EntityKind::Identity => Self::SecurifyingPersona, + pub fn for_securifying_or_updating( + addresses_of_entities: &IndexSet, + ) -> Self { + let account_addresses = addresses_of_entities + .iter() + .filter(|a| a.is_account()) + .collect_vec(); + let identity_addresses = addresses_of_entities + .iter() + .filter(|a| a.is_identity()) + .collect_vec(); + + match (account_addresses.is_empty(), identity_addresses.is_empty()) { + (true, true) => unreachable!("Incorrect implementation"), // weird! + (true, false) => Self::SecurifyingPersona, + (false, false) => Self::SecurifyingAccountsAndPersonas, + (false, true) => Self::SecurifyingAccount, } } @@ -72,18 +89,20 @@ mod tests { #[test] fn test_for_securifying_account() { - assert_eq!( - SUT::for_securifying_or_updating(CAP26EntityKind::Account), - SUT::SecurifyingAccount - ) + // assert_eq!( + // SUT::for_securifying_or_updating(CAP26EntityKind::Account), + // SUT::SecurifyingAccount + // ) + todo!() } #[test] fn test_for_securifying_persona() { - assert_eq!( - SUT::for_securifying_or_updating(CAP26EntityKind::Identity), - SUT::SecurifyingPersona - ) + // assert_eq!( + // SUT::for_securifying_or_updating(CAP26EntityKind::Identity), + // SUT::SecurifyingPersona + // ) + todo!() } #[test] diff --git a/crates/sargon/src/profile/logic/profile_network/profile_network_get_entities.rs b/crates/sargon/src/profile/logic/profile_network/profile_network_get_entities.rs index bbfc55c58..c90688b35 100644 --- a/crates/sargon/src/profile/logic/profile_network/profile_network_get_entities.rs +++ b/crates/sargon/src/profile/logic/profile_network/profile_network_get_entities.rs @@ -48,17 +48,14 @@ impl ProfileNetwork { .collect() } - pub fn contains_entity_by_address( + pub fn contains_entity_by_address( &self, - entity_address: &A, + entity_address: &AddressOfAccountOrPersona, ) -> bool { - self.get_entities_erased(A::entity_kind()) + self.get_entities_erased(entity_address.get_entity_kind()) .into_iter() .any(|e| { - e.address() - == Into::::into( - entity_address.clone(), - ) + AddressOfAccountOrPersona::from(e.address()) == *entity_address }) } } diff --git a/crates/sargon/src/profile/logic/profile_networks.rs b/crates/sargon/src/profile/logic/profile_networks.rs index 0d98b8c77..85aedbabf 100644 --- a/crates/sargon/src/profile/logic/profile_networks.rs +++ b/crates/sargon/src/profile/logic/profile_networks.rs @@ -11,12 +11,12 @@ impl Profile { pub fn has_any_account_on_any_network(&self) -> bool { self.networks.iter().any(|n| !n.accounts.is_empty()) } - pub fn contains_entity_by_address( + pub fn contains_entity_by_address( &self, - entity_address: &A, + entity_address: &AddressOfAccountOrPersona, ) -> bool { self.networks.iter().any(|n: ProfileNetwork| { - n.contains_entity_by_address::(entity_address) + n.contains_entity_by_address(entity_address) }) } } diff --git a/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs b/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs index 8ba4e4927..9be23caea 100644 --- a/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs +++ b/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs @@ -800,11 +800,9 @@ impl SargonOS { impl SargonOS { #[allow(dead_code)] #[cfg(test)] - pub(crate) async fn make_security_structure_of_factor_instances_for_entities_without_consuming_cache_with_derivation_outcome< - A: IsEntityAddress, - >( + pub(crate) async fn make_security_structure_of_factor_instances_for_entities_without_consuming_cache_with_derivation_outcome( &self, - addresses_of_entities: IndexSet, + addresses_of_entities: IndexSet, security_structure_of_factor_sources: SecurityStructureOfFactorSources, // Aka "shield" ) -> Result<( IndexMap, @@ -817,7 +815,7 @@ impl SargonOS { &security_structure_of_factor_sources.matrix_of_factors; let (instances_in_cache_consumer, outcome) = - SecurifyEntityFactorInstancesProvider::for_entity_mfa::( + SecurifyEntityFactorInstancesProvider::for_entity_mfa( Arc::new(self.clients.factor_instances_cache.clone()), Arc::new(profile_snapshot.clone()), matrix_of_factor_sources.clone(), @@ -826,14 +824,20 @@ impl SargonOS { ) .await?; - let mut instances_per_factor_source = outcome + let mut instances_per_preset_per_factor_source = outcome .clone() - .per_factor + .per_derivation_preset .into_iter() - .map(|(k, outcome_per_factor)| { - (k, outcome_per_factor.to_use_directly) + .map(|(preset, pf)| { + ( + preset, + pf + .per_factor + .into_iter() + .map(|(k, v)| (k, v.to_use_directly)).collect::>() + ) }) - .collect::>(); + .collect::>>(); assert_eq!( instances_per_factor_source From 48874f9cf79d04a3f6bab89d33fd535990e9c5e7 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Tue, 17 Dec 2024 15:08:05 +0100 Subject: [PATCH 24/60] wip --- .../agnostic_paths/derivation_preset.rs | 28 +++++++- .../quantified_derivation_preset.rs | 54 ++++++++------ ...curify_entity_factor_instances_provider.rs | 3 +- .../system/sargon_os/sargon_os_accounts.rs | 71 +++++++++++++------ 4 files changed, 109 insertions(+), 47 deletions(-) diff --git a/crates/sargon/src/factor_instances_provider/agnostic_paths/derivation_preset.rs b/crates/sargon/src/factor_instances_provider/agnostic_paths/derivation_preset.rs index 799e1a1f5..9e00648cc 100644 --- a/crates/sargon/src/factor_instances_provider/agnostic_paths/derivation_preset.rs +++ b/crates/sargon/src/factor_instances_provider/agnostic_paths/derivation_preset.rs @@ -24,6 +24,12 @@ pub enum DerivationPreset { #[debug("A-MFA")] AccountMfa, + /// Used to form DerivationPaths used to derive FactorInstances + /// for Authentication Signing (Securified) for accounts + /// `(EntityKind::Account, KeySpace::Securified, KeyKind::AuthenticationSigning)` + #[debug("A-Rola")] + AccountRola, + /// Used to form DerivationPaths used to derive FactorInstances /// for "veci": Virtual Entity Creating (Factor)Instance for personas. /// `(EntityKind::Identity, KeySpace::Unsecurified, KeyKind::TransactionSigning)` @@ -35,6 +41,12 @@ pub enum DerivationPreset { /// `(EntityKind::Identity, KeySpace::Securified, KeyKind::TransactionSigning)` #[debug("I-MFA")] IdentityMfa, + + /// Used to form DerivationPaths used to derive FactorInstances + /// for Authentication Signing (Securified) for peresonas + /// `(EntityKind::Identity, KeySpace::Securified, KeyKind::AuthenticationSigning)` + #[debug("I-Rola")] + IdentityRola, } // ============= @@ -72,8 +84,12 @@ 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, + Self::AccountVeci | Self::AccountMfa | Self::AccountRola => { + CAP26EntityKind::Account + } + Self::IdentityVeci | Self::IdentityMfa | Self::IdentityRola => { + CAP26EntityKind::Identity + } } } @@ -84,6 +100,9 @@ impl DerivationPreset { | Self::IdentityVeci | Self::AccountMfa | Self::IdentityMfa => CAP26KeyKind::TransactionSigning, + Self::AccountRola | Self::IdentityRola => { + CAP26KeyKind::AuthenticationSigning + } } } @@ -96,7 +115,10 @@ impl DerivationPreset { is_hardened: true, } } - Self::AccountMfa | Self::IdentityMfa => KeySpace::Securified, + Self::AccountMfa + | Self::IdentityMfa + | Self::AccountRola + | Self::IdentityRola => KeySpace::Securified, } } diff --git a/crates/sargon/src/factor_instances_provider/agnostic_paths/quantified_derivation_preset.rs b/crates/sargon/src/factor_instances_provider/agnostic_paths/quantified_derivation_preset.rs index cdd5e74d6..1a87f8936 100644 --- a/crates/sargon/src/factor_instances_provider/agnostic_paths/quantified_derivation_preset.rs +++ b/crates/sargon/src/factor_instances_provider/agnostic_paths/quantified_derivation_preset.rs @@ -34,26 +34,38 @@ impl QuantifiedDerivationPreset { .filter(|a| a.is_identity()) .collect_vec(); - match (account_addresses.is_empty(), identity_addresses.is_empty()) { - (true, true) => IdentifiedVecOf::new(), // weird! - (true, false) => IdentifiedVecOf::just(Self::new( - DerivationPreset::IdentityMfa, - identity_addresses.len(), - )), - (false, false) => IdentifiedVecOf::from_iter([ - Self::new( - DerivationPreset::AccountMfa, - account_addresses.len(), - ), - Self::new( - DerivationPreset::IdentityMfa, - identity_addresses.len(), - ), - ]), - (false, true) => IdentifiedVecOf::just(Self::new( - DerivationPreset::AccountMfa, - account_addresses.len(), - )), - } + let presets = + match (account_addresses.is_empty(), identity_addresses.is_empty()) + { + (true, true) => IdentifiedVecOf::new(), // weird! + (true, false) => IdentifiedVecOf::from_iter([ + Self::new( + DerivationPreset::IdentityMfa, + identity_addresses.len(), + ), + Self::new(DerivationPreset::IdentityRola, 1), + ]), + (false, false) => IdentifiedVecOf::from_iter([ + Self::new( + DerivationPreset::AccountMfa, + account_addresses.len(), + ), + Self::new(DerivationPreset::AccountRola, 1), + Self::new( + DerivationPreset::IdentityMfa, + identity_addresses.len(), + ), + Self::new(DerivationPreset::IdentityRola, 1), + ]), + (false, true) => IdentifiedVecOf::from_iter([ + Self::new( + DerivationPreset::AccountMfa, + account_addresses.len(), + ), + Self::new(DerivationPreset::AccountRola, 1), + ]), + }; + + presets } } diff --git a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/securify_entity_factor_instances_provider.rs b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/securify_entity_factor_instances_provider.rs index 668f40ad1..05df9e9f9 100644 --- a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/securify_entity_factor_instances_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/securify_entity_factor_instances_provider.rs @@ -136,6 +136,7 @@ impl SecurifyEntityFactorInstancesProvider { &addresses_of_entities, ); + assert!(quantified_derivation_presets.len() >= 2); // at least one entity kind, and ROLA + TX: at least 2 let (instances_in_cache_consumer, outcome) = provider .provide_for_presets( // QuantifiedDerivationPreset::new( @@ -331,7 +332,7 @@ mod tests { .await .unwrap(); - assert_eq!(outcome.per_derivation_preset.len(), 2); + assert_eq!(outcome.per_derivation_preset.len(), 4); // don't forget to consume instances_in_cache_consumer.consume().await.unwrap(); diff --git a/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs b/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs index 9be23caea..7e74c7aca 100644 --- a/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs +++ b/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs @@ -805,25 +805,27 @@ impl SargonOS { addresses_of_entities: IndexSet, security_structure_of_factor_sources: SecurityStructureOfFactorSources, // Aka "shield" ) -> Result<( - IndexMap, + IndexMap, InstancesInCacheConsumer, FactorInstancesProviderOutcome, )> { let profile_snapshot = self.profile()?; let key_derivation_interactors = self.keys_derivation_interactor(); - let matrix_of_factor_sources = - &security_structure_of_factor_sources.matrix_of_factors; + let (instances_in_cache_consumer, outcome) = SecurifyEntityFactorInstancesProvider::for_entity_mfa( Arc::new(self.clients.factor_instances_cache.clone()), Arc::new(profile_snapshot.clone()), - matrix_of_factor_sources.clone(), + security_structure_of_factor_sources.clone(), addresses_of_entities.clone(), key_derivation_interactors, ) .await?; + let matrix_of_factor_sources = + &security_structure_of_factor_sources.matrix_of_factors; + let mut instances_per_preset_per_factor_source = outcome .clone() .per_derivation_preset @@ -840,9 +842,11 @@ impl SargonOS { .collect::>>(); assert_eq!( - instances_per_factor_source - .keys() - .cloned() + instances_per_preset_per_factor_source + .clone() + .into_iter().flat_map(|(_, y)| { + y.into_iter().map(|(a, _)| a).collect::>() + } ) .collect::>(), matrix_of_factor_sources .all_factors() @@ -853,21 +857,44 @@ impl SargonOS { let security_structure_id = security_structure_of_factor_sources.id(); - let security_structures_of_factor_instances = addresses_of_entities.clone().into_iter().map(|entity_address| - { - let security_structure_of_factor_instances: SecurityStructureOfFactorInstances = { - let matrix_of_factor_instances = MatrixOfFactorInstances::fulfilling_matrix_of_factor_sources_with_instances( - &mut instances_per_factor_source, - matrix_of_factor_sources.clone(), - )?; - SecurityStructureOfFactorInstances::new( - security_structure_id, - matrix_of_factor_instances, - HierarchicalDeterministicFactorInstance::sample_with_key_kind_entity_kind_on_network_and_hardened_index(entity_address.network_id(), CAP26KeyKind::AuthenticationSigning, A::entity_kind(), Hardened::Securified(SecurifiedU30::ZERO)), - )? - }; - Ok((entity_address, security_structure_of_factor_instances)) - }).collect::>>()?; + let mut security_structures_of_factor_instances = IndexMap::::new(); + + let mut distribute_instances_for_entity_of_kind_if_needed = |entity_kind: CAP26EntityKind| -> Result<()> { + let addresses_of_kind = addresses_of_entities + .iter() + .filter(|a| a.get_entity_kind() == entity_kind) + .collect::>(); + + if addresses_of_kind.is_empty() { return Ok(()) }; + let preset = DerivationPreset::mfa_entity_kind(entity_kind); + + let mut instances_per_factor_source = instances_per_preset_per_factor_source.swap_remove(&preset).expect (&format!("Expected to find instances for derivation preset: {:?}", preset)); + + for entity_address in addresses_of_kind { + let security_structure_of_factor_instances: SecurityStructureOfFactorInstances = { + let matrix_of_factor_instances = MatrixOfFactorInstances::fulfilling_matrix_of_factor_sources_with_instances( + &mut instances_per_factor_source, + matrix_of_factor_sources.clone(), + )?; + + // FIXME - TODO: this is wrong! should get from FIP! + let authentication_signing_instance = HierarchicalDeterministicFactorInstance::sample_with_key_kind_entity_kind_on_network_and_hardened_index(entity_address.network_id(), CAP26KeyKind::AuthenticationSigning, entity_kind, Hardened::Securified(SecurifiedU30::ZERO)); + + SecurityStructureOfFactorInstances::new( + security_structure_id, + matrix_of_factor_instances, + authentication_signing_instance, + )? + }; + security_structures_of_factor_instances.insert(entity_address.clone(), security_structure_of_factor_instances); + } + + Ok(()) + }; + + distribute_instances_for_entity_of_kind_if_needed(CAP26EntityKind::Account); + distribute_instances_for_entity_of_kind_if_needed(CAP26EntityKind::Identity); + Ok(( security_structures_of_factor_instances, From f5319b14204736aed60a7b12834920ded11e6d49 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Tue, 17 Dec 2024 15:11:28 +0100 Subject: [PATCH 25/60] [no ci] WIP --- .../agnostic_paths/quantities.rs | 8 ++++++++ ..._derivation_entity_index_profile_analyzing_assigner.rs | 2 ++ 2 files changed, 10 insertions(+) diff --git a/crates/sargon/src/factor_instances_provider/agnostic_paths/quantities.rs b/crates/sargon/src/factor_instances_provider/agnostic_paths/quantities.rs index e9971d99c..253b26f41 100644 --- a/crates/sargon/src/factor_instances_provider/agnostic_paths/quantities.rs +++ b/crates/sargon/src/factor_instances_provider/agnostic_paths/quantities.rs @@ -9,20 +9,28 @@ pub const CACHE_FILLING_QUANTITY_ACCOUNT_VECI: usize = CACHE_FILLING_QUANTITY; /// The quantity of DerivationPreset's to fill cache with for `DerivationPreset::AccountMfa`. pub const CACHE_FILLING_QUANTITY_ACCOUNT_MFA: usize = CACHE_FILLING_QUANTITY; +/// The quantity of DerivationPreset's to fill cache with for `DerivationPreset::AccountRola`. +pub const CACHE_FILLING_QUANTITY_ACCOUNT_ROLA: usize = CACHE_FILLING_QUANTITY; + /// The quantity of DerivationPreset's to fill cache with for `DerivationPreset::IdentityVeci`. pub const CACHE_FILLING_QUANTITY_IDENTITY_VECI: usize = CACHE_FILLING_QUANTITY; /// The quantity of DerivationPreset's to fill cache with for `DerivationPreset::IdentityMfa`. pub const CACHE_FILLING_QUANTITY_IDENTITY_MFA: usize = CACHE_FILLING_QUANTITY; +/// The quantity of DerivationPreset's to fill cache with for `DerivationPreset::IdentityRola`. +pub const CACHE_FILLING_QUANTITY_IDENTITY_ROLA: usize = CACHE_FILLING_QUANTITY; + impl DerivationPreset { /// The quantity of DerivationPreset's to fill cache with. pub fn cache_filling_quantity(&self) -> usize { match self { Self::AccountVeci => CACHE_FILLING_QUANTITY_ACCOUNT_VECI, Self::AccountMfa => CACHE_FILLING_QUANTITY_ACCOUNT_MFA, + Self::AccountRola => CACHE_FILLING_QUANTITY_ACCOUNT_ROLA, Self::IdentityVeci => CACHE_FILLING_QUANTITY_IDENTITY_VECI, Self::IdentityMfa => CACHE_FILLING_QUANTITY_IDENTITY_MFA, + Self::IdentityRola => CACHE_FILLING_QUANTITY_IDENTITY_ROLA, } } } diff --git a/crates/sargon/src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_profile_analyzing_assigner.rs b/crates/sargon/src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_profile_analyzing_assigner.rs index d2994c9e4..a9a51604d 100644 --- a/crates/sargon/src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_profile_analyzing_assigner.rs +++ b/crates/sargon/src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_profile_analyzing_assigner.rs @@ -220,6 +220,8 @@ impl NextDerivationEntityIndexProfileAnalyzingAssigner { DerivationPreset::IdentityMfa => { self.max_identity_mfa(factor_source_id) } + DerivationPreset::AccountRola => todo!(), + DerivationPreset::IdentityRola => todo!(), }; let Some(max) = max else { return Ok(None) }; From ed84dba0c151b6c34541eefae57d8fbe806fc35f Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Tue, 17 Dec 2024 15:37:43 +0100 Subject: [PATCH 26/60] [no ci] WIP --- .../agnostic_paths/index_agnostic_path.rs | 45 +++++++++++ .../provider/factor_instances_provider.rs | 56 ++++++------- .../factor_instances_provider_unit_tests.rs | 79 +++++++++++++------ ...curify_entity_factor_instances_provider.rs | 4 +- .../system/sargon_os/sargon_os_accounts.rs | 66 ++++++++++------ 5 files changed, 169 insertions(+), 81 deletions(-) diff --git a/crates/sargon/src/factor_instances_provider/agnostic_paths/index_agnostic_path.rs b/crates/sargon/src/factor_instances_provider/agnostic_paths/index_agnostic_path.rs index 77f9354bc..e735b7928 100644 --- a/crates/sargon/src/factor_instances_provider/agnostic_paths/index_agnostic_path.rs +++ b/crates/sargon/src/factor_instances_provider/agnostic_paths/index_agnostic_path.rs @@ -119,6 +119,16 @@ impl TryFrom for DerivationPreset { CAP26KeyKind::TransactionSigning, KeySpace::Securified, ) => Ok(DerivationPreset::IdentityMfa), + ( + CAP26EntityKind::Account, + CAP26KeyKind::AuthenticationSigning, + KeySpace::Securified, + ) => Ok(DerivationPreset::AccountRola), + ( + CAP26EntityKind::Identity, + CAP26KeyKind::AuthenticationSigning, + KeySpace::Securified, + ) => Ok(DerivationPreset::IdentityRola), _ => Err(CommonError::InvalidBIP32Path { bad_value: "Invalid combination of entity_kind, key_kind and key_space" @@ -334,4 +344,39 @@ mod tests { assert_json_value_fails::(json!("")); assert_json_value_fails::(json!(" ")); } + + #[test] + fn derivation_preset_rola_valid_account() { + let preset = DerivationPreset::try_from(SUT::new( + NetworkID::Mainnet, + CAP26EntityKind::Account, + CAP26KeyKind::AuthenticationSigning, + KeySpace::Securified, + )) + .unwrap(); + assert_eq!(preset, DerivationPreset::AccountRola); + } + + #[test] + fn derivation_preset_rola_invalid_not_securified() { + let res = DerivationPreset::try_from(SUT::new( + NetworkID::Mainnet, + CAP26EntityKind::Account, + CAP26KeyKind::AuthenticationSigning, + KeySpace::Unsecurified { is_hardened: true }, + )); + assert!(matches!(res, Err(CommonError::InvalidBIP32Path { .. }))); + } + + #[test] + fn derivation_preset_rola_valid_identity() { + let preset = DerivationPreset::try_from(SUT::new( + NetworkID::Mainnet, + CAP26EntityKind::Identity, + CAP26KeyKind::AuthenticationSigning, + KeySpace::Securified, + )) + .unwrap(); + assert_eq!(preset, DerivationPreset::IdentityRola); + } } diff --git a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs index 97a91316d..e247d2495 100644 --- a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs @@ -93,9 +93,9 @@ impl FactorInstancesProvider { // FactorInstances, // >, instances_to_delete: IndexMap< - DerivationPreset, - IndexMap, - > + DerivationPreset, + IndexMap, + >, ) -> InstancesInCacheConsumer { // let instances_clone = instances_per_factor_sources_to_delete.clone(); // let cache_client_clone = self.cache_client.clone(); @@ -138,7 +138,9 @@ impl FactorInstancesProvider { // will be deleted from the cache, they are still present in the cache now // and will continue to be present until the `consume()` is called. let instances_in_cache_consumer = self - .make_instances_in_cache_consumer(enough_instances.clone().cached); + .make_instances_in_cache_consumer( + enough_instances.clone().cached, + ); Ok(( instances_in_cache_consumer, InternalFactorInstancesProviderOutcome::satisfied_by_cache( @@ -374,8 +376,7 @@ impl FactorInstancesProvider { pf_paths .into_iter() .map(|(fs, paths)| (fs, paths)) - - } + } ) .collect::, - >::new(); + let mut pdp_pf_instances = IndexMap::< + DerivationPreset, + IndexMap, + >::new(); - for (preset, per_factor) in per_preset_per_factor_paths { - let mut pf_instances = - IndexMap::::new(); - for (factor_source_id, paths) in per_factor { - 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); + for (preset, per_factor) in per_preset_per_factor_paths { + let mut pf_instances = + IndexMap::::new(); + for (factor_source_id, paths) in per_factor { + 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::(), + ); } - pf_instances.insert( - factor_source_id, - derived_for_factor.into_iter().collect::(), - ); - }; - pdp_pf_instances.insert(preset, pf_instances); - } + pdp_pf_instances.insert(preset, pf_instances); + } Ok(pdp_pf_instances) } diff --git a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider_unit_tests.rs b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider_unit_tests.rs index 70ca149f6..7d851cf44 100644 --- a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider_unit_tests.rs +++ b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider_unit_tests.rs @@ -117,7 +117,7 @@ impl SargonOS { .for_each(|a| assert!(self.account_by_address(*a).is_ok())); let outcome = self.make_security_structure_of_factor_instances_for_entities_without_consuming_cache_with_derivation_outcome( - account_addresses.clone(), + account_addresses.clone().into_iter().map(Into::into).collect(), shield.clone()).await?; let ( @@ -137,7 +137,9 @@ impl SargonOS { .map(|account_address| { let security_structure_of_factor_instances = security_structures_of_factor_instances - .shift_remove(&account_address) + .shift_remove(&AddressOfAccountOrPersona::from( + account_address, + )) .unwrap(); // Production ready code should batch update accounts, submit batch transaction to @@ -510,6 +512,7 @@ async fn cache_is_unchanged_in_case_of_failure() { .clone() .into_iter() .map(|a| a.address()) + .map(AddressOfAccountOrPersona::from) .collect(), shield_0.clone()).await.unwrap(); @@ -581,6 +584,7 @@ async fn cache_is_unchanged_in_case_of_failure() { .clone() .into_iter() .map(|a| a.address()) + .map(AddressOfAccountOrPersona::from) .collect(), shield_0.clone() ) @@ -635,7 +639,7 @@ async fn test_assert_factor_instances_invalid() { let shield_0 = SecurityStructureOfFactorSources::new(DisplayName::sample(), matrix_0); - let (security_structure_of_fis, _, _) = os.make_security_structure_of_factor_instances_for_entities_without_consuming_cache_with_derivation_outcome(IndexSet::from_iter([alice.address()]), shield_0.clone()).await.unwrap(); + let (security_structure_of_fis, _, _) = os.make_security_structure_of_factor_instances_for_entities_without_consuming_cache_with_derivation_outcome(IndexSet::from_iter([AddressOfAccountOrPersona::from(alice.address())]), shield_0.clone()).await.unwrap(); let security_structure_of_fi = security_structure_of_fis.values().next().unwrap().clone(); @@ -976,7 +980,7 @@ async fn test_securified_accounts() { let (security_structures_of_fis, instances_in_cache_consumer, derivation_outcome) = os .make_security_structure_of_factor_instances_for_entities_without_consuming_cache_with_derivation_outcome( - IndexSet::from_iter([alice.address(), bob.address()]), + IndexSet::from_iter([AddressOfAccountOrPersona::from(alice.address()), AddressOfAccountOrPersona::from(bob.address())]), shield_0, ) .await @@ -990,7 +994,9 @@ async fn test_securified_accounts() { // Don't forget to consume! instances_in_cache_consumer.consume().await.unwrap(); - let alice_sec = security_structures_of_fis.get(&alice.address()).unwrap(); + let alice_sec = security_structures_of_fis + .get(&AddressOfAccountOrPersona::from(alice.address())) + .unwrap(); let alice_matrix = alice_sec.matrix_of_factors.clone(); assert_eq!(alice_matrix.primary().get_threshold(), 2); @@ -1029,7 +1035,9 @@ async fn test_securified_accounts() { // assert bob - let bob_sec = security_structures_of_fis.get(&bob.address()).unwrap(); + let bob_sec = security_structures_of_fis + .get(&AddressOfAccountOrPersona::from(bob.address())) + .unwrap(); let bob_matrix = bob_sec.matrix_of_factors.clone(); assert_eq!(bob_matrix.primary().get_threshold(), 2); @@ -1110,7 +1118,7 @@ async fn test_securified_accounts() { let (security_structures_of_fis, instances_in_cache_consumer, _) = os .make_security_structure_of_factor_instances_for_entities_without_consuming_cache_with_derivation_outcome( - IndexSet::from_iter([carol.address()]), + IndexSet::from_iter([AddressOfAccountOrPersona::from(carol.address())]), shield_1.clone(), ) .await @@ -1119,7 +1127,9 @@ async fn test_securified_accounts() { // Don't forget to consume! instances_in_cache_consumer.consume().await.unwrap(); - let carol_sec = security_structures_of_fis.get(&carol.address()).unwrap(); + let carol_sec = security_structures_of_fis + .get(&AddressOfAccountOrPersona::from(carol.address())) + .unwrap(); let carol_matrix = carol_sec.matrix_of_factors.clone(); assert_eq!(carol_matrix.primary_role.get_threshold_factors().len(), 1); @@ -1151,7 +1161,7 @@ async fn test_securified_accounts() { // Update Alice's shield 1 - only Passphrase as override factor let (security_structures_of_fis, instances_in_cache_consumer, derivation_outcome) = os .make_security_structure_of_factor_instances_for_entities_without_consuming_cache_with_derivation_outcome( - IndexSet::from_iter([alice.address()]), + IndexSet::from_iter([AddressOfAccountOrPersona::from(alice.address())]), shield_1, ) .await @@ -1165,7 +1175,9 @@ async fn test_securified_accounts() { "should have used cache" ); - let alice_sec = security_structures_of_fis.get(&alice.address()).unwrap(); + let alice_sec = security_structures_of_fis + .get(&AddressOfAccountOrPersona::from(alice.address())) + .unwrap(); let alice_matrix = alice_sec.matrix_of_factors.clone(); @@ -1265,7 +1277,7 @@ async fn securify_accounts_when_cache_is_half_full_single_factor_source() { let (security_structures_of_fis, instances_in_cache_consumer, derivation_outcome) = os .make_security_structure_of_factor_instances_for_entities_without_consuming_cache_with_derivation_outcome( - first_half_of_accounts.clone().into_iter().map(|a| a.address()).collect(), + first_half_of_accounts.clone().into_iter().map(|a| a.address()).map(AddressOfAccountOrPersona::from).collect(), shield_0.clone(), ) .await @@ -1301,7 +1313,9 @@ async fn securify_accounts_when_cache_is_half_full_single_factor_source() { let (security_structures_of_fis, instances_in_cache_consumer, derivation_outcome) = os .make_security_structure_of_factor_instances_for_entities_without_consuming_cache_with_derivation_outcome( - second_half_of_accounts.clone().into_iter().map(|a| a.address()).collect(), + second_half_of_accounts.clone().into_iter().map(|a| a.address()) + .map(AddressOfAccountOrPersona::from) + .collect(), shield_0.clone(), ) .await @@ -1413,7 +1427,7 @@ async fn securify_accounts_when_cache_is_half_full_multiple_factor_sources() { let (security_structures_of_fis, instances_in_cache_consumer, derivation_outcome) = os .make_security_structure_of_factor_instances_for_entities_without_consuming_cache_with_derivation_outcome( - first_half_of_accounts.clone().into_iter().map(|a| a.address()).collect(), + first_half_of_accounts.clone().into_iter().map(|a| a.address()).map(AddressOfAccountOrPersona::from).collect(), shield_0.clone(), ) .await @@ -1491,7 +1505,9 @@ async fn securify_accounts_when_cache_is_half_full_multiple_factor_sources() { let (security_structures_of_fis, instances_in_cache_consumer, derivation_outcome) = os .make_security_structure_of_factor_instances_for_entities_without_consuming_cache_with_derivation_outcome( - second_half_of_accounts.clone().into_iter().map(|a| a.address()).collect(), + second_half_of_accounts.clone().into_iter().map(|a| a.address()) + .map(AddressOfAccountOrPersona::from) + .collect(), shield_0.clone(), ) .await @@ -1650,7 +1666,9 @@ async fn securify_personas_when_cache_is_half_full_single_factor_source() { let (security_structures_of_fis, instances_in_cache_consumer, derivation_outcome) = os .make_security_structure_of_factor_instances_for_entities_without_consuming_cache_with_derivation_outcome( - first_half_of_personas.clone().into_iter().map(|a| a.address()).collect(), + first_half_of_personas.clone().into_iter().map(|a| a.address()) + .map(AddressOfAccountOrPersona::from) + .collect(), shield_0.clone(), ) .await @@ -1685,7 +1703,7 @@ async fn securify_personas_when_cache_is_half_full_single_factor_source() { let (security_structures_of_fis, instances_in_cache_consumer, derivation_outcome) = os .make_security_structure_of_factor_instances_for_entities_without_consuming_cache_with_derivation_outcome( - second_half_of_personas.clone().into_iter().map(|a| a.address()).collect(), + second_half_of_personas.clone().into_iter().map(|a| a.address()).map(AddressOfAccountOrPersona::from).collect(), shield_0.clone(), ) .await @@ -1762,7 +1780,7 @@ async fn create_single_account() { let (security_structures_of_fis, instances_in_cache_consumer, derivation_outcome) = os .make_security_structure_of_factor_instances_for_entities_without_consuming_cache_with_derivation_outcome( - IndexSet::just(alice.address()), + IndexSet::just(AddressOfAccountOrPersona::from(alice.address())), shield_0.clone(), ) .await @@ -1776,7 +1794,9 @@ async fn create_single_account() { "should have used cache" ); - let alice_sec = security_structures_of_fis.get(&alice.address()).unwrap(); + let alice_sec = security_structures_of_fis + .get(&AddressOfAccountOrPersona::from(alice.address())) + .unwrap(); let alice_matrix = alice_sec.matrix_of_factors.clone(); @@ -1851,7 +1871,7 @@ async fn securified_personas() { let (security_structures_of_fis, instances_in_cache_consumer, derivation_outcome) = os .make_security_structure_of_factor_instances_for_entities_without_consuming_cache_with_derivation_outcome( - IndexSet::from_iter([batman.address(), satoshi.address()]), + IndexSet::from_iter([AddressOfAccountOrPersona::from(batman.address()), AddressOfAccountOrPersona::from(satoshi.address())]), shield_0, ) .await @@ -1865,7 +1885,9 @@ async fn securified_personas() { // Don't forget to consume! instances_in_cache_consumer.consume().await.unwrap(); - let batman_sec = security_structures_of_fis.get(&batman.address()).unwrap(); + let batman_sec = security_structures_of_fis + .get(&AddressOfAccountOrPersona::from(batman.address())) + .unwrap(); let batman_matrix = batman_sec.matrix_of_factors.clone(); assert_eq!(batman_matrix.primary().get_threshold(), 2); @@ -1904,8 +1926,9 @@ async fn securified_personas() { // assert satoshi - let satoshi_sec = - security_structures_of_fis.get(&satoshi.address()).unwrap(); + let satoshi_sec = security_structures_of_fis + .get(&AddressOfAccountOrPersona::from(satoshi.address())) + .unwrap(); let satoshi_matrix = satoshi_sec.matrix_of_factors.clone(); assert_eq!(satoshi_matrix.primary().get_threshold(), 2); @@ -1989,7 +2012,7 @@ async fn securified_personas() { let (security_structures_of_fis, instances_in_cache_consumer, derivation_outcome) = os .make_security_structure_of_factor_instances_for_entities_without_consuming_cache_with_derivation_outcome( - IndexSet::from_iter([hyde.address()]), + IndexSet::from_iter([AddressOfAccountOrPersona::from(hyde.address())]), shield_1.clone(), ) .await @@ -2003,7 +2026,9 @@ async fn securified_personas() { "should have used cache" ); - let hyde_sec = security_structures_of_fis.get(&hyde.address()).unwrap(); + let hyde_sec = security_structures_of_fis + .get(&AddressOfAccountOrPersona::from(hyde.address())) + .unwrap(); let hyde_matrix = hyde_sec.matrix_of_factors.clone(); assert_eq!(hyde_matrix.primary_role.get_threshold_factors().len(), 1); @@ -2035,7 +2060,7 @@ async fn securified_personas() { // Update Batman's shield 1 - only Passphrase as override factor let (security_structures_of_fis, instances_in_cache_consumer, derivation_outcome) = os .make_security_structure_of_factor_instances_for_entities_without_consuming_cache_with_derivation_outcome( - IndexSet::from_iter([batman.address()]), + IndexSet::from_iter([AddressOfAccountOrPersona::from(batman.address())]), shield_1, ) .await @@ -2048,7 +2073,9 @@ async fn securified_personas() { "should have used cache" ); - let batman_sec = security_structures_of_fis.get(&batman.address()).unwrap(); + let batman_sec = security_structures_of_fis + .get(&AddressOfAccountOrPersona::from(batman.address())) + .unwrap(); let batman_matrix = batman_sec.matrix_of_factors.clone(); diff --git a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/securify_entity_factor_instances_provider.rs b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/securify_entity_factor_instances_provider.rs index 05df9e9f9..fd9c0300e 100644 --- a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/securify_entity_factor_instances_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/securify_entity_factor_instances_provider.rs @@ -342,7 +342,7 @@ mod tests { &bdfs.id_from_hash(), ) .unwrap(); - assert_eq!(account_outcome.len(), 1); + assert_eq!(account_outcome.to_use_directly.len(), 1); // let profile = Arc::new(os.profile().unwrap()); // let (instances_in_cache_consumer, outcome) = SUT::for_persona_mfa( @@ -364,6 +364,6 @@ mod tests { &bdfs.id_from_hash(), ) .unwrap(); - assert_eq!(persona_outcome.len(), 1); + assert_eq!(persona_outcome.to_use_directly.len(), 1); } } diff --git a/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs b/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs index 7e74c7aca..a2d901c92 100644 --- a/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs +++ b/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs @@ -811,19 +811,20 @@ impl SargonOS { )> { let profile_snapshot = self.profile()?; let key_derivation_interactors = self.keys_derivation_interactor(); - let (instances_in_cache_consumer, outcome) = SecurifyEntityFactorInstancesProvider::for_entity_mfa( Arc::new(self.clients.factor_instances_cache.clone()), Arc::new(profile_snapshot.clone()), - security_structure_of_factor_sources.clone(), + security_structure_of_factor_sources + .clone() + .matrix_of_factors, addresses_of_entities.clone(), key_derivation_interactors, ) .await?; - let matrix_of_factor_sources = + let matrix_of_factor_sources = &security_structure_of_factor_sources.matrix_of_factors; let mut instances_per_preset_per_factor_source = outcome @@ -832,7 +833,7 @@ impl SargonOS { .into_iter() .map(|(preset, pf)| { ( - preset, + preset, pf .per_factor .into_iter() @@ -844,9 +845,12 @@ impl SargonOS { assert_eq!( instances_per_preset_per_factor_source .clone() - .into_iter().flat_map(|(_, y)| { - y.into_iter().map(|(a, _)| a).collect::>() - } ) + .into_iter() + .flat_map(|(_, y)| { + y.into_iter() + .map(|(a, _)| a) + .collect::>() + }) .collect::>(), matrix_of_factor_sources .all_factors() @@ -857,21 +861,27 @@ impl SargonOS { let security_structure_id = security_structure_of_factor_sources.id(); - let mut security_structures_of_factor_instances = IndexMap::::new(); + let mut security_structures_of_factor_instances = IndexMap::< + AddressOfAccountOrPersona, + SecurityStructureOfFactorInstances, + >::new(); - let mut distribute_instances_for_entity_of_kind_if_needed = |entity_kind: CAP26EntityKind| -> Result<()> { - let addresses_of_kind = addresses_of_entities - .iter() - .filter(|a| a.get_entity_kind() == entity_kind) - .collect::>(); + let mut distribute_instances_for_entity_of_kind_if_needed = + |entity_kind: CAP26EntityKind| -> Result<()> { + let addresses_of_kind = addresses_of_entities + .iter() + .filter(|a| a.get_entity_kind() == entity_kind) + .collect::>(); - if addresses_of_kind.is_empty() { return Ok(()) }; - let preset = DerivationPreset::mfa_entity_kind(entity_kind); + if addresses_of_kind.is_empty() { + return Ok(()); + }; + let preset = DerivationPreset::mfa_entity_kind(entity_kind); - let mut instances_per_factor_source = instances_per_preset_per_factor_source.swap_remove(&preset).expect (&format!("Expected to find instances for derivation preset: {:?}", preset)); + let mut instances_per_factor_source = instances_per_preset_per_factor_source.swap_remove(&preset).expect (&format!("Expected to find instances for derivation preset: {:?}", preset)); - for entity_address in addresses_of_kind { - let security_structure_of_factor_instances: SecurityStructureOfFactorInstances = { + for entity_address in addresses_of_kind { + let security_structure_of_factor_instances: SecurityStructureOfFactorInstances = { let matrix_of_factor_instances = MatrixOfFactorInstances::fulfilling_matrix_of_factor_sources_with_instances( &mut instances_per_factor_source, matrix_of_factor_sources.clone(), @@ -886,15 +896,21 @@ impl SargonOS { authentication_signing_instance, )? }; - security_structures_of_factor_instances.insert(entity_address.clone(), security_structure_of_factor_instances); - } + security_structures_of_factor_instances.insert( + entity_address.clone(), + security_structure_of_factor_instances, + ); + } - Ok(()) - }; + Ok(()) + }; - distribute_instances_for_entity_of_kind_if_needed(CAP26EntityKind::Account); - distribute_instances_for_entity_of_kind_if_needed(CAP26EntityKind::Identity); - + distribute_instances_for_entity_of_kind_if_needed( + CAP26EntityKind::Account, + ); + distribute_instances_for_entity_of_kind_if_needed( + CAP26EntityKind::Identity, + ); Ok(( security_structures_of_factor_instances, From 8da5a2de3eb808bd948a879c57d6c458c60e7575 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Tue, 17 Dec 2024 15:45:03 +0100 Subject: [PATCH 27/60] [no ci] WIP --- .../factor_instances_cache.rs | 16 +++++++++ .../provider/factor_instances_provider.rs | 31 +++------------- .../provider_adopters/cache_filler.rs | 36 +++++++++---------- 3 files changed, 37 insertions(+), 46 deletions(-) diff --git a/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs b/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs index a04e41039..9bdd47b1c 100644 --- a/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs +++ b/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs @@ -399,6 +399,22 @@ pub struct CacheNotSatisfied { >, >, } +impl CacheNotSatisfied { + pub fn cached_instances_to_use(&self) -> CachedInstancesToUse { + todo!() + } + + pub fn remaining_quantities_to_derive(&self) -> QuantitiesToDerive { + todo!() + } +} +pub type QuantitiesToDerive = + IndexMap>; + +pub type CachedInstancesToUse = IndexMap< + DerivationPreset, + IndexMap, +>; #[derive(Debug, Clone, PartialEq, Eq)] pub struct CacheSatisfied { diff --git a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs index e247d2495..cd80d4b39 100644 --- a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs @@ -167,25 +167,15 @@ impl FactorInstancesProvider { async fn derive_more_and_cache( &mut self, - // quantified_derivation_preset: QuantifiedDerivationPreset, - // pf_found_in_cache_leq_requested: IndexMap< - // FactorSourceIDFromHash, - // FactorInstances, - // >, - // pf_pdp_qty_to_derive: IndexMap< - // FactorSourceIDFromHash, - // IndexMap, - // >, not_satisfied: CacheNotSatisfied, derivation_purpose: DerivationPurpose, ) -> Result<( InstancesInCacheConsumer, InternalFactorInstancesProviderOutcome, )> { - let pf_newly_derived = self + let pdp_pf_newly_derived = self .derive_more( - // (pf_pdp_qty_to_derive, - not_satisfied, + not_satisfied.remaining_quantities_to_derive(), derivation_purpose, ) .await?; @@ -297,11 +287,7 @@ impl FactorInstancesProvider { pub(super) async fn derive_more( &self, - // pf_pdp_quantity_to_derive: IndexMap< - // FactorSourceIDFromHash, - // IndexMap, - // >, - not_satisfied: CacheNotSatisfied, + quantities_to_derive: QuantitiesToDerive, derivation_purpose: DerivationPurpose, ) -> Result< IndexMap< @@ -319,19 +305,12 @@ impl FactorInstancesProvider { cache_snapshot, ); - let per_preset_per_factor_paths = not_satisfied - .cached_and_quantities_to_derive + let per_preset_per_factor_paths = quantities_to_derive .into_iter() - // .flat_map(|(derivation_preset, instances_and_qty_to_derive)| { - // // pf_pdp_quantity_to_derive - // // .into_iter() - // not_satisfied.quantities_to_derive.into_iter() .map(|(derivation_preset, per_factor_source)| { let per_factor_paths = per_factor_source .into_iter() - .map(|(factor_source_id, instances_and_qty_to_derive)| { - let qty = - instances_and_qty_to_derive.quantity_to_derive; + .map(|(factor_source_id, qty)| { // `qty` many paths let paths = (0..qty) .map(|_| { diff --git a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/cache_filler.rs b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/cache_filler.rs index 80e00ce89..85caf880b 100644 --- a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/cache_filler.rs +++ b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/cache_filler.rs @@ -22,28 +22,24 @@ impl CacheFiller { interactor, ); - let not_satisfied = CacheNotSatisfied { - cached_and_quantities_to_derive: DerivationPreset::all() - .into_iter() - .map(|preset| { - ( - preset, - IndexMap::kv( - factor_source.id_from_hash(), - CacheInstancesAndRemainingQuantityToDerive { - instances_to_use_from_cache: - FactorInstances::default(), // TODO improve surrounding code. should not have to create CacheInstancesAndRemainingQuantityToDerive... - quantity_to_derive: preset - .cache_filling_quantity(), - }, - ), - ) - }) - .collect::>(), - }; + let quantities_to_derive = DerivationPreset::all() + .into_iter() + .map(|preset| { + ( + preset, + IndexMap::kv( + factor_source.id_from_hash(), + preset.cache_filling_quantity(), + ), + ) + }) + .collect::(); let derived = provider - .derive_more(not_satisfied, DerivationPurpose::pre_deriving_keys()) + .derive_more( + quantities_to_derive, + DerivationPurpose::pre_deriving_keys(), + ) .await?; cache_client.insert_all(&derived).await?; From 9a367a49eddfea2dd8bc9594fff88053b9d4543f Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Tue, 17 Dec 2024 15:59:15 +0100 Subject: [PATCH 28/60] [no ci] WIP --- .../factor_instances_cache.rs | 3 +- .../provider/factor_instances_provider.rs | 198 +++++++++--------- ...ernal_factor_instances_provider_outcome.rs | 157 +++++++------- .../client/factor_instances_cache_client.rs | 5 +- 4 files changed, 182 insertions(+), 181 deletions(-) diff --git a/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs b/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs index 9bdd47b1c..7faf1acec 100644 --- a/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs +++ b/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs @@ -411,10 +411,11 @@ impl CacheNotSatisfied { pub type QuantitiesToDerive = IndexMap>; -pub type CachedInstancesToUse = IndexMap< +pub type InstancesPerDerivationPresetPerFactorSource = IndexMap< DerivationPreset, IndexMap, >; +pub type CachedInstancesToUse = InstancesPerDerivationPresetPerFactorSource; #[derive(Debug, Clone, PartialEq, Eq)] pub struct CacheSatisfied { diff --git a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs index cd80d4b39..ffb544343 100644 --- a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs @@ -88,14 +88,7 @@ impl FactorInstancesProvider { impl FactorInstancesProvider { fn make_instances_in_cache_consumer( &self, - // instances_per_factor_sources_to_delete: IndexMap< - // FactorSourceIDFromHash, - // FactorInstances, - // >, - instances_to_delete: IndexMap< - DerivationPreset, - IndexMap, - >, + instances_to_delete: CachedInstancesToUse, ) -> InstancesInCacheConsumer { // let instances_clone = instances_per_factor_sources_to_delete.clone(); // let cache_client_clone = self.cache_client.clone(); @@ -180,109 +173,105 @@ impl FactorInstancesProvider { ) .await?; - // let Split { - // pf_to_use_directly, - // pf_to_cache, - // } = self.split( - // &quantified_derivation_preset, - // &pf_found_in_cache_leq_requested, - // &pf_newly_derived, - // ); - - // let instances_in_cache_consumer = self - // .make_instances_in_cache_consumer( - // pf_found_in_cache_leq_requested.clone(), - // ); + let pdp_pf_found_in_cache_leq_requested = + not_satisfied.cached_instances_to_use(); - // self.cache_client.insert_all(&pf_to_cache).await?; + let Split { + pdp_pf_to_use_directly, + pdp_pf_to_cache, + } = self + .split(&pdp_pf_found_in_cache_leq_requested, &pdp_pf_newly_derived); - // let outcome = InternalFactorInstancesProviderOutcome::transpose( - // pf_to_cache, - // pf_to_use_directly, - // pf_found_in_cache_leq_requested, - // pf_newly_derived, - // ); - // let outcome = outcome; - // Ok((instances_in_cache_consumer, outcome)) - todo!() + let instances_in_cache_consumer = self + .make_instances_in_cache_consumer( + pdp_pf_found_in_cache_leq_requested.clone(), + ); + + self.cache_client.insert_all(&pdp_pf_to_cache).await?; + + let outcome = InternalFactorInstancesProviderOutcome::transpose( + pdp_pf_to_cache, + pdp_pf_to_use_directly, + pdp_pf_found_in_cache_leq_requested, + pdp_pf_newly_derived, + ); + Ok((instances_in_cache_consumer, 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< - FactorSourceIDFromHash, - FactorInstances, - >, - pf_newly_derived: &IndexMap, + pdp_pf_found_in_cache_leq_requested: &InstancesPerDerivationPresetPerFactorSource, + pdp_pf_newly_derived: &InstancesPerDerivationPresetPerFactorSource, ) -> 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.id_from_hash()) - .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); - } + // // 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.id_from_hash()) + // .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); - pf_to_cache.append_or_insert_to( - factor_source_id, - instances_by_derivation_preset.all_instances(), - ); - } + // (factor_source_id, FactorInstances::from(merged)) + // }) + // .collect::>(); - Split { - pf_to_use_directly, - pf_to_cache, - } + // 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, + // } + + todo!() } pub(super) async fn derive_more( @@ -395,7 +384,12 @@ impl FactorInstancesProvider { } } +/// A split of FactorInstances per DerivationPreset per FactorSource +/// is splitting and newly derived FactorInstances and then pre-pending +/// any instances found in cache to `pdp_pf_to_use_directly`. struct Split { - pf_to_use_directly: IndexMap, - pf_to_cache: IndexMap, + /// Per DerivationPreset per FactorSource instances to use directly + pdp_pf_to_use_directly: InstancesPerDerivationPresetPerFactorSource, + /// Per DerivationPreset per FactorSource instances to cache + pdp_pf_to_cache: InstancesPerDerivationPresetPerFactorSource, } diff --git a/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs b/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs index 2936153c2..4b81785b8 100644 --- a/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs +++ b/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs @@ -61,23 +61,26 @@ pub struct InternalFactorInstancesProviderOutcomePerFactor { >, } -impl InternalFactorInstancesProviderOutcomePerFactor { +impl InternalFactorInstancesProviderOutcome { pub fn new( - per_factor: IndexMap< - FactorSourceIDFromHash, - InternalFactorInstancesProviderOutcomeForFactor, + per_derivation_preset: IndexMap< + DerivationPreset, + InternalFactorInstancesProviderOutcomePerFactor, >, ) -> Self { - Self { per_factor } + Self { + per_derivation_preset, + } } /// "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, + pdp_pf_to_cache: InstancesPerDerivationPresetPerFactorSource, + pdp_pf_to_use_directly: InstancesPerDerivationPresetPerFactorSource, + pdp_pf_found_in_cache: InstancesPerDerivationPresetPerFactorSource, + pdp_pf_newly_derived: InstancesPerDerivationPresetPerFactorSource, ) -> Self { + /* struct Builder { factor_source_id: FactorSourceIDFromHash, @@ -171,6 +174,8 @@ impl InternalFactorInstancesProviderOutcomePerFactor { InternalFactorInstancesProviderOutcomeForFactor, >>(), ) + */ + todo!() } } @@ -184,86 +189,90 @@ mod tests { #[test] fn only_to_cache() { - let i = HierarchicalDeterministicFactorInstance::sample_fia0(); + // let i = HierarchicalDeterministicFactorInstance::sample_fia0(); - let sut = SUT::transpose( - IndexMap::kv( - FactorSourceIDFromHash::sample_at(0), - 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) - ) + // let sut = SUT::transpose( + // IndexMap::kv( + // FactorSourceIDFromHash::sample_at(0), + // 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) + // ) + todo!() } #[test] fn only_to_use_directly() { - let i = HierarchicalDeterministicFactorInstance::sample_fia0(); + // let i = HierarchicalDeterministicFactorInstance::sample_fia0(); - let sut = SUT::transpose( - IndexMap::new(), - IndexMap::kv( - FactorSourceIDFromHash::sample_at(0), - 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) - ) + // let sut = SUT::transpose( + // IndexMap::new(), + // IndexMap::kv( + // FactorSourceIDFromHash::sample_at(0), + // 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) + // ) + todo!() } #[test] fn only_found_in_cache() { - let i = HierarchicalDeterministicFactorInstance::sample_fia0(); + // let i = HierarchicalDeterministicFactorInstance::sample_fia0(); - let sut = SUT::transpose( - IndexMap::new(), - IndexMap::new(), - IndexMap::kv( - FactorSourceIDFromHash::sample_at(0), - FactorInstances::just(i.clone()), - ), - IndexMap::new(), - ); - assert_eq!( - sut.per_factor - .get(&i.factor_source_id()) - .unwrap() - .found_in_cache, - FactorInstances::just(i) - ) + // let sut = SUT::transpose( + // IndexMap::new(), + // IndexMap::new(), + // IndexMap::kv( + // FactorSourceIDFromHash::sample_at(0), + // FactorInstances::just(i.clone()), + // ), + // IndexMap::new(), + // ); + // assert_eq!( + // sut.per_factor + // .get(&i.factor_source_id()) + // .unwrap() + // .found_in_cache, + // FactorInstances::just(i) + // ) + todo!() } #[test] fn only_newly_derived() { - let i = HierarchicalDeterministicFactorInstance::sample_fia0(); + // let i = HierarchicalDeterministicFactorInstance::sample_fia0(); - let sut = SUT::transpose( - IndexMap::new(), - IndexMap::new(), - IndexMap::new(), - IndexMap::kv( - FactorSourceIDFromHash::sample_at(0), - FactorInstances::just(i.clone()), - ), - ); - assert_eq!( - sut.per_factor - .get(&i.factor_source_id()) - .unwrap() - .newly_derived, - FactorInstances::just(i) - ) + // let sut = SUT::transpose( + // IndexMap::new(), + // IndexMap::new(), + // IndexMap::new(), + // IndexMap::kv( + // FactorSourceIDFromHash::sample_at(0), + // FactorInstances::just(i.clone()), + // ), + // ); + // assert_eq!( + // sut.per_factor + // .get(&i.factor_source_id()) + // .unwrap() + // .newly_derived, + // FactorInstances::just(i) + // ) + todo!() } } diff --git a/crates/sargon/src/system/clients/client/factor_instances_cache_client.rs b/crates/sargon/src/system/clients/client/factor_instances_cache_client.rs index 4f2707c4b..1ad7a489c 100644 --- a/crates/sargon/src/system/clients/client/factor_instances_cache_client.rs +++ b/crates/sargon/src/system/clients/client/factor_instances_cache_client.rs @@ -139,10 +139,7 @@ impl FactorInstancesCacheClient { pub async fn insert_all( &self, // per_factor: impl Borrow>, - per_derivation_preset_per_factor: &IndexMap< - DerivationPreset, - IndexMap, - >, + per_derivation_preset_per_factor: &InstancesPerDerivationPresetPerFactorSource, ) -> Result<()> { // self.update_and_persist_cache(|cache| { // cache.insert_all(per_factor.borrow()) From 59d597f5d2608b19461aedf29bffddcc31ee9a6c Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Tue, 17 Dec 2024 16:30:11 +0100 Subject: [PATCH 29/60] [no ci] WIP --- ...entity_index_profile_analyzing_assigner.rs | 117 +++++++++++++++++- .../signing/collector/signatures_collector.rs | 6 +- .../petition_types/petition_for_entity.rs | 2 + .../petition_for_transaction.rs | 1 + .../src/types/samples/account_samples.rs | 12 +- .../src/types/samples/persona_samples.rs | 11 +- 6 files changed, 137 insertions(+), 12 deletions(-) diff --git a/crates/sargon/src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_profile_analyzing_assigner.rs b/crates/sargon/src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_profile_analyzing_assigner.rs index a9a51604d..db320b2f9 100644 --- a/crates/sargon/src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_profile_analyzing_assigner.rs +++ b/crates/sargon/src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_profile_analyzing_assigner.rs @@ -163,6 +163,60 @@ impl NextDerivationEntityIndexProfileAnalyzingAssigner { .max() } + /// Returns the max index of true ROLA keys of securified accounts with + /// factor source matching factor_source_id - if any. + fn max_account_rola( + &self, + factor_source_id: FactorSourceIDFromHash, + ) -> Option { + self.securified_accounts_on_network + .clone() + .into_iter() + .map(|e: SecurifiedAccount| { + e.securified_entity_control + .authentication_signing_factor_instance() + }) + .filter(|f| f.factor_source_id() == factor_source_id) + .map(|fi| { + AssertMatches { + network_id: self.network_id, + key_kind: CAP26KeyKind::AuthenticationSigning, + entity_kind: CAP26EntityKind::Account, + key_space: KeySpace::Securified, + } + .matches(&fi.derivation_path()) + .index() + }) + .max() + } + + /// Returns the max index of true ROLA keys of securified personas with + /// factor source matching factor_source_id - if any. + fn max_identity_rola( + &self, + factor_source_id: FactorSourceIDFromHash, + ) -> Option { + self.securified_personas_on_network + .clone() + .into_iter() + .map(|e: SecurifiedPersona| { + e.securified_entity_control + .authentication_signing_factor_instance() + }) + .filter(|f| f.factor_source_id() == factor_source_id) + .map(|fi| { + AssertMatches { + network_id: self.network_id, + key_kind: CAP26KeyKind::AuthenticationSigning, + entity_kind: CAP26EntityKind::Identity, + key_space: KeySpace::Securified, + } + .matches(&fi.derivation_path()) + .index() + }) + .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. @@ -220,8 +274,12 @@ impl NextDerivationEntityIndexProfileAnalyzingAssigner { DerivationPreset::IdentityMfa => { self.max_identity_mfa(factor_source_id) } - DerivationPreset::AccountRola => todo!(), - DerivationPreset::IdentityRola => todo!(), + DerivationPreset::AccountRola => { + self.max_account_rola(factor_source_id) + } + DerivationPreset::IdentityRola => { + self.max_identity_rola(factor_source_id) + } }; let Some(max) = max else { return Ok(None) }; @@ -515,4 +573,59 @@ mod tests { .ok() ) } + + #[test] + fn test_next_account_rola_at_7_is_8() { + let preset = DerivationPreset::AccountRola; + let network_id = NetworkID::Mainnet; + let sut = SUT::new( + network_id, + Arc::new(Profile::sample_from( + FactorSource::sample_all(), + [ + &Account::sample_at(8), /* unsecurified, should not interfere */ + &Account::sample_at(7), + ], + [], + )), + ); + type F = FactorSourceIDFromHash; + for fid in [F::sample_device()] { + let next = sut + .next(fid, preset.index_agnostic_path_on_network(network_id)) + .unwrap(); + + assert_eq!( + next, + HDPathComponent::from_local_key_space(8, KeySpace::Securified) + .ok() + ); + } + } + + #[test] + fn test_next_identity_rola_at_7_is_8() { + let preset = DerivationPreset::IdentityRola; + let network_id = NetworkID::Mainnet; + let sut = SUT::new( + network_id, + Arc::new(Profile::sample_from( + FactorSource::sample_all(), + [], + [&Persona::sample_at(7)], + )), + ); + type F = FactorSourceIDFromHash; + for fid in [F::sample_device()] { + let next = sut + .next(fid, preset.index_agnostic_path_on_network(network_id)) + .unwrap(); + + assert_eq!( + next, + HDPathComponent::from_local_key_space(8, KeySpace::Securified) + .ok() + ) + } + } } diff --git a/crates/sargon/src/signing/collector/signatures_collector.rs b/crates/sargon/src/signing/collector/signatures_collector.rs index 2e7108da5..165f9aea3 100644 --- a/crates/sargon/src/signing/collector/signatures_collector.rs +++ b/crates/sargon/src/signing/collector/signatures_collector.rs @@ -1519,16 +1519,17 @@ mod tests { fn sample_securified_mainnet( name: impl AsRef, + rola_index: u32, veci: HierarchicalDeterministicFactorInstance, make_role: impl Fn() -> GeneralRoleWithHierarchicalDeterministicFactorInstances, ) -> AccountOrPersona { if TypeId::of::() == TypeId::of::() { AccountOrPersona::from(Account::sample_securified_mainnet( - name, veci, make_role, + name, rola_index, veci, make_role, )) } else { AccountOrPersona::from(Persona::sample_securified_mainnet( - name, veci, make_role, + name, rola_index, veci, make_role, )) } } @@ -1896,6 +1897,7 @@ mod tests { SignableWithEntities::::sample([ sample_securified_mainnet::( "Alice", + 0, if E::entity_kind() == CAP26EntityKind::Identity { HierarchicalDeterministicFactorInstance::sample_fii10() diff --git a/crates/sargon/src/signing/petition_types/petition_for_entity.rs b/crates/sargon/src/signing/petition_types/petition_for_entity.rs index e2e600e0b..917e9a9f8 100644 --- a/crates/sargon/src/signing/petition_types/petition_for_entity.rs +++ b/crates/sargon/src/signing/petition_types/petition_for_entity.rs @@ -436,6 +436,7 @@ impl HasSampleValues Self::from_entity_with_role_kind( Account::sample_securified_mainnet( "Grace", + 6, HierarchicalDeterministicFactorInstance::sample_fii10(), || { GeneralRoleWithHierarchicalDeterministicFactorInstances::r6(HierarchicalDeterministicFactorInstance::sample_id_to_instance( @@ -632,6 +633,7 @@ mod tests { let intent_hash = TransactionIntentHash::sample(); let entity = Account::sample_securified_mainnet( "Alice", + 0, HierarchicalDeterministicFactorInstance::sample_fii10(), || { let fi = HierarchicalDeterministicFactorInstance::sample_id_to_instance( diff --git a/crates/sargon/src/signing/petition_types/petition_for_transaction.rs b/crates/sargon/src/signing/petition_types/petition_for_transaction.rs index 7b053d44d..8eb73e126 100644 --- a/crates/sargon/src/signing/petition_types/petition_for_transaction.rs +++ b/crates/sargon/src/signing/petition_types/petition_for_transaction.rs @@ -259,6 +259,7 @@ impl HasSampleValues for PetitionForTransaction { fn sample() -> Self { let account = Account::sample_securified_mainnet( "Grace", + 6, HierarchicalDeterministicFactorInstance::sample_mainnet_account_device_factor_fs_10_unsecurified_at_index(0), || { GeneralRoleWithHierarchicalDeterministicFactorInstances::r6( diff --git a/crates/sargon/src/types/samples/account_samples.rs b/crates/sargon/src/types/samples/account_samples.rs index 3d3c44d1f..1ce6e8c73 100644 --- a/crates/sargon/src/types/samples/account_samples.rs +++ b/crates/sargon/src/types/samples/account_samples.rs @@ -17,6 +17,7 @@ static ALL_ACCOUNT_SAMPLES: Lazy<[Account; 10]> = Lazy::new(|| { // Carla | 2 | Securified { Single Threshold only } Account::sample_securified_mainnet( "Carla", +2, HierarchicalDeterministicFactorInstance::sample_mainnet_account_device_factor_fs_10_unsecurified_at_index(2), || { let idx = @@ -32,6 +33,7 @@ static ALL_ACCOUNT_SAMPLES: Lazy<[Account; 10]> = Lazy::new(|| { // David | 3 | Securified { Single Override only } Account::sample_securified_mainnet( "David", + 3, HierarchicalDeterministicFactorInstance::sample_mainnet_account_device_factor_fs_10_unsecurified_at_index(3), || { let idx = @@ -47,6 +49,7 @@ static ALL_ACCOUNT_SAMPLES: Lazy<[Account; 10]> = Lazy::new(|| { // Emily | 4 | Securified { Threshold factors only #3 } Account::sample_securified_mainnet( "Emily", + 4, HierarchicalDeterministicFactorInstance::sample_mainnet_account_device_factor_fs_10_unsecurified_at_index(4), || { let idx = @@ -62,6 +65,7 @@ static ALL_ACCOUNT_SAMPLES: Lazy<[Account; 10]> = Lazy::new(|| { // Frank | 5 | Securified { Override factors only #2 } Account::sample_securified_mainnet( "Frank", + 5, HierarchicalDeterministicFactorInstance::sample_mainnet_account_device_factor_fs_10_unsecurified_at_index(5), || { let idx = @@ -77,6 +81,7 @@ static ALL_ACCOUNT_SAMPLES: Lazy<[Account; 10]> = Lazy::new(|| { // Grace | 6 | Securified { Threshold #3 and Override factors #2 } Account::sample_securified_mainnet( "Grace", + 6, HierarchicalDeterministicFactorInstance::sample_mainnet_account_device_factor_fs_10_unsecurified_at_index(6), || { let idx = @@ -92,6 +97,7 @@ static ALL_ACCOUNT_SAMPLES: Lazy<[Account; 10]> = Lazy::new(|| { // Ida | 7 | Securified { Threshold only # 5/5 } Account::sample_securified_mainnet( "Ida", + 7, HierarchicalDeterministicFactorInstance::sample_fia11(), || { let idx = @@ -112,6 +118,7 @@ static ALL_ACCOUNT_SAMPLES: Lazy<[Account; 10]> = Lazy::new(|| { // Klara | 9 | Securified { Threshold 1/1 and Override factors #1 } Account::sample_securified_mainnet( "Klara", + 9, HierarchicalDeterministicFactorInstance::sample_fia12(), || { let idx = @@ -153,6 +160,7 @@ impl Account { pub fn sample_securified_mainnet( name: impl AsRef, + rola_index: u32, veci: HierarchicalDeterministicFactorInstance, make_role: impl Fn() -> GeneralRoleWithHierarchicalDeterministicFactorInstances, ) -> Self { @@ -171,10 +179,6 @@ impl Account { .collect_vec(), ); - let rola_index = u32::from( - veci.derivation_entity_index().index_in_local_key_space(), - ); - let network_id = NetworkID::Mainnet; let address = AccountAddress::new(veci.public_key(), NetworkID::Mainnet); diff --git a/crates/sargon/src/types/samples/persona_samples.rs b/crates/sargon/src/types/samples/persona_samples.rs index c4f50722c..7a60fa617 100644 --- a/crates/sargon/src/types/samples/persona_samples.rs +++ b/crates/sargon/src/types/samples/persona_samples.rs @@ -15,6 +15,7 @@ static ALL_PERSONA_SAMPLES: Lazy<[Persona; 8]> = Lazy::new(|| { // Ziggy | 2 | Securified { Single Threshold only } Persona::sample_securified_mainnet( "Ziggy", + 2, HierarchicalDeterministicFactorInstance::sample_mainnet_identity_device_factor_fs_10_unsecurified_at_index(2), || { let idx = @@ -28,6 +29,7 @@ static ALL_PERSONA_SAMPLES: Lazy<[Persona; 8]> = Lazy::new(|| { // Superman | 3 | Securified { Single Override only } Persona::sample_securified_mainnet( "Superman", + 3, HierarchicalDeterministicFactorInstance::sample_mainnet_identity_device_factor_fs_10_unsecurified_at_index(3), || { let idx = @@ -41,6 +43,7 @@ static ALL_PERSONA_SAMPLES: Lazy<[Persona; 8]> = Lazy::new(|| { // Banksy | 4 | Securified { Threshold factors only #3 } Persona::sample_securified_mainnet( "Banksy", + 4, HierarchicalDeterministicFactorInstance::sample_mainnet_identity_device_factor_fs_10_unsecurified_at_index(4), || { let idx = @@ -54,6 +57,7 @@ static ALL_PERSONA_SAMPLES: Lazy<[Persona; 8]> = Lazy::new(|| { // Voltaire | 5 | Securified { Override factors only #2 } Persona::sample_securified_mainnet( "Voltaire", + 6, HierarchicalDeterministicFactorInstance::sample_mainnet_identity_device_factor_fs_10_unsecurified_at_index(5), || { let idx = @@ -67,6 +71,7 @@ static ALL_PERSONA_SAMPLES: Lazy<[Persona; 8]> = Lazy::new(|| { // Kasparov | 6 | Securified { Threshold #3 and Override factors #2 } Persona::sample_securified_mainnet( "Kasparov", + 6, HierarchicalDeterministicFactorInstance::sample_mainnet_identity_device_factor_fs_10_unsecurified_at_index(6), || { let idx = @@ -80,6 +85,7 @@ static ALL_PERSONA_SAMPLES: Lazy<[Persona; 8]> = Lazy::new(|| { // Pelé | 7 | Securified { Threshold only # 5/5 } Persona::sample_securified_mainnet( "Pelé", + 7, HierarchicalDeterministicFactorInstance::sample_mainnet_identity_device_factor_fs_10_unsecurified_at_index(7), || { let idx = @@ -151,6 +157,7 @@ impl Persona { pub fn sample_securified_mainnet( name: impl AsRef, + rola_index: u32, veci: HierarchicalDeterministicFactorInstance, make_role: impl Fn() -> GeneralRoleWithHierarchicalDeterministicFactorInstances, ) -> Self { @@ -204,10 +211,6 @@ impl Persona { let address = IdentityAddress::new(veci.public_key(), NetworkID::Mainnet); - let rola_index = u32::from( - veci.derivation_entity_index().index_in_local_key_space(), - ); - let security_structure_of_factor_instances = SecurityStructureOfFactorInstances::new( SecurityStructureID::sample(), From e3de138f676503833b8a67085a0d71f55fa47940 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Tue, 17 Dec 2024 16:44:33 +0100 Subject: [PATCH 30/60] [no ci] WIP --- .../factor_instances_cache.rs | 66 ++++++++++++------- .../provider_adopters/cache_filler.rs | 27 ++++---- 2 files changed, 59 insertions(+), 34 deletions(-) diff --git a/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs b/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs index 7faf1acec..251d49952 100644 --- a/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs +++ b/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs @@ -401,11 +401,34 @@ pub struct CacheNotSatisfied { } impl CacheNotSatisfied { pub fn cached_instances_to_use(&self) -> CachedInstancesToUse { - todo!() + self.cached_and_quantities_to_derive + .clone() + .into_iter() + .map(|(preset, v)| { + ( + preset, + v.into_iter() + .map(|(x, y)| (x, y.instances_to_use_from_cache)) + .collect::>() + , + ) + }) + .collect::() } pub fn remaining_quantities_to_derive(&self) -> QuantitiesToDerive { - todo!() + self.cached_and_quantities_to_derive + .clone() + .into_iter() + .map(|(preset, v)| { + ( + preset, + v.into_iter() + .map(|(x, y)| (x, y.quantity_to_derive)) + .collect::>(), + ) + }) + .collect::() } } pub type QuantitiesToDerive = @@ -565,26 +588,25 @@ impl FactorInstancesCache { network_id: NetworkID, factor_source_id: FactorSourceIDFromHash, ) -> bool { - // get. - // 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(_)) - // ) - // }) - todo!() + let cache_filling_quantities = DerivationPreset::all() + .into_iter() + .map(|preset| { + QuantifiedDerivationPreset::new( + preset, + preset.cache_filling_quantity(), + ) + }) + .collect::>(); + + let Ok(outcome) = self.get( + &IndexSet::just(factor_source_id), + &cache_filling_quantities, + network_id, + ) else { + return false; + }; + + outcome.is_satisfied() } pub fn assert_is_full( diff --git a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/cache_filler.rs b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/cache_filler.rs index 85caf880b..1905a532e 100644 --- a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/cache_filler.rs +++ b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/cache_filler.rs @@ -3,6 +3,18 @@ use crate::prelude::*; /// Uses a `FactorInstancesProvider` to fill the cache with instances for a new FactorSource. pub struct CacheFiller; +pub struct CacheFillingQuantities; +impl CacheFillingQuantities { + pub fn for_factor_source(id: FactorSourceIDFromHash) -> QuantitiesToDerive { + DerivationPreset::all() + .into_iter() + .map(|preset| { + (preset, IndexMap::kv(id, preset.cache_filling_quantity())) + }) + .collect::() + } +} + 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 @@ -22,18 +34,9 @@ impl CacheFiller { interactor, ); - let quantities_to_derive = DerivationPreset::all() - .into_iter() - .map(|preset| { - ( - preset, - IndexMap::kv( - factor_source.id_from_hash(), - preset.cache_filling_quantity(), - ), - ) - }) - .collect::(); + let quantities_to_derive = CacheFillingQuantities::for_factor_source( + factor_source.id_from_hash(), + ); let derived = provider .derive_more( From c0e0b420e50c9f3a24ca42baa9e1fdcf852d7931 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Tue, 17 Dec 2024 19:43:28 +0100 Subject: [PATCH 31/60] [no ci] WIP --- .../src/keys_collector/derivation_purpose.rs | 4 + .../factor_instances_cache.rs | 140 ++++++++++-------- .../provider/factor_instances_provider.rs | 21 ++- .../client/factor_instances_cache_client.rs | 62 +++----- crates/sargon/tests/integration/main.rs | 3 + rustc-ice-2024-12-17T15_45_54-6125.txt | 43 ++++++ rustc-ice-2024-12-17T15_46_27-6146.txt | 43 ++++++ rustc-ice-2024-12-17T15_46_47-6151.txt | 43 ++++++ rustc-ice-2024-12-17T15_47_00-6158.txt | 43 ++++++ 9 files changed, 286 insertions(+), 116 deletions(-) create mode 100644 rustc-ice-2024-12-17T15_45_54-6125.txt create mode 100644 rustc-ice-2024-12-17T15_46_27-6146.txt create mode 100644 rustc-ice-2024-12-17T15_46_47-6151.txt create mode 100644 rustc-ice-2024-12-17T15_47_00-6158.txt diff --git a/crates/sargon-uniffi/src/keys_collector/derivation_purpose.rs b/crates/sargon-uniffi/src/keys_collector/derivation_purpose.rs index 53dfc05e8..8e81de364 100644 --- a/crates/sargon-uniffi/src/keys_collector/derivation_purpose.rs +++ b/crates/sargon-uniffi/src/keys_collector/derivation_purpose.rs @@ -23,6 +23,10 @@ pub enum DerivationPurpose { /// for identity MFA SecurifyingPersona, + /// When applying a security shield to accounts and personas mixed, initiates keys collection + /// for account MFA + SecurifyingAccountsAndPersonas, + /// When adding a new factor source, initiates keys collection /// for collecting various factor instances. PreDerivingKeys, diff --git a/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs b/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs index 251d49952..00683f6b1 100644 --- a/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs +++ b/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs @@ -469,43 +469,50 @@ impl FactorInstancesCache { pub fn delete( &self, - pf_instances: &IndexMap, + pdp_pf_instances: &InstancesPerDerivationPresetPerFactorSource, ) { - for (factor_source_id, instances_to_delete) in pf_instances { - if instances_to_delete.is_empty() { - continue; - } - let mut binding = self.map.write().unwrap(); - let existing_for_factor = binding - .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::< - HierarchicalDeterministicFactorInstance, - >::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!"); + for (preset, pf_instances) in pdp_pf_instances { + for (factor_source_id, instances_to_delete) in pf_instances { + if instances_to_delete.is_empty() { + continue; } - let to_keep = existing_for_path - .symmetric_difference(&instances_to_delete) - .cloned() - .collect::(); + let mut binding = self.map.write().unwrap(); + let existing_for_factor = binding + .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 + { + assert_eq!( + DerivationPreset::try_from(index_agnostic_path) + .unwrap(), + *preset + ); + let instances_to_delete = IndexSet::< + HierarchicalDeterministicFactorInstance, + >::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); + // replace + existing_for_factor.insert(index_agnostic_path, to_keep); + } } } @@ -901,27 +908,28 @@ mod tests { #[test] #[should_panic] fn delete_panics_for_unknown() { - let sut = SUT::default(); - let instances = FactorInstances::sample(); - assert_eq!(instances.len(), 2); - let factor_source_ids = instances - .clone() - .into_iter() - .map(|fi| fi.factor_source_id()) - .collect::>(); - assert_eq!(factor_source_ids.len(), 1); - let fsid = factor_source_ids.into_iter().next().unwrap(); - sut.insert_for_factor( - &fsid, - &instances - .clone() - .into_iter() - .take(1) - .collect::(), - ) - .unwrap(); - - sut.delete(&IndexMap::kv(fsid, instances)); + // let sut = SUT::default(); + // let instances = FactorInstances::sample(); + // assert_eq!(instances.len(), 2); + // let factor_source_ids = instances + // .clone() + // .into_iter() + // .map(|fi| fi.factor_source_id()) + // .collect::>(); + // assert_eq!(factor_source_ids.len(), 1); + // let fsid = factor_source_ids.into_iter().next().unwrap(); + // sut.insert_for_factor( + // &fsid, + // &instances + // .clone() + // .into_iter() + // .take(1) + // .collect::(), + // ) + // .unwrap(); + + // sut.delete(&IndexMap::kv(fsid, instances)); + todo!() } #[test] @@ -970,17 +978,19 @@ mod tests { .unwrap(); } - sut.delete(&to_delete); + todo!() - let path = &IndexAgnosticPath::new( - NetworkID::Mainnet, - CAP26EntityKind::Account, - CAP26KeyKind::TransactionSigning, - KeySpace::Unsecurified { is_hardened: true }, - ); - for (f, instances) in to_remain { - assert_eq!(sut.get_mono_factor(f, path).unwrap(), instances) - } + // sut.delete(&to_delete); + + // let path = &IndexAgnosticPath::new( + // NetworkID::Mainnet, + // CAP26EntityKind::Account, + // CAP26KeyKind::TransactionSigning, + // KeySpace::Unsecurified { is_hardened: true }, + // ); + // for (f, instances) in to_remain { + // assert_eq!(sut.get_mono_factor(f, path).unwrap(), instances) + // } } #[test] diff --git a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs index ffb544343..c8147ec97 100644 --- a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs @@ -90,16 +90,15 @@ impl FactorInstancesProvider { &self, instances_to_delete: CachedInstancesToUse, ) -> InstancesInCacheConsumer { - // let instances_clone = instances_per_factor_sources_to_delete.clone(); - // let cache_client_clone = self.cache_client.clone(); - // InstancesInCacheConsumer::new(move || { - // let cache_client_clone_clone = cache_client_clone.clone(); - // let instances_clone_clone = instances_clone.clone(); - // async move { - // cache_client_clone_clone.delete(instances_clone_clone).await - // } - // }) - todo!() + let instances_clone = instances_to_delete.clone(); + let cache_client_clone = self.cache_client.clone(); + InstancesInCacheConsumer::new(move || { + let cache_client_clone_clone = cache_client_clone.clone(); + let instances_clone_clone = instances_clone.clone(); + async move { + cache_client_clone_clone.delete(instances_clone_clone).await + } + }) } async fn _provide_for_presets( @@ -116,7 +115,7 @@ impl FactorInstancesProvider { let network_id = self.network_id; let cached = self .cache_client - .gets( + .get( &factor_sources.iter().map(|f| f.id_from_hash()).collect(), quantified_derivation_presets.clone(), network_id, diff --git a/crates/sargon/src/system/clients/client/factor_instances_cache_client.rs b/crates/sargon/src/system/clients/client/factor_instances_cache_client.rs index 1ad7a489c..f5b76ae86 100644 --- a/crates/sargon/src/system/clients/client/factor_instances_cache_client.rs +++ b/crates/sargon/src/system/clients/client/factor_instances_cache_client.rs @@ -107,13 +107,12 @@ impl FactorInstancesCacheClient { impl FactorInstancesCacheClient { pub async fn delete( &self, - instances_per_factor_sources_to_delete: IndexMap< - FactorSourceIDFromHash, - FactorInstances, + instances_to_delete: impl Borrow< + InstancesPerDerivationPresetPerFactorSource, >, ) -> Result<()> { self.update_and_persist_cache(|cache| { - cache.delete(instances_per_factor_sources_to_delete.borrow()); + cache.delete(instances_to_delete.borrow()); Ok(()) }) .await @@ -160,39 +159,22 @@ impl FactorInstancesCacheClient { .await } - pub async fn gets( + pub async fn get( &self, factor_source_ids: impl Borrow>, - quantified_derivation_presets: IdentifiedVecOf< - QuantifiedDerivationPreset, + quantified_derivation_presets: impl Borrow< + IdentifiedVecOf, >, network_id: NetworkID, ) -> Result { - let mut unaggregated = IndexMap::new(); - let mut is_satisfied = true; - for quantified_preset in quantified_derivation_presets.items() { - let part = self - .get_poly_factor_with_quantities( - factor_source_ids.borrow(), - quantified_preset, - network_id, - ) - .await?; - is_satisfied &= part.is_satisfied(); - unaggregated.insert(quantified_preset, part); - } - todo!("migrate me") - // if is_satisfied { - // let aggregated = IndexMap::new(); - // todo!("impl me"); - // Ok(CachedInstancesWithQuantitiesOutcome::Satisfied(aggregated)) - // } else { - // let aggregated = IndexMap::new(); - // todo!("impl me"); - // Ok(CachedInstancesWithQuantitiesOutcome::NotSatisfied( - // unaggregated, - // )) - // } + self.access_cache_init_if_needed(|cache| { + cache.get( + factor_source_ids.borrow(), + quantified_derivation_presets.borrow(), + network_id, + ) + }) + .await } /// Returns enough instances to satisfy the requested quantity for each factor source, @@ -345,15 +327,15 @@ mod tests { let five = HDPathComponent::from(five); assert_eq!(max_higher_sut1, Some(five)); - sut2.delete(IndexMap::from_iter([( - fsid, - FactorInstances::from_iter([fi5.clone()]), - )])) - .await - .unwrap(); + // sut2.delete(IndexMap::from_iter([( + // fsid, + // FactorInstances::from_iter([fi5.clone()]), + // )])) + // .await + // .unwrap(); - let max_higher_sut1 = sut1.max_index_for(fsid, path).await.unwrap(); - assert_eq!(max_higher_sut1, Some(one)); + // let max_higher_sut1 = sut1.max_index_for(fsid, path).await.unwrap(); + // assert_eq!(max_higher_sut1, Some(one)); todo!("migrate me") diff --git a/crates/sargon/tests/integration/main.rs b/crates/sargon/tests/integration/main.rs index c7bd8ff28..b0e359c94 100644 --- a/crates/sargon/tests/integration/main.rs +++ b/crates/sargon/tests/integration/main.rs @@ -378,6 +378,7 @@ mod integration_tests { let alice = Account::sample_securified_mainnet( "Alice", + 0, HierarchicalDeterministicFactorInstance::sample_mainnet_account_device_factor_fs_10_unsecurified_at_index(0), || { let i = Hardened::from_local_key_space(0u32, IsSecurified(true)) @@ -397,6 +398,7 @@ mod integration_tests { let bob = Account::sample_securified_mainnet( "Bob", + 1, HierarchicalDeterministicFactorInstance::sample_mainnet_account_device_factor_fs_10_unsecurified_at_index(1), || { let i = Hardened::from_local_key_space(1u32, IsSecurified(true)) @@ -415,6 +417,7 @@ mod integration_tests { let carol = Account::sample_securified_mainnet( "Carol", + 3, HierarchicalDeterministicFactorInstance::sample_mainnet_account_device_factor_fs_10_unsecurified_at_index(2), || { let i = Hardened::from_local_key_space(2u32, IsSecurified(true)) diff --git a/rustc-ice-2024-12-17T15_45_54-6125.txt b/rustc-ice-2024-12-17T15_45_54-6125.txt new file mode 100644 index 000000000..e7609f5c5 --- /dev/null +++ b/rustc-ice-2024-12-17T15_45_54-6125.txt @@ -0,0 +1,43 @@ +thread 'rustc' panicked at compiler/rustc_middle/src/query/on_disk_cache.rs:736:21: +Failed to convert DefPathHash DefPathHash(Fingerprint(13937652913882100335, 10241047049989376580)) +stack backtrace: + 0: 0x10578d114 - std::backtrace::Backtrace::create::h6f354995fe6ed83c + 1: 0x10f63b930 - as core[71b200dc152992dd]::ops::function::Fn<(&dyn for<'a, 'b> core[71b200dc152992dd]::ops::function::Fn<(&'a std[621765fbfb3cf71c]::panic::PanicHookInfo<'b>,), Output = ()> + core[71b200dc152992dd]::marker::Sync + core[71b200dc152992dd]::marker::Send, &std[621765fbfb3cf71c]::panic::PanicHookInfo)>>::call + 2: 0x1057a6348 - std::panicking::rust_panic_with_hook::h5f479b9e9a6322e8 + 3: 0x1057a5c58 - std::panicking::begin_panic_handler::{{closure}}::ha8cf151cd9622f7c + 4: 0x1057a3630 - std::sys::backtrace::__rust_end_short_backtrace::hab21fe9cb48a1cec + 5: 0x1057a5920 - _rust_begin_unwind + 6: 0x105804118 - core::panicking::panic_fmt::h6f336e99db0621aa + 7: 0x11031b178 - >::decode + 8: 0x110310f3c - ::decode_span + 9: 0x11027bfac - as rustc_serialize[eeaf3b4f7a694604]::serialize::Decodable>::decode + 10: 0x1103557c8 - >::decode + 11: 0x110275e40 - as rustc_serialize[eeaf3b4f7a694604]::serialize::Decodable>::decode + 12: 0x11030f9a4 - ::load_side_effects + 13: 0x110cc3ac8 - >::try_mark_previous_green:: + 14: 0x110cc3164 - >::try_mark_green:: + 15: 0x110a22558 - rustc_query_system[13c406b8e35c1113]::query::plumbing::ensure_must_run::>, false, false, false>, rustc_query_impl[b88749e18b22b477]::plumbing::QueryCtxt> + 16: 0x110c37364 - rustc_query_impl[b88749e18b22b477]::query_impl::check_mod_type_wf::get_query_incr::__rust_end_short_backtrace + 17: 0x10f88342c - ::run::<(), rustc_data_structures[67897ec8d1a6d338]::sync::parallel::enabled::par_for_each_in<&rustc_hir[1739eb9ffc10a313]::hir_id::OwnerId, &[rustc_hir[1739eb9ffc10a313]::hir_id::OwnerId], ::par_for_each_module::{closure#0}>::{closure#0}::{closure#0}::{closure#0}> + 18: 0x10f981d6c - ::time::<(), rustc_hir_analysis[83ad024ca6f423e2]::check_crate::{closure#0}> + 19: 0x10f90712c - rustc_hir_analysis[83ad024ca6f423e2]::check_crate + 20: 0x10fef0228 - rustc_interface[e1ad8c3b2884d564]::passes::analysis + 21: 0x110b2a950 - rustc_query_impl[b88749e18b22b477]::plumbing::__rust_begin_short_backtrace::> + 22: 0x110ce4230 - >::call_once + 23: 0x110a464b8 - rustc_query_system[13c406b8e35c1113]::query::plumbing::try_execute_query::>, false, false, false>, rustc_query_impl[b88749e18b22b477]::plumbing::QueryCtxt, true> + 24: 0x110c288dc - rustc_query_impl[b88749e18b22b477]::query_impl::analysis::get_query_incr::__rust_end_short_backtrace + 25: 0x10f625200 - ::enter::> + 26: 0x10f640a60 - ::enter::, rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>> + 27: 0x10f65834c - rustc_span[3f3114d94e8e5419]::create_session_globals_then::, rustc_interface[e1ad8c3b2884d564]::util::run_in_thread_with_globals, rustc_driver_impl[b92bbfa11c0ac6c9]::run_compiler::{closure#0}>::{closure#1}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}::{closure#0}::{closure#0}> + 28: 0x10f626ac8 - std[621765fbfb3cf71c]::sys::backtrace::__rust_begin_short_backtrace::, rustc_driver_impl[b92bbfa11c0ac6c9]::run_compiler::{closure#0}>::{closure#1}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>> + 29: 0x10f6986f8 - <::spawn_unchecked_, rustc_driver_impl[b92bbfa11c0ac6c9]::run_compiler::{closure#0}>::{closure#1}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#1} as core[71b200dc152992dd]::ops::function::FnOnce<()>>::call_once::{shim:vtable#0} + 30: 0x1057ae8f0 - std::sys::pal::unix::thread::Thread::new::thread_start::h1aa3e853685327a4 + 31: 0x19eeaf2e4 - __pthread_deallocate + + +rustc version: 1.82.0-nightly (612a33f20 2024-07-29) +platform: aarch64-apple-darwin + +query stack during panic: +#0 [analysis] running analysis passes on this crate +end of query stack diff --git a/rustc-ice-2024-12-17T15_46_27-6146.txt b/rustc-ice-2024-12-17T15_46_27-6146.txt new file mode 100644 index 000000000..666f7acae --- /dev/null +++ b/rustc-ice-2024-12-17T15_46_27-6146.txt @@ -0,0 +1,43 @@ +thread 'rustc' panicked at compiler/rustc_middle/src/query/on_disk_cache.rs:736:21: +Failed to convert DefPathHash DefPathHash(Fingerprint(13937652913882100335, 10241047049989376580)) +stack backtrace: + 0: 0x102d75114 - std::backtrace::Backtrace::create::h6f354995fe6ed83c + 1: 0x10cc23930 - as core[71b200dc152992dd]::ops::function::Fn<(&dyn for<'a, 'b> core[71b200dc152992dd]::ops::function::Fn<(&'a std[621765fbfb3cf71c]::panic::PanicHookInfo<'b>,), Output = ()> + core[71b200dc152992dd]::marker::Sync + core[71b200dc152992dd]::marker::Send, &std[621765fbfb3cf71c]::panic::PanicHookInfo)>>::call + 2: 0x102d8e348 - std::panicking::rust_panic_with_hook::h5f479b9e9a6322e8 + 3: 0x102d8dc58 - std::panicking::begin_panic_handler::{{closure}}::ha8cf151cd9622f7c + 4: 0x102d8b630 - std::sys::backtrace::__rust_end_short_backtrace::hab21fe9cb48a1cec + 5: 0x102d8d920 - _rust_begin_unwind + 6: 0x102dec118 - core::panicking::panic_fmt::h6f336e99db0621aa + 7: 0x10d903178 - >::decode + 8: 0x10d8f8f3c - ::decode_span + 9: 0x10d863fac - as rustc_serialize[eeaf3b4f7a694604]::serialize::Decodable>::decode + 10: 0x10d93d7c8 - >::decode + 11: 0x10d85de40 - as rustc_serialize[eeaf3b4f7a694604]::serialize::Decodable>::decode + 12: 0x10d8f79a4 - ::load_side_effects + 13: 0x10e2abac8 - >::try_mark_previous_green:: + 14: 0x10e2ab164 - >::try_mark_green:: + 15: 0x10e00a558 - rustc_query_system[13c406b8e35c1113]::query::plumbing::ensure_must_run::>, false, false, false>, rustc_query_impl[b88749e18b22b477]::plumbing::QueryCtxt> + 16: 0x10e21f364 - rustc_query_impl[b88749e18b22b477]::query_impl::check_mod_type_wf::get_query_incr::__rust_end_short_backtrace + 17: 0x10ce6b42c - ::run::<(), rustc_data_structures[67897ec8d1a6d338]::sync::parallel::enabled::par_for_each_in<&rustc_hir[1739eb9ffc10a313]::hir_id::OwnerId, &[rustc_hir[1739eb9ffc10a313]::hir_id::OwnerId], ::par_for_each_module::{closure#0}>::{closure#0}::{closure#0}::{closure#0}> + 18: 0x10cf69d6c - ::time::<(), rustc_hir_analysis[83ad024ca6f423e2]::check_crate::{closure#0}> + 19: 0x10ceef12c - rustc_hir_analysis[83ad024ca6f423e2]::check_crate + 20: 0x10d4d8228 - rustc_interface[e1ad8c3b2884d564]::passes::analysis + 21: 0x10e112950 - rustc_query_impl[b88749e18b22b477]::plumbing::__rust_begin_short_backtrace::> + 22: 0x10e2cc230 - >::call_once + 23: 0x10e02e4b8 - rustc_query_system[13c406b8e35c1113]::query::plumbing::try_execute_query::>, false, false, false>, rustc_query_impl[b88749e18b22b477]::plumbing::QueryCtxt, true> + 24: 0x10e2108dc - rustc_query_impl[b88749e18b22b477]::query_impl::analysis::get_query_incr::__rust_end_short_backtrace + 25: 0x10cc0d200 - ::enter::> + 26: 0x10cc28a60 - ::enter::, rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>> + 27: 0x10cc4034c - rustc_span[3f3114d94e8e5419]::create_session_globals_then::, rustc_interface[e1ad8c3b2884d564]::util::run_in_thread_with_globals, rustc_driver_impl[b92bbfa11c0ac6c9]::run_compiler::{closure#0}>::{closure#1}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}::{closure#0}::{closure#0}> + 28: 0x10cc0eac8 - std[621765fbfb3cf71c]::sys::backtrace::__rust_begin_short_backtrace::, rustc_driver_impl[b92bbfa11c0ac6c9]::run_compiler::{closure#0}>::{closure#1}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>> + 29: 0x10cc806f8 - <::spawn_unchecked_, rustc_driver_impl[b92bbfa11c0ac6c9]::run_compiler::{closure#0}>::{closure#1}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#1} as core[71b200dc152992dd]::ops::function::FnOnce<()>>::call_once::{shim:vtable#0} + 30: 0x102d968f0 - std::sys::pal::unix::thread::Thread::new::thread_start::h1aa3e853685327a4 + 31: 0x19eeaf2e4 - __pthread_deallocate + + +rustc version: 1.82.0-nightly (612a33f20 2024-07-29) +platform: aarch64-apple-darwin + +query stack during panic: +#0 [analysis] running analysis passes on this crate +end of query stack diff --git a/rustc-ice-2024-12-17T15_46_47-6151.txt b/rustc-ice-2024-12-17T15_46_47-6151.txt new file mode 100644 index 000000000..388341704 --- /dev/null +++ b/rustc-ice-2024-12-17T15_46_47-6151.txt @@ -0,0 +1,43 @@ +thread 'rustc' panicked at compiler/rustc_middle/src/query/on_disk_cache.rs:736:21: +Failed to convert DefPathHash DefPathHash(Fingerprint(13937652913882100335, 10241047049989376580)) +stack backtrace: + 0: 0x101911114 - std::backtrace::Backtrace::create::h6f354995fe6ed83c + 1: 0x10b7bf930 - as core[71b200dc152992dd]::ops::function::Fn<(&dyn for<'a, 'b> core[71b200dc152992dd]::ops::function::Fn<(&'a std[621765fbfb3cf71c]::panic::PanicHookInfo<'b>,), Output = ()> + core[71b200dc152992dd]::marker::Sync + core[71b200dc152992dd]::marker::Send, &std[621765fbfb3cf71c]::panic::PanicHookInfo)>>::call + 2: 0x10192a348 - std::panicking::rust_panic_with_hook::h5f479b9e9a6322e8 + 3: 0x101929c58 - std::panicking::begin_panic_handler::{{closure}}::ha8cf151cd9622f7c + 4: 0x101927630 - std::sys::backtrace::__rust_end_short_backtrace::hab21fe9cb48a1cec + 5: 0x101929920 - _rust_begin_unwind + 6: 0x101988118 - core::panicking::panic_fmt::h6f336e99db0621aa + 7: 0x10c49f178 - >::decode + 8: 0x10c494f3c - ::decode_span + 9: 0x10c3fffac - as rustc_serialize[eeaf3b4f7a694604]::serialize::Decodable>::decode + 10: 0x10c4d97c8 - >::decode + 11: 0x10c3f9e40 - as rustc_serialize[eeaf3b4f7a694604]::serialize::Decodable>::decode + 12: 0x10c4939a4 - ::load_side_effects + 13: 0x10ce47ac8 - >::try_mark_previous_green:: + 14: 0x10ce47164 - >::try_mark_green:: + 15: 0x10cba6558 - rustc_query_system[13c406b8e35c1113]::query::plumbing::ensure_must_run::>, false, false, false>, rustc_query_impl[b88749e18b22b477]::plumbing::QueryCtxt> + 16: 0x10cdbb364 - rustc_query_impl[b88749e18b22b477]::query_impl::check_mod_type_wf::get_query_incr::__rust_end_short_backtrace + 17: 0x10ba0742c - ::run::<(), rustc_data_structures[67897ec8d1a6d338]::sync::parallel::enabled::par_for_each_in<&rustc_hir[1739eb9ffc10a313]::hir_id::OwnerId, &[rustc_hir[1739eb9ffc10a313]::hir_id::OwnerId], ::par_for_each_module::{closure#0}>::{closure#0}::{closure#0}::{closure#0}> + 18: 0x10bb05d6c - ::time::<(), rustc_hir_analysis[83ad024ca6f423e2]::check_crate::{closure#0}> + 19: 0x10ba8b12c - rustc_hir_analysis[83ad024ca6f423e2]::check_crate + 20: 0x10c074228 - rustc_interface[e1ad8c3b2884d564]::passes::analysis + 21: 0x10ccae950 - rustc_query_impl[b88749e18b22b477]::plumbing::__rust_begin_short_backtrace::> + 22: 0x10ce68230 - >::call_once + 23: 0x10cbca4b8 - rustc_query_system[13c406b8e35c1113]::query::plumbing::try_execute_query::>, false, false, false>, rustc_query_impl[b88749e18b22b477]::plumbing::QueryCtxt, true> + 24: 0x10cdac8dc - rustc_query_impl[b88749e18b22b477]::query_impl::analysis::get_query_incr::__rust_end_short_backtrace + 25: 0x10b7a9200 - ::enter::> + 26: 0x10b7c4a60 - ::enter::, rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>> + 27: 0x10b7dc34c - rustc_span[3f3114d94e8e5419]::create_session_globals_then::, rustc_interface[e1ad8c3b2884d564]::util::run_in_thread_with_globals, rustc_driver_impl[b92bbfa11c0ac6c9]::run_compiler::{closure#0}>::{closure#1}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}::{closure#0}::{closure#0}> + 28: 0x10b7aaac8 - std[621765fbfb3cf71c]::sys::backtrace::__rust_begin_short_backtrace::, rustc_driver_impl[b92bbfa11c0ac6c9]::run_compiler::{closure#0}>::{closure#1}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>> + 29: 0x10b81c6f8 - <::spawn_unchecked_, rustc_driver_impl[b92bbfa11c0ac6c9]::run_compiler::{closure#0}>::{closure#1}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#1} as core[71b200dc152992dd]::ops::function::FnOnce<()>>::call_once::{shim:vtable#0} + 30: 0x1019328f0 - std::sys::pal::unix::thread::Thread::new::thread_start::h1aa3e853685327a4 + 31: 0x19eeaf2e4 - __pthread_deallocate + + +rustc version: 1.82.0-nightly (612a33f20 2024-07-29) +platform: aarch64-apple-darwin + +query stack during panic: +#0 [analysis] running analysis passes on this crate +end of query stack diff --git a/rustc-ice-2024-12-17T15_47_00-6158.txt b/rustc-ice-2024-12-17T15_47_00-6158.txt new file mode 100644 index 000000000..6a6e9084a --- /dev/null +++ b/rustc-ice-2024-12-17T15_47_00-6158.txt @@ -0,0 +1,43 @@ +thread 'rustc' panicked at compiler/rustc_middle/src/query/on_disk_cache.rs:736:21: +Failed to convert DefPathHash DefPathHash(Fingerprint(13937652913882100335, 10241047049989376580)) +stack backtrace: + 0: 0x1035cd114 - std::backtrace::Backtrace::create::h6f354995fe6ed83c + 1: 0x10d47b930 - as core[71b200dc152992dd]::ops::function::Fn<(&dyn for<'a, 'b> core[71b200dc152992dd]::ops::function::Fn<(&'a std[621765fbfb3cf71c]::panic::PanicHookInfo<'b>,), Output = ()> + core[71b200dc152992dd]::marker::Sync + core[71b200dc152992dd]::marker::Send, &std[621765fbfb3cf71c]::panic::PanicHookInfo)>>::call + 2: 0x1035e6348 - std::panicking::rust_panic_with_hook::h5f479b9e9a6322e8 + 3: 0x1035e5c58 - std::panicking::begin_panic_handler::{{closure}}::ha8cf151cd9622f7c + 4: 0x1035e3630 - std::sys::backtrace::__rust_end_short_backtrace::hab21fe9cb48a1cec + 5: 0x1035e5920 - _rust_begin_unwind + 6: 0x103644118 - core::panicking::panic_fmt::h6f336e99db0621aa + 7: 0x10e15b178 - >::decode + 8: 0x10e150f3c - ::decode_span + 9: 0x10e0bbfac - as rustc_serialize[eeaf3b4f7a694604]::serialize::Decodable>::decode + 10: 0x10e1957c8 - >::decode + 11: 0x10e0b5e40 - as rustc_serialize[eeaf3b4f7a694604]::serialize::Decodable>::decode + 12: 0x10e14f9a4 - ::load_side_effects + 13: 0x10eb03ac8 - >::try_mark_previous_green:: + 14: 0x10eb03164 - >::try_mark_green:: + 15: 0x10e862558 - rustc_query_system[13c406b8e35c1113]::query::plumbing::ensure_must_run::>, false, false, false>, rustc_query_impl[b88749e18b22b477]::plumbing::QueryCtxt> + 16: 0x10ea77364 - rustc_query_impl[b88749e18b22b477]::query_impl::check_mod_type_wf::get_query_incr::__rust_end_short_backtrace + 17: 0x10d6c342c - ::run::<(), rustc_data_structures[67897ec8d1a6d338]::sync::parallel::enabled::par_for_each_in<&rustc_hir[1739eb9ffc10a313]::hir_id::OwnerId, &[rustc_hir[1739eb9ffc10a313]::hir_id::OwnerId], ::par_for_each_module::{closure#0}>::{closure#0}::{closure#0}::{closure#0}> + 18: 0x10d7c1d6c - ::time::<(), rustc_hir_analysis[83ad024ca6f423e2]::check_crate::{closure#0}> + 19: 0x10d74712c - rustc_hir_analysis[83ad024ca6f423e2]::check_crate + 20: 0x10dd30228 - rustc_interface[e1ad8c3b2884d564]::passes::analysis + 21: 0x10e96a950 - rustc_query_impl[b88749e18b22b477]::plumbing::__rust_begin_short_backtrace::> + 22: 0x10eb24230 - >::call_once + 23: 0x10e8864b8 - rustc_query_system[13c406b8e35c1113]::query::plumbing::try_execute_query::>, false, false, false>, rustc_query_impl[b88749e18b22b477]::plumbing::QueryCtxt, true> + 24: 0x10ea688dc - rustc_query_impl[b88749e18b22b477]::query_impl::analysis::get_query_incr::__rust_end_short_backtrace + 25: 0x10d465200 - ::enter::> + 26: 0x10d480a60 - ::enter::, rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>> + 27: 0x10d49834c - rustc_span[3f3114d94e8e5419]::create_session_globals_then::, rustc_interface[e1ad8c3b2884d564]::util::run_in_thread_with_globals, rustc_driver_impl[b92bbfa11c0ac6c9]::run_compiler::{closure#0}>::{closure#1}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}::{closure#0}::{closure#0}> + 28: 0x10d466ac8 - std[621765fbfb3cf71c]::sys::backtrace::__rust_begin_short_backtrace::, rustc_driver_impl[b92bbfa11c0ac6c9]::run_compiler::{closure#0}>::{closure#1}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>> + 29: 0x10d4d86f8 - <::spawn_unchecked_, rustc_driver_impl[b92bbfa11c0ac6c9]::run_compiler::{closure#0}>::{closure#1}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#1} as core[71b200dc152992dd]::ops::function::FnOnce<()>>::call_once::{shim:vtable#0} + 30: 0x1035ee8f0 - std::sys::pal::unix::thread::Thread::new::thread_start::h1aa3e853685327a4 + 31: 0x19eeaf2e4 - __pthread_deallocate + + +rustc version: 1.82.0-nightly (612a33f20 2024-07-29) +platform: aarch64-apple-darwin + +query stack during panic: +#0 [analysis] running analysis passes on this crate +end of query stack From 2dc148401883bf00f96c416feee49cf085f351c7 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Tue, 17 Dec 2024 19:43:58 +0100 Subject: [PATCH 32/60] [no ci] WIP --- rustc-ice-2024-12-17T15_45_54-6125.txt | 43 -------------------------- rustc-ice-2024-12-17T15_46_27-6146.txt | 43 -------------------------- rustc-ice-2024-12-17T15_46_47-6151.txt | 43 -------------------------- rustc-ice-2024-12-17T15_47_00-6158.txt | 43 -------------------------- 4 files changed, 172 deletions(-) delete mode 100644 rustc-ice-2024-12-17T15_45_54-6125.txt delete mode 100644 rustc-ice-2024-12-17T15_46_27-6146.txt delete mode 100644 rustc-ice-2024-12-17T15_46_47-6151.txt delete mode 100644 rustc-ice-2024-12-17T15_47_00-6158.txt diff --git a/rustc-ice-2024-12-17T15_45_54-6125.txt b/rustc-ice-2024-12-17T15_45_54-6125.txt deleted file mode 100644 index e7609f5c5..000000000 --- a/rustc-ice-2024-12-17T15_45_54-6125.txt +++ /dev/null @@ -1,43 +0,0 @@ -thread 'rustc' panicked at compiler/rustc_middle/src/query/on_disk_cache.rs:736:21: -Failed to convert DefPathHash DefPathHash(Fingerprint(13937652913882100335, 10241047049989376580)) -stack backtrace: - 0: 0x10578d114 - std::backtrace::Backtrace::create::h6f354995fe6ed83c - 1: 0x10f63b930 - as core[71b200dc152992dd]::ops::function::Fn<(&dyn for<'a, 'b> core[71b200dc152992dd]::ops::function::Fn<(&'a std[621765fbfb3cf71c]::panic::PanicHookInfo<'b>,), Output = ()> + core[71b200dc152992dd]::marker::Sync + core[71b200dc152992dd]::marker::Send, &std[621765fbfb3cf71c]::panic::PanicHookInfo)>>::call - 2: 0x1057a6348 - std::panicking::rust_panic_with_hook::h5f479b9e9a6322e8 - 3: 0x1057a5c58 - std::panicking::begin_panic_handler::{{closure}}::ha8cf151cd9622f7c - 4: 0x1057a3630 - std::sys::backtrace::__rust_end_short_backtrace::hab21fe9cb48a1cec - 5: 0x1057a5920 - _rust_begin_unwind - 6: 0x105804118 - core::panicking::panic_fmt::h6f336e99db0621aa - 7: 0x11031b178 - >::decode - 8: 0x110310f3c - ::decode_span - 9: 0x11027bfac - as rustc_serialize[eeaf3b4f7a694604]::serialize::Decodable>::decode - 10: 0x1103557c8 - >::decode - 11: 0x110275e40 - as rustc_serialize[eeaf3b4f7a694604]::serialize::Decodable>::decode - 12: 0x11030f9a4 - ::load_side_effects - 13: 0x110cc3ac8 - >::try_mark_previous_green:: - 14: 0x110cc3164 - >::try_mark_green:: - 15: 0x110a22558 - rustc_query_system[13c406b8e35c1113]::query::plumbing::ensure_must_run::>, false, false, false>, rustc_query_impl[b88749e18b22b477]::plumbing::QueryCtxt> - 16: 0x110c37364 - rustc_query_impl[b88749e18b22b477]::query_impl::check_mod_type_wf::get_query_incr::__rust_end_short_backtrace - 17: 0x10f88342c - ::run::<(), rustc_data_structures[67897ec8d1a6d338]::sync::parallel::enabled::par_for_each_in<&rustc_hir[1739eb9ffc10a313]::hir_id::OwnerId, &[rustc_hir[1739eb9ffc10a313]::hir_id::OwnerId], ::par_for_each_module::{closure#0}>::{closure#0}::{closure#0}::{closure#0}> - 18: 0x10f981d6c - ::time::<(), rustc_hir_analysis[83ad024ca6f423e2]::check_crate::{closure#0}> - 19: 0x10f90712c - rustc_hir_analysis[83ad024ca6f423e2]::check_crate - 20: 0x10fef0228 - rustc_interface[e1ad8c3b2884d564]::passes::analysis - 21: 0x110b2a950 - rustc_query_impl[b88749e18b22b477]::plumbing::__rust_begin_short_backtrace::> - 22: 0x110ce4230 - >::call_once - 23: 0x110a464b8 - rustc_query_system[13c406b8e35c1113]::query::plumbing::try_execute_query::>, false, false, false>, rustc_query_impl[b88749e18b22b477]::plumbing::QueryCtxt, true> - 24: 0x110c288dc - rustc_query_impl[b88749e18b22b477]::query_impl::analysis::get_query_incr::__rust_end_short_backtrace - 25: 0x10f625200 - ::enter::> - 26: 0x10f640a60 - ::enter::, rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>> - 27: 0x10f65834c - rustc_span[3f3114d94e8e5419]::create_session_globals_then::, rustc_interface[e1ad8c3b2884d564]::util::run_in_thread_with_globals, rustc_driver_impl[b92bbfa11c0ac6c9]::run_compiler::{closure#0}>::{closure#1}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}::{closure#0}::{closure#0}> - 28: 0x10f626ac8 - std[621765fbfb3cf71c]::sys::backtrace::__rust_begin_short_backtrace::, rustc_driver_impl[b92bbfa11c0ac6c9]::run_compiler::{closure#0}>::{closure#1}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>> - 29: 0x10f6986f8 - <::spawn_unchecked_, rustc_driver_impl[b92bbfa11c0ac6c9]::run_compiler::{closure#0}>::{closure#1}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#1} as core[71b200dc152992dd]::ops::function::FnOnce<()>>::call_once::{shim:vtable#0} - 30: 0x1057ae8f0 - std::sys::pal::unix::thread::Thread::new::thread_start::h1aa3e853685327a4 - 31: 0x19eeaf2e4 - __pthread_deallocate - - -rustc version: 1.82.0-nightly (612a33f20 2024-07-29) -platform: aarch64-apple-darwin - -query stack during panic: -#0 [analysis] running analysis passes on this crate -end of query stack diff --git a/rustc-ice-2024-12-17T15_46_27-6146.txt b/rustc-ice-2024-12-17T15_46_27-6146.txt deleted file mode 100644 index 666f7acae..000000000 --- a/rustc-ice-2024-12-17T15_46_27-6146.txt +++ /dev/null @@ -1,43 +0,0 @@ -thread 'rustc' panicked at compiler/rustc_middle/src/query/on_disk_cache.rs:736:21: -Failed to convert DefPathHash DefPathHash(Fingerprint(13937652913882100335, 10241047049989376580)) -stack backtrace: - 0: 0x102d75114 - std::backtrace::Backtrace::create::h6f354995fe6ed83c - 1: 0x10cc23930 - as core[71b200dc152992dd]::ops::function::Fn<(&dyn for<'a, 'b> core[71b200dc152992dd]::ops::function::Fn<(&'a std[621765fbfb3cf71c]::panic::PanicHookInfo<'b>,), Output = ()> + core[71b200dc152992dd]::marker::Sync + core[71b200dc152992dd]::marker::Send, &std[621765fbfb3cf71c]::panic::PanicHookInfo)>>::call - 2: 0x102d8e348 - std::panicking::rust_panic_with_hook::h5f479b9e9a6322e8 - 3: 0x102d8dc58 - std::panicking::begin_panic_handler::{{closure}}::ha8cf151cd9622f7c - 4: 0x102d8b630 - std::sys::backtrace::__rust_end_short_backtrace::hab21fe9cb48a1cec - 5: 0x102d8d920 - _rust_begin_unwind - 6: 0x102dec118 - core::panicking::panic_fmt::h6f336e99db0621aa - 7: 0x10d903178 - >::decode - 8: 0x10d8f8f3c - ::decode_span - 9: 0x10d863fac - as rustc_serialize[eeaf3b4f7a694604]::serialize::Decodable>::decode - 10: 0x10d93d7c8 - >::decode - 11: 0x10d85de40 - as rustc_serialize[eeaf3b4f7a694604]::serialize::Decodable>::decode - 12: 0x10d8f79a4 - ::load_side_effects - 13: 0x10e2abac8 - >::try_mark_previous_green:: - 14: 0x10e2ab164 - >::try_mark_green:: - 15: 0x10e00a558 - rustc_query_system[13c406b8e35c1113]::query::plumbing::ensure_must_run::>, false, false, false>, rustc_query_impl[b88749e18b22b477]::plumbing::QueryCtxt> - 16: 0x10e21f364 - rustc_query_impl[b88749e18b22b477]::query_impl::check_mod_type_wf::get_query_incr::__rust_end_short_backtrace - 17: 0x10ce6b42c - ::run::<(), rustc_data_structures[67897ec8d1a6d338]::sync::parallel::enabled::par_for_each_in<&rustc_hir[1739eb9ffc10a313]::hir_id::OwnerId, &[rustc_hir[1739eb9ffc10a313]::hir_id::OwnerId], ::par_for_each_module::{closure#0}>::{closure#0}::{closure#0}::{closure#0}> - 18: 0x10cf69d6c - ::time::<(), rustc_hir_analysis[83ad024ca6f423e2]::check_crate::{closure#0}> - 19: 0x10ceef12c - rustc_hir_analysis[83ad024ca6f423e2]::check_crate - 20: 0x10d4d8228 - rustc_interface[e1ad8c3b2884d564]::passes::analysis - 21: 0x10e112950 - rustc_query_impl[b88749e18b22b477]::plumbing::__rust_begin_short_backtrace::> - 22: 0x10e2cc230 - >::call_once - 23: 0x10e02e4b8 - rustc_query_system[13c406b8e35c1113]::query::plumbing::try_execute_query::>, false, false, false>, rustc_query_impl[b88749e18b22b477]::plumbing::QueryCtxt, true> - 24: 0x10e2108dc - rustc_query_impl[b88749e18b22b477]::query_impl::analysis::get_query_incr::__rust_end_short_backtrace - 25: 0x10cc0d200 - ::enter::> - 26: 0x10cc28a60 - ::enter::, rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>> - 27: 0x10cc4034c - rustc_span[3f3114d94e8e5419]::create_session_globals_then::, rustc_interface[e1ad8c3b2884d564]::util::run_in_thread_with_globals, rustc_driver_impl[b92bbfa11c0ac6c9]::run_compiler::{closure#0}>::{closure#1}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}::{closure#0}::{closure#0}> - 28: 0x10cc0eac8 - std[621765fbfb3cf71c]::sys::backtrace::__rust_begin_short_backtrace::, rustc_driver_impl[b92bbfa11c0ac6c9]::run_compiler::{closure#0}>::{closure#1}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>> - 29: 0x10cc806f8 - <::spawn_unchecked_, rustc_driver_impl[b92bbfa11c0ac6c9]::run_compiler::{closure#0}>::{closure#1}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#1} as core[71b200dc152992dd]::ops::function::FnOnce<()>>::call_once::{shim:vtable#0} - 30: 0x102d968f0 - std::sys::pal::unix::thread::Thread::new::thread_start::h1aa3e853685327a4 - 31: 0x19eeaf2e4 - __pthread_deallocate - - -rustc version: 1.82.0-nightly (612a33f20 2024-07-29) -platform: aarch64-apple-darwin - -query stack during panic: -#0 [analysis] running analysis passes on this crate -end of query stack diff --git a/rustc-ice-2024-12-17T15_46_47-6151.txt b/rustc-ice-2024-12-17T15_46_47-6151.txt deleted file mode 100644 index 388341704..000000000 --- a/rustc-ice-2024-12-17T15_46_47-6151.txt +++ /dev/null @@ -1,43 +0,0 @@ -thread 'rustc' panicked at compiler/rustc_middle/src/query/on_disk_cache.rs:736:21: -Failed to convert DefPathHash DefPathHash(Fingerprint(13937652913882100335, 10241047049989376580)) -stack backtrace: - 0: 0x101911114 - std::backtrace::Backtrace::create::h6f354995fe6ed83c - 1: 0x10b7bf930 - as core[71b200dc152992dd]::ops::function::Fn<(&dyn for<'a, 'b> core[71b200dc152992dd]::ops::function::Fn<(&'a std[621765fbfb3cf71c]::panic::PanicHookInfo<'b>,), Output = ()> + core[71b200dc152992dd]::marker::Sync + core[71b200dc152992dd]::marker::Send, &std[621765fbfb3cf71c]::panic::PanicHookInfo)>>::call - 2: 0x10192a348 - std::panicking::rust_panic_with_hook::h5f479b9e9a6322e8 - 3: 0x101929c58 - std::panicking::begin_panic_handler::{{closure}}::ha8cf151cd9622f7c - 4: 0x101927630 - std::sys::backtrace::__rust_end_short_backtrace::hab21fe9cb48a1cec - 5: 0x101929920 - _rust_begin_unwind - 6: 0x101988118 - core::panicking::panic_fmt::h6f336e99db0621aa - 7: 0x10c49f178 - >::decode - 8: 0x10c494f3c - ::decode_span - 9: 0x10c3fffac - as rustc_serialize[eeaf3b4f7a694604]::serialize::Decodable>::decode - 10: 0x10c4d97c8 - >::decode - 11: 0x10c3f9e40 - as rustc_serialize[eeaf3b4f7a694604]::serialize::Decodable>::decode - 12: 0x10c4939a4 - ::load_side_effects - 13: 0x10ce47ac8 - >::try_mark_previous_green:: - 14: 0x10ce47164 - >::try_mark_green:: - 15: 0x10cba6558 - rustc_query_system[13c406b8e35c1113]::query::plumbing::ensure_must_run::>, false, false, false>, rustc_query_impl[b88749e18b22b477]::plumbing::QueryCtxt> - 16: 0x10cdbb364 - rustc_query_impl[b88749e18b22b477]::query_impl::check_mod_type_wf::get_query_incr::__rust_end_short_backtrace - 17: 0x10ba0742c - ::run::<(), rustc_data_structures[67897ec8d1a6d338]::sync::parallel::enabled::par_for_each_in<&rustc_hir[1739eb9ffc10a313]::hir_id::OwnerId, &[rustc_hir[1739eb9ffc10a313]::hir_id::OwnerId], ::par_for_each_module::{closure#0}>::{closure#0}::{closure#0}::{closure#0}> - 18: 0x10bb05d6c - ::time::<(), rustc_hir_analysis[83ad024ca6f423e2]::check_crate::{closure#0}> - 19: 0x10ba8b12c - rustc_hir_analysis[83ad024ca6f423e2]::check_crate - 20: 0x10c074228 - rustc_interface[e1ad8c3b2884d564]::passes::analysis - 21: 0x10ccae950 - rustc_query_impl[b88749e18b22b477]::plumbing::__rust_begin_short_backtrace::> - 22: 0x10ce68230 - >::call_once - 23: 0x10cbca4b8 - rustc_query_system[13c406b8e35c1113]::query::plumbing::try_execute_query::>, false, false, false>, rustc_query_impl[b88749e18b22b477]::plumbing::QueryCtxt, true> - 24: 0x10cdac8dc - rustc_query_impl[b88749e18b22b477]::query_impl::analysis::get_query_incr::__rust_end_short_backtrace - 25: 0x10b7a9200 - ::enter::> - 26: 0x10b7c4a60 - ::enter::, rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>> - 27: 0x10b7dc34c - rustc_span[3f3114d94e8e5419]::create_session_globals_then::, rustc_interface[e1ad8c3b2884d564]::util::run_in_thread_with_globals, rustc_driver_impl[b92bbfa11c0ac6c9]::run_compiler::{closure#0}>::{closure#1}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}::{closure#0}::{closure#0}> - 28: 0x10b7aaac8 - std[621765fbfb3cf71c]::sys::backtrace::__rust_begin_short_backtrace::, rustc_driver_impl[b92bbfa11c0ac6c9]::run_compiler::{closure#0}>::{closure#1}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>> - 29: 0x10b81c6f8 - <::spawn_unchecked_, rustc_driver_impl[b92bbfa11c0ac6c9]::run_compiler::{closure#0}>::{closure#1}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#1} as core[71b200dc152992dd]::ops::function::FnOnce<()>>::call_once::{shim:vtable#0} - 30: 0x1019328f0 - std::sys::pal::unix::thread::Thread::new::thread_start::h1aa3e853685327a4 - 31: 0x19eeaf2e4 - __pthread_deallocate - - -rustc version: 1.82.0-nightly (612a33f20 2024-07-29) -platform: aarch64-apple-darwin - -query stack during panic: -#0 [analysis] running analysis passes on this crate -end of query stack diff --git a/rustc-ice-2024-12-17T15_47_00-6158.txt b/rustc-ice-2024-12-17T15_47_00-6158.txt deleted file mode 100644 index 6a6e9084a..000000000 --- a/rustc-ice-2024-12-17T15_47_00-6158.txt +++ /dev/null @@ -1,43 +0,0 @@ -thread 'rustc' panicked at compiler/rustc_middle/src/query/on_disk_cache.rs:736:21: -Failed to convert DefPathHash DefPathHash(Fingerprint(13937652913882100335, 10241047049989376580)) -stack backtrace: - 0: 0x1035cd114 - std::backtrace::Backtrace::create::h6f354995fe6ed83c - 1: 0x10d47b930 - as core[71b200dc152992dd]::ops::function::Fn<(&dyn for<'a, 'b> core[71b200dc152992dd]::ops::function::Fn<(&'a std[621765fbfb3cf71c]::panic::PanicHookInfo<'b>,), Output = ()> + core[71b200dc152992dd]::marker::Sync + core[71b200dc152992dd]::marker::Send, &std[621765fbfb3cf71c]::panic::PanicHookInfo)>>::call - 2: 0x1035e6348 - std::panicking::rust_panic_with_hook::h5f479b9e9a6322e8 - 3: 0x1035e5c58 - std::panicking::begin_panic_handler::{{closure}}::ha8cf151cd9622f7c - 4: 0x1035e3630 - std::sys::backtrace::__rust_end_short_backtrace::hab21fe9cb48a1cec - 5: 0x1035e5920 - _rust_begin_unwind - 6: 0x103644118 - core::panicking::panic_fmt::h6f336e99db0621aa - 7: 0x10e15b178 - >::decode - 8: 0x10e150f3c - ::decode_span - 9: 0x10e0bbfac - as rustc_serialize[eeaf3b4f7a694604]::serialize::Decodable>::decode - 10: 0x10e1957c8 - >::decode - 11: 0x10e0b5e40 - as rustc_serialize[eeaf3b4f7a694604]::serialize::Decodable>::decode - 12: 0x10e14f9a4 - ::load_side_effects - 13: 0x10eb03ac8 - >::try_mark_previous_green:: - 14: 0x10eb03164 - >::try_mark_green:: - 15: 0x10e862558 - rustc_query_system[13c406b8e35c1113]::query::plumbing::ensure_must_run::>, false, false, false>, rustc_query_impl[b88749e18b22b477]::plumbing::QueryCtxt> - 16: 0x10ea77364 - rustc_query_impl[b88749e18b22b477]::query_impl::check_mod_type_wf::get_query_incr::__rust_end_short_backtrace - 17: 0x10d6c342c - ::run::<(), rustc_data_structures[67897ec8d1a6d338]::sync::parallel::enabled::par_for_each_in<&rustc_hir[1739eb9ffc10a313]::hir_id::OwnerId, &[rustc_hir[1739eb9ffc10a313]::hir_id::OwnerId], ::par_for_each_module::{closure#0}>::{closure#0}::{closure#0}::{closure#0}> - 18: 0x10d7c1d6c - ::time::<(), rustc_hir_analysis[83ad024ca6f423e2]::check_crate::{closure#0}> - 19: 0x10d74712c - rustc_hir_analysis[83ad024ca6f423e2]::check_crate - 20: 0x10dd30228 - rustc_interface[e1ad8c3b2884d564]::passes::analysis - 21: 0x10e96a950 - rustc_query_impl[b88749e18b22b477]::plumbing::__rust_begin_short_backtrace::> - 22: 0x10eb24230 - >::call_once - 23: 0x10e8864b8 - rustc_query_system[13c406b8e35c1113]::query::plumbing::try_execute_query::>, false, false, false>, rustc_query_impl[b88749e18b22b477]::plumbing::QueryCtxt, true> - 24: 0x10ea688dc - rustc_query_impl[b88749e18b22b477]::query_impl::analysis::get_query_incr::__rust_end_short_backtrace - 25: 0x10d465200 - ::enter::> - 26: 0x10d480a60 - ::enter::, rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>> - 27: 0x10d49834c - rustc_span[3f3114d94e8e5419]::create_session_globals_then::, rustc_interface[e1ad8c3b2884d564]::util::run_in_thread_with_globals, rustc_driver_impl[b92bbfa11c0ac6c9]::run_compiler::{closure#0}>::{closure#1}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}::{closure#0}::{closure#0}> - 28: 0x10d466ac8 - std[621765fbfb3cf71c]::sys::backtrace::__rust_begin_short_backtrace::, rustc_driver_impl[b92bbfa11c0ac6c9]::run_compiler::{closure#0}>::{closure#1}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>> - 29: 0x10d4d86f8 - <::spawn_unchecked_, rustc_driver_impl[b92bbfa11c0ac6c9]::run_compiler::{closure#0}>::{closure#1}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[71b200dc152992dd]::result::Result<(), rustc_span[3f3114d94e8e5419]::ErrorGuaranteed>>::{closure#1} as core[71b200dc152992dd]::ops::function::FnOnce<()>>::call_once::{shim:vtable#0} - 30: 0x1035ee8f0 - std::sys::pal::unix::thread::Thread::new::thread_start::h1aa3e853685327a4 - 31: 0x19eeaf2e4 - __pthread_deallocate - - -rustc version: 1.82.0-nightly (612a33f20 2024-07-29) -platform: aarch64-apple-darwin - -query stack during panic: -#0 [analysis] running analysis passes on this crate -end of query stack From 64c17f8b61fc7d341f36fd817885daacfc0e3a08 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Wed, 18 Dec 2024 08:01:59 +0100 Subject: [PATCH 33/60] [no ci] WIP --- .../factor_instances_cache.rs | 24 ++++++++++++------- .../provider/factor_instances_provider.rs | 2 +- .../provider_adopters/cache_filler.rs | 7 +++--- .../client/factor_instances_cache_client.rs | 16 ++++++------- 4 files changed, 28 insertions(+), 21 deletions(-) diff --git a/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs b/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs index 00683f6b1..38c50f874 100644 --- a/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs +++ b/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs @@ -195,13 +195,18 @@ impl FactorInstancesCache { Ok(skipped_an_index_resulting_in_non_contiguity) } - /// Inserts all instance in `per_factor`. - pub fn insert_all( + pub fn insert( &self, - per_factor: &IndexMap, + per_derivation_preset_per_factor: impl Borrow< + InstancesPerDerivationPresetPerFactorSource, + >, ) -> Result<()> { - for (factor_source_id, instances) in per_factor { - _ = self.insert_for_factor(factor_source_id, instances)?; + let per_derivation_preset_per_factor = + per_derivation_preset_per_factor.borrow(); + for (_, per_factor) in per_derivation_preset_per_factor { + for (factor_source_id, instances) in per_factor { + _ = self.insert_for_factor(factor_source_id, instances)?; + } } Ok(()) } @@ -689,9 +694,12 @@ mod tests { fn insert_all_factor_source_id_discrepancy_is_err() { let sut = SUT::default(); assert!(sut - .insert_all(&IndexMap::kv( - FactorSourceIDFromHash::sample_password_other(), - FactorInstances::sample() + .insert(IndexMap::kv( + DerivationPreset::AccountMfa, + IndexMap::kv( + FactorSourceIDFromHash::sample_password_other(), + FactorInstances::sample() + ) )) .is_err()) } diff --git a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs index c8147ec97..ff1a8e286 100644 --- a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs @@ -186,7 +186,7 @@ impl FactorInstancesProvider { pdp_pf_found_in_cache_leq_requested.clone(), ); - self.cache_client.insert_all(&pdp_pf_to_cache).await?; + self.cache_client.insert(&pdp_pf_to_cache).await?; let outcome = InternalFactorInstancesProviderOutcome::transpose( pdp_pf_to_cache, diff --git a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/cache_filler.rs b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/cache_filler.rs index 1905a532e..d6687a8b4 100644 --- a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/cache_filler.rs +++ b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/cache_filler.rs @@ -25,7 +25,7 @@ impl CacheFiller { factor_source: FactorSource, network_id: NetworkID, // typically mainnet interactor: Arc, - ) -> Result { + ) -> Result { let provider = FactorInstancesProvider::new( network_id, IndexSet::just(factor_source.clone()), @@ -45,10 +45,9 @@ impl CacheFiller { ) .await?; - cache_client.insert_all(&derived).await?; - - todo!("migrate me") + cache_client.insert(&derived).await?; + todo!() // let derived = // derived.get(&factor_source.id_from_hash()).unwrap().clone(); // let outcome = InternalFactorInstancesProviderOutcomeForFactor::new( diff --git a/crates/sargon/src/system/clients/client/factor_instances_cache_client.rs b/crates/sargon/src/system/clients/client/factor_instances_cache_client.rs index f5b76ae86..b654fc5cb 100644 --- a/crates/sargon/src/system/clients/client/factor_instances_cache_client.rs +++ b/crates/sargon/src/system/clients/client/factor_instances_cache_client.rs @@ -135,16 +135,16 @@ impl FactorInstancesCacheClient { } /// Inserts all instance in `per_factor`. - pub async fn insert_all( + pub async fn insert( &self, - // per_factor: impl Borrow>, - per_derivation_preset_per_factor: &InstancesPerDerivationPresetPerFactorSource, + per_derivation_preset_per_factor: impl Borrow< + InstancesPerDerivationPresetPerFactorSource, + >, ) -> Result<()> { - // self.update_and_persist_cache(|cache| { - // cache.insert_all(per_factor.borrow()) - // }) - // .await - todo!() + self.update_and_persist_cache(|cache| { + cache.insert(per_derivation_preset_per_factor.borrow()) + }) + .await } /// Returns the max derivation entity index for the given `factor_source_id` and `index_agnostic_path`. From 4b477c621b3b3b24751394950f77cfaf03009a25 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Wed, 18 Dec 2024 09:10:39 +0100 Subject: [PATCH 34/60] [no ci] WIP --- .../src/system/sargon_os/sargon_os_factors.rs | 22 +++++-------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/crates/sargon/src/system/sargon_os/sargon_os_factors.rs b/crates/sargon/src/system/sargon_os/sargon_os_factors.rs index 814c728d7..b04c4361b 100644 --- a/crates/sargon/src/system/sargon_os/sargon_os_factors.rs +++ b/crates/sargon/src/system/sargon_os/sargon_os_factors.rs @@ -222,7 +222,7 @@ impl SargonOS { pub async fn pre_derive_and_fill_cache_with_instances_for_factor_source( &self, factor_source: FactorSource, - ) -> Result { + ) -> Result { if !factor_source.factor_source_id().is_hash() { panic!("Unsupported FactorSource which is not HD.") } @@ -237,22 +237,12 @@ impl SargonOS { ) .await?; - assert_eq!(outcome.factor_source_id, factor_source.id_from_hash()); + assert!(outcome.per_derivation_preset.values().all(|pf| pf + .per_factor + .keys() + .collect_vec() + == vec![&factor_source.id_from_hash()])); - #[cfg(test)] - { - 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 - ); - } Ok(outcome) } From 8ae342f1d7a4046557ec01f1ecd55f54189f7906 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Wed, 18 Dec 2024 09:41:03 +0100 Subject: [PATCH 35/60] [no ci] WIP --- .../provider/factor_instances_provider.rs | 187 ++++++++++-------- 1 file changed, 110 insertions(+), 77 deletions(-) diff --git a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs index ff1a8e286..89aa826cd 100644 --- a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs @@ -140,15 +140,9 @@ impl FactorInstancesProvider { ), )) } - CachedInstancesWithQuantitiesOutcome::NotSatisfied( - // quantities_to_derive, - // partial_instances, - unsatisfied, - ) => { + CachedInstancesWithQuantitiesOutcome::NotSatisfied(unsatisfied) => { self.derive_more_and_cache( - // quantified_derivation_preset, - // partial_instances, - // quantities_to_derive, + &quantified_derivation_presets, unsatisfied, derivation_purpose, ) @@ -159,6 +153,9 @@ impl FactorInstancesProvider { async fn derive_more_and_cache( &mut self, + requested_quantified_derivation_presets: &IdentifiedVecOf< + QuantifiedDerivationPreset, + >, not_satisfied: CacheNotSatisfied, derivation_purpose: DerivationPurpose, ) -> Result<( @@ -178,8 +175,11 @@ impl FactorInstancesProvider { let Split { pdp_pf_to_use_directly, pdp_pf_to_cache, - } = self - .split(&pdp_pf_found_in_cache_leq_requested, &pdp_pf_newly_derived); + } = self.split( + requested_quantified_derivation_presets, + &pdp_pf_found_in_cache_leq_requested, + &pdp_pf_newly_derived, + ); let instances_in_cache_consumer = self .make_instances_in_cache_consumer( @@ -201,76 +201,109 @@ impl FactorInstancesProvider { /// based on the originally requested quantity. fn split( &self, + requested_quantified_derivation_presets: &IdentifiedVecOf< + QuantifiedDerivationPreset, + >, pdp_pf_found_in_cache_leq_requested: &InstancesPerDerivationPresetPerFactorSource, pdp_pf_newly_derived: &InstancesPerDerivationPresetPerFactorSource, ) -> 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.id_from_hash()) - // .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, - // } - - todo!() + // 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 pdp_pf_derived_appended_to_from_cache = DerivationPreset::all() + .iter() + .map(|preset| { + let pf_found_in_cache_leq_requested = + pdp_pf_found_in_cache_leq_requested + .get(preset) + // is it correct to `expect` below? maybe we should `filter_map` and if `pdp_pf_found_in_cache_leq_requested` does not contain the preset, we should assert that neither does `pdp_pf_newly_derived`? + .expect("All DerivationPresets should be present"); + + let pf_newly_derived = pdp_pf_newly_derived + .get(preset) + .expect("All DerivationPresets should be present"); // is this correct? + + let pf_instances = self + .factor_sources + .clone() + .into_iter() + .map(|f| f.id_from_hash()) + .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::>(); + + (*preset, pf_instances) + }) + .collect::(); + + let mut pdp_pf_to_use_directly = + InstancesPerDerivationPresetPerFactorSource::new(); + let mut pdp_pf_to_cache = + InstancesPerDerivationPresetPerFactorSource::new(); + + // Using the merged map, split the instances into those to use directly and those to cache. + for (preset, pf_derived_appended_to_from_cache) in + pdp_pf_derived_appended_to_from_cache + { + let mut pf_to_use_directly = IndexMap::new(); + let mut pf_to_cache = + IndexMap::::new(); + + 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(requested_quantified_derivation_preset) = + requested_quantified_derivation_presets.get_id(&preset) + // is this correct? + { + let instances_relevant_to_use_directly_with_abundance = + instances_by_derivation_preset + .remove(&preset) + .expect("Should have contained the preset"); // is this correct? + let (to_use_directly, to_cache) = + instances_relevant_to_use_directly_with_abundance + .split_at( + requested_quantified_derivation_preset.quantity, + ); + 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(), + ); + } + + pdp_pf_to_use_directly.insert(preset, pf_to_use_directly); + pdp_pf_to_cache.insert(preset, pf_to_cache); + } + + Split { + pdp_pf_to_use_directly, + pdp_pf_to_cache, + } } pub(super) async fn derive_more( From 1da8628dbfab7070a5d37f95f30413f0e987601c Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Wed, 18 Dec 2024 11:11:12 +0100 Subject: [PATCH 36/60] [no ci] WIP --- .../sargon/src/core/types/collections/just.rs | 1 + .../factor_instances_cache.rs | 29 +++-- ...ion_entity_index_with_ephemeral_offsets.rs | 2 + .../provider/factor_instances_provider.rs | 106 +++++++++++------- .../factor_instances_provider_outcome.rs | 4 - .../provider_adopters/cache_filler.rs | 73 +++++++++--- crates/sargon/src/lib.rs | 1 + .../system/sargon_os/sargon_os_accounts.rs | 15 ++- 8 files changed, 155 insertions(+), 76 deletions(-) diff --git a/crates/sargon/src/core/types/collections/just.rs b/crates/sargon/src/core/types/collections/just.rs index edbc34de6..de4bdcc64 100644 --- a/crates/sargon/src/core/types/collections/just.rs +++ b/crates/sargon/src/core/types/collections/just.rs @@ -38,6 +38,7 @@ impl JustKV for HashMap { } } + #[cfg(test)] mod tests { use super::*; diff --git a/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs b/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs index 38c50f874..aad4f2cd4 100644 --- a/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs +++ b/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs @@ -405,7 +405,9 @@ pub struct CacheNotSatisfied { >, } impl CacheNotSatisfied { - pub fn cached_instances_to_use(&self) -> CachedInstancesToUse { + pub fn cached_instances_to_use( + &self, + ) -> InstancesPerDerivationPresetPerFactorSource { self.cached_and_quantities_to_derive .clone() .into_iter() @@ -418,7 +420,7 @@ impl CacheNotSatisfied { , ) }) - .collect::() + .collect::() } pub fn remaining_quantities_to_derive(&self) -> QuantitiesToDerive { @@ -443,7 +445,6 @@ pub type InstancesPerDerivationPresetPerFactorSource = IndexMap< DerivationPreset, IndexMap, >; -pub type CachedInstancesToUse = InstancesPerDerivationPresetPerFactorSource; #[derive(Debug, Clone, PartialEq, Eq)] pub struct CacheSatisfied { @@ -986,19 +987,17 @@ mod tests { .unwrap(); } - todo!() + sut.delete(&IndexMap::kv(DerivationPreset::AccountVeci, to_delete)); - // sut.delete(&to_delete); - - // let path = &IndexAgnosticPath::new( - // NetworkID::Mainnet, - // CAP26EntityKind::Account, - // CAP26KeyKind::TransactionSigning, - // KeySpace::Unsecurified { is_hardened: true }, - // ); - // for (f, instances) in to_remain { - // assert_eq!(sut.get_mono_factor(f, path).unwrap(), instances) - // } + let path = &IndexAgnosticPath::new( + NetworkID::Mainnet, + CAP26EntityKind::Account, + CAP26KeyKind::TransactionSigning, + KeySpace::Unsecurified { is_hardened: true }, + ); + for (f, instances) in to_remain { + assert_eq!(sut.get_mono_factor(f, path).unwrap(), instances) + } } #[test] diff --git a/crates/sargon/src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_with_ephemeral_offsets.rs b/crates/sargon/src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_with_ephemeral_offsets.rs index 0cddfde87..c99862764 100644 --- a/crates/sargon/src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_with_ephemeral_offsets.rs +++ b/crates/sargon/src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_with_ephemeral_offsets.rs @@ -120,8 +120,10 @@ mod tests { vec![ HDPathComponent::unsecurified_hardened(0u32).unwrap(), // Account Veci HDPathComponent::Securified(SecurifiedU30::ZERO), // Account MFA + HDPathComponent::Securified(SecurifiedU30::ZERO), // Account Rola HDPathComponent::unsecurified_hardened(0u32).unwrap(), // Identify Veci HDPathComponent::Securified(SecurifiedU30::ZERO), // Identity MFA + HDPathComponent::Securified(SecurifiedU30::ZERO), // Identity Rola ] ); } diff --git a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs index 89aa826cd..bd7b7127a 100644 --- a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs @@ -88,7 +88,7 @@ impl FactorInstancesProvider { impl FactorInstancesProvider { fn make_instances_in_cache_consumer( &self, - instances_to_delete: CachedInstancesToUse, + instances_to_delete: InstancesPerDerivationPresetPerFactorSource, ) -> InstancesInCacheConsumer { let instances_clone = instances_to_delete.clone(); let cache_client_clone = self.cache_client.clone(); @@ -217,12 +217,15 @@ impl FactorInstancesProvider { let pf_found_in_cache_leq_requested = pdp_pf_found_in_cache_leq_requested .get(preset) - // is it correct to `expect` below? maybe we should `filter_map` and if `pdp_pf_found_in_cache_leq_requested` does not contain the preset, we should assert that neither does `pdp_pf_newly_derived`? - .expect("All DerivationPresets should be present"); - - let pf_newly_derived = pdp_pf_newly_derived + .cloned() + // can be nil -> empty, if no instance was found in cache for this preset! + .unwrap_or_default(); + + let pf_newly_derived = pdp_pf_newly_derived .get(preset) - .expect("All DerivationPresets should be present"); // is this correct? + .cloned() + // can be nil -> empty, if we did not derive any new instance for this preset! + .unwrap_or_default(); let pf_instances = self .factor_sources @@ -310,12 +313,7 @@ impl FactorInstancesProvider { &self, quantities_to_derive: QuantitiesToDerive, derivation_purpose: DerivationPurpose, - ) -> Result< - IndexMap< - DerivationPreset, - IndexMap, - >, - > { + ) -> Result { let factor_sources = self.factor_sources.clone(); let network_id = self.network_id; @@ -368,50 +366,80 @@ impl FactorInstancesProvider { >, >>()?; + println!( + "🌈 per_preset_per_factor_paths: {:#?}", + per_preset_per_factor_paths + ); + let mut per_factor_paths = + IndexMap::>::new(); + for (_, pf) in per_preset_per_factor_paths.clone() { + for (factor_source_id, paths) in pf { + per_factor_paths.append_or_insert_to(factor_source_id, paths); + } + } + + println!("🌈 per_factor_paths: {:#?}", per_factor_paths); + let interactor = self.interactor.clone(); let collector = KeysCollector::new( factor_sources, - per_preset_per_factor_paths.clone().into_iter().flat_map( - |(_, pf_paths)| { - pf_paths - .into_iter() - .map(|(fs, paths)| (fs, paths)) - } - ) - .collect::, - >>(), + per_factor_paths, interactor, derivation_purpose, )?; let pf_derived = collector.collect_keys().await.factors_by_source; + + let pf_pdp_derived = pf_derived + .into_iter() + .map(|(k, v)| { + ( + k, + InstancesByDerivationPreset::from(FactorInstances::from(v)) + .0, + ) + }) + .collect::, + >>(); + + // we need to transpose the `pf_pdp_derived` let mut pdp_pf_instances = IndexMap::< DerivationPreset, IndexMap, >::new(); - for (preset, per_factor) in per_preset_per_factor_paths { - let mut pf_instances = - IndexMap::::new(); - for (factor_source_id, paths) in per_factor { - 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::(), - ); + for (factor_source_id, pdp) in pf_pdp_derived { + for (preset, instances) in pdp { + pdp_pf_instances.append_or_insert_to(preset, IndexMap::::kv(factor_source_id, instances)); } - pdp_pf_instances.insert(preset, pf_instances); } + // for (preset, per_factor) in per_preset_per_factor_paths { + // let mut pf_instances = + // IndexMap::::new(); + + // for (factor_source_id, paths) in per_factor { + // 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::(), + // ); + // } + + // pdp_pf_instances.insert(preset, pf_instances); + // } + Ok(pdp_pf_instances) } } diff --git a/crates/sargon/src/factor_instances_provider/provider/outcome/factor_instances_provider_outcome.rs b/crates/sargon/src/factor_instances_provider/provider/outcome/factor_instances_provider_outcome.rs index c6e995861..29f535a99 100644 --- a/crates/sargon/src/factor_instances_provider/provider/outcome/factor_instances_provider_outcome.rs +++ b/crates/sargon/src/factor_instances_provider/provider/outcome/factor_instances_provider_outcome.rs @@ -4,10 +4,6 @@ use crate::prelude::*; /// 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< - // FactorSourceIDFromHash, - // FactorInstancesProviderOutcomeForFactor, - // >, pub per_derivation_preset: IndexMap, } diff --git a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/cache_filler.rs b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/cache_filler.rs index d6687a8b4..ef519598c 100644 --- a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/cache_filler.rs +++ b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/cache_filler.rs @@ -26,6 +26,10 @@ impl CacheFiller { network_id: NetworkID, // typically mainnet interactor: Arc, ) -> Result { + println!( + "🎊 CacheFiller - factor_source: {:?} START", + factor_source.factor_source_id() + ); let provider = FactorInstancesProvider::new( network_id, IndexSet::just(factor_source.clone()), @@ -33,30 +37,71 @@ impl CacheFiller { cache_client.clone(), interactor, ); + println!( + "🎊 CacheFiller - factor_source: {:?} PROVIDER CREATED", + factor_source.factor_source_id() + ); let quantities_to_derive = CacheFillingQuantities::for_factor_source( factor_source.id_from_hash(), ); - let derived = provider + println!( + "🎊 CacheFiller - factor_source: {:?} quantities_to_derive: {:?}", + factor_source.factor_source_id(), + quantities_to_derive + ); + let pdp_pf_derived = provider .derive_more( quantities_to_derive, DerivationPurpose::pre_deriving_keys(), ) .await?; - cache_client.insert(&derived).await?; - - todo!() - // let derived = - // derived.get(&factor_source.id_from_hash()).unwrap().clone(); - // let outcome = InternalFactorInstancesProviderOutcomeForFactor::new( - // factor_source.id_from_hash(), - // derived.clone(), - // FactorInstances::default(), - // FactorInstances::default(), - // derived, - // ); - // Ok(outcome.into()) + println!( + "🎊 CacheFiller - factor_source: {:?} derived: #{:?}", + factor_source.factor_source_id(), + pdp_pf_derived.clone().values().fold(0, |acc, e| acc + + e.values().fold(0, |xacc, xe| xacc + xe.len())) + ); + cache_client.insert(&pdp_pf_derived).await?; + println!( + "🎊 CacheFiller - factor_source: {:?} INSERTED INTO CACHE", + factor_source.factor_source_id() + ); + + let per_derivation_preset = pdp_pf_derived + .into_iter() + .map(|(preset, v)| { + let per_factor = v + .into_iter() + .map(|(factor_source_id, derived)| { + assert_eq!(factor_source_id, factor_source.id_from_hash()); + + let internal_for_factor = InternalFactorInstancesProviderOutcomeForFactor::new( + factor_source.id_from_hash(), + derived.clone(), + FactorInstances::default(), + FactorInstances::default(), + derived, + ); + let for_factor = FactorInstancesProviderOutcomeForFactor::from(internal_for_factor); + + (factor_source_id, for_factor) + }) + .collect::>(); + + + (preset, FactorInstancesProviderOutcomePerFactor { + per_factor, + }) + }).collect::>(); + + Ok(FactorInstancesProviderOutcome { + per_derivation_preset, + }) } } diff --git a/crates/sargon/src/lib.rs b/crates/sargon/src/lib.rs index 2b5e88723..9d7add72d 100644 --- a/crates/sargon/src/lib.rs +++ b/crates/sargon/src/lib.rs @@ -1,3 +1,4 @@ +#![allow(warnings)] #![feature(async_closure)] #![feature(let_chains)] #![feature(core_intrinsics)] diff --git a/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs b/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs index a2d901c92..605c2d920 100644 --- a/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs +++ b/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs @@ -840,7 +840,7 @@ impl SargonOS { .map(|(k, v)| (k, v.to_use_directly)).collect::>() ) }) - .collect::>>(); + .collect::(); assert_eq!( instances_per_preset_per_factor_source @@ -878,9 +878,11 @@ impl SargonOS { }; let preset = DerivationPreset::mfa_entity_kind(entity_kind); - let mut instances_per_factor_source = instances_per_preset_per_factor_source.swap_remove(&preset).expect (&format!("Expected to find instances for derivation preset: {:?}", preset)); + let mut instances_per_factor_source = instances_per_preset_per_factor_source + .swap_remove(&preset) + .expect(&format!("Expected to find instances for derivation preset: {:?}", preset)); - for entity_address in addresses_of_kind { + for (i, entity_address) in addresses_of_kind.clone().into_iter().enumerate() { let security_structure_of_factor_instances: SecurityStructureOfFactorInstances = { let matrix_of_factor_instances = MatrixOfFactorInstances::fulfilling_matrix_of_factor_sources_with_instances( &mut instances_per_factor_source, @@ -888,7 +890,12 @@ impl SargonOS { )?; // FIXME - TODO: this is wrong! should get from FIP! - let authentication_signing_instance = HierarchicalDeterministicFactorInstance::sample_with_key_kind_entity_kind_on_network_and_hardened_index(entity_address.network_id(), CAP26KeyKind::AuthenticationSigning, entity_kind, Hardened::Securified(SecurifiedU30::ZERO)); + let authentication_signing_instance = HierarchicalDeterministicFactorInstance::sample_with_key_kind_entity_kind_on_network_and_hardened_index( + entity_address.network_id(), + CAP26KeyKind::AuthenticationSigning, + entity_kind, + Hardened::Securified(SecurifiedU30::try_from(i as u32).unwrap()) + ); SecurityStructureOfFactorInstances::new( security_structure_id, From 22c5855583abcc0348ef23bd93fe2c2aa7b3af01 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Wed, 18 Dec 2024 11:40:16 +0100 Subject: [PATCH 37/60] [no ci] WIP --- .../sargon/src/core/types/collections/just.rs | 1 - .../factor_instances_cache.rs | 17 ++-- .../provider/factor_instances_provider.rs | 13 ++- ...ernal_factor_instances_provider_outcome.rs | 96 +++++++++++++++---- .../system/sargon_os/sargon_os_accounts.rs | 4 +- 5 files changed, 101 insertions(+), 30 deletions(-) diff --git a/crates/sargon/src/core/types/collections/just.rs b/crates/sargon/src/core/types/collections/just.rs index de4bdcc64..edbc34de6 100644 --- a/crates/sargon/src/core/types/collections/just.rs +++ b/crates/sargon/src/core/types/collections/just.rs @@ -38,7 +38,6 @@ impl JustKV for HashMap { } } - #[cfg(test)] mod tests { use super::*; diff --git a/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs b/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs index aad4f2cd4..d381aa56d 100644 --- a/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs +++ b/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs @@ -336,11 +336,17 @@ impl FactorInstancesCache { // The instances in the cache cannot satisfy the requested quantity // we must derive more! - let is_quantity_satisfied_for_all = per_derivation_preset + let is_quantity_unsatisfied_for_any = per_derivation_preset .iter() .any(|(_, pf)| pf.iter().any(|(_, ci)| ci.quantity_to_derive > 0)); - let outcome = if is_quantity_satisfied_for_all { + let outcome = if is_quantity_unsatisfied_for_any { + CachedInstancesWithQuantitiesOutcome::NotSatisfied( + CacheNotSatisfied { + cached_and_quantities_to_derive: per_derivation_preset, + }, + ) + } else { CachedInstancesWithQuantitiesOutcome::Satisfied(CacheSatisfied { cached: per_derivation_preset .into_iter() @@ -376,13 +382,8 @@ impl FactorInstancesCache { IndexMap, >>(), }) - } else { - CachedInstancesWithQuantitiesOutcome::NotSatisfied( - CacheNotSatisfied { - cached_and_quantities_to_derive: per_derivation_preset, - }, - ) }; + Ok(outcome) } } diff --git a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs index bd7b7127a..e0d2e2fd1 100644 --- a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs @@ -220,7 +220,6 @@ impl FactorInstancesProvider { .cloned() // can be nil -> empty, if no instance was found in cache for this preset! .unwrap_or_default(); - let pf_newly_derived = pdp_pf_newly_derived .get(preset) .cloned() @@ -389,7 +388,7 @@ impl FactorInstancesProvider { )?; let pf_derived = collector.collect_keys().await.factors_by_source; - + let pf_pdp_derived = pf_derived .into_iter() .map(|(k, v)| { @@ -404,7 +403,7 @@ impl FactorInstancesProvider { IndexMap, >>(); - // we need to transpose the `pf_pdp_derived` + // we need to transpose the `pf_pdp_derived` let mut pdp_pf_instances = IndexMap::< DerivationPreset, @@ -413,7 +412,13 @@ impl FactorInstancesProvider { for (factor_source_id, pdp) in pf_pdp_derived { for (preset, instances) in pdp { - pdp_pf_instances.append_or_insert_to(preset, IndexMap::::kv(factor_source_id, instances)); + pdp_pf_instances.append_or_insert_to( + preset, + IndexMap::::kv( + factor_source_id, + instances, + ), + ); } } diff --git a/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs b/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs index 4b81785b8..baab224c2 100644 --- a/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs +++ b/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs @@ -11,18 +11,15 @@ pub struct InternalFactorInstancesProviderOutcome { impl InternalFactorInstancesProviderOutcome { /// Outcome of FactorInstances just from cache, none have been derived. pub fn satisfied_by_cache(satisfied: CacheSatisfied) -> Self { - // Self::new( - // pf_found_in_cache - // .into_iter() - // .map(|(k, v)| { - // ( - // k, - // InternalFactorInstancesProviderOutcomeForFactor::satisfied_by_cache(k, v), - // ) - // }) - // .collect(), - // ) - todo!() + Self::new( + satisfied.cached.into_iter().map(|(preset, x)| { + let per_factor = InternalFactorInstancesProviderOutcomePerFactor::satisfied_by_cache(x); + (preset, per_factor) + }).collect::>() + ) } pub fn get_for_derivation_preset( @@ -73,14 +70,83 @@ impl InternalFactorInstancesProviderOutcome { } } - /// "Transposes" a **collection** of `IndexMap` into `IndexMap` (`InternalFactorInstancesProviderOutcomeForFactor` is essentially a collection of FactorInstance) + /// "Transposes" pub fn transpose( pdp_pf_to_cache: InstancesPerDerivationPresetPerFactorSource, pdp_pf_to_use_directly: InstancesPerDerivationPresetPerFactorSource, pdp_pf_found_in_cache: InstancesPerDerivationPresetPerFactorSource, pdp_pf_newly_derived: InstancesPerDerivationPresetPerFactorSource, ) -> Self { - /* + let mut per_derivation_preset = IndexMap::< + DerivationPreset, + InternalFactorInstancesProviderOutcomePerFactor, + >::new(); + + for preset in DerivationPreset::all().iter() { + let pf_to_cache = + pdp_pf_to_cache.get(preset).cloned().unwrap_or_default(); + let pf_to_use_directly = pdp_pf_to_use_directly + .get(preset) + .cloned() + .unwrap_or_default(); + let pf_found_in_cache = pdp_pf_found_in_cache + .get(preset) + .cloned() + .unwrap_or_default(); + let pf_newly_derived = pdp_pf_newly_derived + .get(preset) + .cloned() + .unwrap_or_default(); + + let per_factor = + InternalFactorInstancesProviderOutcomePerFactor::transpose( + pf_to_cache, + pf_to_use_directly, + pf_found_in_cache, + pf_newly_derived, + ); + + per_derivation_preset.insert(*preset, per_factor); + } + + Self::new(per_derivation_preset) + } +} + +impl InternalFactorInstancesProviderOutcomePerFactor { + 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" + 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, @@ -174,8 +240,6 @@ impl InternalFactorInstancesProviderOutcome { InternalFactorInstancesProviderOutcomeForFactor, >>(), ) - */ - todo!() } } diff --git a/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs b/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs index 605c2d920..8e04362ee 100644 --- a/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs +++ b/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs @@ -882,7 +882,9 @@ impl SargonOS { .swap_remove(&preset) .expect(&format!("Expected to find instances for derivation preset: {:?}", preset)); - for (i, entity_address) in addresses_of_kind.clone().into_iter().enumerate() { + for (i, entity_address) in + addresses_of_kind.clone().into_iter().enumerate() + { let security_structure_of_factor_instances: SecurityStructureOfFactorInstances = { let matrix_of_factor_instances = MatrixOfFactorInstances::fulfilling_matrix_of_factor_sources_with_instances( &mut instances_per_factor_source, From 41b1a1105fb6d833b53ad6a6670850ff995f6057 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Wed, 18 Dec 2024 12:53:55 +0100 Subject: [PATCH 38/60] [no ci] WIP --- Cargo.lock | 4 +- crates/sargon-uniffi/Cargo.toml | 2 +- crates/sargon/Cargo.toml | 2 +- .../factor_instances_cache.rs | 20 ++++-- .../provider/factor_instances_provider.rs | 56 +++++++++------ .../factor_instances_provider_outcome.rs | 37 ++++++---- ...rtual_entity_creating_instance_provider.rs | 3 + crates/sargon/src/lib.rs | 1 - .../client/factor_instances_cache_client.rs | 70 +++++++++++-------- .../system/sargon_os/sargon_os_accounts.rs | 4 +- 10 files changed, 122 insertions(+), 77 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 33a0bb97c..ba11ee775 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2761,7 +2761,7 @@ dependencies = [ [[package]] name = "sargon" -version = "1.1.87" +version = "1.1.90" dependencies = [ "actix-rt", "aes-gcm", @@ -2816,7 +2816,7 @@ dependencies = [ [[package]] name = "sargon-uniffi" -version = "1.1.87" +version = "1.1.90" dependencies = [ "actix-rt", "assert-json-diff", diff --git a/crates/sargon-uniffi/Cargo.toml b/crates/sargon-uniffi/Cargo.toml index 44b7532aa..fd8f8f7be 100644 --- a/crates/sargon-uniffi/Cargo.toml +++ b/crates/sargon-uniffi/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "sargon-uniffi" # Don't forget to update version in crates/sargon/Cargo.toml -version = "1.1.87" +version = "1.1.90" edition = "2021" build = "build.rs" diff --git a/crates/sargon/Cargo.toml b/crates/sargon/Cargo.toml index eac4de308..e6aa0939e 100644 --- a/crates/sargon/Cargo.toml +++ b/crates/sargon/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "sargon" # Don't forget to update version in crates/sargon-uniffi/Cargo.toml -version = "1.1.87" +version = "1.1.90" edition = "2021" build = "build.rs" diff --git a/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs b/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs index d381aa56d..9cfc6e6d3 100644 --- a/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs +++ b/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs @@ -334,13 +334,20 @@ impl FactorInstancesCache { per_derivation_preset.insert(preset, per_factor_source); } + let originally_request_presets = quantified_derivation_presets + .iter() + .map(|x| x.derivation_preset) + .collect::>(); + // The instances in the cache cannot satisfy the requested quantity // we must derive more! - let is_quantity_unsatisfied_for_any = per_derivation_preset - .iter() - .any(|(_, pf)| pf.iter().any(|(_, ci)| ci.quantity_to_derive > 0)); + let is_quantity_unsatisfied_for_any_requested = + per_derivation_preset.iter().any(|(preset, pf)| { + originally_request_presets.contains(preset) /* Only lack of instances for originally requested presets is something which should cause the outcome of this reading from cache to be considered as `NotSatisfied` */ + && pf.iter().any(|(_, ci)| ci.quantity_to_derive > 0) + }); - let outcome = if is_quantity_unsatisfied_for_any { + let outcome = if is_quantity_unsatisfied_for_any_requested { CachedInstancesWithQuantitiesOutcome::NotSatisfied( CacheNotSatisfied { cached_and_quantities_to_derive: per_derivation_preset, @@ -350,6 +357,9 @@ impl FactorInstancesCache { CachedInstancesWithQuantitiesOutcome::Satisfied(CacheSatisfied { cached: per_derivation_preset .into_iter() + // Satisfied, but `per_derivation_preset` contains ALL Presets (in case of `NotSatisfied` - we are cache filling), + // so we filter out only the originally requested ones. + .filter(|(preset, _)| originally_request_presets.contains(preset)) .map(|(preset, v)| { ( preset, @@ -456,7 +466,7 @@ pub struct CacheSatisfied { >, } -#[derive(Debug, PartialEq, Eq, enum_as_inner::EnumAsInner)] +#[derive(Debug, Clone, PartialEq, Eq, enum_as_inner::EnumAsInner)] pub enum CachedInstancesWithQuantitiesOutcome { Satisfied(CacheSatisfied), NotSatisfied(CacheNotSatisfied), diff --git a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs index e0d2e2fd1..741f3c13d 100644 --- a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs @@ -111,28 +111,34 @@ impl FactorInstancesProvider { InstancesInCacheConsumer, InternalFactorInstancesProviderOutcome, )> { + + println!("🌮 FIP - _provide_for_presets: {:?}, purpose: {:?}", quantified_derivation_presets, derivation_purpose); + let factor_sources = self.factor_sources.clone(); let network_id = self.network_id; + + println!("🌮 FIP - _provide_for_presets - calling `cache_client.get`"); let cached = self - .cache_client - .get( - &factor_sources.iter().map(|f| f.id_from_hash()).collect(), - quantified_derivation_presets.clone(), - network_id, - ) - .await?; - - match cached { - CachedInstancesWithQuantitiesOutcome::Satisfied( - enough_instances, - ) => { + .cache_client + .get( + &factor_sources.iter().map(|f| f.id_from_hash()).collect(), + quantified_derivation_presets.clone(), + network_id, + ) + .await?; + + match cached { + CachedInstancesWithQuantitiesOutcome::Satisfied( + enough_instances, + ) => { + println!("🌮 FIP - _provide_for_presets - cached outcome - ✅ SATISFIED ✅"); // When/if caller calls `instances_in_cache_consumer.consume()` the `enough_instances` // will be deleted from the cache, they are still present in the cache now // and will continue to be present until the `consume()` is called. let instances_in_cache_consumer = self - .make_instances_in_cache_consumer( - enough_instances.clone().cached, - ); + .make_instances_in_cache_consumer( + enough_instances.clone().cached, + ); Ok(( instances_in_cache_consumer, InternalFactorInstancesProviderOutcome::satisfied_by_cache( @@ -141,6 +147,7 @@ impl FactorInstancesProvider { )) } CachedInstancesWithQuantitiesOutcome::NotSatisfied(unsatisfied) => { + println!("🌮 FIP - _provide_for_presets - cached outcome - 🙅🏻‍♀️ NotSatisfied => `derive_more_and_cache` 🙅🏻‍♀️ "); self.derive_more_and_cache( &quantified_derivation_presets, unsatisfied, @@ -162,9 +169,12 @@ impl FactorInstancesProvider { InstancesInCacheConsumer, InternalFactorInstancesProviderOutcome, )> { + let remaining_quantities_to_derive = not_satisfied.remaining_quantities_to_derive(); + println!("🌮 FIP - derive_more_and_cache - deriving more, specifically: {:?}", remaining_quantities_to_derive); + let pdp_pf_newly_derived = self .derive_more( - not_satisfied.remaining_quantities_to_derive(), + remaining_quantities_to_derive, derivation_purpose, ) .await?; @@ -194,6 +204,7 @@ impl FactorInstancesProvider { pdp_pf_found_in_cache_leq_requested, pdp_pf_newly_derived, ); + Ok((instances_in_cache_consumer, outcome)) } @@ -365,19 +376,22 @@ impl FactorInstancesProvider { >, >>()?; - println!( - "🌈 per_preset_per_factor_paths: {:#?}", - per_preset_per_factor_paths - ); let mut per_factor_paths = IndexMap::>::new(); + for (_, pf) in per_preset_per_factor_paths.clone() { for (factor_source_id, paths) in pf { per_factor_paths.append_or_insert_to(factor_source_id, paths); } } - println!("🌈 per_factor_paths: {:#?}", per_factor_paths); + println!( + "🌮 FIP-derive_more - per_factor_paths: #{:?}", + per_factor_paths + .clone() + .values() + .fold(0, |acc, e| acc + e.len()) + ); let interactor = self.interactor.clone(); let collector = KeysCollector::new( diff --git a/crates/sargon/src/factor_instances_provider/provider/outcome/factor_instances_provider_outcome.rs b/crates/sargon/src/factor_instances_provider/provider/outcome/factor_instances_provider_outcome.rs index 29f535a99..f883fad77 100644 --- a/crates/sargon/src/factor_instances_provider/provider/outcome/factor_instances_provider_outcome.rs +++ b/crates/sargon/src/factor_instances_provider/provider/outcome/factor_instances_provider_outcome.rs @@ -38,14 +38,26 @@ impl From for FactorInstancesProviderOutcome { fn from(value: InternalFactorInstancesProviderOutcome) -> Self { - // Self { - // per_factor: value - // .per_factor - // .into_iter() - // .map(|(k, v)| (k, v.into())) - // .collect(), - // } - todo!() + Self { + per_derivation_preset: value + .per_derivation_preset + .into_iter() + .map(|(k, v)| (k, v.into())) + .collect(), + } + } +} +impl From + for FactorInstancesProviderOutcomePerFactor +{ + fn from(value: InternalFactorInstancesProviderOutcomePerFactor) -> Self { + FactorInstancesProviderOutcomePerFactor { + per_factor: value + .per_factor + .into_iter() + .map(|(k, v)| (k, v.into())) + .collect(), + } } } @@ -54,11 +66,10 @@ 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() - todo!() + self.per_derivation_preset + .values() + .flat_map(|x| x.per_factor.values().flat_map(|f| f.debug_was_derived.factor_instances())) + .collect() } pub fn total_number_of_newly_derived_instances(&self) -> usize { diff --git a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs index 595108e2f..fe224bc3c 100644 --- a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs @@ -124,6 +124,7 @@ impl VirtualEntityCreatingInstanceProvider { InstancesInCacheConsumer, FactorInstancesProviderOutcomeForFactor, )> { + let provider = FactorInstancesProvider::new( network_id, IndexSet::just(factor_source.clone()), @@ -131,7 +132,9 @@ impl VirtualEntityCreatingInstanceProvider { cache_client, interactor, ); + let derivation_preset = DerivationPreset::veci_entity_kind(entity_kind); + let (instances_in_cache_consumer, outcome) = provider .provide( QuantifiedDerivationPreset::new(derivation_preset, count), diff --git a/crates/sargon/src/lib.rs b/crates/sargon/src/lib.rs index 9d7add72d..2b5e88723 100644 --- a/crates/sargon/src/lib.rs +++ b/crates/sargon/src/lib.rs @@ -1,4 +1,3 @@ -#![allow(warnings)] #![feature(async_closure)] #![feature(let_chains)] #![feature(core_intrinsics)] diff --git a/crates/sargon/src/system/clients/client/factor_instances_cache_client.rs b/crates/sargon/src/system/clients/client/factor_instances_cache_client.rs index b654fc5cb..f7217d7d3 100644 --- a/crates/sargon/src/system/clients/client/factor_instances_cache_client.rs +++ b/crates/sargon/src/system/clients/client/factor_instances_cache_client.rs @@ -327,39 +327,47 @@ mod tests { let five = HDPathComponent::from(five); assert_eq!(max_higher_sut1, Some(five)); - // sut2.delete(IndexMap::from_iter([( - // fsid, - // FactorInstances::from_iter([fi5.clone()]), - // )])) - // .await - // .unwrap(); - - // let max_higher_sut1 = sut1.max_index_for(fsid, path).await.unwrap(); - // assert_eq!(max_higher_sut1, Some(one)); - - todo!("migrate me") + sut2.delete(IndexMap::kv( + DerivationPreset::AccountVeci, + IndexMap::from_iter([( + fsid, + FactorInstances::from_iter([fi5.clone()]), + )]), + )) + .await + .unwrap(); - // // test get_poly_factor_with_quantities - // let poly = sut1 - // .get_poly_factor_with_quantities( - // IndexSet::just(fsid), - // QuantifiedDerivationPreset::new(derivation_preset, 2), - // network, - // ) - // .await - // .unwrap(); - // let satisfied = IndexMap::kv(fsid, instances); - // assert_eq!( - // poly, - // CachedInstancesWithQuantitiesOutcome::Satisfied(satisfied) - // ); + let max_higher_sut1 = sut1.max_index_for(fsid, path).await.unwrap(); + assert_eq!(max_higher_sut1, Some(one)); + + // test get_poly_factor_with_quantities + let poly = sut1 + .get_poly_factor_with_quantities( + IndexSet::just(fsid), + QuantifiedDerivationPreset::new(derivation_preset, 2), + network, + ) + .await + .unwrap(); + + let satisfied = IndexMap::kv(fsid, instances); + + pretty_assertions::assert_eq!( + poly.into_satisfied() + .unwrap() + .cached + .get(&DerivationPreset::AccountVeci) + .cloned() + .unwrap(), + satisfied + ); - // let snap_1 = sut1.snapshot().await.unwrap(); - // let snap_2 = sut2.snapshot().await.unwrap(); - // assert_eq!( - // snap_1.serializable_snapshot(), - // snap_2.serializable_snapshot(), - // ); + let snap_1 = sut1.snapshot().await.unwrap(); + let snap_2 = sut2.snapshot().await.unwrap(); + assert_eq!( + snap_1.serializable_snapshot(), + snap_2.serializable_snapshot(), + ); } #[actix_rt::test] diff --git a/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs b/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs index 8e04362ee..2e86ee13c 100644 --- a/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs +++ b/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs @@ -916,10 +916,10 @@ impl SargonOS { distribute_instances_for_entity_of_kind_if_needed( CAP26EntityKind::Account, - ); + )?; distribute_instances_for_entity_of_kind_if_needed( CAP26EntityKind::Identity, - ); + )?; Ok(( security_structures_of_factor_instances, From 4b8c041482821f2fc6e8550e9a0249203694af5b Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Wed, 18 Dec 2024 14:35:06 +0100 Subject: [PATCH 39/60] [no ci] WIP --- .../factor_instances_cache.rs | 105 +++++++--- .../factor_instances_cache/keyed_instances.rs | 11 +- .../provider/factor_instances_provider.rs | 193 ++++++++++++------ .../factor_instances_provider_outcome.rs | 19 +- .../types/factor_instances.rs | 1 + .../client/factor_instances_cache_client.rs | 43 ++-- 6 files changed, 253 insertions(+), 119 deletions(-) diff --git a/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs b/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs index 9cfc6e6d3..d74c216b0 100644 --- a/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs +++ b/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs @@ -285,7 +285,8 @@ impl FactorInstancesCache { if is_quantity_satisfied { // The instances in the cache can satisfy the requested quantity // for this factor source for this derivation preset - Some(CacheInstancesAndRemainingQuantityToDerive { + let v = + CacheInstancesAndRemainingQuantityToDerive { // 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 @@ -294,7 +295,11 @@ impl FactorInstancesCache { .split_at(target_quantity) .0, quantity_to_derive: 0, - }) + }; + + + assert!(!v.instances_to_use_from_cache.is_empty()); + Some(v) } else { // Since we are deriving more we might as well ensure that the // cache is filled with `CACHE_FILLING_QUANTITY` **AFTER** the @@ -304,11 +309,12 @@ impl FactorInstancesCache { let quantity_to_derive = cache_filling_quantity - count_in_cache + target_quantity; - - Some(CacheInstancesAndRemainingQuantityToDerive { - instances_to_use_from_cache: for_preset.clone(), - quantity_to_derive, - }) +let v = CacheInstancesAndRemainingQuantityToDerive { + instances_to_use_from_cache: for_preset.clone(), + quantity_to_derive, +}; +assert!(v.quantity_to_derive > 0 || !v.instances_to_use_from_cache.is_empty()); + Some(v) } } else if count_in_cache < cache_filling_quantity { // Not requested derivation preset, calculate number @@ -317,6 +323,8 @@ impl FactorInstancesCache { let quantity_to_derive = cache_filling_quantity - count_in_cache; + assert!(quantity_to_derive > 0); + Some(CacheInstancesAndRemainingQuantityToDerive { instances_to_use_from_cache: FactorInstances::default(), quantity_to_derive, @@ -416,37 +424,74 @@ pub struct CacheNotSatisfied { >, } impl CacheNotSatisfied { - pub fn cached_instances_to_use( + + fn map( &self, - ) -> InstancesPerDerivationPresetPerFactorSource { + extract: impl Fn((FactorSourceIDFromHash, CacheInstancesAndRemainingQuantityToDerive)) -> Option<(FactorSourceIDFromHash, R)> + ) -> IndexMap< + DerivationPreset, + IndexMap, +> { self.cached_and_quantities_to_derive .clone() .into_iter() - .map(|(preset, v)| { - ( - preset, - v.into_iter() - .map(|(x, y)| (x, y.instances_to_use_from_cache)) - .collect::>() - , - ) + .filter_map(|(preset, v)| { + + let per_factor = v.into_iter() + .filter_map(|(x, y)| { + // let instances = y.instances_to_use_from_cache; + // if instances.is_empty() { + // None + // } else { + // Some((x, instances)) + // } + extract((x, y)) + }) + .collect::>(); + + if per_factor.is_empty() { + None + } else { + Some((preset, per_factor)) + } }) - .collect::() + .collect::, + >>() + } + + + pub fn cached_instances_to_use( + &self, + ) -> InstancesPerDerivationPresetPerFactorSource { + self.map(|(x, y)| { + let instances = y.instances_to_use_from_cache; + if instances.is_empty() { + None + } else { + Some((x, instances)) + } + }) } pub fn remaining_quantities_to_derive(&self) -> QuantitiesToDerive { - self.cached_and_quantities_to_derive - .clone() - .into_iter() - .map(|(preset, v)| { - ( - preset, - v.into_iter() - .map(|(x, y)| (x, y.quantity_to_derive)) - .collect::>(), - ) - }) - .collect::() + // self.cached_and_quantities_to_derive + // .clone() + // .into_iter() + // .map(|(preset, v)| { + // ( + // preset, + // v.into_iter() + // .map(|(x, y)| (x, y.quantity_to_derive)) + // .collect::>(), + // ) + // }) + // .collect::() + + self.map(|(x, y)| { + Some((x, y.quantity_to_derive)) + }) } } pub type QuantitiesToDerive = diff --git a/crates/sargon/src/factor_instances_provider/factor_instances_cache/keyed_instances.rs b/crates/sargon/src/factor_instances_provider/factor_instances_cache/keyed_instances.rs index b3b0f1de5..5489dea60 100644 --- a/crates/sargon/src/factor_instances_provider/factor_instances_cache/keyed_instances.rs +++ b/crates/sargon/src/factor_instances_provider/factor_instances_cache/keyed_instances.rs @@ -2,11 +2,12 @@ use std::borrow::Borrow; use crate::prelude::*; -pub struct KeyedInstances( +#[derive(Debug)] +pub struct KeyedInstances( pub IndexMap, ); -impl KeyedInstances { +impl KeyedInstances { pub fn validate_from_source( &self, factor_source_id: impl Borrow, @@ -34,9 +35,13 @@ impl KeyedInstances { pub fn new(map: IndexMap) -> Self { Self(map) } + + pub fn len(&self) -> usize { + self.0.len() + } } -impl IntoIterator for KeyedInstances { +impl IntoIterator for KeyedInstances { type Item = as IntoIterator>::Item; type IntoIter = as IntoIterator>::IntoIter; diff --git a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs index 741f3c13d..607e8385d 100644 --- a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs @@ -111,34 +111,36 @@ impl FactorInstancesProvider { InstancesInCacheConsumer, InternalFactorInstancesProviderOutcome, )> { + println!( + "🌮 FIP - _provide_for_presets: {:?}, purpose: {:?}", + quantified_derivation_presets, derivation_purpose + ); - println!("🌮 FIP - _provide_for_presets: {:?}, purpose: {:?}", quantified_derivation_presets, derivation_purpose); - let factor_sources = self.factor_sources.clone(); let network_id = self.network_id; - + println!("🌮 FIP - _provide_for_presets - calling `cache_client.get`"); let cached = self - .cache_client - .get( - &factor_sources.iter().map(|f| f.id_from_hash()).collect(), - quantified_derivation_presets.clone(), - network_id, - ) - .await?; - - match cached { - CachedInstancesWithQuantitiesOutcome::Satisfied( - enough_instances, - ) => { + .cache_client + .get( + &factor_sources.iter().map(|f| f.id_from_hash()).collect(), + quantified_derivation_presets.clone(), + network_id, + ) + .await?; + + match cached { + CachedInstancesWithQuantitiesOutcome::Satisfied( + enough_instances, + ) => { println!("🌮 FIP - _provide_for_presets - cached outcome - ✅ SATISFIED ✅"); // When/if caller calls `instances_in_cache_consumer.consume()` the `enough_instances` // will be deleted from the cache, they are still present in the cache now // and will continue to be present until the `consume()` is called. let instances_in_cache_consumer = self - .make_instances_in_cache_consumer( - enough_instances.clone().cached, - ); + .make_instances_in_cache_consumer( + enough_instances.clone().cached, + ); Ok(( instances_in_cache_consumer, InternalFactorInstancesProviderOutcome::satisfied_by_cache( @@ -169,14 +171,12 @@ impl FactorInstancesProvider { InstancesInCacheConsumer, InternalFactorInstancesProviderOutcome, )> { - let remaining_quantities_to_derive = not_satisfied.remaining_quantities_to_derive(); + let remaining_quantities_to_derive = + not_satisfied.remaining_quantities_to_derive(); println!("🌮 FIP - derive_more_and_cache - deriving more, specifically: {:?}", remaining_quantities_to_derive); - + let pdp_pf_newly_derived = self - .derive_more( - remaining_quantities_to_derive, - derivation_purpose, - ) + .derive_more(remaining_quantities_to_derive, derivation_purpose) .await?; let pdp_pf_found_in_cache_leq_requested = @@ -204,7 +204,7 @@ impl FactorInstancesProvider { pdp_pf_found_in_cache_leq_requested, pdp_pf_newly_derived, ); - + Ok((instances_in_cache_consumer, outcome)) } @@ -218,51 +218,83 @@ impl FactorInstancesProvider { pdp_pf_found_in_cache_leq_requested: &InstancesPerDerivationPresetPerFactorSource, pdp_pf_newly_derived: &InstancesPerDerivationPresetPerFactorSource, ) -> Split { + + let derivation_presets_of_instances_to_merge = pdp_pf_found_in_cache_leq_requested + .keys() + .chain(pdp_pf_newly_derived.keys()) + .cloned() + .collect::>(); + // 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 pdp_pf_derived_appended_to_from_cache = DerivationPreset::all() + let pdp_pf_derived_appended_to_from_cache = derivation_presets_of_instances_to_merge .iter() - .map(|preset| { + .filter_map(|preset| { let pf_found_in_cache_leq_requested = pdp_pf_found_in_cache_leq_requested .get(preset) .cloned() // can be nil -> empty, if no instance was found in cache for this preset! .unwrap_or_default(); - let pf_newly_derived = pdp_pf_newly_derived + + let pf_newly_derived = pdp_pf_newly_derived .get(preset) .cloned() // can be nil -> empty, if we did not derive any new instance for this preset! .unwrap_or_default(); + if pf_found_in_cache_leq_requested.is_empty() + && pf_newly_derived.is_empty() + { + panic!("is this possible? apparently! remove this panic and rely on the filter_map..."); + return None; + } + let pf_instances = self .factor_sources .clone() .into_iter() .map(|f| f.id_from_hash()) .map(|factor_source_id| { + let mut merged = IndexSet::new(); - let from_cache = pf_found_in_cache_leq_requested + + 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)) + assert!( + merged + .clone() + .into_iter() + .all(|f| + DerivationPreset::try_from(f.derivation_path().agnostic()).unwrap() == *preset + ) + ); + assert!(!merged.is_empty()); + (factor_source_id, FactorInstances::from(merged)) + }) .collect::>(); - (*preset, pf_instances) + assert!(!pf_instances.is_empty()); + Some((*preset, pf_instances)) + }) .collect::(); @@ -271,42 +303,89 @@ impl FactorInstancesProvider { let mut pdp_pf_to_cache = InstancesPerDerivationPresetPerFactorSource::new(); + + let originally_requested_presets = requested_quantified_derivation_presets + .iter() + .map(|qdp| qdp.derivation_preset) + .collect::>(); + // Using the merged map, split the instances into those to use directly and those to cache. for (preset, pf_derived_appended_to_from_cache) in pdp_pf_derived_appended_to_from_cache { - let mut pf_to_use_directly = IndexMap::new(); let mut pf_to_cache = - IndexMap::::new(); + IndexMap::::new(); - for (factor_source_id, instances) in + let mut pf_to_use_directly = IndexMap::new(); + + + for (factor, instances) in pf_derived_appended_to_from_cache.clone().into_iter() { - let mut instances_by_derivation_preset = - InstancesByDerivationPreset::from(instances); - - if let Some(requested_quantified_derivation_preset) = - requested_quantified_derivation_presets.get_id(&preset) - // is this correct? - { - let instances_relevant_to_use_directly_with_abundance = - instances_by_derivation_preset - .remove(&preset) - .expect("Should have contained the preset"); // is this correct? - let (to_use_directly, to_cache) = - instances_relevant_to_use_directly_with_abundance - .split_at( - requested_quantified_derivation_preset.quantity, - ); - pf_to_use_directly - .insert(factor_source_id, to_use_directly); - pf_to_cache.insert(factor_source_id, to_cache); - } + assert!( + instances.factor_instances() + .into_iter() + .all(|f| + DerivationPreset::try_from(f.derivation_path().agnostic()).unwrap() == preset + ) + ); - pf_to_cache.append_or_insert_to( - factor_source_id, - instances_by_derivation_preset.all_instances(), + println!( + "🌮 FIP - split - instances: #{:?}", + instances.len() ); + + + if originally_requested_presets.contains(&preset) { + // might have to split + + + + + let requested_quantified_derivation_preset = + requested_quantified_derivation_presets.get_id(&preset).unwrap(); + + println!("🌮 FIP - split - requested_quantified_derivation_preset: {:?}", requested_quantified_derivation_preset); + + let instances_relevant_to_use_directly_with_abundance = instances; + + println!("🌮 FIP - split - #instances_relevant_to_use_directly_with_abundance: {:?}", instances_relevant_to_use_directly_with_abundance.len()); + + let originally_requested_quantity = + requested_quantified_derivation_preset.quantity; + + println!( + "🌮 FIP - split - originally_requested_quantity: {:?}", + originally_requested_quantity + ); + + let (to_use_directly, to_cache) = + instances_relevant_to_use_directly_with_abundance + .split_at(originally_requested_quantity); + + println!( + "🌮 FIP - split - to_use_directly: #{:?}", + to_use_directly.len() + ); + + println!( + "🌮 FIP - split - to_cache: #{:?}", + to_cache.len() + ); + + pf_to_use_directly + .insert(factor, to_use_directly); + + pf_to_cache.insert(factor, to_cache); + + + } else { + // easy case, we don't want to use this directly at all + // meaning all + pf_to_cache.insert(factor, instances); + // we do not add any FactorInstances to `pf_to_use_directly` for this factor + } + } pdp_pf_to_use_directly.insert(preset, pf_to_use_directly); diff --git a/crates/sargon/src/factor_instances_provider/provider/outcome/factor_instances_provider_outcome.rs b/crates/sargon/src/factor_instances_provider/provider/outcome/factor_instances_provider_outcome.rs index f883fad77..80da4806a 100644 --- a/crates/sargon/src/factor_instances_provider/provider/outcome/factor_instances_provider_outcome.rs +++ b/crates/sargon/src/factor_instances_provider/provider/outcome/factor_instances_provider_outcome.rs @@ -68,7 +68,11 @@ impl FactorInstancesProviderOutcome { ) -> FactorInstances { self.per_derivation_preset .values() - .flat_map(|x| x.per_factor.values().flat_map(|f| f.debug_was_derived.factor_instances())) + .flat_map(|x| { + x.per_factor + .values() + .flat_map(|f| f.debug_was_derived.factor_instances()) + }) .collect() } @@ -83,11 +87,14 @@ impl FactorInstancesProviderOutcome { 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() - todo!() + self.per_derivation_preset + .values() + .flat_map(|x| { + x.per_factor + .values() + .flat_map(|f| f.debug_found_in_cache.factor_instances()) + }) + .collect() } pub fn total_number_of_instances_found_in_cache(&self) -> usize { diff --git a/crates/sargon/src/factor_instances_provider/types/factor_instances.rs b/crates/sargon/src/factor_instances_provider/types/factor_instances.rs index 0db4d4db8..8d206dbac 100644 --- a/crates/sargon/src/factor_instances_provider/types/factor_instances.rs +++ b/crates/sargon/src/factor_instances_provider/types/factor_instances.rs @@ -46,6 +46,7 @@ impl FactorInstances { 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); diff --git a/crates/sargon/src/system/clients/client/factor_instances_cache_client.rs b/crates/sargon/src/system/clients/client/factor_instances_cache_client.rs index f7217d7d3..403612682 100644 --- a/crates/sargon/src/system/clients/client/factor_instances_cache_client.rs +++ b/crates/sargon/src/system/clients/client/factor_instances_cache_client.rs @@ -177,29 +177,7 @@ impl FactorInstancesCacheClient { .await } - /// 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. - async fn get_poly_factor_with_quantities( - &self, - factor_source_ids: impl Borrow>, - originally_requested_quantified_derivation_preset: impl Borrow< - QuantifiedDerivationPreset, - >, - network_id: NetworkID, - ) -> Result { - self.access_cache_init_if_needed(|cache| { - cache.get( - factor_source_ids.borrow(), - &IdentifiedVecOf::just( - *originally_requested_quantified_derivation_preset.borrow(), - ), - network_id, - ) - }) - .await - } + /// Reads out the instance of `factor_source_id` without mutating the cache. pub async fn peek_all_instances_of_factor_source( @@ -222,6 +200,25 @@ impl FactorInstancesCacheClient { #[cfg(test)] impl FactorInstancesCacheClient { + + /// 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. + async fn get_poly_factor_with_quantities( + &self, + factor_source_ids: impl Borrow>, + originally_requested_quantified_derivation_preset: impl Borrow< + QuantifiedDerivationPreset, + >, + network_id: NetworkID, + ) -> Result { + self.access_cache_init_if_needed(|cache| { + cache.get_poly_factor_with_quantities(factor_source_ids.borrow(), originally_requested_quantified_derivation_preset.borrow(), network_id) + }) + .await + } + pub async fn insert_single( &self, instance: impl Borrow, From ccf46b6d4a20cd5ba82295a8a9d04f85d8dc2e14 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Wed, 18 Dec 2024 15:19:26 +0100 Subject: [PATCH 40/60] [no ci] WIP --- .../factor_instances_cache.rs | 25 ++---- .../provider/factor_instances_provider.rs | 86 ++++++++++++++++--- 2 files changed, 78 insertions(+), 33 deletions(-) diff --git a/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs b/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs index d74c216b0..673acbd9d 100644 --- a/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs +++ b/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs @@ -439,12 +439,6 @@ impl CacheNotSatisfied { let per_factor = v.into_iter() .filter_map(|(x, y)| { - // let instances = y.instances_to_use_from_cache; - // if instances.is_empty() { - // None - // } else { - // Some((x, instances)) - // } extract((x, y)) }) .collect::>(); @@ -476,21 +470,12 @@ impl CacheNotSatisfied { } pub fn remaining_quantities_to_derive(&self) -> QuantitiesToDerive { - // self.cached_and_quantities_to_derive - // .clone() - // .into_iter() - // .map(|(preset, v)| { - // ( - // preset, - // v.into_iter() - // .map(|(x, y)| (x, y.quantity_to_derive)) - // .collect::>(), - // ) - // }) - // .collect::() - self.map(|(x, y)| { - Some((x, y.quantity_to_derive)) + if y.quantity_to_derive > 0 { + Some((x, y.quantity_to_derive)) + } else { + None + } }) } } diff --git a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs index 607e8385d..9f98bdf01 100644 --- a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs @@ -171,14 +171,26 @@ impl FactorInstancesProvider { InstancesInCacheConsumer, InternalFactorInstancesProviderOutcome, )> { + let remaining_quantities_to_derive = not_satisfied.remaining_quantities_to_derive(); + + assert!(!remaining_quantities_to_derive.is_empty(), "❌ No instances to derive?"); + println!("🌮 FIP - derive_more_and_cache - deriving more, specifically: {:?}", remaining_quantities_to_derive); let pdp_pf_newly_derived = self .derive_more(remaining_quantities_to_derive, derivation_purpose) .await?; + assert!(!pdp_pf_newly_derived.is_empty(), "❌ Failed to derive instances?"); + + for (k, v) in pdp_pf_newly_derived.iter() { + for (x, y) in v.iter() { + println!("🌮 FIP 🔮✨ derived - (preset: {:?}, factor: {:?}) - #{:?} instances ✨🔮", k, x, y.len()); + } + } + let pdp_pf_found_in_cache_leq_requested = not_satisfied.cached_instances_to_use(); @@ -270,6 +282,10 @@ impl FactorInstancesProvider { .get(&factor_source_id) .cloned() .unwrap_or_default(); + + println!("🌮 FIP - split (preset: {:?}, factor: {:?}) - `from_cache`: #{:?}", preset, factor_source_id, from_cache.len()); + println!("🌮 FIP - split (preset: {:?}, factor: {:?}) - `newly_derived`: #{:?}", preset, factor_source_id, newly_derived.len()); + println!("🌮 FIP - split (preset: {:?}, factor: {:?}) - `merged`: #{:?}", preset, factor_source_id, merged.len()); // IMPORTANT: Must put instances from cache **first**... merged.extend(from_cache); @@ -330,8 +346,17 @@ impl FactorInstancesProvider { ) ); + assert!( + instances.factor_instances() + .into_iter() + .all(|f| + f.factor_source_id() == factor + ) + ); + println!( - "🌮 FIP - split - instances: #{:?}", + "🌮 FIP - split (preset: {:?}, factor: {:?}) - instances: #{:?}", + preset, factor, instances.len() ); @@ -358,6 +383,10 @@ impl FactorInstancesProvider { "🌮 FIP - split - originally_requested_quantity: {:?}", originally_requested_quantity ); + + if originally_requested_quantity > instances_relevant_to_use_directly_with_abundance.len() { + println!("🌮 FIP - split ❌❌ not enough instances to use directly! (preset: {:?}, factor: {:?}) ❌❌", preset, factor); + } let (to_use_directly, to_cache) = instances_relevant_to_use_directly_with_abundance @@ -415,10 +444,12 @@ impl FactorInstancesProvider { let per_preset_per_factor_paths = quantities_to_derive .into_iter() + .filter(|(_, per_factor_source)| !per_factor_source.is_empty()) .map(|(derivation_preset, per_factor_source)| { let per_factor_paths = per_factor_source .into_iter() .map(|(factor_source_id, qty)| { + assert!(qty > 0); // `qty` many paths let paths = (0..qty) .map(|_| { @@ -436,6 +467,8 @@ impl FactorInstancesProvider { }) .collect::>>()?; + assert!(!paths.is_empty()); + Ok((factor_source_id, paths)) }) .collect::>(); // we need to transpose the `pf_pdp_derived` + assert!(!pf_pdp_derived.is_empty(), "🙅🏻‍♀️ no instances derived?"); let mut pdp_pf_instances = IndexMap::< DerivationPreset, @@ -504,7 +562,9 @@ impl FactorInstancesProvider { >::new(); for (factor_source_id, pdp) in pf_pdp_derived { + assert!(!pdp.is_empty(), "🙅🏻‍♀️ no instances for factor: {factor_source_id}"); for (preset, instances) in pdp { + assert!(!instances.is_empty(), "🙅🏻‍♀️ no instances for preset: {preset:?}"); pdp_pf_instances.append_or_insert_to( preset, IndexMap::::kv( From 8e4c576e36716894b606864c40039908bda01e16 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Wed, 18 Dec 2024 15:36:28 +0100 Subject: [PATCH 41/60] [no ci] WIP --- .../src/core/error/common_error.rs | 3 ++ crates/sargon/src/core/error/common_error.rs | 3 ++ .../provider/factor_instances_provider.rs | 32 +++++++++++-------- .../test_derivation_interactor.rs | 2 +- 4 files changed, 25 insertions(+), 15 deletions(-) diff --git a/crates/sargon-uniffi/src/core/error/common_error.rs b/crates/sargon-uniffi/src/core/error/common_error.rs index 759c67792..77ee8a4b8 100644 --- a/crates/sargon-uniffi/src/core/error/common_error.rs +++ b/crates/sargon-uniffi/src/core/error/common_error.rs @@ -862,6 +862,9 @@ pub enum CommonError { #[error("Cannot securify entity that has provisional security config")] CannotSecurifyEntityHasProvisionalSecurityConfig = 10241, + + #[error("Too few FactorInstances derived")] + TooFewFactorInstancesDerived = 10242, } #[uniffi::export] diff --git a/crates/sargon/src/core/error/common_error.rs b/crates/sargon/src/core/error/common_error.rs index 48a760836..155b742d3 100644 --- a/crates/sargon/src/core/error/common_error.rs +++ b/crates/sargon/src/core/error/common_error.rs @@ -859,6 +859,9 @@ pub enum CommonError { #[error("Cannot securify entity that has provisional security config")] CannotSecurifyEntityHasProvisionalSecurityConfig = 10241, + + #[error("Too few FactorInstances derived")] + TooFewFactorInstancesDerived = 10242, } impl CommonError { diff --git a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs index 9f98bdf01..fd7511d63 100644 --- a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs @@ -269,10 +269,9 @@ impl FactorInstancesProvider { .clone() .into_iter() .map(|f| f.id_from_hash()) - .map(|factor_source_id| { + .filter_map(|factor_source_id| { - let mut merged = IndexSet::new(); - + let from_cache = pf_found_in_cache_leq_requested .get(&factor_source_id) .cloned() @@ -283,6 +282,13 @@ impl FactorInstancesProvider { .cloned() .unwrap_or_default(); + if from_cache.is_empty() && newly_derived.is_empty() { + return None; + } + + let mut merged = IndexSet::new(); + + println!("🌮 FIP - split (preset: {:?}, factor: {:?}) - `from_cache`: #{:?}", preset, factor_source_id, from_cache.len()); println!("🌮 FIP - split (preset: {:?}, factor: {:?}) - `newly_derived`: #{:?}", preset, factor_source_id, newly_derived.len()); println!("🌮 FIP - split (preset: {:?}, factor: {:?}) - `merged`: #{:?}", preset, factor_source_id, merged.len()); @@ -303,7 +309,7 @@ impl FactorInstancesProvider { ) ); assert!(!merged.is_empty()); - (factor_source_id, FactorInstances::from(merged)) + Some((factor_source_id, FactorInstances::from(merged))) }) .collect::>(); @@ -499,30 +505,28 @@ impl FactorInstancesProvider { for (k, v) in per_factor_paths.iter() { let contains_rola_path = v.iter().any(|p| p.agnostic().key_kind == CAP26KeyKind::AuthenticationSigning); - println!("🌮 FIP - derive_more - 🛣️ per_factor_paths - (factor: {:?}) - v.len(): #{:?} contains_rola_path? {:?}", k, v.len(), contains_rola_path); + println!("🌮 FIP - derive_more - 🛣️ per_factor_paths - (factor: {:?}) - contains_rola_path? {:?}, paths: \n\n{:?}\n\n", k, contains_rola_path, v); } - println!("🛡️ #factor_sources: {:?}", factor_sources.len()); + println!("🛡️ #factor_sources ids: {:?}", factor_sources.iter().map(|f| f.factor_source_id()).collect_vec()); - // println!( - // "🌮 FIP - derive_more - per_factor_paths: #{:?}", - // per_factor_paths - // .clone() - // .values() - // .fold(0, |acc, e| acc + e.len()) - // ); let interactor = self.interactor.clone(); let collector = KeysCollector::new( factor_sources, - per_factor_paths, + per_factor_paths.clone(), interactor, derivation_purpose, )?; let pf_derived = collector.collect_keys().await.factors_by_source; + for (k, v) in pf_derived.iter() { + let requested = per_factor_paths.get(k).unwrap(); + if v.len() < requested.len() { + return Err(CommonError::TooFewFactorInstancesDerived) + } println!("🌮 FIP - derive_more - 🔮🦄🍬 derived - (factor: {:?}) - v.len(): #{:?}", k, v.len()); } diff --git a/crates/sargon/src/keys_collector/derivation_testing/test_keys_collector/test_derivation_interactor.rs b/crates/sargon/src/keys_collector/derivation_testing/test_keys_collector/test_derivation_interactor.rs index 379e89057..1dbcf7d30 100644 --- a/crates/sargon/src/keys_collector/derivation_testing/test_keys_collector/test_derivation_interactor.rs +++ b/crates/sargon/src/keys_collector/derivation_testing/test_keys_collector/test_derivation_interactor.rs @@ -54,7 +54,7 @@ impl TestDerivationInteractor { cloned_client, async move |id| { id.maybe_sample_associated_mnemonic() - .ok_or(CommonError::Unknown) + .ok_or(CommonError::FactorSourceDiscrepancy) }, ) .await From f2693927031cfb0f5e47116d0201e1d821537905 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Wed, 18 Dec 2024 15:38:54 +0100 Subject: [PATCH 42/60] [no ci] WIP --- ...ernal_factor_instances_provider_outcome.rs | 142 +++++++++--------- 1 file changed, 69 insertions(+), 73 deletions(-) diff --git a/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs b/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs index baab224c2..096e14e48 100644 --- a/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs +++ b/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs @@ -253,90 +253,86 @@ mod tests { #[test] fn only_to_cache() { - // let i = HierarchicalDeterministicFactorInstance::sample_fia0(); - - // let sut = SUT::transpose( - // IndexMap::kv( - // FactorSourceIDFromHash::sample_at(0), - // 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) - // ) - todo!() + let i = HierarchicalDeterministicFactorInstance::sample_fia0(); + + let sut = SUT::transpose( + IndexMap::kv( + FactorSourceIDFromHash::sample_at(0), + 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::sample_fia0(); - - // let sut = SUT::transpose( - // IndexMap::new(), - // IndexMap::kv( - // FactorSourceIDFromHash::sample_at(0), - // 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) - // ) - todo!() + let i = HierarchicalDeterministicFactorInstance::sample_fia0(); + + let sut = SUT::transpose( + IndexMap::new(), + IndexMap::kv( + FactorSourceIDFromHash::sample_at(0), + 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::sample_fia0(); - - // let sut = SUT::transpose( - // IndexMap::new(), - // IndexMap::new(), - // IndexMap::kv( - // FactorSourceIDFromHash::sample_at(0), - // FactorInstances::just(i.clone()), - // ), - // IndexMap::new(), - // ); - // assert_eq!( - // sut.per_factor - // .get(&i.factor_source_id()) - // .unwrap() - // .found_in_cache, - // FactorInstances::just(i) - // ) - todo!() + let i = HierarchicalDeterministicFactorInstance::sample_fia0(); + + let sut = SUT::transpose( + IndexMap::new(), + IndexMap::new(), + IndexMap::kv( + FactorSourceIDFromHash::sample_at(0), + 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::sample_fia0(); - - // let sut = SUT::transpose( - // IndexMap::new(), - // IndexMap::new(), - // IndexMap::new(), - // IndexMap::kv( - // FactorSourceIDFromHash::sample_at(0), - // FactorInstances::just(i.clone()), - // ), - // ); - // assert_eq!( - // sut.per_factor - // .get(&i.factor_source_id()) - // .unwrap() - // .newly_derived, - // FactorInstances::just(i) - // ) - todo!() + let i = HierarchicalDeterministicFactorInstance::sample_fia0(); + + let sut = SUT::transpose( + IndexMap::new(), + IndexMap::new(), + IndexMap::new(), + IndexMap::kv( + FactorSourceIDFromHash::sample_at(0), + FactorInstances::just(i.clone()), + ), + ); + assert_eq!( + sut.per_factor + .get(&i.factor_source_id()) + .unwrap() + .newly_derived, + FactorInstances::just(i) + ) } } From e8ff22f628c3033f8ac2576737f4fbd3e6db2e9b Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Wed, 18 Dec 2024 16:23:09 +0100 Subject: [PATCH 43/60] [no ci] WIP --- .../provider/factor_instances_provider.rs | 1 - ...ernal_factor_instances_provider_outcome.rs | 10 - ...rtual_entity_creating_instance_provider.rs | 270 +++++++++++++----- .../sargon/src/profile/logic/create_entity.rs | 14 +- 4 files changed, 215 insertions(+), 80 deletions(-) diff --git a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs index fd7511d63..3cdaae3eb 100644 --- a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs @@ -260,7 +260,6 @@ impl FactorInstancesProvider { if pf_found_in_cache_leq_requested.is_empty() && pf_newly_derived.is_empty() { - panic!("is this possible? apparently! remove this panic and rely on the filter_map..."); return None; } diff --git a/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs b/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs index 096e14e48..010406bb6 100644 --- a/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs +++ b/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs @@ -38,16 +38,6 @@ impl InternalFactorInstancesProviderOutcome { .and_then(|x| x.per_factor.get(&factor_source_id)) } - #[cfg(test)] - pub(crate) fn get( - &self, - preset: DerivationPreset, - factor_source_id: FactorSourceIDFromHash, - ) -> InternalFactorInstancesProviderOutcomeForFactor { - self.get_for_derivation_preset_for_factor(preset, factor_source_id) - .cloned() - .expect("Expected to find factor source") - } } #[derive(Clone, Debug)] diff --git a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs index fe224bc3c..4fd265702 100644 --- a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs @@ -21,10 +21,8 @@ impl VirtualEntityCreatingInstanceProvider { factor_source: FactorSource, network_id: NetworkID, interactor: Arc, - ) -> Result<( - InstancesInCacheConsumer, - FactorInstancesProviderOutcomeForFactor, - )> { + ) -> Result<(InstancesInCacheConsumer, FactorInstancesProviderOutcome)> + { Self::for_entity_veci( CAP26EntityKind::Account, cache_client, @@ -52,10 +50,8 @@ impl VirtualEntityCreatingInstanceProvider { factor_source: FactorSource, network_id: NetworkID, interactor: Arc, - ) -> Result<( - InstancesInCacheConsumer, - FactorInstancesProviderOutcomeForFactor, - )> { + ) -> Result<(InstancesInCacheConsumer, FactorInstancesProviderOutcome)> + { Self::for_entity_veci( CAP26EntityKind::Identity, cache_client, @@ -84,10 +80,8 @@ impl VirtualEntityCreatingInstanceProvider { factor_source: FactorSource, network_id: NetworkID, interactor: Arc, - ) -> Result<( - InstancesInCacheConsumer, - FactorInstancesProviderOutcomeForFactor, - )> { + ) -> Result<(InstancesInCacheConsumer, FactorInstancesProviderOutcome)> + { Self::for_many_entity_vecis( 1, entity_kind, @@ -120,11 +114,8 @@ impl VirtualEntityCreatingInstanceProvider { factor_source: FactorSource, network_id: NetworkID, interactor: Arc, - ) -> Result<( - InstancesInCacheConsumer, - FactorInstancesProviderOutcomeForFactor, - )> { - + ) -> Result<(InstancesInCacheConsumer, FactorInstancesProviderOutcome)> + { let provider = FactorInstancesProvider::new( network_id, IndexSet::just(factor_source.clone()), @@ -132,9 +123,9 @@ impl VirtualEntityCreatingInstanceProvider { cache_client, interactor, ); - + let derivation_preset = DerivationPreset::veci_entity_kind(entity_kind); - + let (instances_in_cache_consumer, outcome) = provider .provide( QuantifiedDerivationPreset::new(derivation_preset, count), @@ -142,14 +133,6 @@ impl VirtualEntityCreatingInstanceProvider { ) .await?; - let outcome = outcome - .get_for_derivation_preset_for_factor( - derivation_preset, - factor_source.id_from_hash(), - ) - .cloned() - .expect("Expected to have instances for the factor source"); - Ok((instances_in_cache_consumer, outcome.into())) } } @@ -179,23 +162,49 @@ mod tests { .unwrap(); consumer.consume().await.unwrap(); - assert_eq!(outcome.factor_source_id, bdfs.id_from_hash()); - - assert_eq!(outcome.debug_found_in_cache.len(), 0); - assert_eq!( - outcome.debug_was_cached.len(), - DerivationPreset::all().len() * CACHE_FILLING_QUANTITY + outcome + .per_derivation_preset + .values() + .flat_map(|x| x.per_factor.keys().cloned().collect_vec()) + .collect::>(), + HashSet::::from_iter([bdfs.id_from_hash()]) ); - assert_eq!( - outcome.debug_was_derived.len(), - DerivationPreset::all().len() * CACHE_FILLING_QUANTITY + 1 - ); + assert!(outcome.per_derivation_preset.values().all(|x| x + .per_factor + .values() + .all(|y| y.debug_found_in_cache.len() == 0))); + + assert!(outcome.per_derivation_preset.clone().into_iter().all( + |(preset, x)| x + .per_factor + .values() + .all(|y| y.debug_was_cached.len() + == preset.cache_filling_quantity()) + )); + + assert!(outcome.per_derivation_preset.clone().into_iter().all( + |(preset, x)| { + x.per_factor.values().all(|y| { + y.debug_was_derived.len() + == preset.cache_filling_quantity() + 1 + } /* One account created */) + } + )); + + let instances_used_directly = outcome + .per_derivation_preset + .get(&DerivationPreset::AccountVeci) + .unwrap() + .per_factor + .get(&bdfs.id_from_hash()) + .unwrap() + .to_use_directly + .factor_instances(); - 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!( @@ -267,6 +276,7 @@ mod tests { let network = NetworkID::Mainnet; let bdfs = FactorSource::sample(); let cache_client = Arc::new(FactorInstancesCacheClient::in_memory()); + let (consumer, outcome) = SUT::for_account_veci( cache_client.clone(), None, @@ -276,24 +286,65 @@ mod tests { ) .await .unwrap(); - consumer.consume().await.unwrap(); - assert_eq!(outcome.factor_source_id, bdfs.id_from_hash()); - - assert_eq!(outcome.debug_found_in_cache.len(), 0); + consumer.consume().await.unwrap(); assert_eq!( - outcome.debug_was_cached.len(), - DerivationPreset::all().len() * CACHE_FILLING_QUANTITY + outcome + .per_derivation_preset + .values() + .flat_map(|x| x.per_factor.keys().cloned().collect_vec()) + .collect::>(), + HashSet::::from_iter([bdfs.id_from_hash()]) ); - assert_eq!( - outcome.debug_was_derived.len(), - DerivationPreset::all().len() * CACHE_FILLING_QUANTITY + 1 - ); + assert!(outcome.per_derivation_preset.values().all(|x| x + .per_factor + .values() + .all(|y| y.debug_found_in_cache.len() == 0))); + + assert!(outcome.per_derivation_preset.clone().into_iter().all( + |(preset, x)| x + .per_factor + .values() + .all(|y| y.debug_was_cached.len() + == preset.cache_filling_quantity()) + )); + + for (k, v) in outcome.per_derivation_preset.iter() { + for (x, y) in v.per_factor.iter() { + println!("🍬 preset: {:?}, factor: {:?}, debug_was_derived.len(): #{:?}", k, x, y.debug_was_derived.len()); + let derivation_based_offset = + if *k == DerivationPreset::AccountVeci { + 1 + } else { + 0 + }; + assert_eq!( + y.debug_was_derived.len(), + k.cache_filling_quantity() + derivation_based_offset + ) + } + } + // assert!(outcome.per_derivation_preset.clone().into_iter().all( + // |(preset, x)| { + // x.per_factor.values().all(|y| { + // y.debug_was_derived.len() + // == preset.cache_filling_quantity() + 1 + // } /* One account created */) + // } + // )); + + let instances_used_directly = outcome + .per_derivation_preset + .get(&DerivationPreset::AccountVeci) + .unwrap() + .per_factor + .get(&bdfs.id_from_hash()) + .unwrap() + .to_use_directly + .factor_instances(); - 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(); @@ -483,13 +534,44 @@ mod tests { .unwrap(); consumer.consume().await.unwrap(); - assert_eq!(outcome.factor_source_id, bdfs.id_from_hash()); - 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); + assert_eq!( + outcome + .per_derivation_preset + .values() + .flat_map(|x| x.per_factor.keys().cloned().collect_vec()) + .collect::>(), + HashSet::::from_iter([bdfs.id_from_hash()]) + ); + + assert!(outcome.per_derivation_preset.values().all(|x| x + .per_factor + .values() + .all(|y| y.debug_found_in_cache.len() == 1))); // This time we found in cache + + assert!(outcome.per_derivation_preset.clone().into_iter().all( + |(_, x)| x + .per_factor + .values() + .all(|y| y.debug_was_cached.len() == 0) + )); + + assert!(outcome.per_derivation_preset.clone().into_iter().all( + |(_, x)| x + .per_factor + .values() + .all(|y| y.debug_was_derived.len() == 0) + )); + + let instances_used_directly = outcome + .per_derivation_preset + .get(&DerivationPreset::AccountVeci) + .unwrap() + .per_factor + .get(&bdfs.id_from_hash()) + .unwrap() + .to_use_directly + .factor_instances(); - 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(); @@ -571,11 +653,33 @@ mod tests { .unwrap(); consumer.consume().await.unwrap(); - assert_eq!(outcome.factor_source_id, bdfs.id_from_hash()); + assert_eq!( + outcome + .per_derivation_preset + .values() + .flat_map(|x| x.per_factor.keys().cloned().collect_vec()) + .collect::>(), + HashSet::::from_iter([bdfs.id_from_hash()]) + ); - assert_eq!(outcome.debug_found_in_cache.len(), 29); - assert_eq!(outcome.debug_was_cached.len(), 0); - assert_eq!(outcome.debug_was_derived.len(), 0); + assert!(outcome.per_derivation_preset.values().all(|x| x + .per_factor + .values() + .all(|y| y.debug_found_in_cache.len() == 29))); + + assert!(outcome.per_derivation_preset.clone().into_iter().all( + |(_, x)| x + .per_factor + .values() + .all(|y| y.debug_was_cached.len() == 0) + )); + + assert!(outcome.per_derivation_preset.clone().into_iter().all( + |(_, x)| x + .per_factor + .values() + .all(|y| y.debug_was_derived.len() == 0) + )); let cached = cache_client .peek_all_instances_of_factor_source(bdfs.id_from_hash()) @@ -608,14 +712,46 @@ mod tests { .unwrap(); consumer.consume().await.unwrap(); - assert_eq!(outcome.factor_source_id, bdfs.id_from_hash()); + assert_eq!( + outcome + .per_derivation_preset + .values() + .flat_map(|x| x.per_factor.keys().cloned().collect_vec()) + .collect::>(), + HashSet::::from_iter([bdfs.id_from_hash()]) + ); + + assert!(outcome.per_derivation_preset.values().all(|x| x + .per_factor + .values() + .all(|y| y.debug_found_in_cache.len() == 0))); - 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); + assert!(outcome.per_derivation_preset.clone().into_iter().all( + |(preset, x)| x.per_factor.values().all( + |y| y.debug_was_cached.len() // OLD-COMMENT: `only 30, not 120...` if test fails, draw inspiration from old comment! + == preset.cache_filling_quantity() + ) + )); + + assert!(outcome.per_derivation_preset.clone().into_iter().all( + |(preset, x)| { + x.per_factor.values().all(|y| { + y.debug_was_derived.len() + == preset.cache_filling_quantity() + 1 + } /* One account created */) + } + )); + + let instances_used_directly = outcome + .per_derivation_preset + .get(&DerivationPreset::AccountVeci) + .unwrap() + .per_factor + .get(&bdfs.id_from_hash()) + .unwrap() + .to_use_directly + .factor_instances(); - 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(); diff --git a/crates/sargon/src/profile/logic/create_entity.rs b/crates/sargon/src/profile/logic/create_entity.rs index 1fe917f04..25838fc9f 100644 --- a/crates/sargon/src/profile/logic/create_entity.rs +++ b/crates/sargon/src/profile/logic/create_entity.rs @@ -31,19 +31,29 @@ impl Profile { let count = count as usize; let fsid = factor_source.factor_source_id(); + let entity_kind = E::entity_kind(); let (instances_in_cache_consumer, outcome) = VirtualEntityCreatingInstanceProvider::for_many_entity_vecis( count, - E::entity_kind(), + entity_kind, factor_instances_cache_client, Arc::new(self.clone()), - factor_source, + factor_source.clone(), network_id, key_derivation_interactor, ) .await?; + let outcome = outcome + .per_derivation_preset + .get(&DerivationPreset::veci_entity_kind(entity_kind)) + .unwrap() + .per_factor + .get(&factor_source.id_from_hash()) + .cloned() + .unwrap(); + let instances_to_use_directly = outcome.clone().to_use_directly; assert_eq!(instances_to_use_directly.len(), count); From 632f90788b63c282ff8153686a85e73977b43755 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Wed, 18 Dec 2024 20:08:17 +0100 Subject: [PATCH 44/60] [no ci] WIP --- crates/sargon/src/core/error/common_error.rs | 2 +- .../factor_instances_cache.rs | 107 +++++----- .../factor_instances_cache/keyed_instances.rs | 4 +- .../provider/factor_instances_provider.rs | 185 +++++++++--------- ...ernal_factor_instances_provider_outcome.rs | 1 - ...rtual_entity_creating_instance_provider.rs | 22 ++- .../types/factor_instances.rs | 2 +- .../collector/derivation_purpose.rs | 37 ++-- .../client/factor_instances_cache_client.rs | 53 ++--- 9 files changed, 219 insertions(+), 194 deletions(-) diff --git a/crates/sargon/src/core/error/common_error.rs b/crates/sargon/src/core/error/common_error.rs index 155b742d3..ad7dfbae2 100644 --- a/crates/sargon/src/core/error/common_error.rs +++ b/crates/sargon/src/core/error/common_error.rs @@ -859,7 +859,7 @@ pub enum CommonError { #[error("Cannot securify entity that has provisional security config")] CannotSecurifyEntityHasProvisionalSecurityConfig = 10241, - + #[error("Too few FactorInstances derived")] TooFewFactorInstancesDerived = 10242, } diff --git a/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs b/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs index 673acbd9d..e54f78bd0 100644 --- a/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs +++ b/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs @@ -285,8 +285,7 @@ impl FactorInstancesCache { if is_quantity_satisfied { // The instances in the cache can satisfy the requested quantity // for this factor source for this derivation preset - let v = - CacheInstancesAndRemainingQuantityToDerive { + let v = CacheInstancesAndRemainingQuantityToDerive { // 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 @@ -295,11 +294,10 @@ impl FactorInstancesCache { .split_at(target_quantity) .0, quantity_to_derive: 0, - }; + }; - assert!(!v.instances_to_use_from_cache.is_empty()); - Some(v) + Some(v) } else { // Since we are deriving more we might as well ensure that the // cache is filled with `CACHE_FILLING_QUANTITY` **AFTER** the @@ -309,11 +307,14 @@ impl FactorInstancesCache { let quantity_to_derive = cache_filling_quantity - count_in_cache + target_quantity; -let v = CacheInstancesAndRemainingQuantityToDerive { - instances_to_use_from_cache: for_preset.clone(), - quantity_to_derive, -}; -assert!(v.quantity_to_derive > 0 || !v.instances_to_use_from_cache.is_empty()); + let v = CacheInstancesAndRemainingQuantityToDerive { + instances_to_use_from_cache: for_preset.clone(), + quantity_to_derive, + }; + assert!( + v.quantity_to_derive > 0 + || !v.instances_to_use_from_cache.is_empty() + ); Some(v) } } else if count_in_cache < cache_filling_quantity { @@ -323,7 +324,7 @@ assert!(v.quantity_to_derive > 0 || !v.instances_to_use_from_cache.is_empty()); let quantity_to_derive = cache_filling_quantity - count_in_cache; - assert!(quantity_to_derive > 0); + assert!(quantity_to_derive > 0); Some(CacheInstancesAndRemainingQuantityToDerive { instances_to_use_from_cache: FactorInstances::default(), @@ -346,12 +347,12 @@ assert!(v.quantity_to_derive > 0 || !v.instances_to_use_from_cache.is_empty()); .iter() .map(|x| x.derivation_preset) .collect::>(); - + // The instances in the cache cannot satisfy the requested quantity // we must derive more! let is_quantity_unsatisfied_for_any_requested = per_derivation_preset.iter().any(|(preset, pf)| { - originally_request_presets.contains(preset) /* Only lack of instances for originally requested presets is something which should cause the outcome of this reading from cache to be considered as `NotSatisfied` */ + originally_request_presets.contains(preset) /* Only lack of instances for originally requested presets is something which should cause the outcome of this reading from cache to be considered as `NotSatisfied` */ && pf.iter().any(|(_, ci)| ci.quantity_to_derive > 0) }); @@ -367,7 +368,9 @@ assert!(v.quantity_to_derive > 0 || !v.instances_to_use_from_cache.is_empty()); .into_iter() // Satisfied, but `per_derivation_preset` contains ALL Presets (in case of `NotSatisfied` - we are cache filling), // so we filter out only the originally requested ones. - .filter(|(preset, _)| originally_request_presets.contains(preset)) + .filter(|(preset, _)| { + originally_request_presets.contains(preset) + }) .map(|(preset, v)| { ( preset, @@ -424,14 +427,15 @@ pub struct CacheNotSatisfied { >, } impl CacheNotSatisfied { - fn map( &self, - extract: impl Fn((FactorSourceIDFromHash, CacheInstancesAndRemainingQuantityToDerive)) -> Option<(FactorSourceIDFromHash, R)> - ) -> IndexMap< - DerivationPreset, - IndexMap, -> { + extract: impl Fn( + ( + FactorSourceIDFromHash, + CacheInstancesAndRemainingQuantityToDerive, + ), + ) -> Option<(FactorSourceIDFromHash, R)>, + ) -> IndexMap> { self.cached_and_quantities_to_derive .clone() .into_iter() @@ -455,18 +459,17 @@ impl CacheNotSatisfied { >>() } - pub fn cached_instances_to_use( &self, ) -> InstancesPerDerivationPresetPerFactorSource { - self.map(|(x, y)| { - let instances = y.instances_to_use_from_cache; - if instances.is_empty() { - None - } else { - Some((x, instances)) - } - }) + self.map(|(x, y)| { + let instances = y.instances_to_use_from_cache; + if instances.is_empty() { + None + } else { + Some((x, instances)) + } + }) } pub fn remaining_quantities_to_derive(&self) -> QuantitiesToDerive { @@ -958,28 +961,30 @@ mod tests { #[test] #[should_panic] fn delete_panics_for_unknown() { - // let sut = SUT::default(); - // let instances = FactorInstances::sample(); - // assert_eq!(instances.len(), 2); - // let factor_source_ids = instances - // .clone() - // .into_iter() - // .map(|fi| fi.factor_source_id()) - // .collect::>(); - // assert_eq!(factor_source_ids.len(), 1); - // let fsid = factor_source_ids.into_iter().next().unwrap(); - // sut.insert_for_factor( - // &fsid, - // &instances - // .clone() - // .into_iter() - // .take(1) - // .collect::(), - // ) - // .unwrap(); - - // sut.delete(&IndexMap::kv(fsid, instances)); - todo!() + let sut = SUT::default(); + let instances = FactorInstances::sample(); + assert_eq!(instances.len(), 2); + let factor_source_ids = instances + .clone() + .into_iter() + .map(|fi| fi.factor_source_id()) + .collect::>(); + assert_eq!(factor_source_ids.len(), 1); + let fsid = factor_source_ids.into_iter().next().unwrap(); + sut.insert_for_factor( + &fsid, + &instances + .clone() + .into_iter() + .take(1) + .collect::(), + ) + .unwrap(); + + sut.delete(&IndexMap::kv( + DerivationPreset::AccountMfa, + IndexMap::kv(fsid, instances), + )); } #[test] diff --git a/crates/sargon/src/factor_instances_provider/factor_instances_cache/keyed_instances.rs b/crates/sargon/src/factor_instances_provider/factor_instances_cache/keyed_instances.rs index 5489dea60..1609ec0d3 100644 --- a/crates/sargon/src/factor_instances_provider/factor_instances_cache/keyed_instances.rs +++ b/crates/sargon/src/factor_instances_provider/factor_instances_cache/keyed_instances.rs @@ -41,7 +41,9 @@ impl KeyedInstances { } } -impl IntoIterator for KeyedInstances { +impl IntoIterator + for KeyedInstances +{ type Item = as IntoIterator>::Item; type IntoIter = as IntoIterator>::IntoIter; diff --git a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs index 3cdaae3eb..a7072e2fa 100644 --- a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs @@ -171,19 +171,24 @@ impl FactorInstancesProvider { InstancesInCacheConsumer, InternalFactorInstancesProviderOutcome, )> { - let remaining_quantities_to_derive = not_satisfied.remaining_quantities_to_derive(); - assert!(!remaining_quantities_to_derive.is_empty(), "❌ No instances to derive?"); - + assert!( + !remaining_quantities_to_derive.is_empty(), + "❌ No instances to derive?" + ); + println!("🌮 FIP - derive_more_and_cache - deriving more, specifically: {:?}", remaining_quantities_to_derive); let pdp_pf_newly_derived = self .derive_more(remaining_quantities_to_derive, derivation_purpose) .await?; - assert!(!pdp_pf_newly_derived.is_empty(), "❌ Failed to derive instances?"); + assert!( + !pdp_pf_newly_derived.is_empty(), + "❌ Failed to derive instances?" + ); for (k, v) in pdp_pf_newly_derived.iter() { for (x, y) in v.iter() { @@ -230,12 +235,12 @@ impl FactorInstancesProvider { pdp_pf_found_in_cache_leq_requested: &InstancesPerDerivationPresetPerFactorSource, pdp_pf_newly_derived: &InstancesPerDerivationPresetPerFactorSource, ) -> Split { - - let derivation_presets_of_instances_to_merge = pdp_pf_found_in_cache_leq_requested - .keys() - .chain(pdp_pf_newly_derived.keys()) - .cloned() - .collect::>(); + let derivation_presets_of_instances_to_merge = + pdp_pf_found_in_cache_leq_requested + .keys() + .chain(pdp_pf_newly_derived.keys()) + .cloned() + .collect::>(); // Start by merging the instances found in cache and the newly derived instances, // into a single collection of instances per factor source, with the @@ -250,7 +255,6 @@ impl FactorInstancesProvider { .cloned() // can be nil -> empty, if no instance was found in cache for this preset! .unwrap_or_default(); - let pf_newly_derived = pdp_pf_newly_derived .get(preset) .cloned() @@ -269,13 +273,10 @@ impl FactorInstancesProvider { .into_iter() .map(|f| f.id_from_hash()) .filter_map(|factor_source_id| { - - - let from_cache = pf_found_in_cache_leq_requested + 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() @@ -286,24 +287,16 @@ impl FactorInstancesProvider { } let mut merged = IndexSet::new(); - - - println!("🌮 FIP - split (preset: {:?}, factor: {:?}) - `from_cache`: #{:?}", preset, factor_source_id, from_cache.len()); - println!("🌮 FIP - split (preset: {:?}, factor: {:?}) - `newly_derived`: #{:?}", preset, factor_source_id, newly_derived.len()); - println!("🌮 FIP - split (preset: {:?}, factor: {:?}) - `merged`: #{:?}", preset, factor_source_id, merged.len()); - // 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); - assert!( merged .clone() .into_iter() - .all(|f| + .all(|f| DerivationPreset::try_from(f.derivation_path().agnostic()).unwrap() == *preset ) ); @@ -324,102 +317,94 @@ impl FactorInstancesProvider { let mut pdp_pf_to_cache = InstancesPerDerivationPresetPerFactorSource::new(); - - let originally_requested_presets = requested_quantified_derivation_presets - .iter() - .map(|qdp| qdp.derivation_preset) - .collect::>(); + let originally_requested_presets = + requested_quantified_derivation_presets + .iter() + .map(|qdp| qdp.derivation_preset) + .collect::>(); // Using the merged map, split the instances into those to use directly and those to cache. for (preset, pf_derived_appended_to_from_cache) in pdp_pf_derived_appended_to_from_cache { let mut pf_to_cache = - IndexMap::::new(); + IndexMap::::new(); let mut pf_to_use_directly = IndexMap::new(); - for (factor, instances) in pf_derived_appended_to_from_cache.clone().into_iter() { - assert!( - instances.factor_instances() + assert!(instances.factor_instances().into_iter().all(|f| { + DerivationPreset::try_from(f.derivation_path().agnostic()) + .unwrap() + == preset + })); + + assert!(instances + .factor_instances() .into_iter() - .all(|f| - DerivationPreset::try_from(f.derivation_path().agnostic()).unwrap() == preset - ) - ); - - assert!( - instances.factor_instances() - .into_iter() - .all(|f| - f.factor_source_id() == factor - ) - ); + .all(|f| f.factor_source_id() == factor)); println!( "🌮 FIP - split (preset: {:?}, factor: {:?}) - instances: #{:?}", preset, factor, instances.len() ); - if originally_requested_presets.contains(&preset) { // might have to split - - - let requested_quantified_derivation_preset = - requested_quantified_derivation_presets.get_id(&preset).unwrap(); - - println!("🌮 FIP - split - requested_quantified_derivation_preset: {:?}", requested_quantified_derivation_preset); - - let instances_relevant_to_use_directly_with_abundance = instances; - - println!("🌮 FIP - split - #instances_relevant_to_use_directly_with_abundance: {:?}", instances_relevant_to_use_directly_with_abundance.len()); - - let originally_requested_quantity = - requested_quantified_derivation_preset.quantity; - - println!( - "🌮 FIP - split - originally_requested_quantity: {:?}", - originally_requested_quantity - ); + requested_quantified_derivation_presets + .get_id(&preset) + .unwrap(); - if originally_requested_quantity > instances_relevant_to_use_directly_with_abundance.len() { - println!("🌮 FIP - split ❌❌ not enough instances to use directly! (preset: {:?}, factor: {:?}) ❌❌", preset, factor); - } - - let (to_use_directly, to_cache) = - instances_relevant_to_use_directly_with_abundance - .split_at(originally_requested_quantity); - - println!( - "🌮 FIP - split - to_use_directly: #{:?}", - to_use_directly.len() - ); - - println!( - "🌮 FIP - split - to_cache: #{:?}", - to_cache.len() - ); - - pf_to_use_directly - .insert(factor, to_use_directly); + println!("🌮 FIP - split - requested_quantified_derivation_preset: {:?}", requested_quantified_derivation_preset); + + let instances_relevant_to_use_directly_with_abundance = + instances; + + println!("🌮 FIP - split - #instances_relevant_to_use_directly_with_abundance: {:?}", instances_relevant_to_use_directly_with_abundance.len()); + + let originally_requested_quantity = + requested_quantified_derivation_preset.quantity; + + println!( + "🌮 FIP - split - originally_requested_quantity: {:?}", + originally_requested_quantity + ); + + if originally_requested_quantity + > instances_relevant_to_use_directly_with_abundance + .len() + { + println!("🌮 FIP - split ❌❌ not enough instances to use directly! (preset: {:?}, factor: {:?}) ❌❌", preset, factor); + } + + let (to_use_directly, to_cache) = + instances_relevant_to_use_directly_with_abundance + .split_at(originally_requested_quantity); + + println!( + "🌮 FIP - split - to_use_directly: #{:?}", + to_use_directly.len() + ); - pf_to_cache.insert(factor, to_cache); + println!( + "🌮 FIP - split - to_cache: #{:?}", + to_cache.len() + ); + pf_to_use_directly.insert(factor, to_use_directly); + pf_to_cache.insert(factor, to_cache); } else { // easy case, we don't want to use this directly at all // meaning all pf_to_cache.insert(factor, instances); // we do not add any FactorInstances to `pf_to_use_directly` for this factor } - } pdp_pf_to_use_directly.insert(preset, pf_to_use_directly); @@ -472,7 +457,7 @@ impl FactorInstancesProvider { }) .collect::>>()?; - assert!(!paths.is_empty()); + assert!(!paths.is_empty()); Ok((factor_source_id, paths)) }) @@ -503,11 +488,18 @@ impl FactorInstancesProvider { } for (k, v) in per_factor_paths.iter() { - let contains_rola_path = v.iter().any(|p| p.agnostic().key_kind == CAP26KeyKind::AuthenticationSigning); + let contains_rola_path = v.iter().any(|p| { + p.agnostic().key_kind == CAP26KeyKind::AuthenticationSigning + }); println!("🌮 FIP - derive_more - 🛣️ per_factor_paths - (factor: {:?}) - contains_rola_path? {:?}, paths: \n\n{:?}\n\n", k, contains_rola_path, v); } - println!("🛡️ #factor_sources ids: {:?}", factor_sources.iter().map(|f| f.factor_source_id()).collect_vec()); - + println!( + "🛡️ #factor_sources ids: {:?}", + factor_sources + .iter() + .map(|f| f.factor_source_id()) + .collect_vec() + ); let interactor = self.interactor.clone(); @@ -520,11 +512,10 @@ impl FactorInstancesProvider { let pf_derived = collector.collect_keys().await.factors_by_source; - for (k, v) in pf_derived.iter() { let requested = per_factor_paths.get(k).unwrap(); if v.len() < requested.len() { - return Err(CommonError::TooFewFactorInstancesDerived) + return Err(CommonError::TooFewFactorInstancesDerived); } println!("🌮 FIP - derive_more - 🔮🦄🍬 derived - (factor: {:?}) - v.len(): #{:?}", k, v.len()); } @@ -565,9 +556,15 @@ impl FactorInstancesProvider { >::new(); for (factor_source_id, pdp) in pf_pdp_derived { - assert!(!pdp.is_empty(), "🙅🏻‍♀️ no instances for factor: {factor_source_id}"); + assert!( + !pdp.is_empty(), + "🙅🏻‍♀️ no instances for factor: {factor_source_id}" + ); for (preset, instances) in pdp { - assert!(!instances.is_empty(), "🙅🏻‍♀️ no instances for preset: {preset:?}"); + assert!( + !instances.is_empty(), + "🙅🏻‍♀️ no instances for preset: {preset:?}" + ); pdp_pf_instances.append_or_insert_to( preset, IndexMap::::kv( diff --git a/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs b/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs index 010406bb6..ad03566ab 100644 --- a/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs +++ b/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs @@ -37,7 +37,6 @@ impl InternalFactorInstancesProviderOutcome { self.get_for_derivation_preset(preset) .and_then(|x| x.per_factor.get(&factor_source_id)) } - } #[derive(Clone, Debug)] diff --git a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs index 4fd265702..b779eb812 100644 --- a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs @@ -184,18 +184,24 @@ mod tests { == preset.cache_filling_quantity()) )); - assert!(outcome.per_derivation_preset.clone().into_iter().all( - |(preset, x)| { - x.per_factor.values().all(|y| { - y.debug_was_derived.len() - == preset.cache_filling_quantity() + 1 - } /* One account created */) + for (k, v) in outcome.per_derivation_preset.iter() { + for (_, y) in v.per_factor.iter() { + let derivation_based_offset = + if *k == DerivationPreset::IdentityVeci { + 1 /* One account created */ + } else { + 0 + }; + assert_eq!( + y.debug_was_derived.len(), + k.cache_filling_quantity() + derivation_based_offset + ) } - )); + } let instances_used_directly = outcome .per_derivation_preset - .get(&DerivationPreset::AccountVeci) + .get(&DerivationPreset::IdentityVeci) .unwrap() .per_factor .get(&bdfs.id_from_hash()) diff --git a/crates/sargon/src/factor_instances_provider/types/factor_instances.rs b/crates/sargon/src/factor_instances_provider/types/factor_instances.rs index 8d206dbac..c5d89a8dd 100644 --- a/crates/sargon/src/factor_instances_provider/types/factor_instances.rs +++ b/crates/sargon/src/factor_instances_provider/types/factor_instances.rs @@ -46,7 +46,7 @@ impl FactorInstances { 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); diff --git a/crates/sargon/src/keys_collector/collector/derivation_purpose.rs b/crates/sargon/src/keys_collector/collector/derivation_purpose.rs index fd5bf8c7a..7f3db0c91 100644 --- a/crates/sargon/src/keys_collector/collector/derivation_purpose.rs +++ b/crates/sargon/src/keys_collector/collector/derivation_purpose.rs @@ -88,21 +88,34 @@ mod tests { } #[test] - fn test_for_securifying_account() { - // assert_eq!( - // SUT::for_securifying_or_updating(CAP26EntityKind::Account), - // SUT::SecurifyingAccount - // ) - todo!() + fn test_for_securifying_account_only() { + assert_eq!( + SUT::for_securifying_or_updating(&IndexSet::from_iter([ + AccountAddress::sample().into() + ])), + SUT::SecurifyingAccount + ) } #[test] - fn test_for_securifying_persona() { - // assert_eq!( - // SUT::for_securifying_or_updating(CAP26EntityKind::Identity), - // SUT::SecurifyingPersona - // ) - todo!() + fn test_for_securifying_persona_only() { + assert_eq!( + SUT::for_securifying_or_updating(&IndexSet::from_iter([ + IdentityAddress::sample().into() + ])), + SUT::SecurifyingPersona + ) + } + + #[test] + fn test_for_securifying_account_and_persona() { + assert_eq!( + SUT::for_securifying_or_updating(&IndexSet::from_iter([ + AccountAddress::sample().into(), + IdentityAddress::sample().into() + ])), + SUT::SecurifyingAccountsAndPersonas + ) } #[test] diff --git a/crates/sargon/src/system/clients/client/factor_instances_cache_client.rs b/crates/sargon/src/system/clients/client/factor_instances_cache_client.rs index 403612682..63f3bda03 100644 --- a/crates/sargon/src/system/clients/client/factor_instances_cache_client.rs +++ b/crates/sargon/src/system/clients/client/factor_instances_cache_client.rs @@ -177,8 +177,6 @@ impl FactorInstancesCacheClient { .await } - - /// Reads out the instance of `factor_source_id` without mutating the cache. pub async fn peek_all_instances_of_factor_source( &self, @@ -200,7 +198,6 @@ impl FactorInstancesCacheClient { #[cfg(test)] impl FactorInstancesCacheClient { - /// 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, @@ -214,7 +211,11 @@ impl FactorInstancesCacheClient { network_id: NetworkID, ) -> Result { self.access_cache_init_if_needed(|cache| { - cache.get_poly_factor_with_quantities(factor_source_ids.borrow(), originally_requested_quantified_derivation_preset.borrow(), network_id) + cache.get_poly_factor_with_quantities( + factor_source_ids.borrow(), + originally_requested_quantified_derivation_preset.borrow(), + network_id, + ) }) .await } @@ -369,26 +370,28 @@ mod tests { #[actix_rt::test] async fn test_insert_all() { - // let file_system = Arc::new(FileSystemClient::in_memory()); - // let sut = SUT::new(file_system); - - // let fs = FactorSourceIDFromHash::sample_at(0); - // sut.insert_all(IndexMap::kv(fs, FactorInstances::sample())) - // .await - // .unwrap(); - - // let max = sut - // .max_index_for( - // fs, - // DerivationPreset::AccountMfa - // .index_agnostic_path_on_network(NetworkID::Mainnet), - // ) - // .await - // .unwrap(); - // assert_eq!( - // max.unwrap(), - // HDPathComponent::Securified(SecurifiedU30::ONE) - // ); - todo!("migrate me") + let file_system = Arc::new(FileSystemClient::in_memory()); + let sut = SUT::new(file_system); + + let fs = FactorSourceIDFromHash::sample_at(0); + sut.insert(&IndexMap::kv( + DerivationPreset::AccountMfa, + IndexMap::kv(fs, FactorInstances::sample()), + )) + .await + .unwrap(); + + let max = sut + .max_index_for( + fs, + DerivationPreset::AccountMfa + .index_agnostic_path_on_network(NetworkID::Mainnet), + ) + .await + .unwrap(); + assert_eq!( + max.unwrap(), + HDPathComponent::Securified(SecurifiedU30::ONE) + ); } } From 9d89a3118b9ec237b63e7f77e4ccf304643a7504 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Wed, 18 Dec 2024 20:17:32 +0100 Subject: [PATCH 45/60] clippy fix --- Cargo.lock | 4 +- crates/sargon-uniffi/Cargo.toml | 2 +- crates/sargon/Cargo.toml | 2 +- .../quantified_derivation_preset.rs | 64 +++++++++---------- .../factor_instances_cache/keyed_instances.rs | 4 ++ ...entity_index_profile_analyzing_assigner.rs | 6 +- .../provider/factor_instances_provider.rs | 2 +- ...rtual_entity_creating_instance_provider.rs | 14 ++-- .../profile_network_get_entities.rs | 4 +- .../system/sargon_os/sargon_os_accounts.rs | 4 +- 10 files changed, 53 insertions(+), 53 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ba11ee775..b6b0a9942 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2761,7 +2761,7 @@ dependencies = [ [[package]] name = "sargon" -version = "1.1.90" +version = "1.1.92" dependencies = [ "actix-rt", "aes-gcm", @@ -2816,7 +2816,7 @@ dependencies = [ [[package]] name = "sargon-uniffi" -version = "1.1.90" +version = "1.1.92" dependencies = [ "actix-rt", "assert-json-diff", diff --git a/crates/sargon-uniffi/Cargo.toml b/crates/sargon-uniffi/Cargo.toml index fd8f8f7be..6a06d9d58 100644 --- a/crates/sargon-uniffi/Cargo.toml +++ b/crates/sargon-uniffi/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "sargon-uniffi" # Don't forget to update version in crates/sargon/Cargo.toml -version = "1.1.90" +version = "1.1.92" edition = "2021" build = "build.rs" diff --git a/crates/sargon/Cargo.toml b/crates/sargon/Cargo.toml index e6aa0939e..e3d95d302 100644 --- a/crates/sargon/Cargo.toml +++ b/crates/sargon/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "sargon" # Don't forget to update version in crates/sargon-uniffi/Cargo.toml -version = "1.1.90" +version = "1.1.92" edition = "2021" build = "build.rs" diff --git a/crates/sargon/src/factor_instances_provider/agnostic_paths/quantified_derivation_preset.rs b/crates/sargon/src/factor_instances_provider/agnostic_paths/quantified_derivation_preset.rs index 1a87f8936..c66437774 100644 --- a/crates/sargon/src/factor_instances_provider/agnostic_paths/quantified_derivation_preset.rs +++ b/crates/sargon/src/factor_instances_provider/agnostic_paths/quantified_derivation_preset.rs @@ -10,7 +10,7 @@ pub struct QuantifiedDerivationPreset { impl Identifiable for QuantifiedDerivationPreset { type ID = DerivationPreset; fn id(&self) -> DerivationPreset { - self.derivation_preset.clone() + self.derivation_preset } } @@ -34,38 +34,34 @@ impl QuantifiedDerivationPreset { .filter(|a| a.is_identity()) .collect_vec(); - let presets = - match (account_addresses.is_empty(), identity_addresses.is_empty()) - { - (true, true) => IdentifiedVecOf::new(), // weird! - (true, false) => IdentifiedVecOf::from_iter([ - Self::new( - DerivationPreset::IdentityMfa, - identity_addresses.len(), - ), - Self::new(DerivationPreset::IdentityRola, 1), - ]), - (false, false) => IdentifiedVecOf::from_iter([ - Self::new( - DerivationPreset::AccountMfa, - account_addresses.len(), - ), - Self::new(DerivationPreset::AccountRola, 1), - Self::new( - DerivationPreset::IdentityMfa, - identity_addresses.len(), - ), - Self::new(DerivationPreset::IdentityRola, 1), - ]), - (false, true) => IdentifiedVecOf::from_iter([ - Self::new( - DerivationPreset::AccountMfa, - account_addresses.len(), - ), - Self::new(DerivationPreset::AccountRola, 1), - ]), - }; - - presets + match (account_addresses.is_empty(), identity_addresses.is_empty()) { + (true, true) => IdentifiedVecOf::new(), // weird! + (true, false) => IdentifiedVecOf::from_iter([ + Self::new( + DerivationPreset::IdentityMfa, + identity_addresses.len(), + ), + Self::new(DerivationPreset::IdentityRola, 1), + ]), + (false, false) => IdentifiedVecOf::from_iter([ + Self::new( + DerivationPreset::AccountMfa, + account_addresses.len(), + ), + Self::new(DerivationPreset::AccountRola, 1), + Self::new( + DerivationPreset::IdentityMfa, + identity_addresses.len(), + ), + Self::new(DerivationPreset::IdentityRola, 1), + ]), + (false, true) => IdentifiedVecOf::from_iter([ + Self::new( + DerivationPreset::AccountMfa, + account_addresses.len(), + ), + Self::new(DerivationPreset::AccountRola, 1), + ]), + } } } diff --git a/crates/sargon/src/factor_instances_provider/factor_instances_cache/keyed_instances.rs b/crates/sargon/src/factor_instances_provider/factor_instances_cache/keyed_instances.rs index 1609ec0d3..64f805f28 100644 --- a/crates/sargon/src/factor_instances_provider/factor_instances_cache/keyed_instances.rs +++ b/crates/sargon/src/factor_instances_provider/factor_instances_cache/keyed_instances.rs @@ -39,6 +39,10 @@ impl KeyedInstances { pub fn len(&self) -> usize { self.0.len() } + + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } } impl IntoIterator diff --git a/crates/sargon/src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_profile_analyzing_assigner.rs b/crates/sargon/src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_profile_analyzing_assigner.rs index db320b2f9..f620daf1a 100644 --- a/crates/sargon/src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_profile_analyzing_assigner.rs +++ b/crates/sargon/src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_profile_analyzing_assigner.rs @@ -590,7 +590,8 @@ mod tests { )), ); type F = FactorSourceIDFromHash; - for fid in [F::sample_device()] { + { + let fid = F::sample_device(); let next = sut .next(fid, preset.index_agnostic_path_on_network(network_id)) .unwrap(); @@ -616,7 +617,8 @@ mod tests { )), ); type F = FactorSourceIDFromHash; - for fid in [F::sample_device()] { + { + let fid = F::sample_device(); let next = sut .next(fid, preset.index_agnostic_path_on_network(network_id)) .unwrap(); diff --git a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs index a7072e2fa..799b956a4 100644 --- a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs @@ -357,7 +357,7 @@ impl FactorInstancesProvider { let requested_quantified_derivation_preset = requested_quantified_derivation_presets - .get_id(&preset) + .get_id(preset) .unwrap(); println!("🌮 FIP - split - requested_quantified_derivation_preset: {:?}", requested_quantified_derivation_preset); diff --git a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs index b779eb812..70934e2ce 100644 --- a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs @@ -174,7 +174,7 @@ mod tests { assert!(outcome.per_derivation_preset.values().all(|x| x .per_factor .values() - .all(|y| y.debug_found_in_cache.len() == 0))); + .all(|y| y.debug_found_in_cache.is_empty()))); assert!(outcome.per_derivation_preset.clone().into_iter().all( |(preset, x)| x @@ -307,7 +307,7 @@ mod tests { assert!(outcome.per_derivation_preset.values().all(|x| x .per_factor .values() - .all(|y| y.debug_found_in_cache.len() == 0))); + .all(|y| y.debug_found_in_cache.is_empty()))); assert!(outcome.per_derivation_preset.clone().into_iter().all( |(preset, x)| x @@ -558,14 +558,14 @@ mod tests { |(_, x)| x .per_factor .values() - .all(|y| y.debug_was_cached.len() == 0) + .all(|y| y.debug_was_cached.is_empty()) )); assert!(outcome.per_derivation_preset.clone().into_iter().all( |(_, x)| x .per_factor .values() - .all(|y| y.debug_was_derived.len() == 0) + .all(|y| y.debug_was_derived.is_empty()) )); let instances_used_directly = outcome @@ -677,14 +677,14 @@ mod tests { |(_, x)| x .per_factor .values() - .all(|y| y.debug_was_cached.len() == 0) + .all(|y| y.debug_was_cached.is_empty()) )); assert!(outcome.per_derivation_preset.clone().into_iter().all( |(_, x)| x .per_factor .values() - .all(|y| y.debug_was_derived.len() == 0) + .all(|y| y.debug_was_derived.is_empty()) )); let cached = cache_client @@ -730,7 +730,7 @@ mod tests { assert!(outcome.per_derivation_preset.values().all(|x| x .per_factor .values() - .all(|y| y.debug_found_in_cache.len() == 0))); + .all(|y| y.debug_found_in_cache.is_empty()))); assert!(outcome.per_derivation_preset.clone().into_iter().all( |(preset, x)| x.per_factor.values().all( diff --git a/crates/sargon/src/profile/logic/profile_network/profile_network_get_entities.rs b/crates/sargon/src/profile/logic/profile_network/profile_network_get_entities.rs index c90688b35..8996c2ca6 100644 --- a/crates/sargon/src/profile/logic/profile_network/profile_network_get_entities.rs +++ b/crates/sargon/src/profile/logic/profile_network/profile_network_get_entities.rs @@ -54,9 +54,7 @@ impl ProfileNetwork { ) -> bool { self.get_entities_erased(entity_address.get_entity_kind()) .into_iter() - .any(|e| { - AddressOfAccountOrPersona::from(e.address()) == *entity_address - }) + .any(|e| e.address() == *entity_address) } } diff --git a/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs b/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs index 2e86ee13c..b5b45aa10 100644 --- a/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs +++ b/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs @@ -880,7 +880,7 @@ impl SargonOS { let mut instances_per_factor_source = instances_per_preset_per_factor_source .swap_remove(&preset) - .expect(&format!("Expected to find instances for derivation preset: {:?}", preset)); + .unwrap_or_else(|| panic!("Expected to find instances for derivation preset: {:?}", preset)); for (i, entity_address) in addresses_of_kind.clone().into_iter().enumerate() @@ -906,7 +906,7 @@ impl SargonOS { )? }; security_structures_of_factor_instances.insert( - entity_address.clone(), + *entity_address, security_structure_of_factor_instances, ); } From 93bc314758d02e2cb05bdf36e45c2164f0148d78 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Wed, 18 Dec 2024 21:24:08 +0100 Subject: [PATCH 46/60] remove prints --- .../types/keys/key_agreement/private_key.rs | 1 - .../provider/factor_instances_provider.rs | 131 ++---------------- .../provider_adopters/cache_filler.rs | 23 --- ...rtual_entity_creating_instance_provider.rs | 11 +- .../bip39/mnemonic.rs | 3 - .../v100/address/non_fungible_global_id.rs | 1 - .../low_level/v1/transaction_intent.rs | 1 - 7 files changed, 14 insertions(+), 157 deletions(-) diff --git a/crates/sargon/src/core/types/keys/key_agreement/private_key.rs b/crates/sargon/src/core/types/keys/key_agreement/private_key.rs index 24e97de2a..c7afd73a7 100644 --- a/crates/sargon/src/core/types/keys/key_agreement/private_key.rs +++ b/crates/sargon/src/core/types/keys/key_agreement/private_key.rs @@ -156,7 +156,6 @@ mod tests { fn public_key() { let private_key = SUT::sample(); let public_key = private_key.public_key(); - println!("{:?}", public_key); assert_eq!( public_key, KeyAgreementPublicKey::from_hex("8679bc1fe3210b2ce84793668b05218fdc4c220bc05387b7d2ac0d4c7b7c5d10".to_owned()) diff --git a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs index 799b956a4..7665c5b02 100644 --- a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs @@ -111,15 +111,9 @@ impl FactorInstancesProvider { InstancesInCacheConsumer, InternalFactorInstancesProviderOutcome, )> { - println!( - "🌮 FIP - _provide_for_presets: {:?}, purpose: {:?}", - quantified_derivation_presets, derivation_purpose - ); - let factor_sources = self.factor_sources.clone(); let network_id = self.network_id; - println!("🌮 FIP - _provide_for_presets - calling `cache_client.get`"); let cached = self .cache_client .get( @@ -133,7 +127,6 @@ impl FactorInstancesProvider { CachedInstancesWithQuantitiesOutcome::Satisfied( enough_instances, ) => { - println!("🌮 FIP - _provide_for_presets - cached outcome - ✅ SATISFIED ✅"); // When/if caller calls `instances_in_cache_consumer.consume()` the `enough_instances` // will be deleted from the cache, they are still present in the cache now // and will continue to be present until the `consume()` is called. @@ -149,7 +142,6 @@ impl FactorInstancesProvider { )) } CachedInstancesWithQuantitiesOutcome::NotSatisfied(unsatisfied) => { - println!("🌮 FIP - _provide_for_presets - cached outcome - 🙅🏻‍♀️ NotSatisfied => `derive_more_and_cache` 🙅🏻‍♀️ "); self.derive_more_and_cache( &quantified_derivation_presets, unsatisfied, @@ -174,27 +166,13 @@ impl FactorInstancesProvider { let remaining_quantities_to_derive = not_satisfied.remaining_quantities_to_derive(); - assert!( - !remaining_quantities_to_derive.is_empty(), - "❌ No instances to derive?" - ); - - println!("🌮 FIP - derive_more_and_cache - deriving more, specifically: {:?}", remaining_quantities_to_derive); + assert!(!remaining_quantities_to_derive.is_empty()); let pdp_pf_newly_derived = self .derive_more(remaining_quantities_to_derive, derivation_purpose) .await?; - assert!( - !pdp_pf_newly_derived.is_empty(), - "❌ Failed to derive instances?" - ); - - for (k, v) in pdp_pf_newly_derived.iter() { - for (x, y) in v.iter() { - println!("🌮 FIP 🔮✨ derived - (preset: {:?}, factor: {:?}) - #{:?} instances ✨🔮", k, x, y.len()); - } - } + assert!(!pdp_pf_newly_derived.is_empty(),); let pdp_pf_found_in_cache_leq_requested = not_satisfied.cached_instances_to_use(); @@ -346,12 +324,6 @@ impl FactorInstancesProvider { .into_iter() .all(|f| f.factor_source_id() == factor)); - println!( - "🌮 FIP - split (preset: {:?}, factor: {:?}) - instances: #{:?}", - preset, factor, - instances.len() - ); - if originally_requested_presets.contains(&preset) { // might have to split @@ -360,42 +332,16 @@ impl FactorInstancesProvider { .get_id(preset) .unwrap(); - println!("🌮 FIP - split - requested_quantified_derivation_preset: {:?}", requested_quantified_derivation_preset); - let instances_relevant_to_use_directly_with_abundance = instances; - println!("🌮 FIP - split - #instances_relevant_to_use_directly_with_abundance: {:?}", instances_relevant_to_use_directly_with_abundance.len()); - let originally_requested_quantity = requested_quantified_derivation_preset.quantity; - println!( - "🌮 FIP - split - originally_requested_quantity: {:?}", - originally_requested_quantity - ); - - if originally_requested_quantity - > instances_relevant_to_use_directly_with_abundance - .len() - { - println!("🌮 FIP - split ❌❌ not enough instances to use directly! (preset: {:?}, factor: {:?}) ❌❌", preset, factor); - } - let (to_use_directly, to_cache) = instances_relevant_to_use_directly_with_abundance .split_at(originally_requested_quantity); - println!( - "🌮 FIP - split - to_use_directly: #{:?}", - to_use_directly.len() - ); - - println!( - "🌮 FIP - split - to_cache: #{:?}", - to_cache.len() - ); - pf_to_use_directly.insert(factor, to_use_directly); pf_to_cache.insert(factor, to_cache); @@ -487,20 +433,6 @@ impl FactorInstancesProvider { } } - for (k, v) in per_factor_paths.iter() { - let contains_rola_path = v.iter().any(|p| { - p.agnostic().key_kind == CAP26KeyKind::AuthenticationSigning - }); - println!("🌮 FIP - derive_more - 🛣️ per_factor_paths - (factor: {:?}) - contains_rola_path? {:?}, paths: \n\n{:?}\n\n", k, contains_rola_path, v); - } - println!( - "🛡️ #factor_sources ids: {:?}", - factor_sources - .iter() - .map(|f| f.factor_source_id()) - .collect_vec() - ); - let interactor = self.interactor.clone(); let collector = KeysCollector::new( @@ -517,38 +449,30 @@ impl FactorInstancesProvider { if v.len() < requested.len() { return Err(CommonError::TooFewFactorInstancesDerived); } - println!("🌮 FIP - derive_more - 🔮🦄🍬 derived - (factor: {:?}) - v.len(): #{:?}", k, v.len()); } - assert!(!pf_derived.is_empty(), "❌❌ no instances derived ❌"); + assert!(!pf_derived.is_empty()); let pf_pdp_derived = pf_derived .into_iter() .filter_map(|(k, v)| { if v.is_empty() { - println!("🌮 FIP - derive_more EMPTY 🐌 for factor: {:?})", k); return None; } - println!("🌮 FIP - derive_more - derived 🛡️ - (factor: {:?}) - v.len(): #{:?}", k, v.len()); - let apor = InstancesByDerivationPreset::from(FactorInstances::from(v)) - .0; - println!("🌮 FIP - derive_more - derived 🦧 - (factor: {:?}) - apor.len() #{:?}", k, apor.len()); - if apor.is_empty() { - None - } else { - Some(( - k, - apor - )) - } + let instances = FactorInstances::from(v); + let instances = InstancesByDerivationPreset::from(instances).0; + if instances.is_empty() { + None + } else { + Some((k, instances)) + } }) .collect::, >>(); - // we need to transpose the `pf_pdp_derived` - assert!(!pf_pdp_derived.is_empty(), "🙅🏻‍♀️ no instances derived?"); + assert!(!pf_pdp_derived.is_empty()); let mut pdp_pf_instances = IndexMap::< DerivationPreset, @@ -556,15 +480,9 @@ impl FactorInstancesProvider { >::new(); for (factor_source_id, pdp) in pf_pdp_derived { - assert!( - !pdp.is_empty(), - "🙅🏻‍♀️ no instances for factor: {factor_source_id}" - ); + assert!(!pdp.is_empty()); for (preset, instances) in pdp { - assert!( - !instances.is_empty(), - "🙅🏻‍♀️ no instances for preset: {preset:?}" - ); + assert!(!instances.is_empty()); pdp_pf_instances.append_or_insert_to( preset, IndexMap::::kv( @@ -575,29 +493,6 @@ impl FactorInstancesProvider { } } - // for (preset, per_factor) in per_preset_per_factor_paths { - // let mut pf_instances = - // IndexMap::::new(); - - // for (factor_source_id, paths) in per_factor { - // 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::(), - // ); - // } - - // pdp_pf_instances.insert(preset, pf_instances); - // } - Ok(pdp_pf_instances) } } diff --git a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/cache_filler.rs b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/cache_filler.rs index ef519598c..1a6f8b208 100644 --- a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/cache_filler.rs +++ b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/cache_filler.rs @@ -26,10 +26,6 @@ impl CacheFiller { network_id: NetworkID, // typically mainnet interactor: Arc, ) -> Result { - println!( - "🎊 CacheFiller - factor_source: {:?} START", - factor_source.factor_source_id() - ); let provider = FactorInstancesProvider::new( network_id, IndexSet::just(factor_source.clone()), @@ -37,20 +33,11 @@ impl CacheFiller { cache_client.clone(), interactor, ); - println!( - "🎊 CacheFiller - factor_source: {:?} PROVIDER CREATED", - factor_source.factor_source_id() - ); let quantities_to_derive = CacheFillingQuantities::for_factor_source( factor_source.id_from_hash(), ); - println!( - "🎊 CacheFiller - factor_source: {:?} quantities_to_derive: {:?}", - factor_source.factor_source_id(), - quantities_to_derive - ); let pdp_pf_derived = provider .derive_more( quantities_to_derive, @@ -58,17 +45,7 @@ impl CacheFiller { ) .await?; - println!( - "🎊 CacheFiller - factor_source: {:?} derived: #{:?}", - factor_source.factor_source_id(), - pdp_pf_derived.clone().values().fold(0, |acc, e| acc - + e.values().fold(0, |xacc, xe| xacc + xe.len())) - ); cache_client.insert(&pdp_pf_derived).await?; - println!( - "🎊 CacheFiller - factor_source: {:?} INSERTED INTO CACHE", - factor_source.factor_source_id() - ); let per_derivation_preset = pdp_pf_derived .into_iter() diff --git a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs index 70934e2ce..f280125aa 100644 --- a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs @@ -318,8 +318,7 @@ mod tests { )); for (k, v) in outcome.per_derivation_preset.iter() { - for (x, y) in v.per_factor.iter() { - println!("🍬 preset: {:?}, factor: {:?}, debug_was_derived.len(): #{:?}", k, x, y.debug_was_derived.len()); + for (_, y) in v.per_factor.iter() { let derivation_based_offset = if *k == DerivationPreset::AccountVeci { 1 @@ -332,14 +331,6 @@ mod tests { ) } } - // assert!(outcome.per_derivation_preset.clone().into_iter().all( - // |(preset, x)| { - // x.per_factor.values().all(|y| { - // y.debug_was_derived.len() - // == preset.cache_filling_quantity() + 1 - // } /* One account created */) - // } - // )); let instances_used_directly = outcome .per_derivation_preset diff --git a/crates/sargon/src/hierarchical_deterministic/bip39/mnemonic.rs b/crates/sargon/src/hierarchical_deterministic/bip39/mnemonic.rs index fac358211..fea725831 100644 --- a/crates/sargon/src/hierarchical_deterministic/bip39/mnemonic.rs +++ b/crates/sargon/src/hierarchical_deterministic/bip39/mnemonic.rs @@ -424,9 +424,6 @@ mod tests { fn find_off_device_sample_other() { let s = "off device sign source sample other off sample other off sample other off sample other off sample other off device sample other off"; let mnemonics = calculate_last_mnemonic_word_from_phrase(s); - for mnemonic in mnemonics.iter() { - println!("{}", mnemonic.words.iter().last().unwrap().word); - } assert!(mnemonics.iter().contains(&SUT::sample_off_device_other())); } diff --git a/crates/sargon/src/profile/v100/address/non_fungible_global_id.rs b/crates/sargon/src/profile/v100/address/non_fungible_global_id.rs index f0898ef54..904a9e5a8 100644 --- a/crates/sargon/src/profile/v100/address/non_fungible_global_id.rs +++ b/crates/sargon/src/profile/v100/address/non_fungible_global_id.rs @@ -335,7 +335,6 @@ mod tests { // local_id: ruid local_id = NonFungibleLocalId::ruid(hex_decode("deadbeef12345678babecafe87654321fadedeaf01234567ecadabba76543210").unwrap()).unwrap(); item = SUT::new(resource_address, local_id); - println!("{}", item.formatted(AddressFormat::Raw)); assert_eq!( item.formatted(AddressFormat::Default), "reso...c9wlxa:{dead...3210}" diff --git a/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v1/transaction_intent.rs b/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v1/transaction_intent.rs index c49f57f4b..9957d8285 100644 --- a/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v1/transaction_intent.rs +++ b/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v1/transaction_intent.rs @@ -212,7 +212,6 @@ mod tests { let sut = SUT::test_with_sbor_depth(SUT::MAX_SBOR_DEPTH, NetworkID::Stokenet) .unwrap(); - println!("{}", &sut.manifest); assert_eq!(sut.transaction_intent_hash().to_string(), "txid_rdx1uwcfczupvvrrtxwxx6p5jugaxvu3j83tj5nz9pnrr44jyxccg2cqhuvzhy") } From d67aea5a54d32fe3934aab50796e247cbc51a918 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Thu, 19 Dec 2024 09:39:47 +0100 Subject: [PATCH 47/60] add ROLA key to builder --- .../security_shield_builder.rs | 32 ++++++ .../security_shield_builder_invalid_reason.rs | 3 + ...security_structure_of_factor_source_ids.rs | 3 + .../security_structure_of_factor_sources.rs | 3 + .../factor_instances_provider_unit_tests.rs | 99 +++++++++++++------ ...curify_entity_factor_instances_provider.rs | 52 ++++------ .../automatic_shield_builder.rs | 74 +++++++++----- .../automatic_shield_builder/mod.rs | 2 +- .../{proto_matrix.rs => proto_shield.rs} | 8 +- .../security_shield_builder.rs | 19 ++++ .../security_shield_builder_invalid_reason.rs | 3 + .../abstract_security_structure_of_factors.rs | 16 ++- ...security_structure_of_factor_source_ids.rs | 14 ++- .../security_structure_of_factor_sources.rs | 20 +++- .../system/sargon_os/sargon_os_accounts.rs | 4 +- 15 files changed, 252 insertions(+), 100 deletions(-) rename crates/sargon/src/profile/mfa/security_structures/automatic_shield_builder/{proto_matrix.rs => proto_shield.rs} (81%) diff --git a/crates/sargon-uniffi/src/profile/mfa/security_structures/security_shield_builder.rs b/crates/sargon-uniffi/src/profile/mfa/security_structures/security_shield_builder.rs index 981b08eb6..8b7c216c1 100644 --- a/crates/sargon-uniffi/src/profile/mfa/security_structures/security_shield_builder.rs +++ b/crates/sargon-uniffi/src/profile/mfa/security_structures/security_shield_builder.rs @@ -109,6 +109,11 @@ impl SecurityShieldBuilder { self.get(|builder| builder.get_name()) } + pub fn get_authentication_signing_factor(&self) -> Option { + self.get(|builder| builder.get_authentication_signing_factor()) + .map(|x| x.into()) + } + pub fn get_primary_threshold_factors(&self) -> Vec { self.get_factors(|builder| builder.get_primary_threshold_factors()) } @@ -135,6 +140,17 @@ impl SecurityShieldBuilder { self.set(|builder| builder.set_name(&name)); } + pub fn set_authentication_signing_factor( + &self, + new: Option, + ) { + self.set(|builder| { + builder.set_authentication_signing_factor( + new.clone().map(|x| x.into_internal()), + ) + }); + } + pub fn remove_factor_from_all_roles( &self, factor_source_id: FactorSourceID, @@ -756,6 +772,18 @@ mod tests { sut.remove_factor_from_confirmation(f.clone()); assert_eq!(xs, sut.get_confirmation_factors()); + assert!(matches!( + sut.validate(), + Some(SecurityShieldBuilderInvalidReason::MissingAuthSigningFactor) + )); + sut.set_authentication_signing_factor(Some( + FactorSourceID::sample_device_other(), + )); + assert_eq!( + sut.get_authentication_signing_factor(), + Some(FactorSourceID::sample_device_other()) + ); + let v0 = sut.validate(); let v1 = sut.validate(); // can call validate many times! assert_eq!(v0, v1); @@ -764,6 +792,10 @@ mod tests { let shield = sut.build().unwrap(); // can call build many times! assert_eq!(shield0, shield); + assert_eq!( + shield.authentication_signing_factor, + FactorSourceID::sample_device_other() + ); assert_eq!(shield.metadata.display_name.value, "S.H.I.E.L.D."); assert_eq!( shield.matrix_of_factors.primary_role.override_factors, diff --git a/crates/sargon-uniffi/src/profile/mfa/security_structures/security_shield_builder_invalid_reason.rs b/crates/sargon-uniffi/src/profile/mfa/security_structures/security_shield_builder_invalid_reason.rs index 16a0a488b..56eb64369 100644 --- a/crates/sargon-uniffi/src/profile/mfa/security_structures/security_shield_builder_invalid_reason.rs +++ b/crates/sargon-uniffi/src/profile/mfa/security_structures/security_shield_builder_invalid_reason.rs @@ -8,6 +8,9 @@ use thiserror::Error as ThisError; Clone, Debug, ThisError, PartialEq, InternalConversion, uniffi::Error, )] pub enum SecurityShieldBuilderInvalidReason { + #[error("Auth Signing Factor Missing")] + MissingAuthSigningFactor, + #[error("Shield name is invalid")] ShieldNameInvalid, diff --git a/crates/sargon-uniffi/src/profile/mfa/security_structures/security_structures/security_structure_of_factor_source_ids.rs b/crates/sargon-uniffi/src/profile/mfa/security_structures/security_structures/security_structure_of_factor_source_ids.rs index 8ece8ba6f..be0a81376 100644 --- a/crates/sargon-uniffi/src/profile/mfa/security_structures/security_structures/security_structure_of_factor_source_ids.rs +++ b/crates/sargon-uniffi/src/profile/mfa/security_structures/security_structures/security_structure_of_factor_source_ids.rs @@ -15,6 +15,9 @@ pub struct SecurityStructureOfFactorSourceIDs { /// The structure of factors to use for certain roles, Primary, Recovery /// and Confirmation role. pub matrix_of_factors: MatrixOfFactorSourceIDs, + + /// The factor to use for authentication signing aka true Rola Key. + pub authentication_signing_factor: FactorSourceID, } delegate_debug_into!( diff --git a/crates/sargon-uniffi/src/profile/mfa/security_structures/security_structures/security_structure_of_factor_sources.rs b/crates/sargon-uniffi/src/profile/mfa/security_structures/security_structures/security_structure_of_factor_sources.rs index 7789cc128..0ebd22f7d 100644 --- a/crates/sargon-uniffi/src/profile/mfa/security_structures/security_structures/security_structure_of_factor_sources.rs +++ b/crates/sargon-uniffi/src/profile/mfa/security_structures/security_structures/security_structure_of_factor_sources.rs @@ -12,6 +12,9 @@ pub struct SecurityStructureOfFactorSources { /// The structure of factors to use for certain roles, Primary, Recovery /// and Confirmation role. pub matrix_of_factors: MatrixOfFactorSources, + + /// The factor to use for authentication signing aka true Rola Key. + pub authentication_signing_factor: FactorSource, } #[uniffi::export] diff --git a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider_unit_tests.rs b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider_unit_tests.rs index 7d851cf44..7246ca41c 100644 --- a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider_unit_tests.rs +++ b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider_unit_tests.rs @@ -483,8 +483,11 @@ async fn cache_is_unchanged_in_case_of_failure() { number_of_days_until_auto_confirm: 1, }; - let shield_0 = - SecurityStructureOfFactorSources::new(DisplayName::sample(), matrix_0); + let shield_0 = SecurityStructureOfFactorSources::new( + DisplayName::sample(), + matrix_0, + FactorSource::sample_device(), + ); let all_accounts = os .profile() @@ -637,8 +640,11 @@ async fn test_assert_factor_instances_invalid() { number_of_days_until_auto_confirm: 1, }; - let shield_0 = - SecurityStructureOfFactorSources::new(DisplayName::sample(), matrix_0); + let shield_0 = SecurityStructureOfFactorSources::new( + DisplayName::sample(), + matrix_0, + FactorSource::sample_device(), + ); let (security_structure_of_fis, _, _) = os.make_security_structure_of_factor_instances_for_entities_without_consuming_cache_with_derivation_outcome(IndexSet::from_iter([AddressOfAccountOrPersona::from(alice.address())]), shield_0.clone()).await.unwrap(); let security_structure_of_fi = @@ -975,8 +981,11 @@ async fn test_securified_accounts() { number_of_days_until_auto_confirm: 1, }; - let shield_0 = - SecurityStructureOfFactorSources::new(DisplayName::sample(), matrix_0); + let shield_0 = SecurityStructureOfFactorSources::new( + DisplayName::sample(), + matrix_0, + FactorSource::sample_device(), + ); let (security_structures_of_fis, instances_in_cache_consumer, derivation_outcome) = os .make_security_structure_of_factor_instances_for_entities_without_consuming_cache_with_derivation_outcome( @@ -1113,8 +1122,11 @@ async fn test_securified_accounts() { number_of_days_until_auto_confirm: 1, }; - let shield_1 = - SecurityStructureOfFactorSources::new(DisplayName::sample(), matrix_1); + let shield_1 = SecurityStructureOfFactorSources::new( + DisplayName::sample(), + matrix_1, + FactorSource::sample_device(), + ); let (security_structures_of_fis, instances_in_cache_consumer, _) = os .make_security_structure_of_factor_instances_for_entities_without_consuming_cache_with_derivation_outcome( @@ -1252,8 +1264,11 @@ async fn securify_accounts_when_cache_is_half_full_single_factor_source() { number_of_days_until_auto_confirm: 1, }; - let shield_0 = - SecurityStructureOfFactorSources::new(DisplayName::sample(), matrix_0); + let shield_0 = SecurityStructureOfFactorSources::new( + DisplayName::sample(), + matrix_0, + FactorSource::sample_device(), + ); let profile = os.profile().unwrap(); let all_accounts = profile .accounts_on_all_networks_including_hidden() @@ -1401,8 +1416,11 @@ async fn securify_accounts_when_cache_is_half_full_multiple_factor_sources() { number_of_days_until_auto_confirm: 1, }; - let shield_0 = - SecurityStructureOfFactorSources::new(DisplayName::sample(), matrix_0); + let shield_0 = SecurityStructureOfFactorSources::new( + DisplayName::sample(), + matrix_0, + FactorSource::sample_device(), + ); let all_accounts = os .profile() .unwrap() @@ -1640,8 +1658,11 @@ async fn securify_personas_when_cache_is_half_full_single_factor_source() { number_of_days_until_auto_confirm: 1, }; - let shield_0 = - SecurityStructureOfFactorSources::new(DisplayName::sample(), matrix_0); + let shield_0 = SecurityStructureOfFactorSources::new( + DisplayName::sample(), + matrix_0, + FactorSource::sample_device(), + ); let all_personas = os .profile() .unwrap() @@ -1775,8 +1796,11 @@ async fn create_single_account() { number_of_days_until_auto_confirm: 1, }; - let shield_0 = - SecurityStructureOfFactorSources::new(DisplayName::sample(), matrix_0); + let shield_0 = SecurityStructureOfFactorSources::new( + DisplayName::sample(), + matrix_0, + FactorSource::sample_device(), + ); let (security_structures_of_fis, instances_in_cache_consumer, derivation_outcome) = os .make_security_structure_of_factor_instances_for_entities_without_consuming_cache_with_derivation_outcome( @@ -1866,8 +1890,11 @@ async fn securified_personas() { number_of_days_until_auto_confirm: 1, }; - let shield_0 = - SecurityStructureOfFactorSources::new(DisplayName::sample(), matrix_0); + let shield_0 = SecurityStructureOfFactorSources::new( + DisplayName::sample(), + matrix_0, + FactorSource::sample_device(), + ); let (security_structures_of_fis, instances_in_cache_consumer, derivation_outcome) = os .make_security_structure_of_factor_instances_for_entities_without_consuming_cache_with_derivation_outcome( @@ -2007,8 +2034,11 @@ async fn securified_personas() { number_of_days_until_auto_confirm: 1, }; - let shield_1 = - SecurityStructureOfFactorSources::new(DisplayName::sample(), matrix_1); + let shield_1 = SecurityStructureOfFactorSources::new( + DisplayName::sample(), + matrix_1, + FactorSource::sample_device(), + ); let (security_structures_of_fis, instances_in_cache_consumer, derivation_outcome) = os .make_security_structure_of_factor_instances_for_entities_without_consuming_cache_with_derivation_outcome( @@ -2174,8 +2204,11 @@ async fn securified_all_accounts_next_veci_does_not_start_at_zero() { number_of_days_until_auto_confirm: 1, }; - let shield_0 = - SecurityStructureOfFactorSources::new(DisplayName::sample(), matrix_0); + let shield_0 = SecurityStructureOfFactorSources::new( + DisplayName::sample(), + matrix_0, + FactorSource::sample_device(), + ); let (_, derivation_outcome) = os .__OFFLINE_ONLY_securify_accounts( unnamed_accounts @@ -2375,8 +2408,11 @@ async fn securified_accounts_asymmetric_indices() { number_of_days_until_auto_confirm: 1, }; - let shield_0 = - SecurityStructureOfFactorSources::new(DisplayName::sample(), matrix_0); + let shield_0 = SecurityStructureOfFactorSources::new( + DisplayName::sample(), + matrix_0, + FactorSource::sample_device(), + ); let (_, derivation_outcome) = os .__OFFLINE_ONLY_securify_accounts( unnamed_accounts @@ -2488,8 +2524,11 @@ async fn securified_accounts_asymmetric_indices() { number_of_days_until_auto_confirm: 1, }; - let shield_1 = - SecurityStructureOfFactorSources::new(DisplayName::sample(), matrix_1); + let shield_1 = SecurityStructureOfFactorSources::new( + DisplayName::sample(), + matrix_1, + FactorSource::sample_device(), + ); let (securified_alice, derivation_outcome) = os .__OFFLINE_ONLY_securify_account(alice.address(), &shield_1) @@ -2553,8 +2592,11 @@ async fn securified_accounts_asymmetric_indices() { number_of_days_until_auto_confirm: 1, }; - let shield_2 = - SecurityStructureOfFactorSources::new(DisplayName::sample(), matrix_2); + let shield_2 = SecurityStructureOfFactorSources::new( + DisplayName::sample(), + matrix_2, + FactorSource::sample_device(), + ); let (securified_bob, derivation_outcome) = os .__OFFLINE_ONLY_securify_account(bob.address(), &shield_2) @@ -2663,6 +2705,7 @@ async fn securified_accounts_asymmetric_indices() { let shield_3fa = SecurityStructureOfFactorSources::new( DisplayName::sample(), matrix_3fa, + FactorSource::sample_device(), ); let (securified_diana, derivation_outcome) = os diff --git a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/securify_entity_factor_instances_provider.rs b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/securify_entity_factor_instances_provider.rs index fd9c0300e..f0972db48 100644 --- a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/securify_entity_factor_instances_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/securify_entity_factor_instances_provider.rs @@ -18,7 +18,7 @@ impl SecurifyEntityFactorInstancesProvider { pub async fn for_account_mfa( cache_client: Arc, profile: Arc, - matrix_of_factor_sources: MatrixOfFactorSources, + security_structure_of_factor_sources: SecurityStructureOfFactorSources, account_addresses: IndexSet, interactor: Arc, ) -> Result<(InstancesInCacheConsumer, FactorInstancesProviderOutcome)> @@ -26,7 +26,7 @@ impl SecurifyEntityFactorInstancesProvider { Self::for_entity_mfa( cache_client, profile, - matrix_of_factor_sources, + security_structure_of_factor_sources, account_addresses.into_iter().map(Into::into).collect(), interactor, ) @@ -47,7 +47,7 @@ impl SecurifyEntityFactorInstancesProvider { pub async fn for_persona_mfa( cache_client: Arc, profile: Arc, - matrix_of_factor_sources: MatrixOfFactorSources, + security_structure_of_factor_sources: SecurityStructureOfFactorSources, persona_addresses: IndexSet, interactor: Arc, ) -> Result<(InstancesInCacheConsumer, FactorInstancesProviderOutcome)> @@ -55,7 +55,7 @@ impl SecurifyEntityFactorInstancesProvider { Self::for_entity_mfa( cache_client, profile, - matrix_of_factor_sources, + security_structure_of_factor_sources, persona_addresses.into_iter().map(Into::into).collect(), interactor, ) @@ -76,12 +76,12 @@ impl SecurifyEntityFactorInstancesProvider { pub async fn for_entity_mfa( cache_client: Arc, profile: Arc, - matrix_of_factor_sources: MatrixOfFactorSources, + security_structure_of_factor_sources: SecurityStructureOfFactorSources, addresses_of_entities: IndexSet, interactor: Arc, ) -> Result<(InstancesInCacheConsumer, FactorInstancesProviderOutcome)> { - let factor_sources_to_use = matrix_of_factor_sources + let factor_sources_to_use = security_structure_of_factor_sources .all_factors() .into_iter() .map(|x| x.to_owned()) @@ -138,14 +138,7 @@ impl SecurifyEntityFactorInstancesProvider { assert!(quantified_derivation_presets.len() >= 2); // at least one entity kind, and ROLA + TX: at least 2 let (instances_in_cache_consumer, outcome) = provider - .provide_for_presets( - // QuantifiedDerivationPreset::new( - // DerivationPreset::mfa_entity_kind(entity_kind), - // addresses_of_entities.len(), - // ), - quantified_derivation_presets, - purpose, - ) + .provide_for_presets(quantified_derivation_presets, purpose) .await?; Ok((instances_in_cache_consumer, outcome.into())) @@ -170,7 +163,7 @@ mod tests { let _ = SUT::for_account_mfa( Arc::new(cache_client), Arc::new(Profile::sample_from([fs.clone()], [&a], [])), - MatrixOfFactorSources::sample(), + SecurityStructureOfFactorSources::sample(), IndexSet::::new(), // <---- EMPTY => should_panic Arc::new(TestDerivationInteractor::default()), ) @@ -187,7 +180,7 @@ mod tests { let _ = SUT::for_account_mfa( Arc::new(cache_client), Arc::new(Profile::sample_from([fs.clone()], [&a], [])), - MatrixOfFactorSources::sample(), + SecurityStructureOfFactorSources::sample(), IndexSet::just(Account::sample_other().address()), // <---- unknown => should_panic Arc::new(TestDerivationInteractor::default()), ) @@ -220,7 +213,7 @@ mod tests { let _ = SUT::for_account_mfa( Arc::new(cache_client), Arc::new(profile), - MatrixOfFactorSources::sample(), + SecurityStructureOfFactorSources::sample(), IndexSet::from_iter([mainnet_account.address()]), Arc::new(TestDerivationInteractor::default()), ) @@ -266,7 +259,7 @@ mod tests { let _ = SUT::for_account_mfa( Arc::new(cache_client), Arc::new(profile), - MatrixOfFactorSources::sample(), + SecurityStructureOfFactorSources::sample(), IndexSet::from_iter([ mainnet_account.address(), stokenet_account.address(), @@ -315,6 +308,12 @@ mod tests { let matrix_0 = MatrixOfFactorSources::new(matrix_ids, factor_sources).unwrap(); + let shield_0 = SecurityStructureOfFactorSources::new( + DisplayName::sample(), + matrix_0, + FactorSource::sample_device(), + ); + let cache_client = Arc::new(os.clients.factor_instances_cache.clone()); let profile = Arc::new(os.profile().unwrap()); let derivation_interactors = os.keys_derivation_interactor(); @@ -322,7 +321,7 @@ mod tests { let (instances_in_cache_consumer, outcome) = SUT::for_entity_mfa( cache_client.clone(), profile, - matrix_0.clone(), + shield_0.clone(), IndexSet::from_iter([ AddressOfAccountOrPersona::from(alice.address()), AddressOfAccountOrPersona::from(batman.address()), @@ -336,6 +335,7 @@ mod tests { // don't forget to consume instances_in_cache_consumer.consume().await.unwrap(); + let account_outcome = outcome .get_derivation_preset_for_factor( DerivationPreset::AccountMfa, @@ -344,20 +344,6 @@ mod tests { .unwrap(); assert_eq!(account_outcome.to_use_directly.len(), 1); - // let profile = Arc::new(os.profile().unwrap()); - // let (instances_in_cache_consumer, outcome) = SUT::for_persona_mfa( - // cache_client.clone(), - // profile, - // matrix_0.clone(), - // IndexSet::just(batman.address()), - // derivation_interactors.clone(), - // ) - // .await - // .unwrap(); - - // // don't forget to consume - // instances_in_cache_consumer.consume().await.unwrap(); - // // let outcome = outcome.per_factor.get(&bdfs.id_from_hash()).unwrap(); let persona_outcome = outcome .get_derivation_preset_for_factor( DerivationPreset::AccountMfa, diff --git a/crates/sargon/src/profile/mfa/security_structures/automatic_shield_builder/automatic_shield_builder.rs b/crates/sargon/src/profile/mfa/security_structures/automatic_shield_builder/automatic_shield_builder.rs index 76eb2a063..b3b727b50 100644 --- a/crates/sargon/src/profile/mfa/security_structures/automatic_shield_builder/automatic_shield_builder.rs +++ b/crates/sargon/src/profile/mfa/security_structures/automatic_shield_builder/automatic_shield_builder.rs @@ -1,7 +1,7 @@ use crate::prelude::*; use super::{ - proto_matrix::ProtoMatrix, quantity::Quantity, + proto_shield::ProtoShield, quantity::Quantity, CallsToAssignUnsupportedFactor, }; @@ -32,7 +32,7 @@ pub(crate) struct AutomaticShieldBuilder { /// The factors assigned to each role, including the factors originally /// set for the primary role. - proto_matrix: ProtoMatrix, + proto_shield: ProtoShield, } impl SecurityShieldBuilder { @@ -111,14 +111,14 @@ impl SecurityShieldBuilder { primary_factors, ); - let proto_matrix = auto_builder.assign()?; + let proto_shield = auto_builder.assign()?; assert_eq!( - proto_matrix.primary.clone().into_iter().collect_vec(), + proto_shield.primary.clone().into_iter().collect_vec(), self.get_primary_threshold_factors(), "Auto assignment should not have changed the primary factors" ); - self.set_state(proto_matrix); + self.set_state(proto_shield); if let Some(invalid_reason) = self.validate() { Err(CommonError::AutomaticShieldBuildingFailure { @@ -129,17 +129,22 @@ impl SecurityShieldBuilder { } } - /// Updates the Primary, Recovery and Confirmation roles with the factors of the given `ProtoMatrix`. - fn set_state(&self, proto_matrix: ProtoMatrix) { + /// Updates the Authentication Signing Factor, + /// Primary (should remain unchanged since these factor should have been set at start of auto assign), + /// Recovery and Confirmation roles with the factors of the given `ProtoShield`. + fn set_state(&self, proto_shield: ProtoShield) { self.reset_factors_in_roles(); - self.set_threshold(proto_matrix.primary.len() as u8); - proto_matrix.primary.into_iter().for_each(|f| { + self.set_authentication_signing_factor(Some( + proto_shield.authentication_signing_factor, + )); + self.set_threshold(proto_shield.primary.len() as u8); + proto_shield.primary.into_iter().for_each(|f| { self.add_factor_source_to_primary_threshold(f); }); - proto_matrix.recovery.into_iter().for_each(|f| { + proto_shield.recovery.into_iter().for_each(|f| { self.add_factor_source_to_recovery_override(f); }); - proto_matrix.confirmation.into_iter().for_each(|f| { + proto_shield.confirmation.into_iter().for_each(|f| { self.add_factor_source_to_confirmation_override(f); }); } @@ -153,10 +158,24 @@ impl AutomaticShieldBuilder { Self { stats_for_testing: AutoBuildOutcomeForTesting::default(), remaining_available_factors: available_factors, - proto_matrix: ProtoMatrix::new(primary), + proto_shield: ProtoShield::new(primary), } } + fn remaining_factors_matching_selector( + &self, + selector: FactorSelector, + ) -> IndexSet { + self.remaining_available_factors + .iter() + .filter(|&f| match selector { + FactorSelector::Category(category) => f.category() == category, + FactorSelector::Kind(kind) => f.factor_source_kind() == kind, + }) + .map(|f| f.id()) + .collect::>() + } + /// Returns `Some(n)` if any factor matching the selector was found where `n` /// is `<= quantity_to_add` and `None` if no factors matching the selector was. /// found. Guaranteed to never return `Some(0)`. @@ -168,15 +187,8 @@ impl AutomaticShieldBuilder { ) -> Option { let target_role = to; - let mut factors_to_add = self - .remaining_available_factors - .iter() - .filter(|&f| match selector { - FactorSelector::Category(category) => f.category() == category, - FactorSelector::Kind(kind) => f.factor_source_kind() == kind, - }) - .map(|f| f.id()) - .collect::>(); + let mut factors_to_add = + self.remaining_factors_matching_selector(selector); if let Some(quantity) = quantity_to_add.as_fixed() { factors_to_add = factors_to_add @@ -193,14 +205,14 @@ impl AutomaticShieldBuilder { self.remaining_available_factors .retain(|f| !factors_to_add.contains(&f.id())); - self.proto_matrix + self.proto_shield .add_factors_for_role(target_role, factors_to_add); Some(number_of_factors_added) } fn factors_for_role(&self, role: RoleKind) -> &IndexSet { - self.proto_matrix.factors_for_role(role) + self.proto_shield.factors_for_role(role) } /// Returns `true` if any factor was assigned, `false` otherwise. @@ -332,12 +344,22 @@ impl AutomaticShieldBuilder { /// Automatic assignment of factors to roles according to [this heuristics][doc]. /// /// [doc]: https://radixdlt.atlassian.net/wiki/spaces/AT/pages/3758063620/MFA+Rules+for+Factors+and+Security+Shields#Automatic-Security-Shield-Construction - fn assign(&mut self) -> Result { + fn assign(&mut self) -> Result { + if let Some(authentication_signing_factor) = self + .remaining_factors_matching_selector(FactorSelector::Kind( + FactorSourceKind::Device, + )) + .first() + { + self.proto_shield.authentication_signing_factor = + *authentication_signing_factor + } + // 📒 "If the user only chose 1 factor for PRIMARY, remove that factor from the list (it cannot be used elsewhere - otherwise it can)." { if self.count_factors_for_role(Primary) == 1 && let Some(only_primary_factor) = - self.proto_matrix.primary.iter().next() + self.proto_shield.primary.iter().next() { self.remaining_available_factors .retain(|f| f.id() != *only_primary_factor); @@ -390,7 +412,7 @@ impl AutomaticShieldBuilder { } } - Ok(self.proto_matrix.clone()) + Ok(self.proto_shield.clone()) } } diff --git a/crates/sargon/src/profile/mfa/security_structures/automatic_shield_builder/mod.rs b/crates/sargon/src/profile/mfa/security_structures/automatic_shield_builder/mod.rs index f50fd048e..e8cfebb4d 100644 --- a/crates/sargon/src/profile/mfa/security_structures/automatic_shield_builder/mod.rs +++ b/crates/sargon/src/profile/mfa/security_structures/automatic_shield_builder/mod.rs @@ -2,7 +2,7 @@ mod auto_build_outcome_for_testing; #[allow(clippy::module_inception)] mod automatic_shield_builder; mod factor_selector; -mod proto_matrix; +mod proto_shield; mod quantity; pub use auto_build_outcome_for_testing::*; diff --git a/crates/sargon/src/profile/mfa/security_structures/automatic_shield_builder/proto_matrix.rs b/crates/sargon/src/profile/mfa/security_structures/automatic_shield_builder/proto_shield.rs similarity index 81% rename from crates/sargon/src/profile/mfa/security_structures/automatic_shield_builder/proto_matrix.rs rename to crates/sargon/src/profile/mfa/security_structures/automatic_shield_builder/proto_shield.rs index 56dde7835..9563cf2c5 100644 --- a/crates/sargon/src/profile/mfa/security_structures/automatic_shield_builder/proto_matrix.rs +++ b/crates/sargon/src/profile/mfa/security_structures/automatic_shield_builder/proto_shield.rs @@ -5,15 +5,19 @@ use RoleKind::*; /// A tiny holder of factors for each Role. /// Used by the AutomaticShieldBuilder to keep track of which factors are assigned to which role. #[derive(Clone, Debug, PartialEq, Eq)] -pub(super) struct ProtoMatrix { +pub(super) struct ProtoShield { + pub(super) authentication_signing_factor: FactorSourceID, pub(super) primary: IndexSet, pub(super) recovery: IndexSet, pub(super) confirmation: IndexSet, } -impl ProtoMatrix { +impl ProtoShield { pub(super) fn new(primary: IndexSet) -> Self { + assert!(!primary.is_empty()); + let authentication_signing_factor = primary.first().cloned().unwrap(); Self { + authentication_signing_factor, primary, recovery: IndexSet::new(), confirmation: IndexSet::new(), diff --git a/crates/sargon/src/profile/mfa/security_structures/security_shield_builder.rs b/crates/sargon/src/profile/mfa/security_structures/security_shield_builder.rs index 261682243..608149dc0 100644 --- a/crates/sargon/src/profile/mfa/security_structures/security_shield_builder.rs +++ b/crates/sargon/src/profile/mfa/security_structures/security_shield_builder.rs @@ -3,6 +3,7 @@ use crate::prelude::*; #[derive(Debug)] pub struct SecurityShieldBuilder { matrix_builder: RwLock, + authentication_signing_factor: RwLock>, name: RwLock, // We eagerly set this, and we use it inside the `build` method, ensuring // that for the same *state* of `MatrixBuilder` we always have the same shield! @@ -25,6 +26,7 @@ impl SecurityShieldBuilder { Self { matrix_builder: RwLock::new(matrix_builder), name, + authentication_signing_factor: RwLock::new(None), shield_id: SecurityStructureID::from(id()), created_on: now(), } @@ -88,6 +90,10 @@ impl SecurityShieldBuilder { self.name.read().unwrap().clone() } + pub fn get_authentication_signing_factor(&self) -> Option { + *self.authentication_signing_factor.read().unwrap() + } + pub fn get_primary_threshold_factors(&self) -> Vec { self.get_factors(|builder| builder.get_primary_threshold_factors()) } @@ -114,6 +120,14 @@ impl SecurityShieldBuilder { self } + pub fn set_authentication_signing_factor( + &self, + new: Option, + ) -> &Self { + *self.authentication_signing_factor.write().unwrap() = new; + self + } + /// Adds the factor source to the primary role threshold list. /// /// Also sets the threshold to 1 this is the first factor set and if @@ -503,6 +517,10 @@ impl SecurityShieldBuilder { SecurityStructureOfFactorSourceIds, SecurityShieldBuilderInvalidReason, > { + let authentication_signing_factor = + self.get_authentication_signing_factor().ok_or( + SecurityShieldBuilderInvalidReason::MissingAuthSigningFactor, + )?; let matrix_result = self.get(|builder| builder.build()); if let Some(validation_error) = matrix_result.as_shield_validation() { @@ -530,6 +548,7 @@ impl SecurityShieldBuilder { let shield = SecurityStructureOfFactorSourceIds { matrix_of_factors, metadata, + authentication_signing_factor, }; Ok(shield) } diff --git a/crates/sargon/src/profile/mfa/security_structures/security_shield_builder_invalid_reason.rs b/crates/sargon/src/profile/mfa/security_structures/security_shield_builder_invalid_reason.rs index 728f3ae0a..7d3982517 100644 --- a/crates/sargon/src/profile/mfa/security_structures/security_shield_builder_invalid_reason.rs +++ b/crates/sargon/src/profile/mfa/security_structures/security_shield_builder_invalid_reason.rs @@ -179,6 +179,9 @@ impl AsShieldBuilderViolation for (RoleKind, NotYetValidReason) { #[repr(u32)] #[derive(Clone, Debug, thiserror::Error, PartialEq)] pub enum SecurityShieldBuilderInvalidReason { + #[error("Auth Signing Factor Missing")] + MissingAuthSigningFactor, + #[error("Shield name is invalid")] ShieldNameInvalid, diff --git a/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/abstract_security_structure_of_factors.rs b/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/abstract_security_structure_of_factors.rs index 9ba771767..5e4ff10fb 100644 --- a/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/abstract_security_structure_of_factors.rs +++ b/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/abstract_security_structure_of_factors.rs @@ -10,6 +10,9 @@ pub struct AbstractSecurityStructure { /// The structure of factors to use for certain roles, Primary, Recovery /// and Confirmation role. pub matrix_of_factors: AbstractMatrixBuilt, + + /// The factor to use for authentication signing aka true Rola Key. + pub authentication_signing_factor: FACTOR, } impl Identifiable for AbstractSecurityStructure { @@ -22,7 +25,9 @@ impl Identifiable for AbstractSecurityStructure { impl AbstractSecurityStructure { pub fn all_factors(&self) -> HashSet<&FACTOR> { - self.matrix_of_factors.all_factors() + let mut all = self.matrix_of_factors.all_factors(); + all.extend([&self.authentication_signing_factor]); + all } } @@ -30,18 +35,25 @@ impl AbstractSecurityStructure { pub fn with_metadata( metadata: SecurityStructureMetadata, matrix_of_factors: AbstractMatrixBuilt, + authentication_signing_factor: FACTOR, ) -> Self { Self { metadata, matrix_of_factors, + authentication_signing_factor, } } pub fn new( display_name: DisplayName, matrix_of_factors: AbstractMatrixBuilt, + authentication_signing_factor: FACTOR, ) -> Self { let metadata = SecurityStructureMetadata::new(display_name); - Self::with_metadata(metadata, matrix_of_factors) + Self::with_metadata( + metadata, + matrix_of_factors, + authentication_signing_factor, + ) } } diff --git a/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_source_ids.rs b/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_source_ids.rs index ec9cd65eb..8effe11a6 100644 --- a/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_source_ids.rs +++ b/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_source_ids.rs @@ -9,12 +9,20 @@ pub type SecurityStructureOfFactorSourceIDs = impl HasSampleValues for SecurityStructureOfFactorSourceIds { fn sample() -> Self { let metadata = SecurityStructureMetadata::sample(); - Self::with_metadata(metadata, MatrixOfFactorSourceIds::sample()) + Self::with_metadata( + metadata, + MatrixOfFactorSourceIds::sample(), + FactorSourceID::sample_device(), + ) } fn sample_other() -> Self { let metadata = SecurityStructureMetadata::sample_other(); - Self::with_metadata(metadata, MatrixOfFactorSourceIds::sample_other()) + Self::with_metadata( + metadata, + MatrixOfFactorSourceIds::sample_other(), + FactorSourceID::sample_ledger(), + ) } } @@ -41,7 +49,7 @@ mod tests { assert_eq_after_json_roundtrip( &sut, r#" - { + { "metadata": { "id": "ffffffff-ffff-ffff-ffff-ffffffffffff", "displayName": "Spending Account", diff --git a/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_sources.rs b/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_sources.rs index c9b3f75e1..bece239af 100644 --- a/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_sources.rs +++ b/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_sources.rs @@ -6,12 +6,20 @@ pub type SecurityStructureOfFactorSources = impl HasSampleValues for SecurityStructureOfFactorSources { fn sample() -> Self { let metadata = SecurityStructureMetadata::sample(); - Self::with_metadata(metadata, MatrixOfFactorSources::sample()) + Self::with_metadata( + metadata, + MatrixOfFactorSources::sample(), + FactorSource::sample_device(), + ) } fn sample_other() -> Self { let metadata = SecurityStructureMetadata::sample_other(); - Self::with_metadata(metadata, MatrixOfFactorSources::sample_other()) + Self::with_metadata( + metadata, + MatrixOfFactorSources::sample_other(), + FactorSource::sample_ledger(), + ) } } @@ -36,6 +44,10 @@ impl TryFrom<(&SecurityStructureOfFactorSourceIDs, &FactorSources)> value: (&SecurityStructureOfFactorSourceIDs, &FactorSources), ) -> Result { let (id_level, factor_sources) = value; + let authentication_signing_factor = factor_sources + .get_id(id_level.authentication_signing_factor) + .cloned() + .ok_or(CommonError::FactorSourceDiscrepancy)?; let matrix_of_factors = MatrixOfFactorSources::try_from(( &id_level.matrix_of_factors, factor_sources, @@ -43,6 +55,7 @@ impl TryFrom<(&SecurityStructureOfFactorSourceIDs, &FactorSources)> Ok(Self { metadata: id_level.metadata.clone(), matrix_of_factors, + authentication_signing_factor, }) } } @@ -54,6 +67,9 @@ impl From Self { metadata: value.metadata, matrix_of_factors: value.matrix_of_factors.into(), + authentication_signing_factor: value + .authentication_signing_factor + .factor_source_id(), } } } diff --git a/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs b/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs index b5b45aa10..74111ed95 100644 --- a/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs +++ b/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs @@ -816,9 +816,7 @@ impl SargonOS { SecurifyEntityFactorInstancesProvider::for_entity_mfa( Arc::new(self.clients.factor_instances_cache.clone()), Arc::new(profile_snapshot.clone()), - security_structure_of_factor_sources - .clone() - .matrix_of_factors, + security_structure_of_factor_sources.clone(), addresses_of_entities.clone(), key_derivation_interactors, ) From 1ff2f544d50aade7ca36f224823e71c2a9bee7c4 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Thu, 19 Dec 2024 12:20:52 +0100 Subject: [PATCH 48/60] fix failing tests (the hard ones - JSON remain... easy) --- .../src/core/error/common_error.rs | 3 + crates/sargon/src/core/error/common_error.rs | 3 + .../agnostic_paths/derivation_preset.rs | 22 ++++++ .../quantified_derivation_preset.rs | 20 ++++- .../factor_instances_provider_unit_tests.rs | 33 ++++---- ...curify_entity_factor_instances_provider.rs | 35 +++++++- .../types/factor_instances.rs | 22 +++++- .../matrices/matrix_of_factor_instances.rs | 59 +++++++++++++- .../role_with_factor_instances.rs | 7 +- .../security_shield_builder.rs | 2 + .../system/sargon_os/sargon_os_accounts.rs | 79 +++++++++++-------- 11 files changed, 226 insertions(+), 59 deletions(-) diff --git a/crates/sargon-uniffi/src/core/error/common_error.rs b/crates/sargon-uniffi/src/core/error/common_error.rs index 77ee8a4b8..07539f136 100644 --- a/crates/sargon-uniffi/src/core/error/common_error.rs +++ b/crates/sargon-uniffi/src/core/error/common_error.rs @@ -865,6 +865,9 @@ pub enum CommonError { #[error("Too few FactorInstances derived")] TooFewFactorInstancesDerived = 10242, + + #[error("Missing Authentication Signing FactorInstance mapping SecurityStructureOfFactorSources into SecurityStructureOfFactorInstances.")] + MissingRolaKeyForSecurityStructureOfFactorInstances = 10243, } #[uniffi::export] diff --git a/crates/sargon/src/core/error/common_error.rs b/crates/sargon/src/core/error/common_error.rs index ad7dfbae2..fc799aae7 100644 --- a/crates/sargon/src/core/error/common_error.rs +++ b/crates/sargon/src/core/error/common_error.rs @@ -862,6 +862,9 @@ pub enum CommonError { #[error("Too few FactorInstances derived")] TooFewFactorInstancesDerived = 10242, + + #[error("Missing Authentication Signing FactorInstance mapping SecurityStructureOfFactorSources into SecurityStructureOfFactorInstances.")] + MissingRolaKeyForSecurityStructureOfFactorInstances = 10243, } impl CommonError { diff --git a/crates/sargon/src/factor_instances_provider/agnostic_paths/derivation_preset.rs b/crates/sargon/src/factor_instances_provider/agnostic_paths/derivation_preset.rs index 9e00648cc..5d35861bd 100644 --- a/crates/sargon/src/factor_instances_provider/agnostic_paths/derivation_preset.rs +++ b/crates/sargon/src/factor_instances_provider/agnostic_paths/derivation_preset.rs @@ -75,6 +75,16 @@ impl DerivationPreset { CAP26EntityKind::Identity => Self::IdentityMfa, } } + + + /// Selects a `DerivationPreset` for MFA based on `CAP26EntityKind`, + /// i.e. either `DerivationPreset::AccountRola` or `DerivationPreset::IdentityRola`. + pub fn rola_entity_kind(entity_kind: CAP26EntityKind) -> Self { + match entity_kind { + CAP26EntityKind::Account => Self::AccountRola, + CAP26EntityKind::Identity => Self::IdentityRola, + } + } } // ============= @@ -158,4 +168,16 @@ mod tests { fn inequality() { assert_ne!(SUT::sample(), SUT::sample_other()); } + + #[test] + fn test_mfa_entity_kind() { + assert_eq!(SUT::mfa_entity_kind(CAP26EntityKind::Account), SUT::AccountMfa); + assert_eq!(SUT::mfa_entity_kind(CAP26EntityKind::Identity), SUT::IdentityMfa); + } + + #[test] + fn test_rola_entity_kind() { + assert_eq!(SUT::rola_entity_kind(CAP26EntityKind::Account), SUT::AccountRola); + assert_eq!(SUT::rola_entity_kind(CAP26EntityKind::Identity), SUT::IdentityRola); + } } diff --git a/crates/sargon/src/factor_instances_provider/agnostic_paths/quantified_derivation_preset.rs b/crates/sargon/src/factor_instances_provider/agnostic_paths/quantified_derivation_preset.rs index c66437774..03b19015c 100644 --- a/crates/sargon/src/factor_instances_provider/agnostic_paths/quantified_derivation_preset.rs +++ b/crates/sargon/src/factor_instances_provider/agnostic_paths/quantified_derivation_preset.rs @@ -41,26 +41,38 @@ impl QuantifiedDerivationPreset { DerivationPreset::IdentityMfa, identity_addresses.len(), ), - Self::new(DerivationPreset::IdentityRola, 1), + Self::new( + DerivationPreset::IdentityRola, + identity_addresses.len(), + ), ]), (false, false) => IdentifiedVecOf::from_iter([ Self::new( DerivationPreset::AccountMfa, account_addresses.len(), ), - Self::new(DerivationPreset::AccountRola, 1), + Self::new( + DerivationPreset::AccountRola, + account_addresses.len(), + ), Self::new( DerivationPreset::IdentityMfa, identity_addresses.len(), ), - Self::new(DerivationPreset::IdentityRola, 1), + Self::new( + DerivationPreset::IdentityRola, + identity_addresses.len(), + ), ]), (false, true) => IdentifiedVecOf::from_iter([ Self::new( DerivationPreset::AccountMfa, account_addresses.len(), ), - Self::new(DerivationPreset::AccountRola, 1), + Self::new( + DerivationPreset::AccountRola, + account_addresses.len(), + ), ]), } } diff --git a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider_unit_tests.rs b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider_unit_tests.rs index 7246ca41c..c8c5d8c57 100644 --- a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider_unit_tests.rs +++ b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider_unit_tests.rs @@ -486,7 +486,7 @@ async fn cache_is_unchanged_in_case_of_failure() { let shield_0 = SecurityStructureOfFactorSources::new( DisplayName::sample(), matrix_0, - FactorSource::sample_device(), + bdfs.clone(), ); let all_accounts = os @@ -643,7 +643,7 @@ async fn test_assert_factor_instances_invalid() { let shield_0 = SecurityStructureOfFactorSources::new( DisplayName::sample(), matrix_0, - FactorSource::sample_device(), + bdfs.clone(), ); let (security_structure_of_fis, _, _) = os.make_security_structure_of_factor_instances_for_entities_without_consuming_cache_with_derivation_outcome(IndexSet::from_iter([AddressOfAccountOrPersona::from(alice.address())]), shield_0.clone()).await.unwrap(); @@ -984,7 +984,7 @@ async fn test_securified_accounts() { let shield_0 = SecurityStructureOfFactorSources::new( DisplayName::sample(), matrix_0, - FactorSource::sample_device(), + bdfs.clone(), ); let (security_structures_of_fis, instances_in_cache_consumer, derivation_outcome) = os @@ -1125,7 +1125,7 @@ async fn test_securified_accounts() { let shield_1 = SecurityStructureOfFactorSources::new( DisplayName::sample(), matrix_1, - FactorSource::sample_device(), + bdfs.clone(), ); let (security_structures_of_fis, instances_in_cache_consumer, _) = os @@ -1267,7 +1267,7 @@ async fn securify_accounts_when_cache_is_half_full_single_factor_source() { let shield_0 = SecurityStructureOfFactorSources::new( DisplayName::sample(), matrix_0, - FactorSource::sample_device(), + bdfs.clone(), ); let profile = os.profile().unwrap(); let all_accounts = profile @@ -1419,7 +1419,7 @@ async fn securify_accounts_when_cache_is_half_full_multiple_factor_sources() { let shield_0 = SecurityStructureOfFactorSources::new( DisplayName::sample(), matrix_0, - FactorSource::sample_device(), + bdfs.clone(), ); let all_accounts = os .profile() @@ -1661,7 +1661,7 @@ async fn securify_personas_when_cache_is_half_full_single_factor_source() { let shield_0 = SecurityStructureOfFactorSources::new( DisplayName::sample(), matrix_0, - FactorSource::sample_device(), + bdfs.clone(), ); let all_personas = os .profile() @@ -1799,9 +1799,9 @@ async fn create_single_account() { let shield_0 = SecurityStructureOfFactorSources::new( DisplayName::sample(), matrix_0, - FactorSource::sample_device(), + bdfs.clone(), ); - + println!("👨‍🔬 test calling `make_security_structure_of_factor_instances_for_entities_without_consuming_cache_with_derivation_outcome` for single account Alice"); let (security_structures_of_fis, instances_in_cache_consumer, derivation_outcome) = os .make_security_structure_of_factor_instances_for_entities_without_consuming_cache_with_derivation_outcome( IndexSet::just(AddressOfAccountOrPersona::from(alice.address())), @@ -1809,6 +1809,7 @@ async fn create_single_account() { ) .await .unwrap(); + println!("👨‍🔬 ✅ `make_security_structure_of_factor_instances_for_entities_without_consuming_cache_with_derivation_outcome` for single account Alice ✅"); // Don't forget to consume! instances_in_cache_consumer.consume().await.unwrap(); @@ -1893,7 +1894,7 @@ async fn securified_personas() { let shield_0 = SecurityStructureOfFactorSources::new( DisplayName::sample(), matrix_0, - FactorSource::sample_device(), + bdfs.clone(), ); let (security_structures_of_fis, instances_in_cache_consumer, derivation_outcome) = os @@ -2037,7 +2038,7 @@ async fn securified_personas() { let shield_1 = SecurityStructureOfFactorSources::new( DisplayName::sample(), matrix_1, - FactorSource::sample_device(), + bdfs.clone(), ); let (security_structures_of_fis, instances_in_cache_consumer, derivation_outcome) = os @@ -2207,7 +2208,7 @@ async fn securified_all_accounts_next_veci_does_not_start_at_zero() { let shield_0 = SecurityStructureOfFactorSources::new( DisplayName::sample(), matrix_0, - FactorSource::sample_device(), + bdfs.clone(), ); let (_, derivation_outcome) = os .__OFFLINE_ONLY_securify_accounts( @@ -2411,7 +2412,7 @@ async fn securified_accounts_asymmetric_indices() { let shield_0 = SecurityStructureOfFactorSources::new( DisplayName::sample(), matrix_0, - FactorSource::sample_device(), + bdfs.clone(), ); let (_, derivation_outcome) = os .__OFFLINE_ONLY_securify_accounts( @@ -2527,7 +2528,7 @@ async fn securified_accounts_asymmetric_indices() { let shield_1 = SecurityStructureOfFactorSources::new( DisplayName::sample(), matrix_1, - FactorSource::sample_device(), + bdfs.clone(), ); let (securified_alice, derivation_outcome) = os @@ -2595,7 +2596,7 @@ async fn securified_accounts_asymmetric_indices() { let shield_2 = SecurityStructureOfFactorSources::new( DisplayName::sample(), matrix_2, - FactorSource::sample_device(), + bdfs.clone(), ); let (securified_bob, derivation_outcome) = os @@ -2705,7 +2706,7 @@ async fn securified_accounts_asymmetric_indices() { let shield_3fa = SecurityStructureOfFactorSources::new( DisplayName::sample(), matrix_3fa, - FactorSource::sample_device(), + bdfs.clone(), ); let (securified_diana, derivation_outcome) = os diff --git a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/securify_entity_factor_instances_provider.rs b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/securify_entity_factor_instances_provider.rs index f0972db48..1cb550a40 100644 --- a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/securify_entity_factor_instances_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/securify_entity_factor_instances_provider.rs @@ -136,11 +136,44 @@ impl SecurifyEntityFactorInstancesProvider { &addresses_of_entities, ); + println!( + "🌮 FIP (Sec) quantified_derivation_presets: {:?}", + quantified_derivation_presets + ); + assert!(quantified_derivation_presets.len() >= 2); // at least one entity kind, and ROLA + TX: at least 2 let (instances_in_cache_consumer, outcome) = provider .provide_for_presets(quantified_derivation_presets, purpose) .await?; + if let Some(rola_accounts_outcome) = outcome + .get_for_derivation_preset_for_factor( + DerivationPreset::AccountRola, + security_structure_of_factor_sources + .authentication_signing_factor + .id_from_hash(), + ) + { + println!( + "🌮 FIP (Sec) rola_accounts_outcome: {:#?}", + rola_accounts_outcome + ); + } + + if let Some(rola_personas_outcome) = outcome + .get_for_derivation_preset_for_factor( + DerivationPreset::IdentityRola, + security_structure_of_factor_sources + .authentication_signing_factor + .id_from_hash(), + ) + { + println!( + "🌮 FIP (Sec) rola_personas_outcome: {:#?}", + rola_personas_outcome + ); + } + Ok((instances_in_cache_consumer, outcome.into())) } } @@ -311,7 +344,7 @@ mod tests { let shield_0 = SecurityStructureOfFactorSources::new( DisplayName::sample(), matrix_0, - FactorSource::sample_device(), + bdfs.clone(), ); let cache_client = Arc::new(os.clients.factor_instances_cache.clone()); diff --git a/crates/sargon/src/factor_instances_provider/types/factor_instances.rs b/crates/sargon/src/factor_instances_provider/types/factor_instances.rs index c5d89a8dd..17f90edc7 100644 --- a/crates/sargon/src/factor_instances_provider/types/factor_instances.rs +++ b/crates/sargon/src/factor_instances_provider/types/factor_instances.rs @@ -43,8 +43,26 @@ impl FactorInstances { self.shift_remove_index(idx) } - pub fn first(&self) -> Option { - self.factor_instances.first().cloned() + fn first_of_key_kind( + &self, + key_kind: CAP26KeyKind, + ) -> Option { + self.factor_instances + .iter() + .find(|i| i.get_key_kind() == key_kind) + .cloned() + } + + pub fn first_transaction_signing( + &self, + ) -> Option { + self.first_of_key_kind(CAP26KeyKind::TransactionSigning) + } + + pub fn first_authentication_signing( + &self, + ) -> Option { + self.first_of_key_kind(CAP26KeyKind::AuthenticationSigning) } pub fn split_at(self, mid: usize) -> (Self, Self) { diff --git a/crates/sargon/src/profile/mfa/security_structures/matrices/matrix_of_factor_instances.rs b/crates/sargon/src/profile/mfa/security_structures/matrices/matrix_of_factor_instances.rs index 7c1fde0a2..5054da3af 100644 --- a/crates/sargon/src/profile/mfa/security_structures/matrices/matrix_of_factor_instances.rs +++ b/crates/sargon/src/profile/mfa/security_structures/matrices/matrix_of_factor_instances.rs @@ -213,6 +213,63 @@ impl HasSampleValues for MatrixOfFactorInstances { } } +impl SecurityStructureOfFactorInstances { + pub fn fulfilling_structure_of_factor_sources_with_instances( + consuming_instances: &mut IndexMap< + FactorSourceIDFromHash, + FactorInstances, + >, + security_structure_of_factor_sources: &SecurityStructureOfFactorSources, + ) -> Result { + for (k, v) in consuming_instances.iter() { + println!("\n\n 👨‍🔬 SSFI: fulfilling_structure_of_factor_sources_with_instances` consuming_instances BEFORE fulfilling matrix:"); + println!( + "👨‍🔬 SSFI - BEFORE - key: {:?}, instances: #{:?}", + k, + v.len() + ); + println!("\n\n 🛡️ 🛡️ 🛡️ 🛡️ 🛡️\n") + } + + let matrix_of_factors = MatrixOfFactorInstances::fulfilling_matrix_of_factor_sources_with_instances( + consuming_instances, + security_structure_of_factor_sources.matrix_of_factors.clone(), + )?; + + for (k, v) in consuming_instances.iter() { + println!("\n\n 👨‍🔬 SSFI: fulfilling_structure_of_factor_sources_with_instances` consuming_instances AFTER fulfilling matrix:"); + println!( + "👨‍🔬 SSFI - AFTER - key: {:?}, instances: #{:?}", + k, + v.len() + ); + println!("\n\n 🛡️ 🛡️ 🛡️ 🛡️ 🛡️\n") + } + + let authentication_signing = if let Some(existing) = consuming_instances + .get_mut( + &security_structure_of_factor_sources + .authentication_signing_factor + .id_from_hash(), + ) { + let instance = existing.first_authentication_signing().ok_or( + CommonError::MissingRolaKeyForSecurityStructureOfFactorInstances, + ).inspect_err(|_| println!("👨‍🔬 SSFI ❌ first_authentication_signing failed => MissingRolaKeyForSecurityStructureOfFactorInstances ❌"))?; + let _ = existing.shift_remove(&instance); // don't forget to consume it! + Ok(instance) + } else { + println!("👨‍🔬 SSFI ❌ get_mut failed => MissingRolaKeyForSecurityStructureOfFactorInstances ❌"); + Err(CommonError::MissingRolaKeyForSecurityStructureOfFactorInstances) + }?; + + Self::new( + security_structure_of_factor_sources.id(), + matrix_of_factors, + authentication_signing, + ) + } +} + impl MatrixOfFactorInstances { /// Maps `MatrixOfFactorSources -> MatrixOfFactorInstances` by /// "assigning" FactorInstances to each MatrixOfFactorInstances from @@ -226,7 +283,7 @@ impl MatrixOfFactorInstances { /// However, the same FactorInstance is NEVER used in two different MatrixOfFactorInstances. /// /// - pub fn fulfilling_matrix_of_factor_sources_with_instances( + fn fulfilling_matrix_of_factor_sources_with_instances( consuming_instances: &mut IndexMap< FactorSourceIDFromHash, FactorInstances, diff --git a/crates/sargon/src/profile/mfa/security_structures/roles/factor_levels/factor_instance_level/role_with_factor_instances.rs b/crates/sargon/src/profile/mfa/security_structures/roles/factor_levels/factor_instance_level/role_with_factor_instances.rs index fb3f872c1..e2dd1a105 100644 --- a/crates/sargon/src/profile/mfa/security_structures/roles/factor_levels/factor_instance_level/role_with_factor_instances.rs +++ b/crates/sargon/src/profile/mfa/security_structures/roles/factor_levels/factor_instance_level/role_with_factor_instances.rs @@ -42,9 +42,10 @@ impl RoleWithFactorInstances { from.iter() .map(|f| { if let Some(existing) = instances.get(&f.id_from_hash()) { - let hd_instance = existing.first().ok_or( - CommonError::MissingFactorMappingInstancesIntoRole, - )?; + let hd_instance = + existing.first_transaction_signing().ok_or( + CommonError::MissingFactorMappingInstancesIntoRole, + )?; let instance = FactorInstance::from(hd_instance); Ok(instance) } else { diff --git a/crates/sargon/src/profile/mfa/security_structures/security_shield_builder.rs b/crates/sargon/src/profile/mfa/security_structures/security_shield_builder.rs index 608149dc0..3497fcbe6 100644 --- a/crates/sargon/src/profile/mfa/security_structures/security_shield_builder.rs +++ b/crates/sargon/src/profile/mfa/security_structures/security_shield_builder.rs @@ -578,6 +578,7 @@ mod tests { let _ = sut .set_name("S.H.I.E.L.D.") + .set_authentication_signing_factor(Some(FactorSourceID::sample_device())) // Primary .set_number_of_days_until_auto_confirm(42) .add_factor_source_to_primary_threshold( @@ -983,6 +984,7 @@ mod test_invalid { sut.add_factor_source_to_confirmation_override( FactorSourceID::sample_arculus(), ); + sut.set_authentication_signing_factor(Some(FactorSourceID::sample_device())); sut } diff --git a/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs b/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs index 74111ed95..502c497c2 100644 --- a/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs +++ b/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs @@ -812,6 +812,8 @@ impl SargonOS { let profile_snapshot = self.profile()?; let key_derivation_interactors = self.keys_derivation_interactor(); + println!("👨‍🔬 SargonOS => SecurifyEntityFactorInstancesProvider::for_entity_mfa"); + let (instances_in_cache_consumer, outcome) = SecurifyEntityFactorInstancesProvider::for_entity_mfa( Arc::new(self.clients.factor_instances_cache.clone()), @@ -822,8 +824,7 @@ impl SargonOS { ) .await?; - let matrix_of_factor_sources = - &security_structure_of_factor_sources.matrix_of_factors; + println!("👨‍🔬 SargonOS => SecurifyEntityFactorInstancesProvider::for_entity_mfa ✅ outcome:\n🔮🔮🔮\n\n{:?}\n🔮🔮🔮🔮🔮🔮🔮🔮\n", outcome); let mut instances_per_preset_per_factor_source = outcome .clone() @@ -850,15 +851,13 @@ impl SargonOS { .collect::>() }) .collect::>(), - matrix_of_factor_sources + security_structure_of_factor_sources .all_factors() .into_iter() .map(|f| f.id_from_hash()) .collect::>() ); - let security_structure_id = security_structure_of_factor_sources.id(); - let mut security_structures_of_factor_instances = IndexMap::< AddressOfAccountOrPersona, SecurityStructureOfFactorInstances, @@ -874,35 +873,51 @@ impl SargonOS { if addresses_of_kind.is_empty() { return Ok(()); }; - let preset = DerivationPreset::mfa_entity_kind(entity_kind); - - let mut instances_per_factor_source = instances_per_preset_per_factor_source - .swap_remove(&preset) - .unwrap_or_else(|| panic!("Expected to find instances for derivation preset: {:?}", preset)); - - for (i, entity_address) in - addresses_of_kind.clone().into_iter().enumerate() - { - let security_structure_of_factor_instances: SecurityStructureOfFactorInstances = { - let matrix_of_factor_instances = MatrixOfFactorInstances::fulfilling_matrix_of_factor_sources_with_instances( - &mut instances_per_factor_source, - matrix_of_factor_sources.clone(), - )?; - - // FIXME - TODO: this is wrong! should get from FIP! - let authentication_signing_instance = HierarchicalDeterministicFactorInstance::sample_with_key_kind_entity_kind_on_network_and_hardened_index( - entity_address.network_id(), - CAP26KeyKind::AuthenticationSigning, - entity_kind, - Hardened::Securified(SecurifiedU30::try_from(i as u32).unwrap()) + + let tx_preset = DerivationPreset::mfa_entity_kind(entity_kind); + let rola_preset = + DerivationPreset::rola_entity_kind(entity_kind); + + let instances_per_factor_source_mfa = instances_per_preset_per_factor_source + .swap_remove(&tx_preset) + .unwrap_or_else(|| panic!("Expected to find instances for derivation preset: {:?}", tx_preset)); + + for (k, v) in instances_per_factor_source_mfa.iter() { + println!( + "👨‍🔬 SargonOS 🦧 mfa - #instances: {:?} for key: {:?}", + v.len(), + k ); + } - SecurityStructureOfFactorInstances::new( - security_structure_id, - matrix_of_factor_instances, - authentication_signing_instance, - )? - }; + let instances_per_factor_source_rola = instances_per_preset_per_factor_source + .swap_remove(&rola_preset) + .unwrap_or_else(|| panic!("Expected to find instances for derivation preset: {:?}", rola_preset)); + + for (k, v) in instances_per_factor_source_rola.iter() { + println!("👨‍🔬 SargonOS 🦧 ROLA - #instances: {:?} for key: {:?}", v.len(), k); + } + + let mut instances_per_factor_source = + instances_per_factor_source_mfa; + for (k, v) in instances_per_factor_source_rola { + instances_per_factor_source.append_or_insert_to(k, v); + } + + for (k, v) in instances_per_factor_source.iter() { + println!("👨‍🔬 SargonOS 🦧 MERGED 🦧 - #instances: {:?} for key: {:?}", v.len(), k); + } + + println!("👨‍🔬 SargonOS instances_per_factor_source: \n\n{:?}\n\n🌈🌈🌈🌈\n", instances_per_factor_source); + + for entity_address in addresses_of_kind.clone().into_iter() { + println!("👨‍🔬 SargonOS calling `SecurityStructureOfFactorInstances::fulfilling_structure_of_factor_sources_with_instances` for entity: {:?}", entity_address); + let security_structure_of_factor_instances = SecurityStructureOfFactorInstances::fulfilling_structure_of_factor_sources_with_instances( + &mut instances_per_factor_source, + &security_structure_of_factor_sources + )?; + + println!("👨‍🔬 SargonOS `SecurityStructureOfFactorInstances::fulfilling_structure_of_factor_sources_with_instances` for entity ✅ : {:?}", entity_address); security_structures_of_factor_instances.insert( *entity_address, security_structure_of_factor_instances, From b2ca5b9876bfe36882be0240700dacaac26e3132 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Thu, 19 Dec 2024 12:51:37 +0100 Subject: [PATCH 49/60] fix all tests --- .../security_shield_builder.rs | 8 +++--- .../security_shield_builder.rs | 28 +++++++++++++++---- ...security_structure_of_factor_source_ids.rs | 14 ++++++++++ .../profile/v100/app_preferences/security.rs | 14 ++++++++++ 4 files changed, 54 insertions(+), 10 deletions(-) diff --git a/crates/sargon-uniffi/src/profile/mfa/security_structures/security_shield_builder.rs b/crates/sargon-uniffi/src/profile/mfa/security_structures/security_shield_builder.rs index 8b7c216c1..7077057a8 100644 --- a/crates/sargon-uniffi/src/profile/mfa/security_structures/security_shield_builder.rs +++ b/crates/sargon-uniffi/src/profile/mfa/security_structures/security_shield_builder.rs @@ -772,10 +772,10 @@ mod tests { sut.remove_factor_from_confirmation(f.clone()); assert_eq!(xs, sut.get_confirmation_factors()); - assert!(matches!( - sut.validate(), - Some(SecurityShieldBuilderInvalidReason::MissingAuthSigningFactor) - )); + assert_eq!( + sut.validate().unwrap(), + SecurityShieldBuilderInvalidReason::MissingAuthSigningFactor + ); sut.set_authentication_signing_factor(Some( FactorSourceID::sample_device_other(), )); diff --git a/crates/sargon/src/profile/mfa/security_structures/security_shield_builder.rs b/crates/sargon/src/profile/mfa/security_structures/security_shield_builder.rs index 3497fcbe6..5f4a63088 100644 --- a/crates/sargon/src/profile/mfa/security_structures/security_shield_builder.rs +++ b/crates/sargon/src/profile/mfa/security_structures/security_shield_builder.rs @@ -122,9 +122,9 @@ impl SecurityShieldBuilder { pub fn set_authentication_signing_factor( &self, - new: Option, + new: impl Into>, ) -> &Self { - *self.authentication_signing_factor.write().unwrap() = new; + *self.authentication_signing_factor.write().unwrap() = new.into(); self } @@ -435,10 +435,21 @@ impl SecurityShieldBuilder { if DisplayName::new(self.get_name()).is_err() { return Some(SecurityShieldBuilderInvalidReason::ShieldNameInvalid); } - self.get(|builder| { + + if let Some(matrix_invalid_reason) = self.get(|builder| { let r = builder.validate(); r.as_shield_validation() - }) + }) { + return Some(matrix_invalid_reason); + } + + if self.get_authentication_signing_factor().is_none() { + return Some( + SecurityShieldBuilderInvalidReason::MissingAuthSigningFactor, + ); + } + + None } /// Validates **just** the primary role **in isolation**. @@ -578,7 +589,9 @@ mod tests { let _ = sut .set_name("S.H.I.E.L.D.") - .set_authentication_signing_factor(Some(FactorSourceID::sample_device())) + .set_authentication_signing_factor(Some( + FactorSourceID::sample_device(), + )) // Primary .set_number_of_days_until_auto_confirm(42) .add_factor_source_to_primary_threshold( @@ -961,6 +974,7 @@ mod test_invalid { #[test] fn valid_is_none() { let sut = SUT::new(); + sut.set_authentication_signing_factor(FactorSourceID::sample_device()); sut.add_factor_source_to_primary_override( FactorSourceID::sample_device(), ); @@ -984,7 +998,9 @@ mod test_invalid { sut.add_factor_source_to_confirmation_override( FactorSourceID::sample_arculus(), ); - sut.set_authentication_signing_factor(Some(FactorSourceID::sample_device())); + sut.set_authentication_signing_factor(Some( + FactorSourceID::sample_device(), + )); sut } diff --git a/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_source_ids.rs b/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_source_ids.rs index 8effe11a6..7eb8d9429 100644 --- a/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_source_ids.rs +++ b/crates/sargon/src/profile/mfa/security_structures/security_structure_of_factors/security_structure_of_factor_source_ids.rs @@ -56,6 +56,13 @@ mod tests { "createdOn": "2023-09-11T16:05:56.000Z", "lastUpdatedOn": "2023-09-11T16:05:56.000Z" }, + "authenticationSigningFactor": { + "discriminator": "fromHash", + "fromHash": { + "kind": "device", + "body": "f1a93d324dd0f2bff89963ab81ed6e0c2ee7e18c0827dc1d3576b2d9f26bbd0a" + } + }, "matrixOfFactors": { "primaryRole": { "threshold": 2, @@ -130,6 +137,13 @@ mod tests { "createdOn": "2023-12-24T17:13:56.123Z", "lastUpdatedOn": "2023-12-24T17:13:56.123Z" }, + "authenticationSigningFactor": { + "discriminator": "fromHash", + "fromHash": { + "kind": "ledgerHQHardwareWallet", + "body": "ab59987eedd181fe98e512c1ba0f5ff059f11b5c7c56f15614dcc9fe03fec58b" + } + }, "matrixOfFactors": { "primaryRole": { "threshold": 1, diff --git a/crates/sargon/src/profile/v100/app_preferences/security.rs b/crates/sargon/src/profile/v100/app_preferences/security.rs index ea13ccf13..7b527c5b3 100644 --- a/crates/sargon/src/profile/v100/app_preferences/security.rs +++ b/crates/sargon/src/profile/v100/app_preferences/security.rs @@ -184,6 +184,13 @@ mod tests { "createdOn": "2023-09-11T16:05:56.000Z", "lastUpdatedOn": "2023-09-11T16:05:56.000Z" }, + "authenticationSigningFactor": { + "discriminator": "fromHash", + "fromHash": { + "kind": "device", + "body": "f1a93d324dd0f2bff89963ab81ed6e0c2ee7e18c0827dc1d3576b2d9f26bbd0a" + } + }, "matrixOfFactors": { "primaryRole": { "threshold": 2, @@ -248,6 +255,13 @@ mod tests { "createdOn": "2023-12-24T17:13:56.123Z", "lastUpdatedOn": "2023-12-24T17:13:56.123Z" }, + "authenticationSigningFactor": { + "discriminator": "fromHash", + "fromHash": { + "kind": "ledgerHQHardwareWallet", + "body": "ab59987eedd181fe98e512c1ba0f5ff059f11b5c7c56f15614dcc9fe03fec58b" + } + }, "matrixOfFactors": { "primaryRole": { "threshold": 1, From cd456d282c27ea38a715d9079027b3b8f2432d8c Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Thu, 19 Dec 2024 13:26:39 +0100 Subject: [PATCH 50/60] fixes --- .../agnostic_paths/derivation_preset.rs | 21 +++- .../quantified_derivation_preset.rs | 100 ++++++++++++------ .../factor_instances_provider_unit_tests.rs | 2 - .../factor_instances_provider_outcome.rs | 6 +- ...ernal_factor_instances_provider_outcome.rs | 12 +-- ...r_instances_provider_outcome_for_factor.rs | 34 ++++-- ...curify_entity_factor_instances_provider.rs | 70 ++++-------- .../matrices/matrix_of_factor_instances.rs | 25 +---- .../system/sargon_os/sargon_os_accounts.rs | 69 +++++------- .../src/types/samples/account_samples.rs | 2 +- .../src/types/samples/persona_samples.rs | 2 +- 11 files changed, 164 insertions(+), 179 deletions(-) diff --git a/crates/sargon/src/factor_instances_provider/agnostic_paths/derivation_preset.rs b/crates/sargon/src/factor_instances_provider/agnostic_paths/derivation_preset.rs index 5d35861bd..6e662864d 100644 --- a/crates/sargon/src/factor_instances_provider/agnostic_paths/derivation_preset.rs +++ b/crates/sargon/src/factor_instances_provider/agnostic_paths/derivation_preset.rs @@ -76,7 +76,6 @@ impl DerivationPreset { } } - /// Selects a `DerivationPreset` for MFA based on `CAP26EntityKind`, /// i.e. either `DerivationPreset::AccountRola` or `DerivationPreset::IdentityRola`. pub fn rola_entity_kind(entity_kind: CAP26EntityKind) -> Self { @@ -171,13 +170,25 @@ mod tests { #[test] fn test_mfa_entity_kind() { - assert_eq!(SUT::mfa_entity_kind(CAP26EntityKind::Account), SUT::AccountMfa); - assert_eq!(SUT::mfa_entity_kind(CAP26EntityKind::Identity), SUT::IdentityMfa); + assert_eq!( + SUT::mfa_entity_kind(CAP26EntityKind::Account), + SUT::AccountMfa + ); + assert_eq!( + SUT::mfa_entity_kind(CAP26EntityKind::Identity), + SUT::IdentityMfa + ); } #[test] fn test_rola_entity_kind() { - assert_eq!(SUT::rola_entity_kind(CAP26EntityKind::Account), SUT::AccountRola); - assert_eq!(SUT::rola_entity_kind(CAP26EntityKind::Identity), SUT::IdentityRola); + assert_eq!( + SUT::rola_entity_kind(CAP26EntityKind::Account), + SUT::AccountRola + ); + assert_eq!( + SUT::rola_entity_kind(CAP26EntityKind::Identity), + SUT::IdentityRola + ); } } diff --git a/crates/sargon/src/factor_instances_provider/agnostic_paths/quantified_derivation_preset.rs b/crates/sargon/src/factor_instances_provider/agnostic_paths/quantified_derivation_preset.rs index 03b19015c..6afd21b29 100644 --- a/crates/sargon/src/factor_instances_provider/agnostic_paths/quantified_derivation_preset.rs +++ b/crates/sargon/src/factor_instances_provider/agnostic_paths/quantified_derivation_preset.rs @@ -22,8 +22,27 @@ impl QuantifiedDerivationPreset { } } - pub fn mfa_for_entities( + /// Returns a the QuantifiedDerivationPresets needed to securify the `addresses_of_entities`, including + /// a new Authentication Signing factor instance for each entity. Will return + /// the `Account` variant of each DerivationPreset for each Account in `addresses_of_entities` + /// and the `Identity` variant of each DerivationPreset for each Persona in `addresses_of_entities`. + pub fn securifying_unsecurified_entities( addresses_of_entities: &IndexSet, + ) -> IdentifiedVecOf { + Self::mfa_for_entities(addresses_of_entities, true) + } + + /// Returns a the QuantifiedDerivationPresets needed to securify the `addresses_of_entities`, Will return + /// the `Account` variant of each DerivationPreset for each Account in `addresses_of_entities` + /// and the `Identity` variant of each DerivationPreset for each Persona in `addresses_of_entities`. + /// + /// if `include_rola_key_for_each_entity` is `true` a ROLA key for each entity will be included. + /// Typically we only set `include_rola_key_for_each_entity` to `true` for securifying + /// unsecurified entities. For already securified entities we might not + /// need to change the ROLA key. + fn mfa_for_entities( + addresses_of_entities: &IndexSet, + include_rola_key_for_each_entity: bool, ) -> IdentifiedVecOf { let account_addresses = addresses_of_entities .iter() @@ -36,44 +55,55 @@ impl QuantifiedDerivationPreset { match (account_addresses.is_empty(), identity_addresses.is_empty()) { (true, true) => IdentifiedVecOf::new(), // weird! - (true, false) => IdentifiedVecOf::from_iter([ - Self::new( - DerivationPreset::IdentityMfa, - identity_addresses.len(), - ), - Self::new( - DerivationPreset::IdentityRola, - identity_addresses.len(), - ), - ]), - (false, false) => IdentifiedVecOf::from_iter([ - Self::new( - DerivationPreset::AccountMfa, - account_addresses.len(), - ), - Self::new( - DerivationPreset::AccountRola, - account_addresses.len(), - ), - Self::new( + (true, false) => { + let mut presets = IdentifiedVecOf::just(Self::new( DerivationPreset::IdentityMfa, identity_addresses.len(), - ), - Self::new( - DerivationPreset::IdentityRola, - identity_addresses.len(), - ), - ]), - (false, true) => IdentifiedVecOf::from_iter([ - Self::new( + )); + if include_rola_key_for_each_entity { + presets.append(Self::new( + DerivationPreset::IdentityRola, + identity_addresses.len(), + )); + } + presets + } + (false, false) => { + let mut presets = IdentifiedVecOf::from_iter([ + Self::new( + DerivationPreset::AccountMfa, + account_addresses.len(), + ), + Self::new( + DerivationPreset::IdentityMfa, + identity_addresses.len(), + ), + ]); + if include_rola_key_for_each_entity { + presets.append(Self::new( + DerivationPreset::AccountRola, + account_addresses.len(), + )); + presets.append(Self::new( + DerivationPreset::IdentityRola, + identity_addresses.len(), + )); + } + presets + } + (false, true) => { + let mut presets = IdentifiedVecOf::just(Self::new( DerivationPreset::AccountMfa, account_addresses.len(), - ), - Self::new( - DerivationPreset::AccountRola, - account_addresses.len(), - ), - ]), + )); + if include_rola_key_for_each_entity { + presets.append(Self::new( + DerivationPreset::AccountRola, + account_addresses.len(), + )); + } + presets + } } } } diff --git a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider_unit_tests.rs b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider_unit_tests.rs index c8c5d8c57..045bc737a 100644 --- a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider_unit_tests.rs +++ b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider_unit_tests.rs @@ -1801,7 +1801,6 @@ async fn create_single_account() { matrix_0, bdfs.clone(), ); - println!("👨‍🔬 test calling `make_security_structure_of_factor_instances_for_entities_without_consuming_cache_with_derivation_outcome` for single account Alice"); let (security_structures_of_fis, instances_in_cache_consumer, derivation_outcome) = os .make_security_structure_of_factor_instances_for_entities_without_consuming_cache_with_derivation_outcome( IndexSet::just(AddressOfAccountOrPersona::from(alice.address())), @@ -1809,7 +1808,6 @@ async fn create_single_account() { ) .await .unwrap(); - println!("👨‍🔬 ✅ `make_security_structure_of_factor_instances_for_entities_without_consuming_cache_with_derivation_outcome` for single account Alice ✅"); // Don't forget to consume! instances_in_cache_consumer.consume().await.unwrap(); diff --git a/crates/sargon/src/factor_instances_provider/provider/outcome/factor_instances_provider_outcome.rs b/crates/sargon/src/factor_instances_provider/provider/outcome/factor_instances_provider_outcome.rs index 80da4806a..5bcac12a2 100644 --- a/crates/sargon/src/factor_instances_provider/provider/outcome/factor_instances_provider_outcome.rs +++ b/crates/sargon/src/factor_instances_provider/provider/outcome/factor_instances_provider_outcome.rs @@ -1,7 +1,7 @@ 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. +/// A collection of `FactorInstancesProviderOutcomePerFactor` keyed under +/// DerivationPreset. #[derive(Clone, Debug)] pub struct FactorInstancesProviderOutcome { pub per_derivation_preset: @@ -26,6 +26,8 @@ impl FactorInstancesProviderOutcome { } } +/// A collection of `FactorInstancesProviderOutcomeForFactor` keyed by their +/// FactorSourceID #[derive(Clone, Debug)] pub struct FactorInstancesProviderOutcomePerFactor { pub per_factor: IndexMap< diff --git a/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs b/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs index ad03566ab..be99d08f7 100644 --- a/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs +++ b/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs @@ -28,15 +28,6 @@ impl InternalFactorInstancesProviderOutcome { ) -> Option<&InternalFactorInstancesProviderOutcomePerFactor> { self.per_derivation_preset.get(&preset) } - - pub fn get_for_derivation_preset_for_factor( - &self, - preset: DerivationPreset, - factor_source_id: FactorSourceIDFromHash, - ) -> Option<&InternalFactorInstancesProviderOutcomeForFactor> { - self.get_for_derivation_preset(preset) - .and_then(|x| x.per_factor.get(&factor_source_id)) - } } #[derive(Clone, Debug)] @@ -59,7 +50,8 @@ impl InternalFactorInstancesProviderOutcome { } } - /// "Transposes" + /// For each value of each collection, "transposes" it. For more info see + /// `InternalFactorInstancesProviderOutcomePerFactor::transpose` pub fn transpose( pdp_pf_to_cache: InstancesPerDerivationPresetPerFactorSource, pdp_pf_to_use_directly: InstancesPerDerivationPresetPerFactorSource, diff --git a/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome_for_factor.rs b/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome_for_factor.rs index 1ab52809a..0c98e3fe7 100644 --- a/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome_for_factor.rs +++ b/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome_for_factor.rs @@ -118,16 +118,30 @@ impl HasSampleValues for InternalFactorInstancesProviderOutcomeForFactor { } fn sample_other() -> Self { - Self::new(FactorSourceIDFromHash::sample_at(1), FactorInstances::new(IndexSet::from_iter([ - HierarchicalDeterministicFactorInstance::sample_mainnet_account_device_factor_fs_1_securified_at_index(2), - ])), FactorInstances::new(IndexSet::from_iter([ - HierarchicalDeterministicFactorInstance::sample_mainnet_account_device_factor_fs_1_securified_at_index(0), - ])), FactorInstances::new(IndexSet::from_iter([ - HierarchicalDeterministicFactorInstance::sample_mainnet_account_device_factor_fs_1_securified_at_index(0), - ])), FactorInstances::new(IndexSet::from_iter([ - HierarchicalDeterministicFactorInstance::sample_mainnet_account_device_factor_fs_1_securified_at_index(1), - HierarchicalDeterministicFactorInstance::sample_mainnet_account_device_factor_fs_1_securified_at_index(2), - ]))) + Self::new( + FactorSourceIDFromHash::sample_at(1), + FactorInstances::new( + IndexSet::from_iter([ + HierarchicalDeterministicFactorInstance::sample_mainnet_account_device_factor_fs_1_securified_at_index(2), + ]) + ), + FactorInstances::new( + IndexSet::from_iter([ + HierarchicalDeterministicFactorInstance::sample_mainnet_account_device_factor_fs_1_securified_at_index(0), + ]) + ), + FactorInstances::new( + IndexSet::from_iter([ + HierarchicalDeterministicFactorInstance::sample_mainnet_account_device_factor_fs_1_securified_at_index(0), + ]) + ), + FactorInstances::new( + IndexSet::from_iter([ + HierarchicalDeterministicFactorInstance::sample_mainnet_account_device_factor_fs_1_securified_at_index(1), + HierarchicalDeterministicFactorInstance::sample_mainnet_account_device_factor_fs_1_securified_at_index(2), + ]) + ) + ) } } diff --git a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/securify_entity_factor_instances_provider.rs b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/securify_entity_factor_instances_provider.rs index 1cb550a40..513b7b750 100644 --- a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/securify_entity_factor_instances_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/securify_entity_factor_instances_provider.rs @@ -23,7 +23,7 @@ impl SecurifyEntityFactorInstancesProvider { interactor: Arc, ) -> Result<(InstancesInCacheConsumer, FactorInstancesProviderOutcome)> { - Self::for_entity_mfa( + Self::securifying_unsecurified( cache_client, profile, security_structure_of_factor_sources, @@ -52,7 +52,7 @@ impl SecurifyEntityFactorInstancesProvider { interactor: Arc, ) -> Result<(InstancesInCacheConsumer, FactorInstancesProviderOutcome)> { - Self::for_entity_mfa( + Self::securifying_unsecurified( cache_client, profile, security_structure_of_factor_sources, @@ -73,7 +73,11 @@ impl SecurifyEntityFactorInstancesProvider { /// /// 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( + pub async fn securifying_unsecurified( + // if you need to UPDATE already securified, upgrade this to conditionally consume ROLA + // factors, by not using `QuantifiedDerivationPreset::securifying_unsecurified_entities` + // below. I.e. create the set of `QuantifiedDerivationPreset` which does not unconditionally + // specify ROLA factors. cache_client: Arc, profile: Arc, security_structure_of_factor_sources: SecurityStructureOfFactorSources, @@ -132,48 +136,15 @@ impl SecurifyEntityFactorInstancesProvider { ); let quantified_derivation_presets = - QuantifiedDerivationPreset::mfa_for_entities( + QuantifiedDerivationPreset::securifying_unsecurified_entities( &addresses_of_entities, ); - println!( - "🌮 FIP (Sec) quantified_derivation_presets: {:?}", - quantified_derivation_presets - ); - assert!(quantified_derivation_presets.len() >= 2); // at least one entity kind, and ROLA + TX: at least 2 let (instances_in_cache_consumer, outcome) = provider .provide_for_presets(quantified_derivation_presets, purpose) .await?; - if let Some(rola_accounts_outcome) = outcome - .get_for_derivation_preset_for_factor( - DerivationPreset::AccountRola, - security_structure_of_factor_sources - .authentication_signing_factor - .id_from_hash(), - ) - { - println!( - "🌮 FIP (Sec) rola_accounts_outcome: {:#?}", - rola_accounts_outcome - ); - } - - if let Some(rola_personas_outcome) = outcome - .get_for_derivation_preset_for_factor( - DerivationPreset::IdentityRola, - security_structure_of_factor_sources - .authentication_signing_factor - .id_from_hash(), - ) - { - println!( - "🌮 FIP (Sec) rola_personas_outcome: {:#?}", - rola_personas_outcome - ); - } - Ok((instances_in_cache_consumer, outcome.into())) } } @@ -351,18 +322,19 @@ mod tests { let profile = Arc::new(os.profile().unwrap()); let derivation_interactors = os.keys_derivation_interactor(); - let (instances_in_cache_consumer, outcome) = SUT::for_entity_mfa( - cache_client.clone(), - profile, - shield_0.clone(), - IndexSet::from_iter([ - AddressOfAccountOrPersona::from(alice.address()), - AddressOfAccountOrPersona::from(batman.address()), - ]), - derivation_interactors.clone(), - ) - .await - .unwrap(); + let (instances_in_cache_consumer, outcome) = + SUT::securifying_unsecurified( + cache_client.clone(), + profile, + shield_0.clone(), + IndexSet::from_iter([ + AddressOfAccountOrPersona::from(alice.address()), + AddressOfAccountOrPersona::from(batman.address()), + ]), + derivation_interactors.clone(), + ) + .await + .unwrap(); assert_eq!(outcome.per_derivation_preset.len(), 4); diff --git a/crates/sargon/src/profile/mfa/security_structures/matrices/matrix_of_factor_instances.rs b/crates/sargon/src/profile/mfa/security_structures/matrices/matrix_of_factor_instances.rs index 5054da3af..9ac9a091d 100644 --- a/crates/sargon/src/profile/mfa/security_structures/matrices/matrix_of_factor_instances.rs +++ b/crates/sargon/src/profile/mfa/security_structures/matrices/matrix_of_factor_instances.rs @@ -221,31 +221,11 @@ impl SecurityStructureOfFactorInstances { >, security_structure_of_factor_sources: &SecurityStructureOfFactorSources, ) -> Result { - for (k, v) in consuming_instances.iter() { - println!("\n\n 👨‍🔬 SSFI: fulfilling_structure_of_factor_sources_with_instances` consuming_instances BEFORE fulfilling matrix:"); - println!( - "👨‍🔬 SSFI - BEFORE - key: {:?}, instances: #{:?}", - k, - v.len() - ); - println!("\n\n 🛡️ 🛡️ 🛡️ 🛡️ 🛡️\n") - } - let matrix_of_factors = MatrixOfFactorInstances::fulfilling_matrix_of_factor_sources_with_instances( consuming_instances, security_structure_of_factor_sources.matrix_of_factors.clone(), )?; - for (k, v) in consuming_instances.iter() { - println!("\n\n 👨‍🔬 SSFI: fulfilling_structure_of_factor_sources_with_instances` consuming_instances AFTER fulfilling matrix:"); - println!( - "👨‍🔬 SSFI - AFTER - key: {:?}, instances: #{:?}", - k, - v.len() - ); - println!("\n\n 🛡️ 🛡️ 🛡️ 🛡️ 🛡️\n") - } - let authentication_signing = if let Some(existing) = consuming_instances .get_mut( &security_structure_of_factor_sources @@ -253,8 +233,9 @@ impl SecurityStructureOfFactorInstances { .id_from_hash(), ) { let instance = existing.first_authentication_signing().ok_or( - CommonError::MissingRolaKeyForSecurityStructureOfFactorInstances, - ).inspect_err(|_| println!("👨‍🔬 SSFI ❌ first_authentication_signing failed => MissingRolaKeyForSecurityStructureOfFactorInstances ❌"))?; + CommonError::MissingRolaKeyForSecurityStructureOfFactorInstances, + )?; + let _ = existing.shift_remove(&instance); // don't forget to consume it! Ok(instance) } else { diff --git a/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs b/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs index 502c497c2..56babcb5b 100644 --- a/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs +++ b/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs @@ -812,10 +812,12 @@ impl SargonOS { let profile_snapshot = self.profile()?; let key_derivation_interactors = self.keys_derivation_interactor(); - println!("👨‍🔬 SargonOS => SecurifyEntityFactorInstancesProvider::for_entity_mfa"); - + // if you need to UPDATE already securified, upgrade this to conditionally consume ROLA + // factors, by not using `QuantifiedDerivationPreset::securifying_unsecurified_entities` + // inside of SecurifyEntityFactorInstancesProvider::securifying_unsecurified. I.e. create the set of `QuantifiedDerivationPreset` which does not unconditionally + // specify ROLA factors. let (instances_in_cache_consumer, outcome) = - SecurifyEntityFactorInstancesProvider::for_entity_mfa( + SecurifyEntityFactorInstancesProvider::securifying_unsecurified( Arc::new(self.clients.factor_instances_cache.clone()), Arc::new(profile_snapshot.clone()), security_structure_of_factor_sources.clone(), @@ -824,8 +826,6 @@ impl SargonOS { ) .await?; - println!("👨‍🔬 SargonOS => SecurifyEntityFactorInstancesProvider::for_entity_mfa ✅ outcome:\n🔮🔮🔮\n\n{:?}\n🔮🔮🔮🔮🔮🔮🔮🔮\n", outcome); - let mut instances_per_preset_per_factor_source = outcome .clone() .per_derivation_preset @@ -874,50 +874,35 @@ impl SargonOS { return Ok(()); }; - let tx_preset = DerivationPreset::mfa_entity_kind(entity_kind); - let rola_preset = - DerivationPreset::rola_entity_kind(entity_kind); - - let instances_per_factor_source_mfa = instances_per_preset_per_factor_source - .swap_remove(&tx_preset) - .unwrap_or_else(|| panic!("Expected to find instances for derivation preset: {:?}", tx_preset)); - - for (k, v) in instances_per_factor_source_mfa.iter() { - println!( - "👨‍🔬 SargonOS 🦧 mfa - #instances: {:?} for key: {:?}", - v.len(), - k - ); - } - - let instances_per_factor_source_rola = instances_per_preset_per_factor_source - .swap_remove(&rola_preset) - .unwrap_or_else(|| panic!("Expected to find instances for derivation preset: {:?}", rola_preset)); - - for (k, v) in instances_per_factor_source_rola.iter() { - println!("👨‍🔬 SargonOS 🦧 ROLA - #instances: {:?} for key: {:?}", v.len(), k); - } - - let mut instances_per_factor_source = - instances_per_factor_source_mfa; - for (k, v) in instances_per_factor_source_rola { - instances_per_factor_source.append_or_insert_to(k, v); - } - - for (k, v) in instances_per_factor_source.iter() { - println!("👨‍🔬 SargonOS 🦧 MERGED 🦧 - #instances: {:?} for key: {:?}", v.len(), k); - } - - println!("👨‍🔬 SargonOS instances_per_factor_source: \n\n{:?}\n\n🌈🌈🌈🌈\n", instances_per_factor_source); + let mut instances_per_factor_source = { + let tx_preset = + DerivationPreset::mfa_entity_kind(entity_kind); + let rola_preset = + DerivationPreset::rola_entity_kind(entity_kind); + + let instances_per_factor_source_mfa = instances_per_preset_per_factor_source + .swap_remove(&tx_preset) + .unwrap_or_else(|| panic!("Expected to find instances for derivation preset: {:?}", tx_preset)); + + let instances_per_factor_source_rola = instances_per_preset_per_factor_source + .swap_remove(&rola_preset) + .unwrap_or_else(|| panic!("Expected to find instances for derivation preset: {:?}", rola_preset)); + + // Merge `instances_per_factor_source_mfa` and `instances_per_factor_source_rola` together + let mut instances_per_factor_source = + instances_per_factor_source_mfa; + for (k, v) in instances_per_factor_source_rola { + instances_per_factor_source.append_or_insert_to(k, v); + } + instances_per_factor_source + }; for entity_address in addresses_of_kind.clone().into_iter() { - println!("👨‍🔬 SargonOS calling `SecurityStructureOfFactorInstances::fulfilling_structure_of_factor_sources_with_instances` for entity: {:?}", entity_address); let security_structure_of_factor_instances = SecurityStructureOfFactorInstances::fulfilling_structure_of_factor_sources_with_instances( &mut instances_per_factor_source, &security_structure_of_factor_sources )?; - println!("👨‍🔬 SargonOS `SecurityStructureOfFactorInstances::fulfilling_structure_of_factor_sources_with_instances` for entity ✅ : {:?}", entity_address); security_structures_of_factor_instances.insert( *entity_address, security_structure_of_factor_instances, diff --git a/crates/sargon/src/types/samples/account_samples.rs b/crates/sargon/src/types/samples/account_samples.rs index 1ce6e8c73..31c69e05f 100644 --- a/crates/sargon/src/types/samples/account_samples.rs +++ b/crates/sargon/src/types/samples/account_samples.rs @@ -17,7 +17,7 @@ static ALL_ACCOUNT_SAMPLES: Lazy<[Account; 10]> = Lazy::new(|| { // Carla | 2 | Securified { Single Threshold only } Account::sample_securified_mainnet( "Carla", -2, + 2, HierarchicalDeterministicFactorInstance::sample_mainnet_account_device_factor_fs_10_unsecurified_at_index(2), || { let idx = diff --git a/crates/sargon/src/types/samples/persona_samples.rs b/crates/sargon/src/types/samples/persona_samples.rs index 7a60fa617..9ddcbb2be 100644 --- a/crates/sargon/src/types/samples/persona_samples.rs +++ b/crates/sargon/src/types/samples/persona_samples.rs @@ -71,7 +71,7 @@ static ALL_PERSONA_SAMPLES: Lazy<[Persona; 8]> = Lazy::new(|| { // Kasparov | 6 | Securified { Threshold #3 and Override factors #2 } Persona::sample_securified_mainnet( "Kasparov", - 6, + 6, HierarchicalDeterministicFactorInstance::sample_mainnet_identity_device_factor_fs_10_unsecurified_at_index(6), || { let idx = From e8d16d6df71ef1636ca832c7074e264d6dca0940 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Thu, 19 Dec 2024 14:00:02 +0100 Subject: [PATCH 51/60] fix swift tests --- .../Profile/MFA/SecurityShieldsBuilderTests.swift | 7 +++++++ .../provider/factor_instances_provider.rs | 1 - .../matrices/matrix_of_factor_instances.rs | 1 - 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apple/Tests/TestCases/Profile/MFA/SecurityShieldsBuilderTests.swift b/apple/Tests/TestCases/Profile/MFA/SecurityShieldsBuilderTests.swift index d259f0097..7061ba22b 100644 --- a/apple/Tests/TestCases/Profile/MFA/SecurityShieldsBuilderTests.swift +++ b/apple/Tests/TestCases/Profile/MFA/SecurityShieldsBuilderTests.swift @@ -104,6 +104,9 @@ struct ShieldTests { #expect(builder.validate() == .ConfirmationRoleMustHaveAtLeastOneFactor) builder.addFactorSourceToConfirmationOverride(factorSourceId: .sampleArculus) + + builder.setAuthenticationSigningFactor(new: .sampleDevice) + #expect(builder.validate() == nil) #expect((try? builder.build()) != nil) } @@ -173,6 +176,8 @@ struct ShieldTests { builder.addFactorSourceToRecoveryOverride(factorSourceId: .sampleArculus) builder.addFactorSourceToConfirmationOverride(factorSourceId: .sampleArculusOther) + builder.setAuthenticationSigningFactor(new: .sampleDevice) + let shield = try! builder.build() #expect(shield.matrixOfFactors.primaryRole.overrideFactors.isEmpty) @@ -205,6 +210,8 @@ struct ShieldTests { builder.removeFactorFromPrimary(factorSourceId: .sampleArculusOther) builder.removeFactorFromRecovery(factorSourceId: .sampleLedgerOther) + builder.setAuthenticationSigningFactor(new: .sampleDevice) + // Validate #expect(builder.validate() == nil) diff --git a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs index 7665c5b02..511041830 100644 --- a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider.rs @@ -417,7 +417,6 @@ impl FactorInstancesProvider { Ok((derivation_preset, per_factor_paths)) }) .collect::>, IndexMap< DerivationPreset, IndexMap>, diff --git a/crates/sargon/src/profile/mfa/security_structures/matrices/matrix_of_factor_instances.rs b/crates/sargon/src/profile/mfa/security_structures/matrices/matrix_of_factor_instances.rs index 9ac9a091d..dffcb1745 100644 --- a/crates/sargon/src/profile/mfa/security_structures/matrices/matrix_of_factor_instances.rs +++ b/crates/sargon/src/profile/mfa/security_structures/matrices/matrix_of_factor_instances.rs @@ -239,7 +239,6 @@ impl SecurityStructureOfFactorInstances { let _ = existing.shift_remove(&instance); // don't forget to consume it! Ok(instance) } else { - println!("👨‍🔬 SSFI ❌ get_mut failed => MissingRolaKeyForSecurityStructureOfFactorInstances ❌"); Err(CommonError::MissingRolaKeyForSecurityStructureOfFactorInstances) }?; From 671538520775684d076087e72558a92cf697ecef Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Thu, 19 Dec 2024 14:07:41 +0100 Subject: [PATCH 52/60] fmt --- ...ernal_factor_instances_provider_outcome.rs | 20 +++++++++---------- ...rtual_entity_creating_instance_provider.rs | 9 +++++---- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs b/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs index be99d08f7..18616217a 100644 --- a/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs +++ b/crates/sargon/src/factor_instances_provider/provider/outcome/internal_factor_instances_provider_outcome.rs @@ -109,16 +109,16 @@ impl InternalFactorInstancesProviderOutcomePerFactor { 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(), - ) +pf_found_in_cache + .into_iter() + .map(|(k, v)| { + ( + k, + InternalFactorInstancesProviderOutcomeForFactor::satisfied_by_cache(k, v), + ) + }) + .collect(), + ) } /// "Transposes" diff --git a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs index f280125aa..50699bb1d 100644 --- a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs @@ -724,10 +724,11 @@ mod tests { .all(|y| y.debug_found_in_cache.is_empty()))); assert!(outcome.per_derivation_preset.clone().into_iter().all( - |(preset, x)| x.per_factor.values().all( - |y| y.debug_was_cached.len() // OLD-COMMENT: `only 30, not 120...` if test fails, draw inspiration from old comment! - == preset.cache_filling_quantity() - ) + |(preset, x)| x + .per_factor + .values() + .all(|y| y.debug_was_cached.len() + == preset.cache_filling_quantity()) )); assert!(outcome.per_derivation_preset.clone().into_iter().all( From 3a2168188e4f970579a7d85af8e167d3c3a2c344 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Fri, 20 Dec 2024 08:44:11 +0100 Subject: [PATCH 53/60] merge --- Cargo.lock | 4 ++-- crates/sargon-uniffi/Cargo.toml | 2 +- crates/sargon/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dc127ed3a..9f9f88052 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2761,7 +2761,7 @@ dependencies = [ [[package]] name = "sargon" -version = "1.1.92" +version = "1.1.93" dependencies = [ "actix-rt", "aes-gcm", @@ -2816,7 +2816,7 @@ dependencies = [ [[package]] name = "sargon-uniffi" -version = "1.1.92" +version = "1.1.93" dependencies = [ "actix-rt", "assert-json-diff", diff --git a/crates/sargon-uniffi/Cargo.toml b/crates/sargon-uniffi/Cargo.toml index 604fc535e..4bba6a821 100644 --- a/crates/sargon-uniffi/Cargo.toml +++ b/crates/sargon-uniffi/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "sargon-uniffi" # Don't forget to update version in crates/sargon/Cargo.toml -version = "1.1.92" +version = "1.1.93" edition = "2021" build = "build.rs" diff --git a/crates/sargon/Cargo.toml b/crates/sargon/Cargo.toml index e3d95d302..10708a6ac 100644 --- a/crates/sargon/Cargo.toml +++ b/crates/sargon/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "sargon" # Don't forget to update version in crates/sargon-uniffi/Cargo.toml -version = "1.1.92" +version = "1.1.93" edition = "2021" build = "build.rs" From d69166b977d9b0a363fbd9251cb63e0933274afe Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Fri, 20 Dec 2024 09:45:56 +0100 Subject: [PATCH 54/60] __OFFLINE_ONLY_securify_entities --- .../src/core/error/common_error.rs | 3 + crates/sargon/src/core/error/common_error.rs | 3 + .../factor_instances_provider_unit_tests.rs | 271 +++++++++++++----- .../profile/logic/account/query_accounts.rs | 14 + .../profile_network_get_entities.rs | 17 +- .../supporting_types/account_or_persona.rs | 6 + .../profile/v100/entity/account/account.rs | 3 + .../profile/v100/entity/has_security_state.rs | 34 +++ .../profile/v100/entity/persona/persona.rs | 3 + .../v100/networks/network/profile_network.rs | 36 ++- .../profile/v100/networks/profile_networks.rs | 11 +- crates/sargon/src/profile/v100/profile.rs | 25 +- .../system/sargon_os/profile_state_holder.rs | 7 + .../system/sargon_os/sargon_os_accounts.rs | 55 +++- 14 files changed, 387 insertions(+), 101 deletions(-) diff --git a/crates/sargon-uniffi/src/core/error/common_error.rs b/crates/sargon-uniffi/src/core/error/common_error.rs index 07539f136..5816cadb0 100644 --- a/crates/sargon-uniffi/src/core/error/common_error.rs +++ b/crates/sargon-uniffi/src/core/error/common_error.rs @@ -868,6 +868,9 @@ pub enum CommonError { #[error("Missing Authentication Signing FactorInstance mapping SecurityStructureOfFactorSources into SecurityStructureOfFactorInstances.")] MissingRolaKeyForSecurityStructureOfFactorInstances = 10243, + + #[error("SecurityStateAccessController address mismatch")] + SecurityStateAccessControllerAddressMismatch = 10244, } #[uniffi::export] diff --git a/crates/sargon/src/core/error/common_error.rs b/crates/sargon/src/core/error/common_error.rs index fc799aae7..62a4c2df1 100644 --- a/crates/sargon/src/core/error/common_error.rs +++ b/crates/sargon/src/core/error/common_error.rs @@ -865,6 +865,9 @@ pub enum CommonError { #[error("Missing Authentication Signing FactorInstance mapping SecurityStructureOfFactorSources into SecurityStructureOfFactorInstances.")] MissingRolaKeyForSecurityStructureOfFactorInstances = 10243, + + #[error("SecurityStateAccessController address mismatch")] + SecurityStateAccessControllerAddressMismatch = 10244, } impl CommonError { diff --git a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider_unit_tests.rs b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider_unit_tests.rs index 045bc737a..4e0810109 100644 --- a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider_unit_tests.rs +++ b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider_unit_tests.rs @@ -70,20 +70,37 @@ impl SargonOS { account_address: AccountAddress, security_structure_of_factor_instances: SecurityStructureOfFactorInstances, ) -> Result { - let mut account = self.account_by_address(account_address).unwrap(); + let entity = self.__OFFLINE_ONLY_securify_entity_without_saving( + AddressOfAccountOrPersona::Account(account_address), + security_structure_of_factor_instances, + )?; + + entity + .clone() + .as_account_entity() + .ok_or(CommonError::ExpectedAccountButGotPersona { + address: entity.address().to_string(), + }) + .cloned() + } + + pub(crate) fn __OFFLINE_ONLY_securify_entity_without_saving( + &self, + entity_address: AddressOfAccountOrPersona, + security_structure_of_factor_instances: SecurityStructureOfFactorInstances, + ) -> Result { + let mut entity = self.entity_by_address(entity_address)?; let veci: HierarchicalDeterministicFactorInstance; let access_controller_address: AccessControllerAddress; - match account.security_state() { + match entity.security_state() { EntitySecurityState::Unsecured { value } => { veci = value.transaction_signing.clone(); // THIS IS COMPLETELY WRONG! // The real solution should get the AccessControllerAddress on chain access_controller_address = - AccessControllerAddress::with_node_id_of( - &account.address(), - ); + AccessControllerAddress::with_node_id_of(&entity.address()); } EntitySecurityState::Securified { value } => { veci = value.veci.clone().unwrap(); @@ -97,11 +114,11 @@ impl SargonOS { security_structure_of_factor_instances, )?; - account.security_state = EntitySecurityState::Securified { + entity.set_security_state(EntitySecurityState::Securified { value: securified_control, - }; + })?; - Ok(account) + Ok(entity) } /// Uses FactorInstancesProvider to get factor instances for the `shield`. @@ -112,12 +129,34 @@ impl SargonOS { account_addresses: IndexSet, shield: &SecurityStructureOfFactorSources, ) -> Result<(Accounts, FactorInstancesProviderOutcome)> { - account_addresses + let (entities, outcome) = self + .__OFFLINE_ONLY_securify_entities( + account_addresses.into_iter().map(Into::into).collect(), + shield, + ) + .await?; + + let accounts = entities + .into_iter() + .map(|e| e.into_account_entity().unwrap()) + .collect(); + Ok((accounts, outcome)) + } + + async fn __OFFLINE_ONLY_securify_entities( + &self, + entity_addresses: IndexSet, + shield: &SecurityStructureOfFactorSources, + ) -> Result<( + IdentifiedVecOf, + FactorInstancesProviderOutcome, + )> { + entity_addresses .iter() - .for_each(|a| assert!(self.account_by_address(*a).is_ok())); + .for_each(|a| assert!(self.entity_by_address(*a).is_ok())); let outcome = self.make_security_structure_of_factor_instances_for_entities_without_consuming_cache_with_derivation_outcome( - account_addresses.clone().into_iter().map(Into::into).collect(), + entity_addresses.clone().into_iter().map(Into::into).collect(), shield.clone()).await?; let ( @@ -132,37 +171,36 @@ impl SargonOS { // consume! instances_in_cache_consumer.consume().await?; - let securified_accounts = account_addresses + let securified_entities = entity_addresses .into_iter() - .map(|account_address| { + .map(|entity_address| { let security_structure_of_factor_instances = security_structures_of_factor_instances - .shift_remove(&AddressOfAccountOrPersona::from( - account_address, - )) + .shift_remove(&entity_address) .unwrap(); - // Production ready code should batch update accounts, submit batch transaction to + // Production ready code should batch update entities, submit batch transaction to // network, and then batch update all accounts in Profile. - self.__OFFLINE_ONLY_securify_account_without_saving( - account_address, + self.__OFFLINE_ONLY_securify_entity_without_saving( + entity_address, security_structure_of_factor_instances, ) }) - .collect::>()?; + .collect::>>()?; assert!(security_structures_of_factor_instances.is_empty()); // Assert that none of the NEW FactorInstances collide with the existing ones self.profile() .unwrap() - .assert_new_factor_instances_not_already_used( - securified_accounts.clone(), + .assert_new_factor_instances_not_already_used_erased( + securified_entities.clone(), )?; - self.update_entities(securified_accounts.clone()).await?; + self.update_entities_erased(securified_entities.clone()) + .await?; Ok(( - securified_accounts.into_iter().collect(), + securified_entities.into_iter().collect(), derivation_outcome, )) } @@ -704,7 +742,7 @@ async fn test_assert_factor_instances_invalid() { } #[actix_rt::test] -async fn add_account_and_personas_mixed() { +async fn add_account_and_personas_mixed_veci() { let os = SargonOS::fast_boot().await; let profile = os.profile().unwrap(); assert!(profile @@ -2342,7 +2380,7 @@ async fn securified_all_accounts_next_veci_does_not_start_at_zero() { } #[actix_rt::test] -async fn securified_accounts_asymmetric_indices() { +async fn securified_accounts_and_personas_mixed_asymmetric_indices() { let (os, bdfs) = SargonOS::with_bdfs().await; let cache = os.cache_snapshot().await; assert_eq!( @@ -2385,6 +2423,16 @@ async fn securified_accounts_asymmetric_indices() { .into_iter() .collect_vec(); + let (_, derivation_outcome) = os.batch_create_many_personas_with_factor_source_with_derivation_outcome_then_save_once(bdfs.clone(), CACHE_FILLING_QUANTITY as u16, network, "Persona".to_owned()).await.unwrap(); + assert!(derivation_outcome.debug_was_derived.is_empty()); + + let unnamed_personas = os + .profile() + .unwrap() + .personas_on_all_networks_including_hidden() + .into_iter() + .collect_vec(); + // This is NOT a valid Matrix! But for the purpose of this test, it's fine. // We are not testing valid matrices here... we are testing the factor // instances provider... @@ -2412,13 +2460,26 @@ async fn securified_accounts_asymmetric_indices() { matrix_0, bdfs.clone(), ); + + let mut unnamed_accounts_and_personas_mixed_addresses = IndexSet::new(); + unnamed_accounts_and_personas_mixed_addresses.extend( + unnamed_accounts + .clone() + .into_iter() + .map(|e| e.address()) + .map(AddressOfAccountOrPersona::from), + ); + unnamed_accounts_and_personas_mixed_addresses.extend( + unnamed_personas + .clone() + .into_iter() + .map(|e| e.address()) + .map(AddressOfAccountOrPersona::from), + ); + let (_, derivation_outcome) = os - .__OFFLINE_ONLY_securify_accounts( - unnamed_accounts - .clone() - .iter() - .map(|a| a.address()) - .collect(), + .__OFFLINE_ONLY_securify_entities( + unnamed_accounts_and_personas_mixed_addresses, &shield_0, ) .await @@ -2766,14 +2827,29 @@ async fn securified_accounts_asymmetric_indices() { os.clear_cache().await; // CLEAR CACHE - let (more_unnamed_accounts, _) = os.batch_create_many_accounts_with_bdfs_with_derivation_outcome_then_save_once(2 * CACHE_FILLING_QUANTITY as u16, network, "more".to_owned()).await.unwrap(); + let (more_unnamed_accounts, _) = os.batch_create_many_accounts_with_bdfs_with_derivation_outcome_then_save_once(2 * CACHE_FILLING_QUANTITY as u16, network, "more accounts".to_owned()).await.unwrap(); - let (many_securified_accounts, derivation_outcome) = os - .__OFFLINE_ONLY_securify_accounts( - more_unnamed_accounts - .into_iter() - .map(|a| a.address()) - .collect(), + let (more_unnamed_personas, _) = os.batch_create_many_personas_with_bdfs_with_derivation_outcome_then_save_once(2 * CACHE_FILLING_QUANTITY as u16, network, "more personas".to_owned()).await.unwrap(); + + let mut unnamed_accounts_and_personas_mixed_addresses = IndexSet::new(); + unnamed_accounts_and_personas_mixed_addresses.extend( + more_unnamed_accounts + .clone() + .into_iter() + .map(|e| e.address()) + .map(AddressOfAccountOrPersona::from), + ); + unnamed_accounts_and_personas_mixed_addresses.extend( + more_unnamed_personas + .clone() + .into_iter() + .map(|e| e.address()) + .map(AddressOfAccountOrPersona::from), + ); + + let (many_securified_entities, derivation_outcome) = os + .__OFFLINE_ONLY_securify_entities( + unnamed_accounts_and_personas_mixed_addresses.clone(), &shield_3fa, ) .await @@ -2785,51 +2861,96 @@ async fn securified_accounts_asymmetric_indices() { ); os.clear_cache().await; // CLEAR CACHE - for index in 0..many_securified_accounts.len() { - let securified_account = many_securified_accounts + for index in 0..many_securified_entities.len() { + let securified_entity = many_securified_entities .clone() .into_iter() .nth(index) .unwrap(); let offset = (index + 1) as u32; - - assert_eq!( - securified_account - .try_get_secured_control() - .unwrap() - .security_structure - .matrix_of_factors - .primary_role - .all_hd_factors() + if securified_entity.is_account_entity() { + assert_eq!( + securified_entity + .try_get_secured_control() + .unwrap() + .security_structure + .matrix_of_factors + .primary_role + .all_hd_factors() + .into_iter() + .map(|f| (f.factor_source_id, f.derivation_entity_index())) + .collect::>(), + [ + ( + bdfs.id_from_hash(), + HDPathComponent::Securified( + SecurifiedU30::try_from(diana_mfa_device + offset) + .unwrap() + ) + ), + ( + arculus.id_from_hash(), + HDPathComponent::Securified( + SecurifiedU30::try_from(diana_mfa_arculus + offset) + .unwrap() + ) + ), + ( + ledger.id_from_hash(), + HDPathComponent::Securified( + SecurifiedU30::try_from(diana_mfa_ledger + offset) + .unwrap() + ) + ), + ] .into_iter() - .map(|f| (f.factor_source_id, f.derivation_entity_index())) - .collect::>(), - [ - ( - bdfs.id_from_hash(), - HDPathComponent::Securified( - SecurifiedU30::try_from(diana_mfa_device + offset) + .collect::>() + ); + } else { + pretty_assertions::assert_eq!( + securified_entity + .try_get_secured_control() + .unwrap() + .security_structure + .matrix_of_factors + .primary_role + .all_hd_factors() + .into_iter() + .map(|f| (f.factor_source_id, f.derivation_entity_index())) + .collect::>(), + [ + ( + bdfs.id_from_hash(), + HDPathComponent::Securified( + SecurifiedU30::try_from( + offset - more_unnamed_accounts.len() as u32 + ) .unwrap() - ) - ), - ( - arculus.id_from_hash(), - HDPathComponent::Securified( - SecurifiedU30::try_from(diana_mfa_arculus + offset) + ) + ), + ( + arculus.id_from_hash(), + HDPathComponent::Securified( + SecurifiedU30::try_from( + offset - more_unnamed_accounts.len() as u32 + ) .unwrap() - ) - ), - ( - ledger.id_from_hash(), - HDPathComponent::Securified( - SecurifiedU30::try_from(diana_mfa_ledger + offset) + ) + ), + ( + ledger.id_from_hash(), + HDPathComponent::Securified( + SecurifiedU30::try_from( + offset - more_unnamed_accounts.len() as u32 + ) .unwrap() - ) - ), - ] - .into_iter() - .collect::>() - ); + ) + ), + ] + .into_iter() + .collect::>() + ); + } } } diff --git a/crates/sargon/src/profile/logic/account/query_accounts.rs b/crates/sargon/src/profile/logic/account/query_accounts.rs index 0bdbace8d..37e244ff7 100644 --- a/crates/sargon/src/profile/logic/account/query_accounts.rs +++ b/crates/sargon/src/profile/logic/account/query_accounts.rs @@ -47,6 +47,20 @@ impl Profile { Err(CommonError::UnknownAccount) } + pub fn entity_by_address( + &self, + entity_address: AddressOfAccountOrPersona, + ) -> Result { + self.networks + .get_id(entity_address.network_id()) + .and_then(|n| n.entity_by_address(&entity_address)) + .ok_or(if entity_address.is_account() { + CommonError::UnknownAccount + } else { + CommonError::UnknownPersona + }) + } + pub fn get_entities_of_kind_on_network_in_key_space( &self, entity_kind: CAP26EntityKind, diff --git a/crates/sargon/src/profile/logic/profile_network/profile_network_get_entities.rs b/crates/sargon/src/profile/logic/profile_network/profile_network_get_entities.rs index 8996c2ca6..844d3889b 100644 --- a/crates/sargon/src/profile/logic/profile_network/profile_network_get_entities.rs +++ b/crates/sargon/src/profile/logic/profile_network/profile_network_get_entities.rs @@ -48,13 +48,24 @@ impl ProfileNetwork { .collect() } + pub fn entity_by_address( + &self, + entity_address: &AddressOfAccountOrPersona, + ) -> Option { + let entities = self + .get_entities_erased(entity_address.get_entity_kind()) + .into_iter() + .filter(|e| e.address() == *entity_address) + .collect_vec(); + assert!(entities.len() <= 1); + entities.first().cloned() + } + pub fn contains_entity_by_address( &self, entity_address: &AddressOfAccountOrPersona, ) -> bool { - self.get_entities_erased(entity_address.get_entity_kind()) - .into_iter() - .any(|e| e.address() == *entity_address) + self.entity_by_address(entity_address).is_some() } } diff --git a/crates/sargon/src/profile/supporting_types/account_or_persona.rs b/crates/sargon/src/profile/supporting_types/account_or_persona.rs index 591699b84..d2513cabd 100644 --- a/crates/sargon/src/profile/supporting_types/account_or_persona.rs +++ b/crates/sargon/src/profile/supporting_types/account_or_persona.rs @@ -27,6 +27,12 @@ impl HasSecurityState for AccountOrPersona { Self::PersonaEntity(p) => p.security_state(), } } + fn set_security_state_unchecked(&mut self, new_state: EntitySecurityState) { + match self { + Self::AccountEntity(a) => a.set_security_state_unchecked(new_state), + Self::PersonaEntity(p) => p.set_security_state_unchecked(new_state), + } + } } impl IsKeySpaceAware for AccountOrPersona { diff --git a/crates/sargon/src/profile/v100/entity/account/account.rs b/crates/sargon/src/profile/v100/entity/account/account.rs index 09b268a67..68b4a1a9d 100644 --- a/crates/sargon/src/profile/v100/entity/account/account.rs +++ b/crates/sargon/src/profile/v100/entity/account/account.rs @@ -82,6 +82,9 @@ impl HasSecurityState for Account { fn security_state(&self) -> EntitySecurityState { self.security_state.clone() } + fn set_security_state_unchecked(&mut self, new_state: EntitySecurityState) { + self.security_state = new_state; + } } impl IsSecurityStateAware for Account { diff --git a/crates/sargon/src/profile/v100/entity/has_security_state.rs b/crates/sargon/src/profile/v100/entity/has_security_state.rs index 389977716..3466f7126 100644 --- a/crates/sargon/src/profile/v100/entity/has_security_state.rs +++ b/crates/sargon/src/profile/v100/entity/has_security_state.rs @@ -2,6 +2,40 @@ use crate::prelude::*; pub trait HasSecurityState: HasFactorInstances + IsSecurityStateAware { fn security_state(&self) -> EntitySecurityState; + fn set_security_state_unchecked(&mut self, new_state: EntitySecurityState); + + fn set_security_state( + &mut self, + new_state: EntitySecurityState, + ) -> Result<()> { + match (&self.security_state(), &new_state) { + ( + &EntitySecurityState::Securified { .. }, + &EntitySecurityState::Unsecured { .. }, + ) => { + Err(CommonError::SecurityStateSecurifiedButExpectedUnsecurified) + } + ( + EntitySecurityState::Securified { + value: sec_existing, + }, + EntitySecurityState::Securified { value: sec_new }, + ) => { + if sec_new.access_controller_address + != sec_existing.access_controller_address + { + Err(CommonError::SecurityStateAccessControllerAddressMismatch) + } else { + self.set_security_state_unchecked(new_state); + Ok(()) + } + } + _ => { + self.set_security_state_unchecked(new_state); + Ok(()) + } + } + } fn try_get_secured_control(&self) -> Result { self.security_state() diff --git a/crates/sargon/src/profile/v100/entity/persona/persona.rs b/crates/sargon/src/profile/v100/entity/persona/persona.rs index d59181548..9671040f3 100644 --- a/crates/sargon/src/profile/v100/entity/persona/persona.rs +++ b/crates/sargon/src/profile/v100/entity/persona/persona.rs @@ -75,6 +75,9 @@ impl HasSecurityState for Persona { fn security_state(&self) -> EntitySecurityState { self.security_state.clone() } + fn set_security_state_unchecked(&mut self, new_state: EntitySecurityState) { + self.security_state = new_state; + } } impl IsBaseEntity for Persona { type Address = IdentityAddress; diff --git a/crates/sargon/src/profile/v100/networks/network/profile_network.rs b/crates/sargon/src/profile/v100/networks/network/profile_network.rs index 152f6c257..d74b78523 100644 --- a/crates/sargon/src/profile/v100/networks/network/profile_network.rs +++ b/crates/sargon/src/profile/v100/networks/network/profile_network.rs @@ -163,22 +163,28 @@ impl ProfileNetwork { &mut self, updated_entities: IdentifiedVecOf, ) -> Result<()> { - match E::entity_kind() { - CAP26EntityKind::Account => { - updated_entities.to_accounts().and_then(|xs| { - self.accounts - .update_items(xs) - .map_err(|_| CommonError::UnknownAccount) - }) - } - CAP26EntityKind::Identity => { - updated_entities.to_personas().and_then(|xs| { - self.personas - .update_items(xs) - .map_err(|_| CommonError::UnknownPersona) - }) - } + self.update_entities_erased( + updated_entities.into_iter().map(Into::into).collect(), + ) + } + + pub fn update_entities_erased( + &mut self, + updated_entities: IdentifiedVecOf, + ) -> Result<()> { + for entity in updated_entities { + match entity { + AccountOrPersona::AccountEntity(account) => self + .accounts + .try_update_with(&account.id(), |a| *a = account.clone()) + .map_err(|_| CommonError::UnknownAccount), + AccountOrPersona::PersonaEntity(persona) => self + .personas + .try_update_with(&persona.id(), |p| *p = persona.clone()) + .map_err(|_| CommonError::UnknownPersona), + }?; } + Ok(()) } /// Returns a clone of the updated account if found, else None. diff --git a/crates/sargon/src/profile/v100/networks/profile_networks.rs b/crates/sargon/src/profile/v100/networks/profile_networks.rs index b5b9e104d..299ed5a8f 100644 --- a/crates/sargon/src/profile/v100/networks/profile_networks.rs +++ b/crates/sargon/src/profile/v100/networks/profile_networks.rs @@ -23,11 +23,20 @@ impl ProfileNetworks { pub fn update_entities( &mut self, updated_entities: IdentifiedVecOf, + ) -> Result<()> { + self.update_entities_erased( + updated_entities.into_iter().map(Into::into).collect(), + ) + } + + pub fn update_entities_erased( + &mut self, + updated_entities: IdentifiedVecOf, ) -> Result<()> { let network = updated_entities.assert_elements_not_empty_and_on_same_network()?; self.try_try_update_with(&network, |n| { - n.update_entities(updated_entities.clone()) + n.update_entities_erased(updated_entities.clone()) }) } diff --git a/crates/sargon/src/profile/v100/profile.rs b/crates/sargon/src/profile/v100/profile.rs index 1644a7450..ff649081f 100644 --- a/crates/sargon/src/profile/v100/profile.rs +++ b/crates/sargon/src/profile/v100/profile.rs @@ -290,10 +290,22 @@ impl Profile { &self, entities: IdentifiedVecOf, ) -> Result<()> { - let instances_of_new_entities = entities + let entities = entities .items() .into_iter() .map(Into::::into) + .collect::>(); + + self.assert_new_factor_instances_not_already_used_erased(entities) + } + + pub fn assert_new_factor_instances_not_already_used_erased( + &self, + entities: IdentifiedVecOf, + ) -> Result<()> { + let instances_of_new_entities = entities + .items() + .into_iter() .map(|e| (e.clone(), e.unique_all_factor_instances())) .collect::>>(); @@ -392,7 +404,16 @@ impl Profile { &mut self, updated_entities: IdentifiedVecOf, ) -> Result<()> { - self.networks.update_entities(updated_entities) + self.update_entities_erased( + updated_entities.into_iter().map(Into::into).collect(), + ) + } + + pub fn update_entities_erased( + &mut self, + updated_entities: IdentifiedVecOf, + ) -> Result<()> { + self.networks.update_entities_erased(updated_entities) } /// Returns a clone of the updated account if found, else None. diff --git a/crates/sargon/src/system/sargon_os/profile_state_holder.rs b/crates/sargon/src/system/sargon_os/profile_state_holder.rs index 0d4e1f043..7102c7334 100644 --- a/crates/sargon/src/system/sargon_os/profile_state_holder.rs +++ b/crates/sargon/src/system/sargon_os/profile_state_holder.rs @@ -86,6 +86,13 @@ impl ProfileStateHolder { }) } + pub fn entity_by_address( + &self, + entity_address: AddressOfAccountOrPersona, + ) -> Result { + self.try_access_profile_with(|p| p.entity_by_address(entity_address)) + } + /// Looks up the account by account address, returns Err if the account is /// unknown, will return a hidden account if queried for. pub fn account_by_address( diff --git a/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs b/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs index 56babcb5b..789349428 100644 --- a/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs +++ b/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs @@ -31,6 +31,13 @@ impl SargonOS { self.profile_state_holder.account_by_address(address) } + pub fn entity_by_address( + &self, + entity_address: AddressOfAccountOrPersona, + ) -> Result { + self.profile_state_holder.entity_by_address(entity_address) + } + /// Creates a new unsaved mainnet account named "Unnamed {N}", where `N` is the /// index of the next account for the BDFS. /// @@ -603,19 +610,57 @@ impl SargonOS { pub async fn update_entities( &self, updated: IdentifiedVecOf, + ) -> Result<()> { + self.update_entities_erased( + updated.into_iter().map(Into::into).collect(), + ) + .await + } + + pub async fn update_entities_erased( + &self, + updated: IdentifiedVecOf, ) -> Result<()> { let addresses = updated .clone() .into_iter() .map(|e| e.address()) .collect::>(); - self.update_profile_with(|p| p.update_entities(updated.clone())) + + let account_addresses = addresses + .iter() + .filter_map(|e| e.as_account()) + .cloned() + .collect::>(); + let identity_addresses = addresses + .iter() + .filter_map(|e| e.as_identity()) + .cloned() + .collect::>(); + + let modified_any_account = !account_addresses.is_empty(); + let modified_any_persona = !identity_addresses.is_empty(); + + self.update_profile_with(|p| p.update_entities_erased(updated.clone())) .await?; - if let Some(event) = E::profile_modified_event(true, addresses) { - self.event_bus - .emit(EventNotification::profile_modified(event)) - .await; + if modified_any_account { + if let Some(event) = + Account::profile_modified_event(true, account_addresses) + { + self.event_bus + .emit(EventNotification::profile_modified(event)) + .await; + } + } + if modified_any_persona { + if let Some(event) = + Persona::profile_modified_event(true, identity_addresses) + { + self.event_bus + .emit(EventNotification::profile_modified(event)) + .await; + } } Ok(()) } From a8146bbec912dbecc1df6e71937056735904fa97 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Fri, 20 Dec 2024 10:29:24 +0100 Subject: [PATCH 55/60] [no ci] WIP --- .../factor_instances_provider_unit_tests.rs | 132 +++++++----------- 1 file changed, 50 insertions(+), 82 deletions(-) diff --git a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider_unit_tests.rs b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider_unit_tests.rs index 4e0810109..9e966db78 100644 --- a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider_unit_tests.rs +++ b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider_unit_tests.rs @@ -2868,89 +2868,57 @@ async fn securified_accounts_and_personas_mixed_asymmetric_indices() { .nth(index) .unwrap(); - let offset = (index + 1) as u32; - if securified_entity.is_account_entity() { - assert_eq!( - securified_entity - .try_get_secured_control() - .unwrap() - .security_structure - .matrix_of_factors - .primary_role - .all_hd_factors() - .into_iter() - .map(|f| (f.factor_source_id, f.derivation_entity_index())) - .collect::>(), - [ - ( - bdfs.id_from_hash(), - HDPathComponent::Securified( - SecurifiedU30::try_from(diana_mfa_device + offset) - .unwrap() - ) - ), - ( - arculus.id_from_hash(), - HDPathComponent::Securified( - SecurifiedU30::try_from(diana_mfa_arculus + offset) - .unwrap() - ) - ), - ( - ledger.id_from_hash(), - HDPathComponent::Securified( - SecurifiedU30::try_from(diana_mfa_ledger + offset) - .unwrap() - ) - ), - ] - .into_iter() - .collect::>() - ); + let (index_device, index_arculus, index_ledger) = if securified_entity + .is_account_entity() + { + let offset = (index + 1) as u32; + ( + diana_mfa_device + offset, + diana_mfa_arculus + offset, + diana_mfa_ledger + offset, + ) } else { - pretty_assertions::assert_eq!( - securified_entity - .try_get_secured_control() - .unwrap() - .security_structure - .matrix_of_factors - .primary_role - .all_hd_factors() - .into_iter() - .map(|f| (f.factor_source_id, f.derivation_entity_index())) - .collect::>(), - [ - ( - bdfs.id_from_hash(), - HDPathComponent::Securified( - SecurifiedU30::try_from( - offset - more_unnamed_accounts.len() as u32 - ) - .unwrap() - ) - ), - ( - arculus.id_from_hash(), - HDPathComponent::Securified( - SecurifiedU30::try_from( - offset - more_unnamed_accounts.len() as u32 - ) - .unwrap() - ) - ), - ( - ledger.id_from_hash(), - HDPathComponent::Securified( - SecurifiedU30::try_from( - offset - more_unnamed_accounts.len() as u32 - ) - .unwrap() - ) - ), - ] + let index_device = (unnamed_personas.len() + index + - more_unnamed_accounts.len()) + as u32; + let index_arculus = (index - more_unnamed_accounts.len()) as u32; + let index_ledger = (index - more_unnamed_accounts.len()) as u32; + (index_device, index_arculus, index_ledger) + }; + + pretty_assertions::assert_eq!( + securified_entity + .try_get_secured_control() + .unwrap() + .security_structure + .matrix_of_factors + .primary_role + .all_hd_factors() .into_iter() - .collect::>() - ); - } + .map(|f| (f.factor_source_id, f.derivation_entity_index())) + .collect::>(), + [ + ( + bdfs.id_from_hash(), + HDPathComponent::Securified( + SecurifiedU30::try_from(index_device).unwrap() + ) + ), + ( + arculus.id_from_hash(), + HDPathComponent::Securified( + SecurifiedU30::try_from(index_arculus).unwrap() + ) + ), + ( + ledger.id_from_hash(), + HDPathComponent::Securified( + SecurifiedU30::try_from(index_ledger).unwrap() + ) + ) + ] + .into_iter() + .collect::>() + ); } } From 92fe297ba8320721799dc734c5d5827441b5fb47 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Fri, 20 Dec 2024 10:34:09 +0100 Subject: [PATCH 56/60] fix last test --- .../factor_instances_provider_unit_tests.rs | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider_unit_tests.rs b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider_unit_tests.rs index 9e966db78..411bf52db 100644 --- a/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider_unit_tests.rs +++ b/crates/sargon/src/factor_instances_provider/provider/factor_instances_provider_unit_tests.rs @@ -2868,23 +2868,19 @@ async fn securified_accounts_and_personas_mixed_asymmetric_indices() { .nth(index) .unwrap(); - let (index_device, index_arculus, index_ledger) = if securified_entity - .is_account_entity() - { - let offset = (index + 1) as u32; - ( - diana_mfa_device + offset, - diana_mfa_arculus + offset, - diana_mfa_ledger + offset, - ) - } else { - let index_device = (unnamed_personas.len() + index - - more_unnamed_accounts.len()) - as u32; - let index_arculus = (index - more_unnamed_accounts.len()) as u32; - let index_ledger = (index - more_unnamed_accounts.len()) as u32; - (index_device, index_arculus, index_ledger) - }; + let (index_device, index_arculus, index_ledger) = + if securified_entity.is_account_entity() { + let offset = (index + 1) as u32; + ( + diana_mfa_device + offset, + diana_mfa_arculus + offset, + diana_mfa_ledger + offset, + ) + } else { + let base = + (index as i32 - more_unnamed_accounts.len() as i32) as u32; + (base + unnamed_personas.len() as u32, base, base) + }; pretty_assertions::assert_eq!( securified_entity From 8d0d1092616c29d39fbf0a25acb9c343213e36da Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Fri, 20 Dec 2024 11:39:09 +0100 Subject: [PATCH 57/60] add more tests --- .../profile/v100/entity/has_security_state.rs | 128 ++++++++++++++++++ .../system/sargon_os/sargon_os_accounts.rs | 54 ++++++-- 2 files changed, 174 insertions(+), 8 deletions(-) diff --git a/crates/sargon/src/profile/v100/entity/has_security_state.rs b/crates/sargon/src/profile/v100/entity/has_security_state.rs index 3466f7126..2f79b4df2 100644 --- a/crates/sargon/src/profile/v100/entity/has_security_state.rs +++ b/crates/sargon/src/profile/v100/entity/has_security_state.rs @@ -4,6 +4,8 @@ pub trait HasSecurityState: HasFactorInstances + IsSecurityStateAware { fn security_state(&self) -> EntitySecurityState; fn set_security_state_unchecked(&mut self, new_state: EntitySecurityState); + // TODO: Should we check `provisional_securified_config` of `self` and/or + // of `new_state`? fn set_security_state( &mut self, new_state: EntitySecurityState, @@ -57,3 +59,129 @@ impl HasFactorInstances for T { self.security_state().unique_tx_signing_factor_instances() } } + +#[cfg(test)] +mod tests { + + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = AccountOrPersona; + + fn test_set_security_state_fail_cannot_unsecurify(sut: impl Into) { + let mut sut = sut.into(); + assert!(sut.is_securified()); + + let unsecurified = EntitySecurityState::sample(); + assert!(unsecurified.is_unsecured()); + + let result = sut.set_security_state(unsecurified); + assert_eq!( + result, + Err(CommonError::SecurityStateSecurifiedButExpectedUnsecurified) + ); + + // assert unchanged + assert!(sut.is_securified()); + } + + #[test] + fn set_security_state_fail_cannot_unsecurify_account() { + test_set_security_state_fail_cannot_unsecurify(Account::sample_at(2)) + } + + #[test] + fn set_security_state_fail_cannot_unsecurify_persona() { + test_set_security_state_fail_cannot_unsecurify(Persona::sample_at(2)) + } + + fn test_set_security_state_fail_can_change_unsecurified( + sut: impl Into, + ) { + let mut sut = sut.into(); + assert!(!sut.is_securified()); + + let unsecurified = EntitySecurityState::sample(); + assert!(unsecurified.is_unsecured()); + + let result = sut.set_security_state(unsecurified.clone()); + assert!(result.is_ok()); + assert_eq!(sut.security_state(), unsecurified); + } + + #[test] + fn set_security_state_fail_can_change_unsecurified_account() { + test_set_security_state_fail_can_change_unsecurified(Account::sample()); + } + + #[test] + fn set_security_state_fail_can_change_unsecurified_persona() { + test_set_security_state_fail_can_change_unsecurified(Persona::sample()); + } + + fn test_set_security_state_fail_access_controller_mismatch( + sut: impl Into, + ) { + let mut sut = sut.into(); + let entity_state = sut.security_state(); + assert!(sut.is_securified()); + + let other_securified = EntitySecurityState::Securified { + value: SecuredEntityControl::sample(), + }; + + let result = sut.set_security_state(other_securified); + assert_eq!( + result, + Err(CommonError::SecurityStateAccessControllerAddressMismatch) + ); + + // assert unchanged + assert_eq!(sut.security_state(), entity_state); + } + + #[test] + fn set_security_state_fail_access_controller_mismatch_account() { + test_set_security_state_fail_access_controller_mismatch( + Account::sample_at(2), + ); + } + + #[test] + fn set_security_state_fail_access_controller_mismatch_persona() { + test_set_security_state_fail_access_controller_mismatch( + Persona::sample_at(2), + ) + } + + fn test_set_security_state_can_change_securified(sut: impl Into) { + let mut sut = sut.into(); + let entity_state = sut.security_state(); + assert!(sut.is_securified()); + let access_controller_address = entity_state + .clone() + .as_securified() + .unwrap() + .access_controller_address; + + let mut value = SecuredEntityControl::sample(); + value.access_controller_address = access_controller_address; + let other_securified = EntitySecurityState::Securified { value }; + + let result = sut.set_security_state(other_securified); + + assert!(result.is_ok()); + assert!(sut.is_securified()); + assert_ne!(sut.security_state(), entity_state); + } + + #[test] + fn set_security_state_can_change_securified_account() { + test_set_security_state_can_change_securified(Account::sample_at(2)); + } + + #[test] + fn set_security_state_can_change_securified_persona() { + test_set_security_state_can_change_securified(Persona::sample_at(2)); + } +} diff --git a/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs b/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs index 789349428..e6b85d344 100644 --- a/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs +++ b/crates/sargon/src/system/sargon_os/sargon_os_accounts.rs @@ -1409,26 +1409,64 @@ mod tests { } #[actix_rt::test] - async fn update_account_updates_in_memory_profile() { + async fn update_account_and_persona_updates_in_memory_profile() { // ARRANGE - let os = SUT::fast_boot().await; + let event_bus_driver = RustEventBusDriver::new(); + let drivers = Drivers::with_event_bus(event_bus_driver.clone()); + let clients = Clients::new(Bios::new(drivers)); + let interactors = Interactors::new_from_clients(&clients); + let os = timeout( + SARGON_OS_TEST_MAX_ASYNC_DURATION, + SUT::boot_with_clients_and_interactor(clients, interactors), + ) + .await + .unwrap(); + os.new_wallet(false).await.unwrap(); let mut account = Account::sample(); os.with_timeout(|x| x.add_account(account.clone())) .await .unwrap(); - // ACT - account.display_name = DisplayName::random(); - os.with_timeout(|x| x.update_account(account.clone())) + let mut persona = Persona::sample(); + os.with_timeout(|x| x.add_persona(persona.clone())) .await .unwrap(); + // ACT + account.display_name = DisplayName::random(); + persona.display_name = DisplayName::random(); + os.with_timeout(|x| { + x.update_entities_erased(IdentifiedVecOf::from_iter([ + AccountOrPersona::from(account.clone()), + AccountOrPersona::from(persona.clone()), + ])) + }) + .await + .unwrap(); + // ASSERT + assert_eq!(os.profile().unwrap().networks[0].accounts[0], account); + assert_eq!(os.profile().unwrap().networks[0].personas[0], persona); + use EventKind::*; assert_eq!( - os.profile().unwrap().networks[0].accounts[0], - account.clone() - ) + event_bus_driver + .recorded() + .into_iter() + .map(|e| e.event.kind()) + .collect_vec(), + vec![ + Booted, + ProfileSaved, + ProfileSaved, + AccountAdded, + ProfileSaved, + PersonaAdded, + ProfileSaved, + AccountUpdated, + PersonaUpdated + ] + ); } #[actix_rt::test] From 717cd3d29bcf70bec9cad232519b006a13bb92cd Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Fri, 20 Dec 2024 11:57:21 +0100 Subject: [PATCH 58/60] Disallow setting FactorSource for ROLA to one with an unsupported/disallowed FactorSourceKind - add query methods which can query which kinds are supported/if a kind is supported --- .../security_shield_builder.rs | 52 ++++++++++++ .../security_shield_builder.rs | 84 ++++++++++++++++++- .../v100/factors/factor_source_kind.rs | 22 +++-- 3 files changed, 152 insertions(+), 6 deletions(-) diff --git a/crates/sargon-uniffi/src/profile/mfa/security_structures/security_shield_builder.rs b/crates/sargon-uniffi/src/profile/mfa/security_structures/security_shield_builder.rs index 7077057a8..4504cdfa3 100644 --- a/crates/sargon-uniffi/src/profile/mfa/security_structures/security_shield_builder.rs +++ b/crates/sargon-uniffi/src/profile/mfa/security_structures/security_shield_builder.rs @@ -252,6 +252,29 @@ impl SecurityShieldBuilder { #[uniffi::export] impl SecurityShieldBuilder { + /// "Statically" queries which FactorSourceKinds are disallowed for authentication signing. + pub fn disallowed_factor_source_kinds_for_authentication_signing( + &self, + ) -> Vec { + sargon::SecurityShieldBuilder::disallowed_factor_source_kinds_for_authentication_signing().into_type() + } + + /// "Statically" queries which FactorSourceKinds are allowed for authentication signing. + pub fn allowed_factor_source_kinds_for_authentication_signing( + &self, + ) -> Vec { + sargon::SecurityShieldBuilder::allowed_factor_source_kinds_for_authentication_signing().into_type() + } + + /// "Statically" queries if `factor_source_kind`` is allowed for authentication signing. + pub fn is_allowed_factor_source_kind_for_authentication_signing( + &self, + factor_source_kind: FactorSourceKind, + ) -> bool { + sargon::SecurityShieldBuilder::is_allowed_factor_source_kind_for_authentication_signing( + factor_source_kind.clone().into()) + } + pub fn addition_of_factor_source_of_kind_to_primary_threshold_is_fully_valid( &self, factor_source_kind: FactorSourceKind, @@ -561,6 +584,35 @@ mod tests { #[allow(clippy::upper_case_acronyms)] type SUT = SecurityShieldBuilder; + #[test] + fn rola() { + let sut = SUT::new(); + assert_eq!(sut.disallowed_factor_source_kinds_for_authentication_signing().len(), sargon::SecurityShieldBuilder::disallowed_factor_source_kinds_for_authentication_signing().len()); + + assert_eq!(sut.allowed_factor_source_kinds_for_authentication_signing().len(), sargon::SecurityShieldBuilder::allowed_factor_source_kinds_for_authentication_signing().len()); + + assert!( + sut.is_allowed_factor_source_kind_for_authentication_signing( + FactorSourceKind::Device + ) + ); + assert!( + !sut.is_allowed_factor_source_kind_for_authentication_signing( + FactorSourceKind::Password + ) + ); + assert!( + !sut.is_allowed_factor_source_kind_for_authentication_signing( + FactorSourceKind::TrustedContact + ) + ); + assert!( + !sut.is_allowed_factor_source_kind_for_authentication_signing( + FactorSourceKind::SecurityQuestions + ) + ); + } + #[test] fn test() { let sut = SUT::new(); diff --git a/crates/sargon/src/profile/mfa/security_structures/security_shield_builder.rs b/crates/sargon/src/profile/mfa/security_structures/security_shield_builder.rs index 5f4a63088..799ef8618 100644 --- a/crates/sargon/src/profile/mfa/security_structures/security_shield_builder.rs +++ b/crates/sargon/src/profile/mfa/security_structures/security_shield_builder.rs @@ -120,11 +120,26 @@ impl SecurityShieldBuilder { self } + /// Sets the ROLA (authentication signing) factor to `new` if and only if + /// `new` is not Some(invalid), where invalid is defined by `allowed_factor_source_kinds_for_authentication_signing`, + /// that is, it checks the `FactorSourceKind` of the factor, according to the + /// rules defined in [doc][doc]. + /// + /// [doc]: https://radixdlt.atlassian.net/wiki/spaces/AT/pages/3758063620/MFA+Rules+for+Factors+and+Security+Shield pub fn set_authentication_signing_factor( &self, new: impl Into>, ) -> &Self { - *self.authentication_signing_factor.write().unwrap() = new.into(); + let new = new.into(); + if let Some(new) = new.as_ref() { + if !Self::is_allowed_factor_source_kind_for_authentication_signing( + new.get_factor_source_kind(), + ) { + warn!("Invalid FactorSourceKind for ROLA"); + return self; + } + } + *self.authentication_signing_factor.write().unwrap() = new; self } @@ -295,6 +310,30 @@ impl SecurityShieldBuilder { } impl SecurityShieldBuilder { + pub fn disallowed_factor_source_kinds_for_authentication_signing( + ) -> IndexSet { + IndexSet::from_iter([ + FactorSourceKind::Password, + FactorSourceKind::SecurityQuestions, + FactorSourceKind::TrustedContact, + ]) + } + + pub fn allowed_factor_source_kinds_for_authentication_signing( + ) -> IndexSet { + let all = FactorSourceKind::all(); + let disallowed = + Self::disallowed_factor_source_kinds_for_authentication_signing(); + all.difference(&disallowed).cloned().collect() + } + + pub fn is_allowed_factor_source_kind_for_authentication_signing( + factor_source_kind: FactorSourceKind, + ) -> bool { + Self::allowed_factor_source_kinds_for_authentication_signing() + .contains(&factor_source_kind) + } + /// Returns `true` for `Ok` and `Err(NotYetValid)`. pub fn addition_of_factor_source_of_kind_to_primary_threshold_is_valid_or_can_be( &self, @@ -583,6 +622,49 @@ mod tests { assert_eq!(sut.get_threshold(), 42); } + #[test] + fn allowed_rola() { + let allowed = + SUT::allowed_factor_source_kinds_for_authentication_signing(); + assert_eq!( + allowed, + IndexSet::::from_iter([ + FactorSourceKind::LedgerHQHardwareWallet, + FactorSourceKind::ArculusCard, + FactorSourceKind::OffDeviceMnemonic, + FactorSourceKind::Device, + ]) + ); + } + + #[test] + fn is_allowed_rola() { + let disallowed = + SUT::disallowed_factor_source_kinds_for_authentication_signing(); + assert!(disallowed.iter().all(|k| { + !SUT::is_allowed_factor_source_kind_for_authentication_signing(*k) + })); + } + + #[test] + fn test_invalid_rola_kind_does_not_change_rola() { + let sut = SUT::new(); + assert!(sut.get_authentication_signing_factor().is_none()); + let valid = FactorSourceID::sample_device(); + sut.set_authentication_signing_factor(valid); + assert_eq!(sut.get_authentication_signing_factor().unwrap(), valid); + + let invalid_factors = vec![ + FactorSourceID::sample_password(), + FactorSourceID::sample_security_questions(), + FactorSourceID::sample_trusted_contact(), + ]; + for invalid in invalid_factors { + sut.set_authentication_signing_factor(invalid); // should not have changed anything + } + assert_eq!(sut.get_authentication_signing_factor().unwrap(), valid); + } + #[test] fn test() { let sut = SUT::default(); diff --git a/crates/sargon/src/profile/v100/factors/factor_source_kind.rs b/crates/sargon/src/profile/v100/factors/factor_source_kind.rs index 037f8a62e..c881b4ba3 100644 --- a/crates/sargon/src/profile/v100/factors/factor_source_kind.rs +++ b/crates/sargon/src/profile/v100/factors/factor_source_kind.rs @@ -11,6 +11,7 @@ use crate::prelude::*; Eq, Hash, PartialOrd, + enum_iterator::Sequence, Ord, )] pub enum FactorSourceKind { @@ -93,6 +94,13 @@ pub enum FactorSourceKind { TrustedContact, } +impl FactorSourceKind { + /// All FactorSourceKind + pub fn all() -> IndexSet { + enum_iterator::all::().collect() + } +} + impl FactorSourceKind { pub fn discriminant(&self) -> String { // We do `to_value.as_str` instead of `to_string(_pretty)` to avoid unwanted quotation marks around the string. @@ -168,6 +176,15 @@ mod tests { #[allow(clippy::upper_case_acronyms)] type SUT = FactorSourceKind; + #[test] + fn ord() { + assert!(SUT::Device < SUT::TrustedContact); + let unsorted = SUT::all(); // is in fact sorted + let mut sorted = unsorted.clone(); + sorted.sort(); + assert_eq!(unsorted, sorted); + } + #[test] fn string_roundtrip() { use FactorSourceKind::*; @@ -214,11 +231,6 @@ mod tests { ); } - #[test] - fn ord() { - assert!(SUT::Device < SUT::TrustedContact); - } - #[test] fn discriminant() { assert_eq!(SUT::Device.discriminant(), "device"); From 4d0b9ab73d232112e0fc6b29d1673190bbf0c7ca Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Fri, 20 Dec 2024 13:02:03 +0100 Subject: [PATCH 59/60] review fixes --- .../factor_instances_cache.rs | 157 ++++++++---------- 1 file changed, 69 insertions(+), 88 deletions(-) diff --git a/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs b/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs index e54f78bd0..f79eecaa5 100644 --- a/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs +++ b/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs @@ -272,80 +272,78 @@ impl FactorInstancesCache { let count_in_cache = for_preset.len(); - let val = if let Some(quantified_derivation_preset) = - quantified_derivation_presets.get_id(preset) - { - // The `preset` was part of the originally requested preset - // with a target quantity. - let target_quantity = quantified_derivation_preset.quantity; - - let is_quantity_satisfied = - count_in_cache >= target_quantity; - - if is_quantity_satisfied { - // The instances in the cache can satisfy the requested quantity - // for this factor source for this derivation preset - let v = CacheInstancesAndRemainingQuantityToDerive { - // 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.) - instances_to_use_from_cache: for_preset - .split_at(target_quantity) - .0, - quantity_to_derive: 0, - }; - - assert!(!v.instances_to_use_from_cache.is_empty()); - Some(v) - } else { - // 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; - let v = CacheInstancesAndRemainingQuantityToDerive { - instances_to_use_from_cache: for_preset.clone(), + let maybe_instances_with_remaining_qty_to_derive = + if let Some(quantified_derivation_preset) = + quantified_derivation_presets.get_id(preset) + { + // The `preset` was part of the originally requested preset + // with a target quantity. + let target_quantity = + quantified_derivation_preset.quantity; + + let is_quantity_satisfied = + count_in_cache >= target_quantity; + + if is_quantity_satisfied { + // The instances in the cache can satisfy the requested quantity + // for this factor source for this derivation preset + let instances_to_use_from_cache = + for_preset.split_at(target_quantity).0; + assert!(!instances_to_use_from_cache.is_empty()); + Some(CacheInstancesAndRemainingQuantityToDerive { + // 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.) + instances_to_use_from_cache, + quantity_to_derive: 0, + }) + } else { + // 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; + Some(CacheInstancesAndRemainingQuantityToDerive { + instances_to_use_from_cache: for_preset.clone(), + quantity_to_derive, + }) + } + } else if count_in_cache < cache_filling_quantity { + // Not 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. + let quantity_to_derive = + cache_filling_quantity - count_in_cache; + + Some(CacheInstancesAndRemainingQuantityToDerive { + instances_to_use_from_cache: + FactorInstances::default(), quantity_to_derive, - }; - assert!( - v.quantity_to_derive > 0 - || !v.instances_to_use_from_cache.is_empty() - ); - Some(v) - } - } else if count_in_cache < cache_filling_quantity { - // Not 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. - let quantity_to_derive = - cache_filling_quantity - count_in_cache; - - assert!(quantity_to_derive > 0); - - Some(CacheInstancesAndRemainingQuantityToDerive { - instances_to_use_from_cache: FactorInstances::default(), - quantity_to_derive, - }) - } else { - None - }; - if let Some(val) = val { - per_factor_source.insert(*factor_source_id, val); + }) + } else { + None + }; + if let Some(instances_with_remaining_qty_to_derive) = + maybe_instances_with_remaining_qty_to_derive + { + per_factor_source.insert( + *factor_source_id, + instances_with_remaining_qty_to_derive, + ); } } - if per_factor_source.is_empty() { - continue; + if !per_factor_source.is_empty() { + per_derivation_preset.insert(preset, per_factor_source); } - per_derivation_preset.insert(preset, per_factor_source); } let originally_request_presets = quantified_derivation_presets .iter() - .map(|x| x.derivation_preset) + .map(|quantified_preset| quantified_preset.derivation_preset) .collect::>(); // The instances in the cache cannot satisfy the requested quantity @@ -371,26 +369,12 @@ impl FactorInstancesCache { .filter(|(preset, _)| { originally_request_presets.contains(preset) }) - .map(|(preset, v)| { + .map(|(preset, per_factor)| { ( preset, - v.into_iter() - .map(|(fsid, x)| { - assert_eq!(x.quantity_to_derive, 0); - let instances = - x.instances_to_use_from_cache; - assert!(instances.clone().into_iter().all( - |fi| { - fi.factor_source_id() == fsid - && DerivationPreset::try_from( - fi.derivation_path() - .agnostic(), - ) - .unwrap() - == preset - } - )); - (fsid, instances) + per_factor.into_iter() + .map(|(fsid, instances_and_remaining_qty_to_derive)| { + (fsid, instances_and_remaining_qty_to_derive.instances_to_use_from_cache) }) .collect::>(), ) }) - .collect::, - >>(), + .collect::(), }) }; From ee842094071a10fdee5481f0705a6eed89c0395c Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Fri, 20 Dec 2024 13:22:44 +0100 Subject: [PATCH 60/60] review polish --- .../factor_instances_cache.rs | 30 +++++++++---------- ...rtual_entity_creating_instance_provider.rs | 12 ++++---- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs b/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs index f79eecaa5..b935ce6af 100644 --- a/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs +++ b/crates/sargon/src/factor_instances_provider/factor_instances_cache/factor_instances_cache.rs @@ -346,15 +346,20 @@ impl FactorInstancesCache { .map(|quantified_preset| quantified_preset.derivation_preset) .collect::>(); - // The instances in the cache cannot satisfy the requested quantity - // we must derive more! let is_quantity_unsatisfied_for_any_requested = - per_derivation_preset.iter().any(|(preset, pf)| { - originally_request_presets.contains(preset) /* Only lack of instances for originally requested presets is something which should cause the outcome of this reading from cache to be considered as `NotSatisfied` */ - && pf.iter().any(|(_, ci)| ci.quantity_to_derive > 0) + per_derivation_preset + .iter() + .any(|(preset, pf)| { + /* Only lack of instances for originally requested presets is something which should cause the outcome of this reading from cache to be considered as `NotSatisfied` */ + let was_preset_originally_requested = originally_request_presets.contains(preset); + let need_to_derive_more = pf.iter().any(|(_, instances_and_remaining_qty_to_derive)| instances_and_remaining_qty_to_derive.quantity_to_derive > 0); + // We need to derive more instances for this derivation preset + was_preset_originally_requested && need_to_derive_more }); let outcome = if is_quantity_unsatisfied_for_any_requested { + // The instances in the cache cannot satisfy the requested quantity + // we must derive more! CachedInstancesWithQuantitiesOutcome::NotSatisfied( CacheNotSatisfied { cached_and_quantities_to_derive: per_derivation_preset, @@ -421,12 +426,10 @@ impl CacheNotSatisfied { .clone() .into_iter() .filter_map(|(preset, v)| { - - let per_factor = v.into_iter() - .filter_map(|(x, y)| { - extract((x, y)) - }) - .collect::>(); + let per_factor = v + .into_iter() + .filter_map(|(x, y)| extract((x, y))) + .collect::>(); if per_factor.is_empty() { None @@ -434,10 +437,7 @@ impl CacheNotSatisfied { Some((preset, per_factor)) } }) - .collect::, - >>() + .collect() } pub fn cached_instances_to_use( diff --git a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs index 50699bb1d..1f8465586 100644 --- a/crates/sargon/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs +++ b/crates/sargon/src/factor_instances_provider/provider/provider_adopters/virtual_entity_creating_instance_provider.rs @@ -184,17 +184,17 @@ mod tests { == preset.cache_filling_quantity()) )); - for (k, v) in outcome.per_derivation_preset.iter() { - for (_, y) in v.per_factor.iter() { + for (preset, per_factor) in outcome.per_derivation_preset.iter() { + for (_, for_factor) in per_factor.per_factor.iter() { let derivation_based_offset = - if *k == DerivationPreset::IdentityVeci { - 1 /* One account created */ + if *preset == DerivationPreset::IdentityVeci { + 1 /* One persona created */ } else { 0 }; assert_eq!( - y.debug_was_derived.len(), - k.cache_filling_quantity() + derivation_based_offset + for_factor.debug_was_derived.len(), + preset.cache_filling_quantity() + derivation_based_offset ) } }