Skip to content
This repository was archived by the owner on Feb 4, 2025. It is now read-only.

FactorInstancesProvider #18

Merged
merged 73 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from 61 commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
551f555
Revert "WIP"
CyonAlexRDX Oct 9, 2024
b6a1a40
remove design.md
CyonAlexRDX Oct 9, 2024
92dd942
rename Cache -> FactorInstancesCache and rename FIProvider outcomes
CyonAlexRDX Oct 9, 2024
113045b
split outcome
CyonAlexRDX Oct 9, 2024
ceaee8b
add support for perseonas
CyonAlexRDX Oct 9, 2024
9f24311
add unit test mixing accounts and personas creation.
CyonAlexRDX Oct 9, 2024
3e1e6b6
WIP SEC pers
CyonAlexRDX Oct 10, 2024
863db76
WIP
CyonAlexRDX Oct 10, 2024
e7c4cec
cleanup and add docs
Sajjon Oct 10, 2024
289d76c
WIP
CyonAlexRDX Oct 10, 2024
b9f0637
WIP
CyonAlexRDX Oct 10, 2024
15c423c
WIP
CyonAlexRDX Oct 10, 2024
20b0810
WIP
CyonAlexRDX Oct 10, 2024
68e1a66
WIP
CyonAlexRDX Oct 10, 2024
4bdeabb
WIP
CyonAlexRDX Oct 10, 2024
1116345
Change `struct NetworkAgnosticPath` to `enum DerivationPreset`. Chang…
CyonAlexRDX Oct 10, 2024
e193399
WIP
CyonAlexRDX Oct 10, 2024
2aa8091
document cache, add tests, make validating instances
Sajjon Oct 10, 2024
080951c
split NextIndexAssigner
Sajjon Oct 10, 2024
674f272
tests for NextDerivationEntityIndexProfileAnalyzingAssigner
Sajjon Oct 10, 2024
b809f3e
docs
Sajjon Oct 10, 2024
0e96ce3
rename LocalOffsets -> EphemeralOffset, add tests of NextDerivationEn…
Sajjon Oct 10, 2024
416c2ee
remove unused code
Sajjon Oct 10, 2024
8136341
Doc KeySpace
CyonAlexRDX Oct 11, 2024
eceddfc
[no ci] prepare
CyonAlexRDX Oct 11, 2024
f74fcc3
[no ci] sketch query from cache
CyonAlexRDX Oct 11, 2024
8297d2c
[no ci] pf_quantity_missing_from_cache and pf_quantity_missing_from_c…
CyonAlexRDX Oct 11, 2024
60e9cae
[no ci] sketch derive_more
CyonAlexRDX Oct 11, 2024
002d475
[no ci] add `interactors` to `derive_more`
CyonAlexRDX Oct 11, 2024
0e73b27
[no ci] derive_more
CyonAlexRDX Oct 11, 2024
ac1e50c
[no ci] excluding works
CyonAlexRDX Oct 11, 2024
9358de1
pf_mixed
CyonAlexRDX Oct 11, 2024
827b05d
[no ci] sketch done
CyonAlexRDX Oct 11, 2024
f6845ed
[no ci] borken
CyonAlexRDX Oct 11, 2024
693b39f
[no ci] cleanup BROKEN
CyonAlexRDX Oct 11, 2024
70956bc
test append_to_or_insert and Cache::delete
Sajjon Oct 11, 2024
516a44f
hmm cache hmm
Sajjon Oct 11, 2024
5df0baf
hmm poly_factor_with_quantities
Sajjon Oct 11, 2024
c560bd1
hmm close I think
Sajjon Oct 11, 2024
7eb40ad
ok some tests working
Sajjon Oct 11, 2024
a9f36f1
getting there
Sajjon Oct 12, 2024
79aab62
pruning
Sajjon Oct 12, 2024
cec9c94
its working, its working its woooooooooorkiiiiiiing
Sajjon Oct 12, 2024
f439723
remove prints
Sajjon Oct 12, 2024
8983e31
split out NextIndex Cache analyzer
Sajjon Oct 12, 2024
0df13f3
remove unneeded lifetime
Sajjon Oct 12, 2024
a1db98e
remove unused code
Sajjon Oct 12, 2024
fd1f391
more appendable collection into seperate file
Sajjon Oct 12, 2024
e8736e4
clean up
Sajjon Oct 12, 2024
4ac0467
Merge pull request #19 from radixdlt/factor_instances_provider_simpli…
CyonAlexRDX Oct 12, 2024
6ec6af5
cleanup
Sajjon Oct 12, 2024
f989bce
clean up poly
CyonAlexRDX Oct 12, 2024
b2a2f8d
doc the get poly method
Sajjon Oct 12, 2024
2674ee2
split
Sajjon Oct 12, 2024
38cd499
split and doc
Sajjon Oct 12, 2024
1fec655
Merge pull request #20 from radixdlt/cache_cleanup
CyonAlexRDX Oct 12, 2024
47ce0bd
more docs
CyonAlexRDX Oct 14, 2024
c7c3951
split out special functions on FactorInstancesProvider to be adopters…
CyonAlexRDX Oct 14, 2024
c20c647
Merge pull request #21 from radixdlt/factor_instances_provider_ctor_m…
CyonAlexRDX Oct 14, 2024
1419d98
Ensure correct behaviour of KeysCollector fails due to Interactor. Ad…
CyonAlexRDX Oct 14, 2024
c6ef757
clean up
CyonAlexRDX Oct 14, 2024
fd21bfa
Update next_derivation_entity_index_profile_analyzing_assigner.rs
CyonAlexRDX Oct 15, 2024
40d9967
Update next_derivation_entity_index_profile_analyzing_assigner.rs
CyonAlexRDX Oct 15, 2024
f87e3e9
Update next_derivation_entity_index_profile_analyzing_assigner.rs
CyonAlexRDX Oct 15, 2024
9da8c85
review comments
Sajjon Oct 15, 2024
250a460
clean up
Sajjon Oct 15, 2024
8feb867
clean up
Sajjon Oct 15, 2024
72bfe24
clean up
Sajjon Oct 15, 2024
420f4f3
fix err in doc
Sajjon Oct 15, 2024
d772506
fix bug where we did not scan VECIs of securified accounts
Sajjon Oct 15, 2024
371d5bb
add
Sajjon Oct 15, 2024
2bbdb80
add tests for IndexAgnosticPath and DerivationPreset conversion.
Sajjon Oct 15, 2024
e824680
Update next_derivation_entity_index_with_ephemeral_offsets_for_factor…
CyonAlexRDX Oct 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"cSpell.words": [
"analyser",
"Appendable",
"Banksy",
"bdfs",
"Fulfillable",
Expand Down
92 changes: 92 additions & 0 deletions src/factor_instances_provider/agnostic_paths/derivation_preset.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
use crate::prelude::*;

/// Derivation Presets are Network agnostic and Index agnostic
/// "templates" for DerivationPaths.
#[derive(Clone, Copy, Hash, PartialEq, Eq, enum_iterator::Sequence, derive_more::Debug)]
pub enum DerivationPreset {
/// Used to form DerivationPaths used to derive FactorInstances
/// for "veci": Virtual Entity Creating (Factor)Instance for accounts.
/// `(EntityKind::Account, KeySpace::Unsecurified, KeyKind::TransactionSigning)`
#[debug("A-VECI")]
AccountVeci,

/// Used to form DerivationPaths used to derive FactorInstances
/// for "mfa" to securify accounts.
/// `(EntityKind::Account, KeySpace::Securified, KeyKind::TransactionSigning)`
#[debug("A-MFA")]
AccountMfa,

/// Used to form DerivationPaths used to derive FactorInstances
/// for "veci": Virtual Entity Creating (Factor)Instance for personas.
/// `(EntityKind::Identity, KeySpace::Unsecurified, KeyKind::TransactionSigning)`
#[debug("I-VECI")]
IdentityVeci,

/// Used to form DerivationPaths used to derive FactorInstances
/// for "mfa" to securify personas.
/// `(EntityKind::Identity, KeySpace::Securified, KeyKind::TransactionSigning)`
#[debug("I-MFA")]
IdentityMfa,
}

// =============
// Construction
// =============
impl DerivationPreset {
/// All DerivationPreset's, used to fill cache.
pub fn all() -> IndexSet<Self> {
enum_iterator::all::<Self>().collect()
}

/// Selects a `DerivationPreset` for veci based on `CAP26EntityKind`,
/// i.e. either `DerivationPreset::AccountVeci` or `DerivationPreset::IdentityVeci`.
pub fn veci_entity_kind(entity_kind: CAP26EntityKind) -> Self {
match entity_kind {
CAP26EntityKind::Account => Self::AccountVeci,
CAP26EntityKind::Identity => Self::IdentityVeci,
}
}

/// Selects a `DerivationPreset` for MFA based on `CAP26EntityKind`,
/// i.e. either `DerivationPreset::AccountMfa` or `DerivationPreset::IdentityMfa`.
pub fn mfa_entity_kind(entity_kind: CAP26EntityKind) -> Self {
match entity_kind {
CAP26EntityKind::Account => Self::AccountMfa,
CAP26EntityKind::Identity => Self::IdentityMfa,
}
}
}

// =============
// Instance Methods
// =============
impl DerivationPreset {
/// Returns the `CAP26EntityKind` of the `DerivationPreset`.
pub fn entity_kind(&self) -> CAP26EntityKind {
match self {
Self::AccountVeci | Self::AccountMfa => CAP26EntityKind::Account,
Self::IdentityVeci | Self::IdentityMfa => CAP26EntityKind::Identity,
}
}

/// Returns the `CAP26KeyKind` of the `DerivationPreset`.
pub fn key_kind(&self) -> CAP26KeyKind {
match self {
Self::AccountVeci | Self::IdentityVeci => CAP26KeyKind::TransactionSigning,
Self::AccountMfa | Self::IdentityMfa => CAP26KeyKind::TransactionSigning,
}
}

/// Returns the `KeySpace` of the `DerivationPreset`.
pub fn key_space(&self) -> KeySpace {
match self {
Self::AccountVeci | Self::IdentityVeci => KeySpace::Unsecurified,
Self::AccountMfa | Self::IdentityMfa => KeySpace::Securified,
}
}

/// Maps a DerivationPreset to a `IndexAgnosticPath` which is network aware.
pub fn index_agnostic_path_on_network(&self, network_id: NetworkID) -> IndexAgnosticPath {
IndexAgnosticPath::from((network_id, *self))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
use crate::prelude::*;

use super::quantities;

/// A DerivationPath which is not indexed. On a specific network.
#[derive(Clone, Copy, Hash, PartialEq, Eq, derive_more::Debug, derive_more::Display)]
#[display("{}/{}/{}/?{}", network_id, entity_kind, key_kind, key_space.indicator())]
#[debug("{:?}/{:?}/{:?}/?{}", network_id, entity_kind, key_kind, key_space.indicator())]
pub struct IndexAgnosticPath {
pub network_id: NetworkID,
pub entity_kind: CAP26EntityKind,
pub key_kind: CAP26KeyKind,
pub key_space: KeySpace,
}

impl IndexAgnosticPath {
pub fn new(
network_id: NetworkID,
entity_kind: CAP26EntityKind,
key_kind: CAP26KeyKind,
key_space: KeySpace,
) -> Self {
Self {
network_id,
entity_kind,
key_kind,
key_space,
}
}
}

impl From<(NetworkID, DerivationPreset)> for IndexAgnosticPath {
fn from((network_id, agnostic_path): (NetworkID, DerivationPreset)) -> Self {
Self::new(
network_id,
agnostic_path.entity_kind(),
agnostic_path.key_kind(),
agnostic_path.key_space(),
)
}
}

impl TryFrom<IndexAgnosticPath> for DerivationPreset {
type Error = CommonError;
/// Tries to convert an IndexAgnosticPath to a DerivationPreset,
/// is failing if the path is not a standard DerivationPreset
fn try_from(value: IndexAgnosticPath) -> Result<DerivationPreset> {
match (value.entity_kind, value.key_kind, value.key_space) {
(
CAP26EntityKind::Account,
CAP26KeyKind::TransactionSigning,
KeySpace::Unsecurified,
) => Ok(DerivationPreset::AccountVeci),
(
CAP26EntityKind::Identity,
CAP26KeyKind::TransactionSigning,
KeySpace::Unsecurified,
) => Ok(DerivationPreset::IdentityVeci),
(CAP26EntityKind::Account, CAP26KeyKind::TransactionSigning, KeySpace::Securified) => {
Ok(DerivationPreset::AccountMfa)
}
(CAP26EntityKind::Identity, CAP26KeyKind::TransactionSigning, KeySpace::Securified) => {
Ok(DerivationPreset::IdentityMfa)
}
_ => Err(CommonError::NonStandardDerivationPath),

Check warning on line 65 in src/factor_instances_provider/agnostic_paths/index_agnostic_path.rs

View check run for this annotation

Codecov / codecov/patch

src/factor_instances_provider/agnostic_paths/index_agnostic_path.rs#L65

Added line #L65 was not covered by tests
}
}
}

impl From<(IndexAgnosticPath, HDPathComponent)> for DerivationPath {
fn from((path, index): (IndexAgnosticPath, HDPathComponent)) -> Self {
assert_eq!(index.key_space(), path.key_space);
Self::new(path.network_id, path.entity_kind, path.key_kind, index)
}
}

impl DerivationPath {
pub fn agnostic(&self) -> IndexAgnosticPath {
IndexAgnosticPath {
network_id: self.network_id,
entity_kind: self.entity_kind,
key_kind: self.key_kind,
key_space: self.key_space(),
}
}
}
impl HierarchicalDeterministicFactorInstance {
pub fn agnostic_path(&self) -> IndexAgnosticPath {
self.derivation_path().agnostic()
}
}
9 changes: 9 additions & 0 deletions src/factor_instances_provider/agnostic_paths/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
mod derivation_preset;
mod index_agnostic_path;
mod quantified_derivation_preset;
mod quantities;

pub use derivation_preset::*;
pub use index_agnostic_path::*;
pub use quantified_derivation_preset::*;
pub use quantities::*;
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use crate::prelude::*;

#[derive(Clone, Copy, Hash, PartialEq, Eq, derive_more::Debug)]
#[debug("🎯: {:?} #{}", self.derivation_preset, self.quantity)]
pub struct QuantifiedDerivationPreset {
pub derivation_preset: DerivationPreset,
pub quantity: usize,
}

impl QuantifiedDerivationPreset {
pub fn new(derivation_preset: DerivationPreset, quantity: usize) -> Self {
Self {
derivation_preset,
quantity,
}
}
}
4 changes: 4 additions & 0 deletions src/factor_instances_provider/agnostic_paths/quantities.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
use crate::prelude::*;

/// The quantity of DerivationPreset's to fill cache with.
pub const CACHE_FILLING_QUANTITY: usize = 30;
7 changes: 7 additions & 0 deletions src/factor_instances_provider/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
mod agnostic_paths;
mod next_index_assigner;
mod provider;

pub use agnostic_paths::*;
pub use next_index_assigner::*;
pub use provider::*;
11 changes: 11 additions & 0 deletions src/factor_instances_provider/next_index_assigner/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
mod next_derivation_entity_index_assigner;
mod next_derivation_entity_index_cache_analyzing_assigner;
mod next_derivation_entity_index_profile_analyzing_assigner;
mod next_derivation_entity_index_with_ephemeral_offsets;
mod next_derivation_entity_index_with_ephemeral_offsets_for_factor_source;

pub use next_derivation_entity_index_assigner::*;
pub use next_derivation_entity_index_cache_analyzing_assigner::*;
pub use next_derivation_entity_index_profile_analyzing_assigner::*;
pub use next_derivation_entity_index_with_ephemeral_offsets::*;
pub use next_derivation_entity_index_with_ephemeral_offsets_for_factor_source::*;
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
use crate::prelude::*;

/// An assigner of derivation entity indices, used by the FactorInstancesProvider
/// to map `IndexAgnosticPath` -> `DerivationPath` for some FactorSource on
/// some NetworkID.
///
/// This assigner works with the:
/// * cache
/// * profile
/// * local offsets
///
/// More specifically the assigner's `next` method performs approximately this
/// operation:
///
/// ```ignore
/// pub fn next(
/// &mut self,
/// fs_id: FactorSourceIDFromHash,
/// path: IndexAgnosticPath,
/// ) -> Result<HDPathComponent> {
/// let next_from_cache = self.cache_analyzing.next(fs_id, path).unwrap_or(0);
/// let next_from_profile = self.profile_analyzing.next(fs_id, path).unwrap_or(0);
///
/// let max_index = std::cmp::max(next_from_profile, next_from_cache);
/// let ephemeral_offset = self.ephemeral_offsets.reserve()
///
/// max_index + ephemeral_offset
/// ```
pub struct NextDerivationEntityIndexAssigner {
#[allow(dead_code)]
network_id: NetworkID,
profile_analyzing: NextDerivationEntityIndexProfileAnalyzingAssigner,
cache_analyzing: NextDerivationEntityIndexCacheAnalyzingAssigner,
ephemeral_offsets: NextDerivationEntityIndexWithEphemeralOffsets,
}

impl NextDerivationEntityIndexAssigner {
pub fn new(
network_id: NetworkID,
profile: impl Into<Option<Profile>>,
cache: FactorInstancesCache,
) -> Self {
let profile_analyzing =
NextDerivationEntityIndexProfileAnalyzingAssigner::new(network_id, profile);

Check warning on line 44 in src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_assigner.rs

View check run for this annotation

Codecov / codecov/patch

src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_assigner.rs#L44

Added line #L44 was not covered by tests
let cache_analyzing = NextDerivationEntityIndexCacheAnalyzingAssigner::new(cache);
let ephemeral_offsets = NextDerivationEntityIndexWithEphemeralOffsets::default();
Self {
network_id,
profile_analyzing,
cache_analyzing,
ephemeral_offsets,
}
}

/// Returns the next index for the given `FactorSourceIDFromHash` and
/// `IndexAgnosticPath`, by analyzing the cache, the profile and adding
/// local ephemeral offsets.
pub fn next(
&self,
factor_source_id: FactorSourceIDFromHash,
index_agnostic_path: IndexAgnosticPath,
) -> Result<HDPathComponent> {
let default_index = HDPathComponent::new_with_key_space_and_base_index(
index_agnostic_path.key_space,
U30::new(0).unwrap(),
);

let maybe_next_from_cache = self
.cache_analyzing
.next(factor_source_id, index_agnostic_path)?;

Check warning on line 70 in src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_assigner.rs

View check run for this annotation

Codecov / codecov/patch

src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_assigner.rs#L70

Added line #L70 was not covered by tests

let next_from_cache = maybe_next_from_cache.unwrap_or(default_index);
let ephemeral = self
.ephemeral_offsets
.reserve(factor_source_id, index_agnostic_path);

let maybe_next_from_profile = self
.profile_analyzing
.next(factor_source_id, index_agnostic_path)?;

Check warning on line 79 in src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_assigner.rs

View check run for this annotation

Codecov / codecov/patch

src/factor_instances_provider/next_index_assigner/next_derivation_entity_index_assigner.rs#L79

Added line #L79 was not covered by tests

let next_from_profile = maybe_next_from_profile.unwrap_or(default_index);

let max_index = std::cmp::max(next_from_profile, next_from_cache);

max_index.add_n(ephemeral)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use crate::prelude::*;

pub struct NextDerivationEntityIndexCacheAnalyzingAssigner {
cache: FactorInstancesCache,
}
impl NextDerivationEntityIndexCacheAnalyzingAssigner {
pub fn new(cache: FactorInstancesCache) -> Self {
Self { cache }
}

fn max(
&self,
factor_source_id: FactorSourceIDFromHash,
index_agnostic_path: IndexAgnosticPath,
) -> Result<Option<HDPathComponent>> {
let max = self
.cache
.max_index_for(factor_source_id, index_agnostic_path);
Ok(max)
}

/// Returns the next index for the given `FactorSourceIDFromHash` and
/// `IndexAgnosticPath`, by analyzing the cache. In case of read failure
/// will this method return `Err`, if the cache did not contain any data for
/// the given `FactorSourceIDFromHash` and `IndexAgnosticPath`, then `Ok(None)` is returned.
///
/// If some index was found, this method returns `max + 1`.
///
/// Can also fail if addition of one would overflow.
pub fn next(
&self,
factor_source_id: FactorSourceIDFromHash,
index_agnostic_path: IndexAgnosticPath,
) -> Result<Option<HDPathComponent>> {
let max = self.max(factor_source_id, index_agnostic_path)?;
let Some(max) = max else { return Ok(None) };
max.add_one().map(Some)
}
}
Loading
Loading