Skip to content

Commit

Permalink
Remove support for storage layout v9 (#2372)
Browse files Browse the repository at this point in the history
* Remove support for storage layout v9

This PR drops support for storage layout v9. The following
simplifications are implemented as well:
* Drop the `Option` fields from `PersistentState`. These were only kept
  for stable memory compatibility with v8.
* Make loading the `PersistentState` infallible.
* Moved initialization of default values from `StorablePersistentState`
  to `PersistentState`.

* Improve docs based on review feedback
  • Loading branch information
Frederik Rothenberger authored Mar 19, 2024
1 parent 728ad5a commit 90c8902
Show file tree
Hide file tree
Showing 13 changed files with 204 additions and 402 deletions.
17 changes: 6 additions & 11 deletions src/internet_identity/src/activity_stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use crate::activity_stats::activity_counter::ActivityCounter;
use crate::state;
use crate::storage::anchor::{Anchor, Device};
use candid::{CandidType, Deserialize};
use ic_cdk::api::time;
use internet_identity_interface::internet_identity::types::Timestamp;

pub mod activity_counter;
Expand Down Expand Up @@ -86,28 +85,24 @@ pub struct OngoingActivityStats<T: ActivityCounter> {
pub fn update_activity_stats(anchor: &Anchor, current_device: &Device) {
state::persistent_state_mut(|persistent_state| {
// Active anchor stats across all domains
let active_anchor_stats = persistent_state
persistent_state
.active_anchor_stats
.get_or_insert_with(|| ActivityStats::new(time()));
active_anchor_stats.update_counters(&anchor.last_activity());
.update_counters(&anchor.last_activity());

// Active anchor stats, II domains only
if let Some(domain) = current_device.ii_domain() {
let context = DomainActivityContext {
anchor,
current_domain: domain,
};
let domain_active_anchor_stats = persistent_state
persistent_state
.domain_active_anchor_stats
.get_or_insert_with(|| ActivityStats::new(time()));
domain_active_anchor_stats.update_counters(&context);
.update_counters(&context);

// Active authn methods stats, II domains only
let authn_method_stats = persistent_state
persistent_state
.active_authn_method_stats
.get_or_insert_with(|| ActivityStats::new(time()));

authn_method_stats.update_counters(&current_device);
.update_counters(&current_device);
}
})
}
8 changes: 2 additions & 6 deletions src/internet_identity/src/anchor_management/registration.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::anchor_management::{activity_bookkeeping, post_operation_bookkeeping};
use crate::state::{ChallengeInfo, DEFAULT_MAX_INFLIGHT_CAPTCHAS};
use crate::state::ChallengeInfo;
use crate::storage::anchor::Device;
use crate::{random_salt, secs_to_nanos, state};
use candid::Principal;
Expand All @@ -26,11 +26,7 @@ pub async fn create_challenge() -> Challenge {

// Error out if there are too many inflight challenges
if inflight_challenges.len()
>= state::persistent_state_mut(|state| {
*state
.max_inflight_captchas
.get_or_insert(DEFAULT_MAX_INFLIGHT_CAPTCHAS)
}) as usize
>= state::persistent_state(|s| s.max_inflight_captchas) as usize
{
trap("too many inflight captchas");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,7 @@ use std::cmp::min;
/// There is a maximum of `max_tokens` tokens, when reached the tokens not increase any further.
/// This is the maximum number of calls that can be handled in a burst.
pub fn process_rate_limit() {
let Some(config) = state::persistent_state(|ps| ps.registration_rate_limit.clone()) else {
// rate limit disabled -> nothing to do
return;
};
let config = state::persistent_state(|ps| ps.registration_rate_limit.clone());

state::registration_rate_limit_mut(|state_opt| {
let state = if let Some(state) = state_opt {
Expand Down
6 changes: 2 additions & 4 deletions src/internet_identity/src/delegation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,7 @@ fn update_latest_delegation_origins(frontend: FrontendHostname) {
let now_ns = time();

persistent_state_mut(|persistent_state| {
let latest_delegation_origins = persistent_state
.latest_delegation_origins
.get_or_insert(HashMap::new());
let latest_delegation_origins = &mut persistent_state.latest_delegation_origins;

if let Some(timestamp_ns) = latest_delegation_origins.get_mut(&frontend) {
*timestamp_ns = now_ns;
Expand All @@ -102,7 +100,7 @@ fn update_latest_delegation_origins(frontend: FrontendHostname) {

// if we still have too many entries, drop the oldest
if latest_delegation_origins.len() as u64
> persistent_state.max_num_latest_delegation_origins.unwrap()
> persistent_state.max_num_latest_delegation_origins
{
// if this case is hit often (i.e. we routinely have more than 1000 entries), we should
// consider using a more efficient data structure
Expand Down
181 changes: 89 additions & 92 deletions src/internet_identity/src/http/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,106 +138,103 @@ fn persistent_state_metrics(
w: &mut MetricsEncoder<Vec<u8>>,
persistent_state: &PersistentState,
) -> Result<(), std::io::Error> {
if let Some(ref register_rate_limit_config) = persistent_state.registration_rate_limit {
let register_rate_limit_config = &persistent_state.registration_rate_limit;
w.encode_gauge(
"internet_identity_register_rate_limit_max_tokens",
register_rate_limit_config.max_tokens as f64,
"The maximum number of `register` calls that are allowed in any time window.",
)?;
w.encode_gauge(
"internet_identity_register_rate_limit_time_per_tokens_seconds",
Duration::from_nanos(register_rate_limit_config.time_per_token_ns).as_secs() as f64,
"Min number of seconds between two register calls to not exceed the rate limit (sustained).",
)?;

let stats = &persistent_state.active_anchor_stats;
if let Some(ref daily_active_anchor_stats) = stats.completed.daily_events {
w.encode_gauge(
"internet_identity_register_rate_limit_max_tokens",
register_rate_limit_config.max_tokens as f64,
"The maximum number of `register` calls that are allowed in any time window.",
"internet_identity_daily_active_anchors",
daily_active_anchor_stats.counter as f64,
"The number of unique active anchors in the last completed 24h collection window.",
)?;
w.encode_gauge(
"internet_identity_register_rate_limit_time_per_tokens_seconds",
Duration::from_nanos(register_rate_limit_config.time_per_token_ns).as_secs() as f64,
"Min number of seconds between two register calls to not exceed the rate limit (sustained).",
"internet_identity_daily_active_anchors_start_timestamp_seconds",
Duration::from_nanos(daily_active_anchor_stats.start_timestamp).as_secs() as f64,
"Timestamp of the last completed 24h collection window for unique active anchors.",
)?;
}
if let Some(ref stats) = persistent_state.active_anchor_stats {
if let Some(ref daily_active_anchor_stats) = stats.completed.daily_events {
w.encode_gauge(
"internet_identity_daily_active_anchors",
daily_active_anchor_stats.counter as f64,
"The number of unique active anchors in the last completed 24h collection window.",
)?;
w.encode_gauge(
"internet_identity_daily_active_anchors_start_timestamp_seconds",
Duration::from_nanos(daily_active_anchor_stats.start_timestamp).as_secs() as f64,
"Timestamp of the last completed 24h collection window for unique active anchors.",
)?;
}
if let Some(ref monthly_active_anchor_stats) = stats.completed.monthly_events {
w.encode_gauge(
"internet_identity_monthly_active_anchors",
monthly_active_anchor_stats.counter as f64,
"The number of unique active anchors in the last completed 30-day collection window.",
)?;
w.encode_gauge(
"internet_identity_monthly_active_anchors_start_timestamp_seconds",
Duration::from_nanos(monthly_active_anchor_stats.start_timestamp).as_secs() as f64,
"Timestamp of the last completed 30-day collection window for unique active anchors.",
)?;
}
};
if let Some(ref stats) = persistent_state.domain_active_anchor_stats {
const BOTH_DOMAINS: &str = "both_ii_domains";

let labels = ActivityMetricsLabels {
daily_stats_label: "internet_identity_daily_active_anchors_by_domain",
daily_stats_doc: "The number of unique active anchors in the last completed 24h collection window aggregated by II domains used.",
monthly_stats_label: "internet_identity_monthly_active_anchors_by_domain",
monthly_stats_doc: "The number of unique active anchors in the last completed 30-day collection window aggregated by II domains used.",
};
labelled_activity_metrics(w, stats, labels, |counter, encoder| {
encoder
.value(
&[("domain", IC0_APP_DOMAIN)],
counter.ic0_app_counter as f64,
)?
.value(
&[("domain", INTERNETCOMPUTER_ORG_DOMAIN)],
counter.internetcomputer_org_counter as f64,
)?
.value(
&[("domain", BOTH_DOMAINS)],
counter.both_ii_domains_counter as f64,
)?;
Ok(())
})?;
};
if let Some(ref stats) = persistent_state.active_authn_method_stats {
let labels = ActivityMetricsLabels {
daily_stats_label: "internet_identity_daily_active_authn_methods",
daily_stats_doc: "The number of unique authentication methods used in the last completed 24h collection window on II domains.",
monthly_stats_label: "internet_identity_monthly_active_authn_methods",
monthly_stats_doc: "The number of unique authentication methods used in the last completed 30-day collection window on II domains.",
};
labelled_activity_metrics(w, stats, labels, |counter, encoder| {
encoder
.value(
&[("type", "webauthn_auth")],
counter.webauthn_auth_counter as f64,
)?
.value(
&[("type", "webauthn_recovery")],
counter.webauthn_recovery_counter as f64,
)?
.value(
&[("type", "recovery_phrase")],
counter.recovery_phrase_counter as f64,
)?
.value(
&[("type", "browser_storage_key")],
counter.browser_storage_key_counter as f64,
)?
.value(&[("type", "other")], counter.other_counter as f64)?;
Ok(())
})?;
};
if let Some(delegation_origins_limit) = persistent_state.max_num_latest_delegation_origins {
if let Some(ref monthly_active_anchor_stats) = stats.completed.monthly_events {
w.encode_gauge(
"internet_identity_monthly_active_anchors",
monthly_active_anchor_stats.counter as f64,
"The number of unique active anchors in the last completed 30-day collection window.",
)?;
w.encode_gauge(
"internet_identity_max_num_latest_delegation_origins",
delegation_origins_limit as f64,
"The maximum number of latest delegation origins that were used with II bound devices.",
"internet_identity_monthly_active_anchors_start_timestamp_seconds",
Duration::from_nanos(monthly_active_anchor_stats.start_timestamp).as_secs() as f64,
"Timestamp of the last completed 30-day collection window for unique active anchors.",
)?;
}
let stats = &persistent_state.domain_active_anchor_stats;
const BOTH_DOMAINS: &str = "both_ii_domains";

let labels = ActivityMetricsLabels {
daily_stats_label: "internet_identity_daily_active_anchors_by_domain",
daily_stats_doc: "The number of unique active anchors in the last completed 24h collection window aggregated by II domains used.",
monthly_stats_label: "internet_identity_monthly_active_anchors_by_domain",
monthly_stats_doc: "The number of unique active anchors in the last completed 30-day collection window aggregated by II domains used.",
};
labelled_activity_metrics(w, stats, labels, |counter, encoder| {
encoder
.value(
&[("domain", IC0_APP_DOMAIN)],
counter.ic0_app_counter as f64,
)?
.value(
&[("domain", INTERNETCOMPUTER_ORG_DOMAIN)],
counter.internetcomputer_org_counter as f64,
)?
.value(
&[("domain", BOTH_DOMAINS)],
counter.both_ii_domains_counter as f64,
)?;
Ok(())
})?;

let stats = &persistent_state.active_authn_method_stats;
let labels = ActivityMetricsLabels {
daily_stats_label: "internet_identity_daily_active_authn_methods",
daily_stats_doc: "The number of unique authentication methods used in the last completed 24h collection window on II domains.",
monthly_stats_label: "internet_identity_monthly_active_authn_methods",
monthly_stats_doc: "The number of unique authentication methods used in the last completed 30-day collection window on II domains.",
};
labelled_activity_metrics(w, stats, labels, |counter, encoder| {
encoder
.value(
&[("type", "webauthn_auth")],
counter.webauthn_auth_counter as f64,
)?
.value(
&[("type", "webauthn_recovery")],
counter.webauthn_recovery_counter as f64,
)?
.value(
&[("type", "recovery_phrase")],
counter.recovery_phrase_counter as f64,
)?
.value(
&[("type", "browser_storage_key")],
counter.browser_storage_key_counter as f64,
)?
.value(&[("type", "other")], counter.other_counter as f64)?;
Ok(())
})?;

w.encode_gauge(
"internet_identity_max_num_latest_delegation_origins",
persistent_state.max_num_latest_delegation_origins as f64,
"The maximum number of latest delegation origins that were used with II bound devices.",
)?;
Ok(())
}

Expand Down
26 changes: 9 additions & 17 deletions src/internet_identity/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,15 +340,10 @@ fn stats() -> InternetIdentityStats {
state::persistent_state(|persistent_state| {
let origins = persistent_state
.latest_delegation_origins
.as_ref()
.map(|latest_delegation_origins| {
latest_delegation_origins.keys().cloned().collect()
})
.unwrap_or_default();
(
origins,
persistent_state.max_num_latest_delegation_origins.unwrap(),
)
.keys()
.cloned()
.collect();
(origins, persistent_state.max_num_latest_delegation_origins)
});

state::storage_borrow(|storage| InternetIdentityStats {
Expand Down Expand Up @@ -402,15 +397,12 @@ fn init(maybe_arg: Option<InternetIdentityInit>) {
fn post_upgrade(maybe_arg: Option<InternetIdentityInit>) {
init_assets();
state::init_from_stable_memory();
// immediately migrate the persistent state to the new layout
state::storage_borrow_mut(|storage| storage.migrate_persistent_state());
// load the persistent state after initializing storage, otherwise the memory address to load it from cannot be calculated
state::load_persistent_state();

// We drop all the signatures on upgrade, users will
// re-request them if needed.
update_root_hash();
// load the persistent state after initializing storage, otherwise the memory address to load it from cannot be calculated
state::load_persistent_state();

apply_install_arg(maybe_arg);
}

Expand All @@ -431,17 +423,17 @@ fn apply_install_arg(maybe_arg: Option<InternetIdentityInit>) {
}
if let Some(rate_limit) = arg.register_rate_limit {
state::persistent_state_mut(|persistent_state| {
persistent_state.registration_rate_limit = Some(rate_limit);
persistent_state.registration_rate_limit = rate_limit;
})
}
if let Some(limit) = arg.max_num_latest_delegation_origins {
state::persistent_state_mut(|persistent_state| {
persistent_state.max_num_latest_delegation_origins = Some(limit);
persistent_state.max_num_latest_delegation_origins = limit;
})
}
if let Some(limit) = arg.max_inflight_captchas {
state::persistent_state_mut(|persistent_state| {
persistent_state.max_inflight_captchas = Some(limit);
persistent_state.max_inflight_captchas = limit;
})
}
}
Expand Down
Loading

0 comments on commit 90c8902

Please sign in to comment.