Skip to content

Commit

Permalink
feat: ledger blind sign (#6264)
Browse files Browse the repository at this point in the history
Description
---
Add key manager support to create transactions on chain where a ledger
device is required to spend outputs

Motivation and Context
---
Cold storage support

How Has This Been Tested?
---
Manual localnet testing

Breaking Changes
---

- [ ] None
- [x] Requires data directory on base node to be deleted
- [x] Requires hard fork
- [ ] Other - Please specify

This PR changes transaction hash mismatches which will invlaidate
previous utxo's.

---------

Co-authored-by: SW van Heerden <swvheerden@gmail.com>
  • Loading branch information
brianp and SWvheerden committed May 16, 2024
1 parent 9920916 commit 301ea00
Show file tree
Hide file tree
Showing 63 changed files with 3,097 additions and 1,234 deletions.
19 changes: 17 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 @@ -30,6 +30,7 @@ members = [
"applications/minotari_app_utilities",
"applications/minotari_merge_mining_proxy",
"applications/minotari_miner",
"applications/minotari_ledger_wallet/comms",
"integration_tests",
"hashing",
]
Expand Down
3 changes: 2 additions & 1 deletion applications/minotari_console_wallet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ license = "BSD-3-Clause"
[dependencies]
minotari_app_grpc = { path = "../minotari_app_grpc" }
minotari_app_utilities = { path = "../minotari_app_utilities" }
minotari_ledger_wallet_comms = { path = "../../applications/minotari_ledger_wallet/comms", version = "1.0.0-pre.13" }
tari_common = { path = "../../common" }
tari_common_types = { path = "../../base_layer/common_types" }
tari_comms = { path = "../../comms/core" }
Expand Down Expand Up @@ -88,7 +89,7 @@ tari_features = { path = "../../common/tari_features", version = "1.0.0-pre.13"
[features]
default = ["libtor"]
grpc = []
ledger = ["ledger-transport-hid"]
ledger = ["ledger-transport-hid", ]
libtor = ["tari_libtor"]

[package.metadata.cargo-machete]
Expand Down
59 changes: 46 additions & 13 deletions applications/minotari_console_wallet/src/init/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ use std::{fs, io, path::PathBuf, str::FromStr, sync::Arc, time::Instant};
use ledger_transport_hid::{hidapi::HidApi, TransportNativeHID};
use log::*;
use minotari_app_utilities::{consts, identity_management::setup_node_identity};
use minotari_ledger_wallet_comms::{
error::LedgerDeviceError,
ledger_wallet::{get_transport, Instruction, LedgerWallet},
};
use minotari_wallet::{
error::{WalletError, WalletStorageError},
output_manager_service::storage::database::OutputManagerDatabase,
Expand All @@ -50,15 +54,21 @@ use tari_common::{
},
exit_codes::{ExitCode, ExitError},
};
use tari_common_types::wallet_types::WalletType;
use tari_common_types::{
types::{PrivateKey, PublicKey},
wallet_types::WalletType,
};
use tari_comms::{
multiaddr::Multiaddr,
peer_manager::{Peer, PeerFeatures, PeerQuery},
types::CommsPublicKey,
NodeIdentity,
};
use tari_core::{consensus::ConsensusManager, transactions::CryptoFactories};
use tari_crypto::keys::PublicKey;
use tari_core::{
consensus::ConsensusManager,
transactions::{transaction_components::TransactionError, CryptoFactories},
};
use tari_crypto::{keys::PublicKey as PublicKeyTrait, ristretto::RistrettoPublicKey};
use tari_key_manager::{cipher_seed::CipherSeed, mnemonic::MnemonicLanguage};
use tari_p2p::{peer_seeds::SeedPeer, TransportType};
use tari_shutdown::ShutdownSignal;
Expand Down Expand Up @@ -818,42 +828,65 @@ pub fn prompt_wallet_type(
non_interactive: bool,
) -> Option<WalletType> {
if non_interactive {
return Some(WalletType::Software);
return Some(WalletType::default());
}

if wallet_config.wallet_type.is_some() {
return wallet_config.wallet_type;
return wallet_config.wallet_type.clone();
}

match boot_mode {
WalletBoot::New => {
#[cfg(not(feature = "ledger"))]
return Some(WalletType::Software);
return Some(WalletType::default());

#[cfg(feature = "ledger")]
{
if prompt("\r\nWould you like to use a connected hardware wallet? (Supported types: Ledger)") {
print!("Scanning for connected Ledger hardware device... ");
let err = "No connected device was found. Please make sure the device is plugged in before
continuing.";
match TransportNativeHID::new(&HidApi::new().expect(err)) {
Ok(_) => {
match get_transport() {
Ok(hid) => {
println!("Device found.");
let account = prompt_ledger_account().expect("An account value");
Some(WalletType::Ledger(account))
let ledger = LedgerWallet::new(account, wallet_config.network, None);
match ledger
.build_command(Instruction::GetPublicAlpha, vec![])
.execute_with_transport(&hid)
{
Ok(result) => {
debug!(target: LOG_TARGET, "result length: {}, data: {:?}", result.data().len(), result.data());
if result.data().len() < 33 {
debug!(target: LOG_TARGET, "result less than 33");
panic!(
"'get_public_key' insufficient data - expected 33 got {} bytes ({:?})",
result.data().len(),
result
);
}

let key = match PublicKey::from_canonical_bytes(&result.data()[1..33]) {
Ok(k) => k,
Err(e) => panic!("{}", e),
};

let ledger = LedgerWallet::new(account, wallet_config.network, Some(key));
Some(WalletType::Ledger(ledger))
},
Err(e) => panic!("{}", e),
}
},
Err(e) => panic!("{}", e),
}
} else {
Some(WalletType::Software)
Some(WalletType::default())
}
}
},
_ => None,
}
}

pub fn prompt_ledger_account() -> Option<usize> {
pub fn prompt_ledger_account() -> Option<u64> {
let question =
"\r\nPlease enter an account number for your ledger. A simple 1-9, easily remembered numbers are suggested.";
println!("{}", question);
Expand Down
1 change: 0 additions & 1 deletion applications/minotari_console_wallet/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,6 @@ pub fn run_wallet_with_cli(

let recovery_seed = get_recovery_seed(boot_mode, &cli)?;

// This is deactivated at the moment as full support is not yet complete
let wallet_type = prompt_wallet_type(boot_mode, &config.wallet, cli.non_interactive_mode);

// get command line password if provided
Expand Down
Loading

0 comments on commit 301ea00

Please sign in to comment.