Skip to content
Open
Show file tree
Hide file tree
Changes from 11 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
1 change: 1 addition & 0 deletions Cargo.lock

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

14 changes: 14 additions & 0 deletions e2e/tests-dfx/call.bash
Original file line number Diff line number Diff line change
Expand Up @@ -297,3 +297,17 @@ teardown() {
assert_command dfx canister call inter2_mo read
assert_match '(8 : nat)'
}

@test "call well known canisters" {
assert_command dfx canister --ic call governance list_proposals '(
record {
include_reward_status = vec {};
omit_large_fields = null;
before_proposal = null;
limit = 1 : nat32;
exclude_topic = vec {};
include_all_manage_neuron_proposals = null;
include_status = vec {};
},
)'
}
9 changes: 9 additions & 0 deletions e2e/tests-dfx/sign_send.bash
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,12 @@ teardown() {

rm "$TMP_NAME_FILE"
}

@test "sign query message for a well known canister" {
cd "$E2E_TEMP_DIR"
mkdir not-a-project-dir
cd not-a-project-dir

assert_command dfx canister sign --query registry read --network ic
assert_match "Query message generated at \[message.json\]"
}
5 changes: 5 additions & 0 deletions src/dfx-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ edition.workspace = true
repository.workspace = true
license.workspace = true
rust-version.workspace = true
build = "assets/build.rs"

[build-dependencies]
serde_json.workspace = true
itertools.workspace = true

[dependencies]
aes-gcm.workspace = true
Expand Down
54 changes: 54 additions & 0 deletions src/dfx-core/assets/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use std::{env, fs::File, io::Write, path::Path};

use itertools::Itertools;
use serde_json::Value;

fn define_well_known_canisters() {
let well_known_canisters = serde_json::from_str::<Value>(
&std::fs::read_to_string(format!(
"{}/assets/canister_ids.json",
env!("CARGO_MANIFEST_DIR")
))
.unwrap(),
)
.unwrap();
let well_known_canisters = well_known_canisters.as_object().unwrap();
let well_known_canisters = well_known_canisters.iter().map(|(key, val)| {
(
key.as_str(),
val.as_object()
.unwrap()
.values()
.last()
.unwrap()
.as_str()
.unwrap(),
)
});

let out_dir = env::var("OUT_DIR").unwrap();
let loader_path = Path::new(&out_dir).join("well_known_canisters.rs");
let mut f = File::create(loader_path).unwrap();
f.write_all(
format!(
"
const WELL_KNOWN_CANISTERS: &[(&str, &str)] = &[
{}
];
pub fn map_wellknown_canisters() -> HashMap<CanisterName, Principal> {{
WELL_KNOWN_CANISTERS.iter().map(|(key, value)| (key.to_string(), (*value).try_into().unwrap())).collect()
}}
",
well_known_canisters
.map(|(key, val)| format!("(\"{}\", \"{}\")", key, val))
.join(",\n")
)
.as_bytes(),
)
.unwrap()
Comment on lines +34 to +48
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is a global mapping of well-known canister ids, could we initialize this into a LazyLock rather than adding it as a member to CanisterIdStore?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The version of rust used by sdk doesn't have LazyLock stabilized.

}

fn main() {
define_well_known_canisters();
}
62 changes: 62 additions & 0 deletions src/dfx-core/assets/canister_ids.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{
"registry": {
"local": "rwlgt-iiaaa-aaaaa-aaaaa-cai",
"mainnet": "rwlgt-iiaaa-aaaaa-aaaaa-cai",
"small01": "rwlgt-iiaaa-aaaaa-aaaaa-cai"
},
"governance": {
"local": "rrkah-fqaaa-aaaaa-aaaaq-cai",
"mainnet": "rrkah-fqaaa-aaaaa-aaaaq-cai",
"small01": "rrkah-fqaaa-aaaaa-aaaaq-cai"
},
"ledger": {
"local": "ryjl3-tyaaa-aaaaa-aaaba-cai",
"mainnet": "ryjl3-tyaaa-aaaaa-aaaba-cai",
"small01": "ryjl3-tyaaa-aaaaa-aaaba-cai"
},
"icp-ledger-archive": {
"local": "qjdve-lqaaa-aaaaa-aaaeq-cai",
"mainnet": "qjdve-lqaaa-aaaaa-aaaeq-cai",
"small01": "qjdve-lqaaa-aaaaa-aaaeq-cai"
},
"icp-ledger-archive-1": {
"local": "qsgjb-riaaa-aaaaa-aaaga-cai",
"mainnet": "qsgjb-riaaa-aaaaa-aaaga-cai",
"small01": "qsgjb-riaaa-aaaaa-aaaga-cai"
},
"root": {
"local": "r7inp-6aaaa-aaaaa-aaabq-cai",
"mainnet": "r7inp-6aaaa-aaaaa-aaabq-cai",
"small01": "r7inp-6aaaa-aaaaa-aaabq-cai"
},
"cycles-minting": {
"local": "rkp4c-7iaaa-aaaaa-aaaca-cai",
"mainnet": "rkp4c-7iaaa-aaaaa-aaaca-cai",
"small01": "rkp4c-7iaaa-aaaaa-aaaca-cai"
},
"lifeline": {
"local": "rno2w-sqaaa-aaaaa-aaacq-cai",
"mainnet": "rno2w-sqaaa-aaaaa-aaacq-cai",
"small01": "rno2w-sqaaa-aaaaa-aaacq-cai"
},
"genesis-token": {
"local": "renrk-eyaaa-aaaaa-aaada-cai",
"mainnet": "renrk-eyaaa-aaaaa-aaada-cai",
"small01": "renrk-eyaaa-aaaaa-aaada-cai"
},
"sns-wasm": {
"local": "qaa6y-5yaaa-aaaaa-aaafa-cai",
"mainnet": "qaa6y-5yaaa-aaaaa-aaafa-cai",
"small01": "qaa6y-5yaaa-aaaaa-aaafa-cai"
},
"identity": {
"local": "rdmx6-jaaaa-aaaaa-aaadq-cai",
"mainnet": "rdmx6-jaaaa-aaaaa-aaadq-cai",
"small01": "rdmx6-jaaaa-aaaaa-aaadq-cai"
},
"nns-ui": {
"local": "qoctq-giaaa-aaaaa-aaaea-cai",
"mainnet": "qoctq-giaaa-aaaaa-aaaea-cai",
"small01": "qoctq-giaaa-aaaaa-aaaea-cai"
}
}
23 changes: 22 additions & 1 deletion src/dfx-core/src/config/model/canister_id_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@ use candid::Principal as CanisterId;
use ic_agent::export::Principal;
use serde::{Deserialize, Serialize, Serializer};
use slog::{warn, Logger};
use std::collections::BTreeMap;
use std::collections::{BTreeMap, HashMap};
use std::ops::{Deref, DerefMut, Sub};
use std::path::PathBuf;
use std::str::FromStr;
use std::sync::Arc;
use std::time::{Duration, SystemTime};
use time::format_description::well_known::Rfc3339;
use time::OffsetDateTime;

include!(concat!(env!("OUT_DIR"), "/well_known_canisters.rs"));

pub type CanisterName = String;
pub type NetworkName = String;
pub type CanisterIdString = String;
Expand Down Expand Up @@ -94,6 +97,8 @@ pub struct CanisterIdStore {
// which does not include remote canister ids
ids: CanisterIds,

well_known_ids: HashMap<CanisterName, Principal>,

// Only canisters that will time out at some point have their timestamp of acquisition saved
acquisition_timestamps: CanisterTimestamps,

Expand Down Expand Up @@ -166,6 +171,7 @@ impl CanisterIdStore {
acquisition_timestamps,
remote_ids,
pull_ids,
well_known_ids: map_wellknown_canisters(),
};

if let NetworkTypeDescriptor::Playground {
Expand All @@ -189,6 +195,16 @@ impl CanisterIdStore {
self.remote_ids
.as_ref()
.and_then(|remote_ids| self.get_name_in(canister_id, remote_ids))
.or_else(|| {
let principal = match Principal::from_str(canister_id) {
Ok(p) => p,
Err(_) => return None,
};
self.well_known_ids
.iter()
.find(|(_, id)| &&principal == id)
.map(|(name, _)| name)
})
.or_else(|| self.get_name_in_project(canister_id))
.or_else(|| self.get_name_in_pull_ids(canister_id))
}
Expand Down Expand Up @@ -246,6 +262,7 @@ impl CanisterIdStore {
.as_ref()
.and_then(|remote_ids| self.find_in(canister_name, remote_ids))
.or_else(|| self.find_in(canister_name, &self.ids))
.or_else(|| self.well_known_ids.get(canister_name).copied())
.or_else(|| self.pull_ids.get(canister_name).copied())
}
pub fn get_name_id_map(&self) -> BTreeMap<String, String> {
Expand Down Expand Up @@ -293,6 +310,10 @@ impl CanisterIdStore {
.and_then(|s| CanisterId::from_text(s).ok())
}

pub fn is_well_known(&self, canister_id: &CanisterId) -> bool {
self.well_known_ids.values().any(|val| val == canister_id)
}

pub fn get(&self, canister_name: &str) -> Result<CanisterId, CanisterIdStoreError> {
self.find(canister_name).ok_or_else(|| {
let network = if self.network_descriptor.name == "local" {
Expand Down
18 changes: 15 additions & 3 deletions src/dfx/src/commands/canister/sign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ use crate::commands::canister::call::get_effective_canister_id;
use crate::lib::environment::Environment;
use crate::lib::error::DfxResult;
use crate::lib::operations::canister::get_canister_id_and_candid_path;
use crate::lib::root_key::fetch_root_key_if_needed;
use crate::lib::sign::signed_message::SignedMessageV1;
use crate::util::clap::argument_from_cli::ArgumentFromCliPositionalOpt;
use crate::util::{blob_from_arguments, get_candid_type};
use crate::util::{blob_from_arguments, fetch_remote_did_file, get_candid_type};
use anyhow::{anyhow, bail};
use candid::Principal;
use candid_parser::utils::CandidSource;
Expand Down Expand Up @@ -81,8 +82,19 @@ pub async fn exec(
let (canister_id, maybe_candid_path) =
get_canister_id_and_candid_path(env, opts.canister_name.as_str())?;

let method_type =
maybe_candid_path.and_then(|path| get_candid_type(CandidSource::File(&path), method_name));
let method_type = match maybe_candid_path
.and_then(|path| get_candid_type(CandidSource::File(&path), method_name))
{
Some(mt) => Some(mt),
None => {
let agent = env.get_agent();
fetch_root_key_if_needed(env).await?;
fetch_remote_did_file(agent, canister_id)
.await
.and_then(|did| get_candid_type(CandidSource::Text(&did), method_name))
}
};

let is_query_method = method_type.as_ref().map(|(_, f)| f.is_query());

let (argument_from_cli, argument_type) = opts.argument_from_cli.get_argument_and_type()?;
Expand Down
10 changes: 9 additions & 1 deletion src/dfx/src/lib/operations/canister/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,13 +357,21 @@ pub fn get_canister_id_and_candid_path(
) -> DfxResult<(CanisterId, Option<PathBuf>)> {
let canister_id_store = env.get_canister_id_store()?;
let (canister_name, canister_id) = if let Ok(id) = Principal::from_text(canister) {
if canister_id_store.is_well_known(&id) {
return Ok((id, None));
}

if let Some(canister_name) = canister_id_store.get_name(canister) {
(canister_name.to_string(), id)
} else {
return Ok((id, None));
}
} else {
(canister.to_string(), canister_id_store.get(canister)?)
let canister_id = canister_id_store.get(canister)?;
if canister_id_store.is_well_known(&canister_id) {
return Ok((canister_id, None));
}
(canister.to_string(), canister_id)
};
let config = env.get_config_or_anyhow()?;
let candid_path = match CanisterInfo::load(&config, &canister_name, Some(canister_id)) {
Expand Down
Loading