Skip to content

Commit

Permalink
Remove support for storage layout v9
Browse files Browse the repository at this point in the history
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`.
  • Loading branch information
Frederik Rothenberger committed Mar 18, 2024
1 parent 728ad5a commit bdbdd72
Show file tree
Hide file tree
Showing 13 changed files with 203 additions and 399 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 bdbdd72

Please sign in to comment.