Skip to content

Commit 38ed600

Browse files
committed
Fix comments
1 parent 1bcd08f commit 38ed600

File tree

12 files changed

+218
-20
lines changed

12 files changed

+218
-20
lines changed

.github/workflows/build.yml

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -229,9 +229,9 @@ jobs:
229229
- name: Run tests in the emulator
230230
run: nix-shell --run "
231231
poetry run core/emu.py
232-
--headless --quiet --temporary-profile
233-
--mnemonic \"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about\"
234-
--command env --chdir ../mintlayer-core
232+
--headless --quiet --temporary-profile
233+
--mnemonic \"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about\"
234+
--command env --chdir ../mintlayer-core
235235
cargo-nextest nextest run --archive-file tests.tar.zst -j1 trezor_signer
236236
"
237237
working-directory: ./mintlayer-trezor-firmware
@@ -268,6 +268,9 @@ jobs:
268268
run_tests_on_ledger:
269269
needs: run_tests_on_ledger_preparation
270270
runs-on: ubuntu-latest
271+
strategy:
272+
matrix:
273+
model: [nanosplus, nanox, flex, stax]
271274
steps:
272275
- name: Checkout the core repository
273276
uses: actions/checkout@v4
@@ -292,7 +295,7 @@ jobs:
292295
sudo docker run --rm \
293296
-v "$(realpath ./mintlayer-ledger-app):/app" \
294297
ghcr.io/ledgerhq/ledger-app-builder/ledger-app-dev-tools:latest \
295-
sh -c 'cd /app && cargo ledger build nanosplus'
298+
sh -c 'cargo ledger build ${{ matrix.model }}'
296299
- name: Run Ledger emulator and execute tests
297300
run: |
298301
set -e
@@ -301,7 +304,7 @@ jobs:
301304
-v "$(realpath ./mintlayer-ledger-app):/app" \
302305
--publish 5001:5001 --publish 9999:9999 \
303306
ghcr.io/ledgerhq/ledger-app-builder/ledger-app-dev-tools:latest \
304-
sh -c 'cd /app && speculos --apdu-port 9999 --api-port 5001 --display headless --model nanosp -s "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" target/nanosplus/release/mintlayer-app'
307+
sh -c 'speculos --apdu-port 9999 --api-port 5000 --display headless -s "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" target/nanosplus/release/mintlayer-app'
305308
306309
echo "--- Waiting for emulator to initialize ---"
307310
sleep 15

node-gui/src/main_window/main_widget/tabs/wallet/status_bar.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,13 @@ pub fn view_status_bar(wallet_info: &WalletExtraInfo) -> Option<Element<'static,
6868
]
6969
}
7070
#[cfg(feature = "ledger")]
71-
WalletExtraInfo::LedgerWallet { app_version } => {
72-
row![rich_text([span("App version: ").font(bold_font), span(app_version.clone())])
73-
.size(TEXT_SIZE),]
71+
WalletExtraInfo::LedgerWallet { app_version, model } => {
72+
row![
73+
rich_text([span("Model name: ").font(bold_font), span(model.clone())])
74+
.size(TEXT_SIZE),
75+
rich_text([span("App version: ").font(bold_font), span(app_version.clone())])
76+
.size(TEXT_SIZE),
77+
]
7478
}
7579
};
7680

node-gui/src/main_window/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ use wallet_types::{seed_phrase::StoreSeedPhrase, wallet_type::WalletType, Import
4040

4141
#[cfg(any(feature = "trezor", feature = "ledger"))]
4242
use crate::widgets::create_hw_wallet::hw_wallet_create_dialog;
43+
#[cfg(any(feature = "trezor", feature = "ledger"))]
44+
use crate::widgets::create_hw_wallet::HardwareWalletType;
4345
use crate::{
4446
main_window::{main_menu::MenuMessage, main_widget::MainWidgetMessage},
4547
widgets::{
@@ -870,6 +872,7 @@ impl MainWindow {
870872
}),
871873
Box::new(|| MainWindowMessage::CloseDialog),
872874
ImportOrCreate::Create,
875+
HardwareWalletType::Trezor,
873876
)
874877
.into(),
875878
#[cfg(feature = "ledger")]
@@ -880,6 +883,7 @@ impl MainWindow {
880883
}),
881884
Box::new(|| MainWindowMessage::CloseDialog),
882885
ImportOrCreate::Create,
886+
HardwareWalletType::Ledger,
883887
)
884888
.into(),
885889
},
@@ -904,6 +908,7 @@ impl MainWindow {
904908
}),
905909
Box::new(|| MainWindowMessage::CloseDialog),
906910
ImportOrCreate::Import,
911+
HardwareWalletType::Trezor,
907912
)
908913
.into(),
909914
#[cfg(feature = "ledger")]
@@ -914,6 +919,7 @@ impl MainWindow {
914919
}),
915920
Box::new(|| MainWindowMessage::CloseDialog),
916921
ImportOrCreate::Import,
922+
HardwareWalletType::Ledger,
917923
)
918924
.into(),
919925
}

node-gui/src/widgets/create_hw_wallet.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,43 @@ use iced_aw::Card;
2525

2626
use wallet_types::ImportOrCreate;
2727

28+
#[derive(Debug, Clone, Copy)]
29+
pub enum HardwareWalletType {
30+
#[cfg(feature = "trezor")]
31+
Trezor,
32+
#[cfg(feature = "ledger")]
33+
Ledger,
34+
}
35+
36+
impl HardwareWalletType {
37+
fn name(self) -> &'static str {
38+
match self {
39+
#[cfg(feature = "trezor")]
40+
Self::Trezor => "Trezor",
41+
#[cfg(feature = "ledger")]
42+
Self::Ledger => "Ledger",
43+
}
44+
}
45+
}
46+
2847
pub struct CreateHwWalletDialog<Message> {
2948
on_import: Box<dyn Fn() -> Message>,
3049
on_close: Box<dyn Fn() -> Message>,
3150
mode: ImportOrCreate,
51+
hw_wallet_type: HardwareWalletType,
3252
}
3353

3454
pub fn hw_wallet_create_dialog<Message>(
3555
on_import: Box<dyn Fn() -> Message>,
3656
on_close: Box<dyn Fn() -> Message>,
3757
mode: ImportOrCreate,
58+
hw_wallet_type: HardwareWalletType,
3859
) -> CreateHwWalletDialog<Message> {
3960
CreateHwWalletDialog {
4061
on_import,
4162
on_close,
4263
mode,
64+
hw_wallet_type,
4365
}
4466
}
4567

@@ -74,14 +96,20 @@ impl<Message> Component<Message, Theme, iced::Renderer> for CreateHwWalletDialog
7496
.width(100.0)
7597
.on_press(ImportEvent::Ok);
7698

99+
let hw_wallet_name = self.hw_wallet_type.name();
100+
77101
let card = match self.mode {
78102
ImportOrCreate::Create => Card::new(
79103
Text::new("Create new Wallet"),
80-
Text::new("Create a new Trezor wallet using the connected Trezor device"),
104+
Text::new(format!(
105+
"Create a new {hw_wallet_name} wallet using the connected {hw_wallet_name} device"
106+
)),
81107
),
82108
ImportOrCreate::Import => Card::new(
83109
Text::new("Recover new Wallet"),
84-
Text::new("Recover a new wallet using the connected Trezor device"),
110+
Text::new(format!(
111+
"Recover a new wallet using the connected {hw_wallet_name} device"
112+
)),
85113
),
86114
};
87115
if state.importing {

node-gui/src/widgets/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
// limitations under the License.
1515

1616
pub mod confirm_broadcast;
17-
#[cfg(feature = "trezor")]
17+
#[cfg(any(feature = "trezor", feature = "ledger"))]
1818
pub mod create_hw_wallet;
1919
pub mod esc_handler;
2020
pub mod new_wallet_account;

wallet/src/signer/ledger_signer/ledger_messages.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ use crypto::key::{
2727
};
2828
use serialization::Encode;
2929
use utils::ensure;
30-
use wallet_types::hw_data::LedgerFullInfo;
3130

3231
use ledger_lib::{Device, Exchange};
3332
use ledger_proto::StatusCode;
@@ -140,7 +139,7 @@ pub async fn sign_challenge<L: Exchange>(
140139

141140
pub async fn check_current_app<L: Exchange + Device + Send>(
142141
ledger: &mut L,
143-
) -> SignerResult<LedgerFullInfo> {
142+
) -> SignerResult<String> {
144143
let info = ledger
145144
.app_info(TIMEOUT_DUR)
146145
.await
@@ -153,7 +152,7 @@ pub async fn check_current_app<L: Exchange + Device + Send>(
153152
LedgerError::DifferentActiveApp(name)
154153
);
155154

156-
Ok(LedgerFullInfo { app_version })
155+
Ok(app_version)
157156
}
158157

159158
pub async fn get_extended_public_key_raw<L: Exchange>(

wallet/src/signer/ledger_signer/mod.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,15 @@ use wallet_storage::{
7070
};
7171
use wallet_types::{
7272
account_info::DEFAULT_ACCOUNT_INDEX,
73-
hw_data::{HardwareWalletFullInfo, LedgerData, LedgerFullInfo},
73+
hw_data::{HardwareWalletFullInfo, LedgerData, LedgerFullInfo, LedgerModel},
7474
partially_signed_transaction::{PartiallySignedTransaction, TokensAdditionalInfo},
7575
signature_status::SignatureStatus,
7676
AccountId,
7777
};
7878

7979
use async_trait::async_trait;
8080
use itertools::{izip, Itertools};
81-
use ledger_lib::{Exchange, Filters, LedgerHandle, LedgerProvider, Transport};
81+
use ledger_lib::{info::Model, Exchange, Filters, LedgerHandle, LedgerProvider, Transport};
8282
use mintlayer_ledger_messages::{
8383
AddrType, Bip32Path as LedgerBip32Path, CoinType, InputAdditionalInfoReq,
8484
InputAddressPath as LedgerInputAddressPath, Signature as LedgerSignature, TxInputReq,
@@ -1052,15 +1052,16 @@ async fn find_ledger_device() -> SignerResult<(LedgerHandle, LedgerFullInfo)> {
10521052
.map_err(|err| LedgerError::DeviceError(err.to_string()))?;
10531053

10541054
let device = devices.pop().ok_or(LedgerError::NoDeviceFound)?;
1055+
let model = to_ledger_model(&device.model);
10551056

10561057
let mut handle = provider
10571058
.connect(device)
10581059
.await
10591060
.map_err(|err| LedgerError::DeviceError(err.to_string()))?;
10601061

1061-
let full_info = check_current_app(&mut handle).await?;
1062+
let app_version = check_current_app(&mut handle).await?;
10621063

1063-
Ok((handle, full_info))
1064+
Ok((handle, LedgerFullInfo { app_version, model }))
10641065
}
10651066

10661067
/// Check that the public keys in the provided key chain are the same as the ones from the
@@ -1240,6 +1241,16 @@ impl SignerProvider for LedgerSignerProvider {
12401241
}
12411242
}
12421243

1244+
fn to_ledger_model(model: &Model) -> LedgerModel {
1245+
match model {
1246+
Model::NanoS => LedgerModel::NanoS,
1247+
Model::NanoSPlus => LedgerModel::NanoSPlus,
1248+
Model::NanoX => LedgerModel::NanoX,
1249+
Model::Stax => LedgerModel::Stax,
1250+
Model::Unknown(m) => LedgerModel::Unknown(*m),
1251+
}
1252+
}
1253+
12431254
#[cfg(feature = "enable-ledger-device-tests")]
12441255
#[cfg(test)]
12451256
mod tests;
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// Copyright (c) 2025 RBB S.r.l
2+
3+
// SPDX-License-Identifier: MIT
4+
// Licensed under the MIT License;
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// https://github.com/mintlayer/mintlayer-core/blob/master/LICENSE
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
//! Speculos runtime handle, provides out-of-band interaction with a simulator instance
17+
//! via the
18+
//! [HTTP API](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/LedgerHQ/speculos/master/speculos/api/static/swagger/swagger.json)
19+
//! to allow button pushes and screenshots when executing integration tests.
20+
//!
21+
//!
22+
23+
use std::net::SocketAddr;
24+
25+
use logging::log;
26+
use reqwest::Client;
27+
use serde::{Deserialize, Serialize};
28+
use strum::{Display, EnumIter};
29+
30+
/// Button enumeration
31+
#[derive(Clone, Copy, PartialEq, Debug, Display, EnumIter)]
32+
#[strum(serialize_all = "kebab-case")]
33+
pub enum Button {
34+
Left,
35+
Right,
36+
Both,
37+
}
38+
39+
/// Button actions
40+
#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize, Display, EnumIter)]
41+
#[serde(rename_all = "kebab-case")]
42+
pub enum Action {
43+
Press,
44+
Release,
45+
PressAndRelease,
46+
}
47+
48+
/// Button action object for serialization and use with the HTTP API
49+
#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)]
50+
struct ButtonAction {
51+
action: Action,
52+
}
53+
54+
/// Handle for interacting with a Speculos instance
55+
#[derive(Debug)]
56+
pub struct Handle {
57+
addr: SocketAddr,
58+
}
59+
60+
impl Handle {
61+
pub fn new(addr: SocketAddr) -> Self {
62+
Self { addr }
63+
}
64+
65+
/// Get speculos HTTP address
66+
pub fn addr(&self) -> SocketAddr {
67+
self.addr
68+
}
69+
70+
/// Send a button action to the simulator
71+
pub async fn button(&self, button: Button, action: Action) -> anyhow::Result<()> {
72+
log::debug!("Sending button request: {}:{}", button, action);
73+
74+
// Post action to HTTP API
75+
let r = Client::new()
76+
.post(format!("http://{}/button/{}", self.addr(), button))
77+
.json(&ButtonAction { action })
78+
.send()
79+
.await?;
80+
81+
log::debug!("Button request complete: {}", r.status());
82+
83+
Ok(())
84+
}
85+
}
86+
87+
#[cfg(test)]
88+
mod tests {
89+
use super::*;
90+
use strum::IntoEnumIterator;
91+
92+
/// Check button string encoding
93+
#[test]
94+
fn button_encoding() {
95+
for button in Button::iter() {
96+
let expected = match button {
97+
Button::Left => "left",
98+
Button::Right => "right",
99+
Button::Both => "both",
100+
};
101+
assert_eq!(&button.to_string(), expected);
102+
}
103+
}
104+
105+
/// Check button action encoding
106+
#[test]
107+
fn action_encoding() {
108+
for action in Action::iter() {
109+
let expected = match action {
110+
Action::Press => r#"{"action":"press"}"#,
111+
Action::Release => r#"{"action":"release"}"#,
112+
Action::PressAndRelease => r#"{"action":"press-and-release"}"#,
113+
};
114+
assert_eq!(
115+
&serde_json::to_string(&ButtonAction { action }).unwrap(),
116+
expected
117+
);
118+
}
119+
}
120+
}

0 commit comments

Comments
 (0)