Skip to content

Commit

Permalink
Add support for ledger nano sim to CI (#551)
Browse files Browse the repository at this point in the history
* Add support for ledger nano sim to CI

* working directory

* cleanup

* Update action

* Use alternative branch

* Try detached mode

* use new flag

* Fix test

* changelog

* Change ref to develop

---------

Co-authored-by: Thibault Martinez <[email protected]>
  • Loading branch information
Alexandcoats and thibault-martinez authored Jul 14, 2023
1 parent 8cc7982 commit 83c04f7
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 9 deletions.
21 changes: 21 additions & 0 deletions .github/actions/ledger-nano/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: "ledger-nano-setup"
description: "Setup a simulated ledger nano instance"
runs:
using: "composite"
steps:
- name: Checkout ledger shimmer app files
uses: actions/checkout@v3
with:
repository: iotaledger/ledger-iota-app
ref: develop
path: ledger-iota-app

- name: Update submodules
shell: bash
run: git submodule update --init --recursive
working-directory: ledger-iota-app

- name: Run the simulator
shell: bash
run: ./build.sh -s -v shimmer -b
working-directory: ledger-iota-app
3 changes: 3 additions & 0 deletions .github/workflows/private-tangle-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ jobs:
- name: Start private tangle
uses: "./.github/actions/private-tangle/setup"

- name: Start ledger nano
uses: "./.github/actions/ledger-nano"

- name: Run tests
uses: actions-rs/cargo@v1
with:
Expand Down
1 change: 1 addition & 0 deletions sdk/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `WalletBuilder::with_storage_options` method, allowing storage encryption;
- `StorageOptions::{new, with_encryption_key}` methods and getters;
- `MinimumStorageDepositBasicOutput`;
- `LedgerSecretManager::non_interactive` field;

### Changed

Expand Down
60 changes: 51 additions & 9 deletions sdk/src/client/secret/ledger_nano.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ use crypto::{
signatures::secp256k1_ecdsa::{self, EvmAddress},
};
use iota_ledger_nano::{
get_app_config, get_buffer_size, get_ledger, get_opened_app, LedgerBIP32Index, Packable as LedgerNanoPackable,
TransportTypes,
api::errors::APIError, get_app_config, get_buffer_size, get_ledger, get_opened_app, LedgerBIP32Index,
Packable as LedgerNanoPackable, TransportTypes,
};
use packable::{error::UnexpectedEOF, unpacker::SliceUnpacker, Packable, PackableExt};
use tokio::sync::Mutex;
Expand Down Expand Up @@ -90,15 +90,14 @@ impl From<crate::types::block::Error> for Error {
// LedgerDeviceNotFound: No usable Ledger device was found
// LedgerMiscError: Everything else.
// LedgerEssenceTooLarge: Essence with bip32 input indices need more space then the internal buffer is big
#[cfg(feature = "ledger_nano")]
impl From<iota_ledger_nano::api::errors::APIError> for Error {
fn from(error: iota_ledger_nano::api::errors::APIError) -> Self {
impl From<APIError> for Error {
fn from(error: APIError) -> Self {
log::info!("ledger error: {}", error);
match error {
iota_ledger_nano::api::errors::APIError::ConditionsOfUseNotSatisfied => Self::DeniedByUser,
iota_ledger_nano::api::errors::APIError::EssenceTooLarge => Self::EssenceTooLarge,
iota_ledger_nano::api::errors::APIError::SecurityStatusNotSatisfied => Self::DongleLocked,
iota_ledger_nano::api::errors::APIError::TransportError => Self::DeviceNotFound,
APIError::ConditionsOfUseNotSatisfied => Self::DeniedByUser,
APIError::EssenceTooLarge => Self::EssenceTooLarge,
APIError::SecurityStatusNotSatisfied => Self::DongleLocked,
APIError::TransportError => Self::DeviceNotFound,
_ => Self::MiscError,
}
}
Expand All @@ -109,6 +108,8 @@ impl From<iota_ledger_nano::api::errors::APIError> for Error {
pub struct LedgerSecretManager {
/// Specifies if a real Ledger hardware is used or only a simulator is used.
pub is_simulator: bool,
/// Specifies whether the wallet should be in non-interactive mode.
pub non_interactive: bool,
/// Mutex to prevent multiple simultaneous requests to a ledger.
pub mutex: Mutex<()>,
}
Expand Down Expand Up @@ -152,6 +153,9 @@ impl SecretManage for LedgerSecretManager {

// get ledger
let ledger = get_ledger(coin_type, bip32_account, self.is_simulator).map_err(Error::from)?;
ledger
.set_non_interactive_mode(self.non_interactive)
.map_err(Error::from)?;

let addresses = ledger
.get_addresses(options.ledger_nano_prompt, bip32, address_indexes.len())
Expand Down Expand Up @@ -198,6 +202,9 @@ impl SecretManage for LedgerSecretManager {
let lock = self.mutex.lock().await;

let ledger = get_ledger(coin_type, account_index, self.is_simulator).map_err(Error::from)?;
ledger
.set_non_interactive_mode(self.non_interactive)
.map_err(Error::from)?;

log::debug!("[LEDGER] prepare_blind_signing");
log::debug!("[LEDGER] {:?} {:?}", bip32_index, msg);
Expand Down Expand Up @@ -286,6 +293,9 @@ impl SecretManage for LedgerSecretManager {
let lock = self.mutex.lock().await;

let ledger = get_ledger(coin_type, bip32_account, self.is_simulator).map_err(Error::from)?;
ledger
.set_non_interactive_mode(self.non_interactive)
.map_err(Error::from)?;
let blind_signing = needs_blind_signing(prepared_transaction, ledger.get_buffer_size());

// if essence + bip32 input indices are larger than the buffer size or the essence contains
Expand Down Expand Up @@ -466,6 +476,7 @@ impl LedgerSecretManager {
pub fn new(is_simulator: bool) -> Self {
Self {
is_simulator,
non_interactive: false,
mutex: Mutex::new(()),
}
}
Expand Down Expand Up @@ -600,3 +611,34 @@ fn merge_unlocks(
}
Ok(merged_unlocks)
}

#[cfg(test)]
mod tests {
use super::*;
use crate::{
client::{api::GetAddressesOptions, constants::IOTA_COIN_TYPE, secret::SecretManager},
types::block::address::ToBech32Ext,
};

#[tokio::test]
#[ignore = "requires ledger nano instance"]
async fn ed25519_address() {
let mut secret_manager = LedgerSecretManager::new(true);
secret_manager.non_interactive = true;

let addresses = SecretManager::LedgerNano(secret_manager)
.generate_ed25519_addresses(
GetAddressesOptions::default()
.with_coin_type(IOTA_COIN_TYPE)
.with_account_index(0)
.with_range(0..1),
)
.await
.unwrap();

assert_eq!(
addresses[0].to_bech32_unchecked("atoi").to_string(),
"atoi1qqdnv60ryxynaeyu8paq3lp9rkll7d7d92vpumz88fdj4l0pn5mru50gvd8"
);
}
}

0 comments on commit 83c04f7

Please sign in to comment.