From 5ecaaf3d5c81f13762521f834318235432ae0665 Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Wed, 28 Sep 2022 18:44:33 -0400 Subject: [PATCH 1/2] add shuffle account tool, to store usable keys from mnemonic --- Cargo.lock | 1 + shuffle/cli/Cargo.toml | 3 +++ shuffle/cli/src/account.rs | 24 ++++++++++++++++++- shuffle/cli/src/deploy.rs | 24 ++++++++++++++----- shuffle/cli/src/main.rs | 17 ++++++++++--- shuffle/cli/src/shared.rs | 24 ++++++++++++++++++- shuffle/cli/src/test.rs | 2 +- .../examples/main/generated/diemStdlib/mod.ts | 10 ++++---- types/src/chain_id.rs | 2 +- 9 files changed, 89 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3ee865e127..a522b47311 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8628,6 +8628,7 @@ dependencies = [ "move-core-types", "move-package", "move-unit-test", + "ol-keys", "once_cell", "rand 0.8.4", "reqwest 0.11.10", diff --git a/shuffle/cli/Cargo.toml b/shuffle/cli/Cargo.toml index 2bd3ae3ca6..99f2aa36ed 100644 --- a/shuffle/cli/Cargo.toml +++ b/shuffle/cli/Cargo.toml @@ -54,6 +54,9 @@ serde_yaml = "0.8.17" smoke-test = { path = "../../testsuite/smoke-test" } transaction-builder-generator = { path = "../../diem-move/transaction-builder-generator" } +######### 0L ######## +ol-keys = { path = "../../ol/keys"} + [[bin]] name = "shuffle" path = "src/main.rs" diff --git a/shuffle/cli/src/account.rs b/shuffle/cli/src/account.rs index c26df97d99..6b809cc1c7 100644 --- a/shuffle/cli/src/account.rs +++ b/shuffle/cli/src/account.rs @@ -30,7 +30,7 @@ use std::{ }; // Creates new account from randomly generated private/public key pair. -pub async fn handle(home: &Home, root: Option, network: Network) -> Result<()> { +pub async fn handle(home: &Home, root: Option, network: Network, from_mnem: bool) -> Result<()> { let network_home = home.new_network_home(&network.get_name()); network_home.generate_paths_if_nonexistent()?; check_nodeconfig_exists_if_localhost_used(home, &network)?; @@ -41,6 +41,10 @@ pub async fn handle(home: &Home, root: Option, network: Network) -> Res false => return Ok(()), } } + if from_mnem { //////// 0L //////// + save_private_key(&network_home)?; + return Ok(()) + } let new_account = generate_new_account(&network_home)?; let test_account = generate_test_account(&network_home)?; @@ -139,6 +143,24 @@ fn generate_test_account(network_home: &NetworkHome) -> Result { )) } +//////// 0L //////// +fn save_private_key(network_home: &NetworkHome) -> Result { + println!("DANGER: This is saving a private key to disk. This is not recommended for production KEYS."); + let (_, acc, w) = ol_keys::wallet::get_account_from_prompt(); + let test_key = w.get_private_key(&acc)?; + // save the key + network_home.save_key_from_prompt(&acc, &test_key)?; + + // network_home.generate_testkey_address_file(&test_key.public_key())?; + Ok(LocalAccount::new( + acc, + test_key, + 0, + )) +} +//////// end 0L //////// + + pub async fn get_treasury_account( client: &DevApiClient, root_key_path: &Path, diff --git a/shuffle/cli/src/deploy.rs b/shuffle/cli/src/deploy.rs index 7d59cfbb63..f1cf074790 100644 --- a/shuffle/cli/src/deploy.rs +++ b/shuffle/cli/src/deploy.rs @@ -14,19 +14,29 @@ use diem_sdk::{ LocalAccount, }, }; -use diem_types::{chain_id::ChainId, transaction::authenticator::AuthenticationKey}; +use diem_types::{chain_id::{ChainId, NamedChain}, transaction::authenticator::AuthenticationKey}; use generate_key::load_key; use std::path::Path; use url::Url; /// Deploys shuffle's main Move Package to the sender's address. -pub async fn handle(network_home: &NetworkHome, project_path: &Path, url: Url) -> Result<()> { +pub async fn handle(network_home: &NetworkHome, project_path: &Path, url: Url, chain_name: NamedChain, use_mnem: bool) -> Result<()> { if !network_home.key_path_for(LATEST_USERNAME).exists() { return Err(anyhow!( "An account hasn't been created yet! Run shuffle account first." )); } - let account_key = load_key(network_home.key_path_for(LATEST_USERNAME)); + + ///////// 0L //////// + let account_key = if use_mnem { + let (_, b, c) = ol_keys::wallet::get_account_from_prompt(); + c.get_private_key(&b)? + } else { + load_key(network_home.key_path_for(LATEST_USERNAME)) + + }; + ///////// end 0L //////// + println!("Using Public Key {}", &account_key.public_key()); let address = AuthenticationKey::ed25519(&account_key.public_key()).derived_address(); println!("Sending txn from address {}", address.to_hex_literal()); @@ -35,13 +45,14 @@ pub async fn handle(network_home: &NetworkHome, project_path: &Path, url: Url) - let seq_number = client.get_account_sequence_number(address).await?; let mut account = LocalAccount::new(address, account_key, seq_number); - deploy(&client, &mut account, project_path).await + deploy(&client, &mut account, project_path, chain_name).await } pub async fn deploy( client: &DevApiClient, account: &mut LocalAccount, project_path: &Path, + chain_name: NamedChain, ) -> Result<()> { let compiled_package = build_move_package( project_path.join(shared::MAIN_PKG_PATH).as_ref(), @@ -61,7 +72,7 @@ pub async fn deploy( let mut binary = vec![]; module.serialize(&mut binary)?; - let hash = send_module_transaction(client, account, binary).await?; + let hash = send_module_transaction(client, account, binary, chain_name).await?; client.check_txn_executed_from_hash(hash.as_str()).await?; } @@ -72,8 +83,9 @@ async fn send_module_transaction( client: &DevApiClient, account: &mut LocalAccount, module_binary: Vec, + chain_name: NamedChain, ) -> Result { - let factory = TransactionFactory::new(ChainId::test()); + let factory = TransactionFactory::new(ChainId::new(chain_name.id())); let publish_txn = account.sign_with_transaction_builder(factory.payload( TransactionPayload::ModuleBundle(ModuleBundle::singleton(module_binary)), )); diff --git a/shuffle/cli/src/main.rs b/shuffle/cli/src/main.rs index f5b16bf759..579f5ffa77 100644 --- a/shuffle/cli/src/main.rs +++ b/shuffle/cli/src/main.rs @@ -6,7 +6,7 @@ use crate::{ test::TestCommand, }; use anyhow::{anyhow, Result}; -use diem_types::account_address::AccountAddress; +use diem_types::{account_address::AccountAddress}; use std::path::PathBuf; use structopt::StructOpt; @@ -33,19 +33,24 @@ pub async fn main() -> Result<()> { Subcommand::Deploy { project_path, network, + mnem, } => { + let name = normalized_network_name(network.clone()).to_owned(); deploy::handle( - &home.new_network_home(normalized_network_name(network.clone()).as_str()), + &home.new_network_home(&name), &shared::normalized_project_path(project_path)?, shared::normalized_network_url(&home, network)?, + home.read_networks_toml()?.get(&name)?.get_chain_name(), + mnem, ) .await } - Subcommand::Account { root, network } => { + Subcommand::Account { root, network, mnem } => { account::handle( &home, root, home.get_network_struct_from_toml(normalized_network_name(network).as_str())?, + mnem, ) .await } @@ -136,6 +141,9 @@ pub enum Subcommand { #[structopt(short, long)] network: Option, + + #[structopt(short, long)] + mnem: bool, }, Account { #[structopt(short, long, help = "Creates account from mint.key passed in by user")] @@ -143,6 +151,9 @@ pub enum Subcommand { #[structopt(short, long)] network: Option, + + #[structopt(short, long)] + mnem: bool, }, #[structopt(about = "Starts a REPL for onchain inspection")] Console { diff --git a/shuffle/cli/src/shared.rs b/shuffle/cli/src/shared.rs index e86ca60eab..a97e541ea1 100644 --- a/shuffle/cli/src/shared.rs +++ b/shuffle/cli/src/shared.rs @@ -5,8 +5,9 @@ use crate::context::UserContext; use anyhow::{anyhow, Result}; use diem_crypto::ed25519::{Ed25519PrivateKey, Ed25519PublicKey}; use diem_sdk::client::AccountAddress; -use diem_types::transaction::authenticator::AuthenticationKey; +use diem_types::{transaction::authenticator::AuthenticationKey, chain_id::NamedChain}; use directories::BaseDirs; +use generate_key::save_key; use move_package::{ compilation::compiled_package::CompiledPackage, source_package::{layout::SourcePackageLayout, manifest_parser}, @@ -201,6 +202,19 @@ impl NetworkHome { )) } + //////// 0L /////// + pub fn save_key_from_prompt(&self, acc: &AccountAddress, key: &Ed25519PrivateKey) -> Result<()>{ + let username = acc.to_string(); + save_key(key.to_owned(), self.key_path_for(LATEST_USERNAME).as_path()); + // save address file + let file_path = self.address_path_for(&LATEST_USERNAME); + let mut file = File::create(&file_path)?; + file.write_all(username.as_bytes())?; + println!("Keys saved to {}", file_path.parent().unwrap().to_str().unwrap()); + Ok(()) + } + //////// end 0L //////// + pub fn generate_testkey_address_file(&self, public_key: &Ed25519PublicKey) -> Result<()> { let address = AuthenticationKey::ed25519(public_key).derived_address(); let address_filepath = self.address_path_for(TEST_USERNAME); @@ -372,6 +386,7 @@ pub struct Network { json_rpc_url: Url, dev_api_url: Url, faucet_url: Option, + chain_id: Option //////// 0L //////// } impl Network { @@ -380,12 +395,14 @@ impl Network { json_rpc_url: Url, dev_api_url: Url, faucet_url: Option, + chain_id: Option, //////// 0L //////// ) -> Network { Network { name, json_rpc_url, dev_api_url, faucet_url, + chain_id, //////// 0L //////// } } @@ -411,6 +428,10 @@ impl Network { None => Err(anyhow!("This network doesn't have a faucet url")), } } + + pub fn get_chain_name(&self) -> NamedChain { + self.chain_id.unwrap_or(NamedChain::TESTING) + } } impl Default for Network { @@ -420,6 +441,7 @@ impl Default for Network { Url::from_str("http://127.0.0.1:8080").unwrap(), Url::from_str("http://127.0.0.1:8080").unwrap(), None, + Some(NamedChain::TESTING), //////// 0L //////// ) } } diff --git a/shuffle/cli/src/test.rs b/shuffle/cli/src/test.rs index 665b5e00ec..5ed08a7614 100644 --- a/shuffle/cli/src/test.rs +++ b/shuffle/cli/src/test.rs @@ -45,7 +45,7 @@ pub async fn run_e2e_tests( // happen once, and the second redundant build would be skipped. At least // it's cached atm. shared::codegen_typescript_libraries(project_path, &account1.address())?; - deploy::deploy(&client, &mut account1, project_path).await?; + deploy::deploy(&client, &mut account1, project_path, network.get_chain_name()).await?; let tmp_dir = TempDir::new()?; let key1_path = tmp_dir.path().join("private1.key"); diff --git a/shuffle/move/examples/main/generated/diemStdlib/mod.ts b/shuffle/move/examples/main/generated/diemStdlib/mod.ts index b3e592335f..bb88e23dbe 100644 --- a/shuffle/move/examples/main/generated/diemStdlib/mod.ts +++ b/shuffle/move/examples/main/generated/diemStdlib/mod.ts @@ -129,7 +129,7 @@ export class Stdlib { serializer.serializeBytes(content_uri); const content_uri_serialized: bytes = serializer.getBytes(); const args: Seq = [content_uri_serialized]; - const module_id: DiemTypes.ModuleId = new DiemTypes.ModuleId(new DiemTypes.AccountAddress([[104], [160], [48], [213], [182], [75], [129], [10], [39], [144], [118], [101], [228], [198], [118], [196]]), new DiemTypes.Identifier("TestNFT")); + const module_id: DiemTypes.ModuleId = new DiemTypes.ModuleId(new DiemTypes.AccountAddress([[122], [193], [190], [132], [229], [60], [172], [191], [134], [251], [188], [45], [228], [177], [151], [201]]), new DiemTypes.Identifier("TestNFT")); const function_name: DiemTypes.Identifier = new DiemTypes.Identifier("create_nft"); const script = new DiemTypes.ScriptFunction(module_id, function_name, tyArgs, args); return new DiemTypes.TransactionPayloadVariantScriptFunction(script); @@ -141,7 +141,7 @@ export class Stdlib { static encodeInitializeNftCollectionScriptFunction(nft_type: DiemTypes.TypeTag): DiemTypes.TransactionPayload { const tyArgs: Seq = [nft_type]; const args: Seq = []; - const module_id: DiemTypes.ModuleId = new DiemTypes.ModuleId(new DiemTypes.AccountAddress([[104], [160], [48], [213], [182], [75], [129], [10], [39], [144], [118], [101], [228], [198], [118], [196]]), new DiemTypes.Identifier("NFTStandard")); + const module_id: DiemTypes.ModuleId = new DiemTypes.ModuleId(new DiemTypes.AccountAddress([[122], [193], [190], [132], [229], [60], [172], [191], [134], [251], [188], [45], [228], [177], [151], [201]]), new DiemTypes.Identifier("NFTStandard")); const function_name: DiemTypes.Identifier = new DiemTypes.Identifier("initialize_nft_collection"); const script = new DiemTypes.ScriptFunction(module_id, function_name, tyArgs, args); return new DiemTypes.TransactionPayloadVariantScriptFunction(script); @@ -156,7 +156,7 @@ export class Stdlib { serializer.serializeBytes(message_bytes); const message_bytes_serialized: bytes = serializer.getBytes(); const args: Seq = [message_bytes_serialized]; - const module_id: DiemTypes.ModuleId = new DiemTypes.ModuleId(new DiemTypes.AccountAddress([[104], [160], [48], [213], [182], [75], [129], [10], [39], [144], [118], [101], [228], [198], [118], [196]]), new DiemTypes.Identifier("Message")); + const module_id: DiemTypes.ModuleId = new DiemTypes.ModuleId(new DiemTypes.AccountAddress([[122], [193], [190], [132], [229], [60], [172], [191], [134], [251], [188], [45], [228], [177], [151], [201]]), new DiemTypes.Identifier("Message")); const function_name: DiemTypes.Identifier = new DiemTypes.Identifier("set_message"); const script = new DiemTypes.ScriptFunction(module_id, function_name, tyArgs, args); return new DiemTypes.TransactionPayloadVariantScriptFunction(script); @@ -178,7 +178,7 @@ export class Stdlib { serializer.serializeU64(creation_num); const creation_num_serialized: bytes = serializer.getBytes(); const args: Seq = [to_serialized, creator_serialized, creation_num_serialized]; - const module_id: DiemTypes.ModuleId = new DiemTypes.ModuleId(new DiemTypes.AccountAddress([[104], [160], [48], [213], [182], [75], [129], [10], [39], [144], [118], [101], [228], [198], [118], [196]]), new DiemTypes.Identifier("NFTStandard")); + const module_id: DiemTypes.ModuleId = new DiemTypes.ModuleId(new DiemTypes.AccountAddress([[122], [193], [190], [132], [229], [60], [172], [191], [134], [251], [188], [45], [228], [177], [151], [201]]), new DiemTypes.Identifier("NFTStandard")); const function_name: DiemTypes.Identifier = new DiemTypes.Identifier("transfer"); const script = new DiemTypes.ScriptFunction(module_id, function_name, tyArgs, args); return new DiemTypes.TransactionPayloadVariantScriptFunction(script); @@ -242,7 +242,7 @@ export class Stdlib { } } - static SET_MESSAGE_CODE = Stdlib.fromHexString('a11ceb0b0400000005010002030205050705070c1408201000000001000100020c0a0200074d6573736167650b7365745f6d65737361676568a030d5b64b810a27907665e4c676c4000001040b000b01110002'); + static SET_MESSAGE_CODE = Stdlib.fromHexString('a11ceb0b0400000005010002030205050705070c1408201000000001000100020c0a0200074d6573736167650b7365745f6d6573736167657ac1be84e53cacbf86fbbc2de4b197c9000001040b000b01110002'); static ScriptArgs: {[name: string]: ScriptDef} = { SetMessage: { diff --git a/types/src/chain_id.rs b/types/src/chain_id.rs index 52b7014e94..61401fb9b0 100644 --- a/types/src/chain_id.rs +++ b/types/src/chain_id.rs @@ -9,7 +9,7 @@ use std::{convert::TryFrom, fmt, str::FromStr}; /// When signing transactions for such chains, the numerical chain ID should still be used /// (e.g. MAINNET has numeric chain ID 1, TESTNET has chain ID 2, etc) #[repr(u8)] -#[derive(Copy, Clone, Debug, Serialize)] ///////// 0L //////// +#[derive(Copy, Clone, Debug, Serialize, PartialEq)] ///////// 0L //////// pub enum NamedChain { /// Users might accidentally initialize the ChainId field to 0, hence reserving ChainId 0 for accidental /// initialization. From 288d34b4a91c89f6ae13fec9529b1c100ae7704a Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Wed, 28 Sep 2022 18:48:13 -0400 Subject: [PATCH 2/2] shuffle messages --- shuffle/cli/src/account.rs | 5 +++-- shuffle/cli/src/shared.rs | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/shuffle/cli/src/account.rs b/shuffle/cli/src/account.rs index 6b809cc1c7..9726882778 100644 --- a/shuffle/cli/src/account.rs +++ b/shuffle/cli/src/account.rs @@ -118,7 +118,9 @@ fn archive_current_files(network_home: &NetworkHome) -> Result<()> { let time = duration_since_epoch(); let archive_dir = network_home.create_archive_dir(time)?; network_home.archive_old_key_for(LATEST_USERNAME, &archive_dir)?; - network_home.archive_old_address_for(LATEST_USERNAME, &archive_dir) + network_home.archive_old_address_for(LATEST_USERNAME, &archive_dir)?; + println!("Archived old keys. Manually delete these files if they contain PRODUCTION KEYS {}", archive_dir.display()); + Ok(()) } fn generate_new_account(network_home: &NetworkHome) -> Result { @@ -151,7 +153,6 @@ fn save_private_key(network_home: &NetworkHome) -> Result { // save the key network_home.save_key_from_prompt(&acc, &test_key)?; - // network_home.generate_testkey_address_file(&test_key.public_key())?; Ok(LocalAccount::new( acc, test_key, diff --git a/shuffle/cli/src/shared.rs b/shuffle/cli/src/shared.rs index a97e541ea1..46af3fa436 100644 --- a/shuffle/cli/src/shared.rs +++ b/shuffle/cli/src/shared.rs @@ -211,6 +211,7 @@ impl NetworkHome { let mut file = File::create(&file_path)?; file.write_all(username.as_bytes())?; println!("Keys saved to {}", file_path.parent().unwrap().to_str().unwrap()); + println!("To delete all keys check all paths in .shuffle/networks, since this tool may backup the keys."); Ok(()) } //////// end 0L ////////