Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support submitting proof of uniqueness to LocalUserIndex #6068

Merged
merged 5 commits into from
Jul 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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
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,
}
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
Loading