Skip to content

Commit

Permalink
Support submitting proof of uniqueness to LocalUserIndex (#6068)
Browse files Browse the repository at this point in the history
  • Loading branch information
hpeebles authored Jul 19, 2024
1 parent 5d9c944 commit 5398ec4
Show file tree
Hide file tree
Showing 22 changed files with 193 additions and 48 deletions.
15 changes: 13 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ members = [
"backend/libraries/ledger_utils",
"backend/libraries/msgpack",
"backend/libraries/p256_key_pair",
"backend/libraries/proof_of_unique_personhood",
"backend/libraries/storage_bucket_client",
"backend/libraries/search",
"backend/libraries/serializer",
Expand Down
4 changes: 4 additions & 0 deletions backend/canisters/local_user_index/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## [unreleased]

### Added

- Support submitting proof of uniqueness to LocalUserIndex ([#6068](https://github.com/open-chat-labs/open-chat/pull/6068))

### Changed

- Clear old data from the failed upgrades log ([#6062](https://github.com/open-chat-labs/open-chat/pull/6062))
Expand Down
2 changes: 2 additions & 0 deletions backend/canisters/local_user_index/api/src/lifecycle/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ pub struct Args {
pub cycles_dispenser_canister_id: CanisterId,
pub escrow_canister_id: CanisterId,
pub event_relay_canister_id: CanisterId,
pub internet_identity_canister_id: CanisterId,
pub video_call_operators: Vec<Principal>,
pub oc_secret_key_der: Option<Vec<u8>>,
pub ic_root_key: Vec<u8>,
pub test_mode: bool,
}
2 changes: 2 additions & 0 deletions backend/canisters/local_user_index/impl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@ jwt = { path = "../../../libraries/jwt" }
ledger_utils = { path = "../../../libraries/ledger_utils" }
local_user_index_canister = { path = "../api" }
msgpack = { path = "../../../libraries/msgpack" }
proof_of_unique_personhood = { path = "../../../libraries/proof_of_unique_personhood" }
rand = { workspace = true }
serde = { workspace = true }
serde_bytes = { workspace = true }
serde_json = { workspace = true }
serializer = { path = "../../../libraries/serializer" }
satoshi_dice_canister = { path = "../../../bots/examples/satoshi_dice/api" }
Expand Down
69 changes: 67 additions & 2 deletions backend/canisters/local_user_index/impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,22 @@ use event_store_utils::EventDeduper;
use local_user_index_canister::GlobalUser;
use model::global_user_map::GlobalUserMap;
use model::local_user_map::LocalUserMap;
use proof_of_unique_personhood::verify_proof_of_unique_personhood;
use serde::{Deserialize, Serialize};
use std::cell::RefCell;
use std::collections::{HashMap, VecDeque};
use std::time::Duration;
use types::{
BuildVersion, CanisterId, CanisterWasm, ChannelLatestMessageIndex, ChatId, ChunkedCanisterWasm,
CommunityCanisterChannelSummary, CommunityCanisterCommunitySummary, CommunityId, Cycles, MessageContent, ReferralType,
TimestampMillis, Timestamped, User, UserId,
TimestampMillis, Timestamped, UniquePersonProof, User, UserId,
};
use user_canister::Event as UserEvent;
use user_index_canister::Event as UserIndexEvent;
use utils::canister;
use utils::canister::{CanistersRequiringUpgrade, FailedUpgradeCount};
use utils::canister_event_sync_queue::CanisterEventSyncQueue;
use utils::consts::CYCLES_REQUIRED_FOR_UPGRADE;
use utils::consts::{CYCLES_REQUIRED_FOR_UPGRADE, IC_ROOT_KEY};
use utils::env::Environment;
use utils::time::MINUTE_IN_MS;

Expand Down Expand Up @@ -52,11 +53,43 @@ impl RuntimeState {
RuntimeState { env, data }
}

pub fn calling_user_id(&self) -> UserId {
let caller = self.env.caller();
self.data.global_users.get(&caller).unwrap().user_id
}

pub fn calling_user(&self) -> GlobalUser {
let caller = self.env.caller();
self.data.global_users.get(&caller).unwrap()
}

pub fn get_calling_user_and_process_credentials(&mut self, credential_jwts: Option<&[String]>) -> GlobalUser {
let mut user_details = self.calling_user();

if user_details.unique_person_proof.is_none() {
if let Some(unique_person_proof) = credential_jwts.as_ref().and_then(|jwts| {
let now = self.env.now();
self.data
.extract_proof_of_unique_personhood(user_details.principal, jwts, now)
}) {
let user_id = user_details.user_id;
self.push_event_to_user_index(UserIndexEvent::NotifyUniquePersonProof(Box::new((
user_id,
unique_person_proof.clone(),
))));
if self.data.local_users.contains(&user_id) {
self.push_event_to_user(
user_id,
UserEvent::NotifyUniquePersonProof(Box::new(unique_person_proof.clone())),
);
}
user_details.unique_person_proof = Some(unique_person_proof);
}
}

user_details
}

pub fn is_caller_user_index_canister(&self) -> bool {
let caller = self.env.caller();
self.data.user_index_canister_id == caller
Expand Down Expand Up @@ -196,6 +229,7 @@ impl RuntimeState {
cycles_dispenser: self.data.cycles_dispenser_canister_id,
escrow: self.data.escrow_canister_id,
event_relay: event_relay_canister_id,
internet_identity: self.data.internet_identity_canister_id,
},
oc_secret_key_initialized: self.data.oc_secret_key_der.is_some(),
canister_upgrades_failed: canister_upgrades_metrics.failed,
Expand All @@ -216,6 +250,8 @@ struct Data {
pub proposals_bot_canister_id: CanisterId,
pub cycles_dispenser_canister_id: CanisterId,
pub escrow_canister_id: CanisterId,
#[serde(default = "internet_identity_canister_id")]
pub internet_identity_canister_id: CanisterId,
pub canisters_requiring_upgrade: CanistersRequiringUpgrade,
pub canister_pool: canister::Pool,
pub total_cycles_spent_on_canisters: Cycles,
Expand All @@ -232,6 +268,16 @@ struct Data {
pub event_store_client: EventStoreClient<CdkRuntime>,
pub event_deduper: EventDeduper,
pub users_to_delete_queue: VecDeque<UserToDelete>,
#[serde(with = "serde_bytes", default = "ic_root_key")]
pub ic_root_key: Vec<u8>,
}

fn ic_root_key() -> Vec<u8> {
IC_ROOT_KEY.to_vec()
}

fn internet_identity_canister_id() -> CanisterId {
CanisterId::from_text("rdmx6-jaaaa-aaaaa-aaadq-cai").unwrap()
}

#[derive(Serialize, Deserialize)]
Expand Down Expand Up @@ -259,9 +305,11 @@ impl Data {
cycles_dispenser_canister_id: CanisterId,
escrow_canister_id: CanisterId,
event_relay_canister_id: CanisterId,
internet_identity_canister_id: CanisterId,
canister_pool_target_size: u16,
video_call_operators: Vec<Principal>,
oc_secret_key_der: Option<Vec<u8>>,
ic_root_key: Vec<u8>,
test_mode: bool,
) -> Self {
Data {
Expand All @@ -276,6 +324,7 @@ impl Data {
proposals_bot_canister_id,
cycles_dispenser_canister_id,
escrow_canister_id,
internet_identity_canister_id,
canisters_requiring_upgrade: CanistersRequiringUpgrade::default(),
canister_pool: canister::Pool::new(canister_pool_target_size),
total_cycles_spent_on_canisters: 0,
Expand All @@ -294,8 +343,23 @@ impl Data {
.build(),
event_deduper: EventDeduper::default(),
users_to_delete_queue: VecDeque::new(),
ic_root_key,
}
}

pub fn extract_proof_of_unique_personhood(
&self,
principal: Principal,
credential_jwts: &[String],
now: TimestampMillis,
) -> Option<UniquePersonProof> {
credential_jwts
.iter()
.filter_map(|jwt| {
verify_proof_of_unique_personhood(principal, self.identity_canister_id, jwt, &self.ic_root_key, now).ok()
})
.next()
}
}

#[derive(Serialize, Debug)]
Expand Down Expand Up @@ -335,4 +399,5 @@ pub struct CanisterIds {
pub cycles_dispenser: CanisterId,
pub escrow: CanisterId,
pub event_relay: CanisterId,
pub internet_identity: CanisterId,
}
2 changes: 2 additions & 0 deletions backend/canisters/local_user_index/impl/src/lifecycle/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@ fn init(args: Args) {
args.cycles_dispenser_canister_id,
args.escrow_canister_id,
args.event_relay_canister_id,
args.internet_identity_canister_id,
canister_pool_target_size,
args.video_call_operators,
args.oc_secret_key_der,
args.ic_root_key,
args.test_mode,
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ async fn invite_users_to_channel(args: Args) -> Response {
.map(|u| (u.user_id, u.principal))
.collect();

(state.calling_user().user_id, users)
(state.calling_user_id(), users)
});

let c2c_args = c2c_invite_users_to_channel::Args {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ struct PrepareResult {
}

fn prepare(args: &Args, state: &RuntimeState) -> PrepareResult {
let invited_by = state.calling_user().user_id;
let invited_by = state.calling_user_id();
let users = args
.user_ids
.iter()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ struct PrepareResult {
}

fn prepare(args: &Args, state: &RuntimeState) -> PrepareResult {
let invited_by = state.calling_user().user_id;
let invited_by = state.calling_user_id();
let users = args
.user_ids
.iter()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
use crate::guards::caller_is_openchat_user;
use crate::{mutate_state, read_state};
use crate::mutate_state;
use canister_tracing_macros::trace;
use ic_cdk::update;
use local_user_index_canister::join_channel::{Response::*, *};

#[update(guard = "caller_is_openchat_user")]
#[trace]
async fn join_channel(args: Args) -> Response {
let user_details = read_state(|state| state.calling_user());
let user_details = mutate_state(|state| {
state.get_calling_user_and_process_credentials(
args.verified_credential_args.as_ref().map(|c| c.credential_jwts.as_slice()),
)
});

let c2c_args = community_canister::c2c_join_channel::Args {
user_id: user_details.user_id,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
use crate::guards::caller_is_openchat_user;
use crate::{mutate_state, read_state};
use crate::mutate_state;
use canister_tracing_macros::trace;
use ic_cdk::update;
use local_user_index_canister::join_community::{Response::*, *};

#[update(guard = "caller_is_openchat_user")]
#[trace]
async fn join_community(args: Args) -> Response {
let user_details = read_state(|state| state.calling_user());
let user_details = mutate_state(|state| {
state.get_calling_user_and_process_credentials(
args.verified_credential_args.as_ref().map(|c| c.credential_jwts.as_slice()),
)
});

let c2c_args = community_canister::c2c_join_community::Args {
user_id: user_details.user_id,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::guards::caller_is_openchat_user;
use crate::{mutate_state, read_state, RuntimeState};
use crate::{mutate_state, RuntimeState};
use canister_tracing_macros::trace;
use ic_cdk::update;
use local_user_index_canister::join_group::{Response::*, *};
Expand All @@ -10,7 +10,11 @@ use user_index_canister::Event as UserIndexEvent;
#[update(guard = "caller_is_openchat_user")]
#[trace]
async fn join_group(args: Args) -> Response {
let user_details = read_state(|state| state.calling_user());
let user_details = mutate_state(|state| {
state.get_calling_user_and_process_credentials(
args.verified_credential_args.as_ref().map(|c| c.credential_jwts.as_slice()),
)
});

let c2c_args = group_canister::c2c_join_group::Args {
user_id: user_details.user_id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ struct PrepareResult {
}

fn prepare(state: &RuntimeState) -> PrepareResult {
let user_id = state.calling_user().user_id;
let user_id = state.calling_user_id();

PrepareResult {
user_id,
Expand Down
1 change: 1 addition & 0 deletions backend/canisters/user_index/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Clear old data from the failed upgrades log ([#6062](https://github.com/open-chat-labs/open-chat/pull/6062))
- Fix fee then retry transfer if fee too high ([#6063](https://github.com/open-chat-labs/open-chat/pull/6063))
- Handle transfer fee changing in either direction ([#6064](https://github.com/open-chat-labs/open-chat/pull/6064))
- Accept proofs of uniqueness from LocalUserIndexes ([#6068](https://github.com/open-chat-labs/open-chat/pull/6068))

## [[2.0.1242](https://github.com/open-chat-labs/open-chat/releases/tag/v2.0.1242-user_index)] - 2024-07-17

Expand Down
3 changes: 2 additions & 1 deletion backend/canisters/user_index/api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use candid::Principal;
use serde::{Deserialize, Serialize};
use types::{
CanisterId, ChannelLatestMessageIndex, ChatId, CommunityId, MessageContent, MessageContentInitial, MessageId, MessageIndex,
User, UserId,
UniquePersonProof, User, UserId,
};

mod lifecycle;
Expand All @@ -22,6 +22,7 @@ pub enum Event {
OpenChatBotMessage(Box<OpenChatBotMessage>),
OpenChatBotMessageV2(Box<OpenChatBotMessageV2>),
UserDeleted(Box<UserDeleted>),
NotifyUniquePersonProof(Box<(UserId, UniquePersonProof)>),
}

#[derive(Serialize, Deserialize, Clone, Debug)]
Expand Down
2 changes: 1 addition & 1 deletion backend/canisters/user_index/impl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ ic-cdk = { workspace = true }
ic-cdk-timers = { workspace = true }
ic-ledger-types = { workspace = true }
ic-stable-structures = { workspace = true }
ic-verifiable-credentials = { workspace = true }
icrc_ledger_canister_c2c_client = { path = "../../../external_canisters/icrc_ledger/c2c_client" }
icrc-ledger-types = { workspace = true }
identity_canister = { path = "../../identity/api" }
Expand All @@ -47,6 +46,7 @@ modclub_canister_c2c_client = { path = "../../../external_canisters/modclub/c2c_
msgpack = { path = "../../../libraries/msgpack" }
nns_governance_canister = { path = "../../../external_canisters/nns_governance/api" }
nns_governance_canister_c2c_client = { path = "../../../external_canisters/nns_governance/c2c_client" }
proof_of_unique_personhood = { path = "../../../libraries/proof_of_unique_personhood" }
pulldown-cmark = { workspace = true }
rand = { workspace = true }
serde = { workspace = true }
Expand Down
Loading

0 comments on commit 5398ec4

Please sign in to comment.