Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

## DFX

### feat: Initialise the nns with an account controlled by a secp256k1 key

This enables easy access to toy ICP using command line tools.

### feat: default to run ic-wasm shrink when build canisters
This behavior applies to Motoko, Rust and Custom canisters.
If you want to disable this behavior, you can config it in dfx.json:
Expand Down
5 changes: 5 additions & 0 deletions e2e/assets/nns/ident-1/identity.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHQCAQEEICJxApEbuZznKFpV+VKACRK30i6+7u5Z13/DOl18cIC+oAcGBSuBBAAK
oUQDQgAEPas6Iag4TUx+Uop+3NhE6s3FlayFtbwdhRVjvOar0kPTfE/N8N6btRnd
74ly5xXEBNSXiENyxhEuzOZrIWMCNQ==
-----END EC PRIVATE KEY-----
19 changes: 18 additions & 1 deletion e2e/tests-dfx/nns.bash
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@ assert_nns_canister_id_matches() {
dfx_start_for_nns_install
dfx nns install

echo Checking that the install worked...
echo "Checking that the install worked..."
echo " The expected wasms should be installed..."
# Note: The installation is quite expensive, so we test extensively on one installation
# rather than doing a separate installation for every test. The tests are read-only
# so no test should affect the output of another.
Expand Down Expand Up @@ -144,6 +145,22 @@ assert_nns_canister_id_matches() {
wasm_matches internet_identity internet_identity_dev.wasm
wasm_matches nns-dapp nns-dapp_local.wasm

echo " Accounts should have funds..."
account_has_funds() {
assert_command dfx ledger balance "$1"
assert_eq "1000000000.00000000 ICP"
}
SECP256K1_ACCOUNT_ID="2b8fbde99de881f695f279d2a892b1137bfe81a42d7694e064b1be58701e1138"
ED25519_ACCOUNT_ID="5b315d2f6702cb3a27d826161797d7b2c2e131cd312aece51d4d5574d1247087"
account_has_funds "$SECP256K1_ACCOUNT_ID"
account_has_funds "$ED25519_ACCOUNT_ID"

echo " The secp256k1 account can be controlled from the command line"
install_asset nns
dfx identity import --force --disable-encryption ident-1 ident-1/identity.pem
assert_command dfx ledger account-id --identity ident-1
assert_eq "$SECP256K1_ACCOUNT_ID"

echo Stopping dfx...
dfx stop
}
Expand Down
14 changes: 12 additions & 2 deletions src/dfx/src/lib/nns/install_nns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use ic_agent::Agent;
use ic_utils::interfaces::management_canister::builders::InstallMode;
use ic_utils::interfaces::ManagementCanister;
use reqwest::Url;
use std::ffi::OsStr;
use std::fs;
use std::io::Write;
use std::path::Component;
Expand Down Expand Up @@ -75,7 +76,10 @@ pub async fn install_nns(
let ic_nns_init_opts = IcNnsInitOpts {
wasm_dir: nns_wasm_dir(env),
nns_url: nns_url.to_string(),
test_accounts: Some(canisters::TEST_ACCOUNT.to_string()),
test_accounts: vec![
canisters::ED25519_TEST_ACCOUNT.to_string(),
canisters::SECP256K1_TEST_ACCOUNT.to_string(),
],
sns_subnets: Some(subnet_id.to_string()),
};
ic_nns_init(ic_nns_init_path, &ic_nns_init_opts).await?;
Expand Down Expand Up @@ -450,7 +454,7 @@ pub struct IcNnsInitOpts {
wasm_dir: PathBuf,
/// The ID of a test account that ic-nns-init will create and to initialise with tokens.
/// Note: At present only one test account is supported.
test_accounts: Option<String>,
test_accounts: Vec<String>,
/// A subnet for SNS canisters.
/// Note: In this context we support at most one subnet.
sns_subnets: Option<String>,
Expand All @@ -477,6 +481,12 @@ pub async fn ic_nns_init(ic_nns_init_path: &Path, opts: &IcNnsInitOpts) -> anyho
cmd.arg("--sns-subnet");
cmd.arg(subnet);
});
let args: Vec<_> = cmd
.get_args()
.into_iter()
.map(OsStr::to_string_lossy)
.collect();
println!("ic-nns-init {}", args.join(" "));
cmd.stdout(std::process::Stdio::inherit());
cmd.stderr(std::process::Stdio::inherit());
let output = cmd
Expand Down
31 changes: 30 additions & 1 deletion src/dfx/src/lib/nns/install_nns/canisters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,4 +179,33 @@ pub const SNS_CANISTERS: [&SnsCanisterInstallation; 5] = [
];

/// Test account with well known public & private keys, used in NNS_LEDGER, NNS_DAPP and third party projects.
pub const TEST_ACCOUNT: &str = "5b315d2f6702cb3a27d826161797d7b2c2e131cd312aece51d4d5574d1247087";
/// The keys use the ED25519 curve, used for BasicIdentity on th eInternet Computer.
/// The keys are as follows, in the tweetnacl format used by agent-js:
/// ```
/// const publicKey = "Uu8wv55BKmk9ZErr6OIt5XR1kpEGXcOSOC1OYzrAwuk=";
/// const privateKey =
/// "N3HB8Hh2PrWqhWH2Qqgr1vbU9T3gb1zgdBD8ZOdlQnVS7zC/nkEqaT1kSuvo4i3ldHWSkQZdw5I4LU5jOsDC6Q==";
/// const identity = Ed25519KeyIdentity.fromKeyPair(
/// base64ToUInt8Array(publicKey),
/// base64ToUInt8Array(privateKey)
/// );
/// ```
pub const ED25519_TEST_ACCOUNT: &str =
"5b315d2f6702cb3a27d826161797d7b2c2e131cd312aece51d4d5574d1247087";

/// Test account for command line usage. The test account is typically called ident-1
/// The keys use the secp256k1 curve. To use:
/// ```
/// $ cat ~/.config/dfx/identity/ident-1/identity.pem
/// -----BEGIN EC PRIVATE KEY-----
/// MHQCAQEEICJxApEbuZznKFpV+VKACRK30i6+7u5Z13/DOl18cIC+oAcGBSuBBAAK
/// oUQDQgAEPas6Iag4TUx+Uop+3NhE6s3FlayFtbwdhRVjvOar0kPTfE/N8N6btRnd
/// 74ly5xXEBNSXiENyxhEuzOZrIWMCNQ==
/// -----END EC PRIVATE KEY-----
/// ```
/// The test account should match the output of:
/// ```
/// $ dfx --identity ident-1 ledger account-id
/// ```
pub const SECP256K1_TEST_ACCOUNT: &str =
"2b8fbde99de881f695f279d2a892b1137bfe81a42d7694e064b1be58701e1138";
Comment on lines +192 to +221
Copy link
Contributor

Choose a reason for hiding this comment

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

How about using the anonymous identity for this? It's present for all dfx installations already so the key doesn't have to be imported

Copy link
Contributor Author

@bitdivine bitdivine Sep 26, 2022

Choose a reason for hiding this comment

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

This way normal API calls can be used. In this PR the secp256k1 key matches the existing ed25519 account (5b...), where it is also the case that code needs to have and use the secret key explicitly. It is a "no magic" philosophy. That said, if we did initialize the anonymous identity with ICP, how would this work? What is the account ID of the anonymous identity and what dfx call would transfer funds from the anonymous identity to another? Does the anonymous account use secp256k1? I mean, there might well be a use case for giving the anonymous ID funds but we would probably want to check the ramifications. In the case of the pre-populated ed25519 the account can be, and is, used like any other account. The idea was to do the same here. We can change the current approach but is that what we want?

Copy link
Contributor

Choose a reason for hiding this comment

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

NVM, I stand corrected: I just tried it out, and the anonymous principal did receive ICP, but is not allowed to send:

❯ dfx ledger account-id --of-principal 2vxsx-fae
1c7a48ba6a562aa9eaa2481a9049cdf0433b9738c992d698c31d8abf89cadc79
❯ dfx-wip ledger balance $(dfx --identity anonymous ledger account-id)
1000000000.00000000 ICP
❯ dfx-wip --identity anonymous ledger transfer --amount 5.7 e213184a548871a47fb526f3cba24e2ee2fbbc8129c4ab497ef2ce535130a0a4 --memo 1284
[Canister ryjl3-tyaaa-aaaaa-aaaba-cai] Panicked at 'Sending from 2vxsx-fae is not allowed', rosetta-api/ledger_canister/src/main.rs:140:9

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Interesting. Thank you for looking. I didn't know about dfx --identity anonymous. It is in the docs example of dfx identity list. That could be useful.