CLI: collect and deduplicate signers (#8398)

* Rename (keypair util is not a thing)

* Add method to generate_unique_signers

* Cli: refactor signer handling and remote-wallet init

* Fixup unit tests

* Fixup intergation tests

* Update keypair path print statement

* Remove &None

* Use deterministic key in test

* Retain storage-account as index

* Make signer index-handling less brittle

* Cache pubkey on RemoteKeypair::new

* Make signer_of consistent + return pubkey

* Remove &matches double references

* Nonce authorities need special handling
This commit is contained in:
Tyera Eulberg
2020-02-24 17:03:30 -07:00
committed by GitHub
parent 89baa94002
commit 12a9b5f35e
22 changed files with 2095 additions and 1635 deletions

View File

@@ -1,5 +1,5 @@
use crate::remote_wallet::{
initialize_wallet_manager, DerivationPath, RemoteWallet, RemoteWalletError, RemoteWalletInfo,
DerivationPath, RemoteWallet, RemoteWalletError, RemoteWalletInfo, RemoteWalletManager,
};
use dialoguer::{theme::ColorfulTheme, Select};
use log::*;
@@ -378,9 +378,8 @@ fn extend_and_serialize(derivation_path: &DerivationPath) -> Vec<u8> {
/// Choose a Ledger wallet based on matching info fields
pub fn get_ledger_from_info(
info: RemoteWalletInfo,
wallet_manager: &RemoteWalletManager,
) -> Result<Arc<LedgerWallet>, RemoteWalletError> {
let wallet_manager = initialize_wallet_manager()?;
let _device_count = wallet_manager.update_devices()?;
let devices = wallet_manager.list_devices();
let (pubkeys, device_paths): (Vec<Pubkey>, Vec<String>) = devices
.iter()

View File

@@ -1,7 +1,8 @@
use crate::{
ledger::get_ledger_from_info,
remote_wallet::{
DerivationPath, RemoteWallet, RemoteWalletError, RemoteWalletInfo, RemoteWalletType,
DerivationPath, RemoteWallet, RemoteWalletError, RemoteWalletInfo, RemoteWalletManager,
RemoteWalletType,
},
};
use solana_sdk::{
@@ -12,24 +13,29 @@ use solana_sdk::{
pub struct RemoteKeypair {
pub wallet_type: RemoteWalletType,
pub derivation_path: DerivationPath,
pub pubkey: Pubkey,
}
impl RemoteKeypair {
pub fn new(wallet_type: RemoteWalletType, derivation_path: DerivationPath) -> Self {
Self {
pub fn new(
wallet_type: RemoteWalletType,
derivation_path: DerivationPath,
) -> Result<Self, RemoteWalletError> {
let pubkey = match &wallet_type {
RemoteWalletType::Ledger(wallet) => wallet.get_pubkey(&derivation_path)?,
};
Ok(Self {
wallet_type,
derivation_path,
}
pubkey,
})
}
}
impl Signer for RemoteKeypair {
fn try_pubkey(&self) -> Result<Pubkey, SignerError> {
match &self.wallet_type {
RemoteWalletType::Ledger(wallet) => wallet
.get_pubkey(&self.derivation_path)
.map_err(|e| e.into()),
}
Ok(self.pubkey)
}
fn try_sign_message(&self, message: &[u8]) -> Result<Signature, SignerError> {
@@ -44,17 +50,18 @@ impl Signer for RemoteKeypair {
pub fn generate_remote_keypair(
path: String,
explicit_derivation_path: Option<DerivationPath>,
wallet_manager: &RemoteWalletManager,
) -> Result<RemoteKeypair, RemoteWalletError> {
let (remote_wallet_info, mut derivation_path) = RemoteWalletInfo::parse_path(path)?;
if let Some(derivation) = explicit_derivation_path {
derivation_path = derivation;
}
if remote_wallet_info.manufacturer == "ledger" {
let ledger = get_ledger_from_info(remote_wallet_info)?;
Ok(RemoteKeypair {
wallet_type: RemoteWalletType::Ledger(ledger),
let ledger = get_ledger_from_info(remote_wallet_info, wallet_manager)?;
Ok(RemoteKeypair::new(
RemoteWalletType::Ledger(ledger),
derivation_path,
})
)?)
} else {
Err(RemoteWalletError::DeviceTypeMismatch)
}

View File

@@ -299,6 +299,17 @@ pub fn initialize_wallet_manager() -> Result<Arc<RemoteWalletManager>, RemoteWal
Ok(RemoteWalletManager::new(hidapi))
}
pub fn maybe_wallet_manager() -> Result<Option<Arc<RemoteWalletManager>>, RemoteWalletError> {
let wallet_manager = initialize_wallet_manager()?;
let device_count = wallet_manager.update_devices()?;
if device_count > 0 {
Ok(Some(wallet_manager))
} else {
drop(wallet_manager);
Ok(None)
}
}
#[cfg(test)]
mod tests {
use super::*;