Skip to content

Commit 61292c5

Browse files
committed
Remove podman usage from Ledger tests, fix comments
1 parent b304ef1 commit 61292c5

File tree

11 files changed

+260
-712
lines changed

11 files changed

+260
-712
lines changed

Cargo.lock

Lines changed: 97 additions & 203 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ reedline = "0.38"
211211
ref-cast = "1.0"
212212
regex = "1.10"
213213
replace_with = "0.1"
214+
reqwest = "0.12"
214215
rfd = { version = "0.15", default-features = false }
215216
ripemd = "0.1"
216217
rlimit = "0.10"
@@ -258,15 +259,13 @@ hickory-client = "0.24"
258259
hickory-server = "0.24"
259260
zeroize = "1.5"
260261

261-
reqwest = "0.12"
262-
263262
[workspace.dependencies.ledger-lib]
264263
git = "https://github.com/ledger-community/rust-ledger.git"
265-
rev = "4be10b810bb6500b7d8bc0b67e64fef24257e0e8"
264+
rev = "510bb3ca30639af4bdb12a918b6bbbdb75fa5f52"
266265

267266
[workspace.dependencies.ledger-proto]
268267
git = "https://github.com/ledger-community/rust-ledger.git"
269-
rev = "4be10b810bb6500b7d8bc0b67e64fef24257e0e8"
268+
rev = "510bb3ca30639af4bdb12a918b6bbbdb75fa5f52"
270269

271270
[workspace.dependencies.trezor-client]
272271
git = "https://github.com/mintlayer/mintlayer-trezor-firmware"
@@ -320,4 +319,5 @@ default = ["trezor", "ledger"]
320319
# is fontconfig-parser <- fontdb <- cosmic-text <- various "iced" crates.
321320
# TODO: investigate this further.
322321
fontconfig-parser = { git = "https://github.com/Riey/fontconfig-parser", rev = "f7d13a779e6ee282ce75acbc00a1270c0350e0c2" }
323-
ledger-proto = { git = "https://github.com/ledger-community/rust-ledger.git", rev = "4be10b810bb6500b7d8bc0b67e64fef24257e0e8" }
322+
# The patch is needed because there is now release of the library. We use the same hash for all Ledger libs
323+
ledger-proto = { git = "https://github.com/ledger-community/rust-ledger.git", rev = "510bb3ca30639af4bdb12a918b6bbbdb75fa5f52" }

wallet/src/signer/ledger_signer/ledger_messages.rs

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,13 @@
1313
// See the License for the specific language governing permissions and
1414
// limitations under the License.
1515

16-
use std::{collections::BTreeMap, time::Duration};
16+
use std::{
17+
collections::BTreeMap,
18+
mem::{size_of, size_of_val},
19+
time::Duration,
20+
};
1721

22+
use crate::signer::{ledger_signer::LedgerError, SignerError, SignerResult};
1823
use crypto::key::{
1924
extended::ExtendedPublicKey,
2025
hdkd::{
@@ -23,11 +28,10 @@ use crypto::key::{
2328
},
2429
secp256k1::{extended_keys::Secp256k1ExtendedPublicKey, Secp256k1PublicKey},
2530
};
26-
use ledger_lib::Exchange;
2731
use serialization::{Decode, DecodeAll, Encode};
2832
use utils::ensure;
2933

30-
use crate::signer::{ledger_signer::LedgerError, SignerError, SignerResult};
34+
use ledger_lib::Exchange;
3135

3236
const MAX_MSG_SIZE: usize = (u8::MAX - 5) as usize; // 4 bytes for the header + 1 for len
3337
const TIMEOUT_DUR: Duration = Duration::from_secs(100);
@@ -96,19 +100,20 @@ struct SignatureResult {
96100
}
97101

98102
/// Check that the response ends with the OK status code and return the rest of the response back
99-
fn ok_response(resp: Vec<u8>) -> SignerResult<Vec<u8>> {
100-
let (resp, status_code) = resp.split_last_chunk().ok_or(LedgerError::InvalidResponse)?;
103+
fn ok_response(mut resp: Vec<u8>) -> SignerResult<Vec<u8>> {
104+
let (_, status_code) = resp.split_last_chunk().ok_or(LedgerError::InvalidResponse)?;
101105
let response_status = u16::from_be_bytes(*status_code);
102106

103107
ensure!(
104108
response_status == OK_RESPONSE,
105109
LedgerError::ErrorResponse(response_status)
106110
);
107111

108-
Ok(resp.to_vec())
112+
resp.truncate(resp.len() - size_of_val(&response_status));
113+
Ok(resp)
109114
}
110115

111-
/// send a message to the Ledger and check the respons status code is ok
116+
/// Send a message to the Ledger and check the response status code is ok
112117
async fn exchange_message<L: Exchange>(
113118
ledger: &mut L,
114119
msg_buf: &[u8],
@@ -241,7 +246,9 @@ pub async fn sign_tx<L: Exchange>(
241246
let mut msg_buf = Vec::with_capacity(15);
242247

243248
msg_buf.extend([CLA, Ins::SIGN_TX, P1::TX_META, P2::MORE]);
244-
msg_buf.push(1 + 1 + 4 + 4); // data len coin + version + 2 u32 lens
249+
let data_len =
250+
(size_of_val(&chain_type) + size_of_val(&TX_VERSION) + size_of::<u32>() * 2) as u8;
251+
msg_buf.push(data_len);
245252
msg_buf.push(chain_type);
246253
msg_buf.push(TX_VERSION);
247254
msg_buf.extend((inputs.len() as u32).to_be_bytes());

wallet/src/signer/ledger_signer/mod.rs

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,21 @@
1414
// limitations under the License.
1515

1616
mod ledger_messages;
17-
use std::{borrow::Cow, collections::BTreeMap, sync::Arc};
1817

19-
use async_trait::async_trait;
20-
use itertools::{izip, Itertools};
18+
use std::{borrow::Cow, collections::BTreeMap, sync::Arc};
2119

20+
use crate::{
21+
key_chain::{make_account_path, AccountKeyChains, FoundPubKey},
22+
signer::{
23+
ledger_signer::ledger_messages::{
24+
check_current_app, get_app_name, get_extended_public_key, sign_challenge, sign_tx,
25+
LedgerBip32Path, LedgerInputAddressPath, LedgerSignature, LedgerTxInput,
26+
LedgerTxInputCommitment, LedgerTxOutput,
27+
},
28+
signer_utils::{is_htlc_utxo, sign_input_with_standalone_key},
29+
Signer, SignerError, SignerResult,
30+
},
31+
};
2232
use common::{
2333
chain::{
2434
config::ChainType,
@@ -54,36 +64,26 @@ use crypto::key::{
5464
signature::SignatureKind,
5565
PrivateKey, SigAuxDataProvider, Signature, SignatureError,
5666
};
57-
use ledger_lib::{Exchange, Filters, LedgerHandle, LedgerProvider, Transport};
58-
use randomness::make_true_rng;
5967
use serialization::Encode;
60-
use tokio::sync::Mutex;
6168
use utils::ensure;
6269
use wallet_storage::{WalletStorageReadLocked, WalletStorageReadUnlocked};
6370
use wallet_types::{
6471
hw_data::LedgerData, partially_signed_transaction::PartiallySignedTransaction,
6572
signature_status::SignatureStatus,
6673
};
6774

68-
use crate::{
69-
key_chain::{make_account_path, AccountKeyChains, FoundPubKey},
70-
signer::{
71-
ledger_signer::ledger_messages::{
72-
check_current_app, get_app_name, get_extended_public_key, sign_challenge, sign_tx,
73-
LedgerBip32Path, LedgerInputAddressPath, LedgerSignature, LedgerTxInput,
74-
LedgerTxInputCommitment, LedgerTxOutput,
75-
},
76-
signer_utils::{is_htlc_utxo, sign_input_with_standalone_key},
77-
Signer, SignerError, SignerResult,
78-
},
79-
};
75+
use async_trait::async_trait;
76+
use itertools::{izip, Itertools};
77+
use ledger_lib::{Exchange, Filters, LedgerHandle, LedgerProvider, Transport};
78+
use randomness::make_true_rng;
79+
use tokio::sync::Mutex;
8080

8181
/// Signer errors
8282
#[derive(thiserror::Error, Debug, Eq, PartialEq)]
8383
pub enum LedgerError {
8484
#[error("No connected Ledger device found")]
8585
NoDeviceFound,
86-
#[error("Different active app: \"{0}\", opened on the Ledger. Please open the Mintlayer app.")]
86+
#[error("A different app is currently open on your Ledger device: \"{0}\". Please close it and open the Mintlayer app instead.")]
8787
DifferentActiveApp(String),
8888
#[error("Received an invalid response from the Ledger device")]
8989
InvalidResponse,
@@ -93,7 +93,7 @@ pub enum LedgerError {
9393
DeviceError(String),
9494
#[error("Missing hardware wallet data in database")]
9595
MissingHardwareWalletData,
96-
#[error("Derivation path is to long to send to Ledger")]
96+
#[error("Derivation path is too long to send to Ledger")]
9797
PathToLong,
9898
#[error("Invalid public key returned from Ledger")]
9999
InvalidKey,
@@ -105,7 +105,7 @@ pub enum LedgerError {
105105
MultipleSignaturesReturned,
106106
#[error("Missing multisig index for signature returned from Device")]
107107
MissingMultisigIndexForSignature,
108-
#[error("Invalid Signature error: {0}")]
108+
#[error("Signature error: {0}")]
109109
SignatureError(#[from] SignatureError),
110110
}
111111

@@ -117,13 +117,13 @@ struct StandaloneInput {
117117
type StandaloneInputs = BTreeMap</*input index*/ u32, Vec<StandaloneInput>>;
118118

119119
#[async_trait]
120-
pub trait LProvider {
121-
type L;
120+
pub trait LedgerFinder {
121+
type Ledger;
122122

123123
async fn find_ledger_device_from_db<T: WalletStorageReadLocked + Send>(
124124
&self,
125125
db_tx: T,
126-
) -> (T, SignerResult<(Self::L, LedgerData)>);
126+
) -> (T, SignerResult<(Self::Ledger, LedgerData)>);
127127
}
128128

129129
pub struct LedgerSigner<L, P> {
@@ -136,7 +136,7 @@ pub struct LedgerSigner<L, P> {
136136
impl<L, P> LedgerSigner<L, P>
137137
where
138138
L: Exchange + Send,
139-
P: LProvider<L = L>,
139+
P: LedgerFinder<Ledger = L>,
140140
{
141141
pub fn new(chain_config: Arc<ChainConfig>, client: Arc<Mutex<L>>, provider: P) -> Self {
142142
Self::new_with_sig_aux_data_provider(
@@ -245,20 +245,20 @@ where
245245
}
246246

247247
#[allow(clippy::too_many_arguments)]
248-
fn make_signature<'a, 'b, F, F2>(
248+
fn make_signature<'a, 'b, MakeWitnessFn, StandaloneSignerFn>(
249249
&self,
250250
signatures: &[LedgerSignature],
251251
standalone_inputs: &'a [StandaloneInput],
252252
destination: &'b Destination,
253253
sighash_type: SigHashType,
254254
sighash: H256,
255255
key_chain: &impl AccountKeyChains,
256-
make_witness: F,
257-
sign_with_standalone_private_key: F2,
256+
make_witness: MakeWitnessFn,
257+
sign_with_standalone_private_key: StandaloneSignerFn,
258258
) -> SignerResult<(Option<InputWitness>, SignatureStatus)>
259259
where
260-
F: Fn(StandardInputSignature) -> InputWitness,
261-
F2: Fn(&'a StandaloneInput, &'b Destination) -> SignerResult<InputWitness>,
260+
MakeWitnessFn: Fn(StandardInputSignature) -> InputWitness,
261+
StandaloneSignerFn: Fn(&'a StandaloneInput, &'b Destination) -> SignerResult<InputWitness>,
262262
{
263263
match destination {
264264
Destination::AnyoneCanSpend => Ok((
@@ -359,7 +359,7 @@ where
359359
.collect()
360360
}
361361

362-
fn check_signature_status(
362+
fn check_multisig_signature_status(
363363
&self,
364364
sighash: H256,
365365
current_signatures: &AuthorizedClassicalMultisigSpend,
@@ -401,7 +401,7 @@ where
401401
current_signatures.add_signature(idx as u8, sig);
402402
}
403403

404-
let status = self.check_signature_status(sighash, &current_signatures)?;
404+
let status = self.check_multisig_signature_status(sighash, &current_signatures)?;
405405

406406
Ok((current_signatures, status))
407407
}
@@ -459,7 +459,7 @@ where
459459
impl<L, P> Signer for LedgerSigner<L, P>
460460
where
461461
L: Exchange + Send,
462-
P: Send + Sync + LProvider<L = L>,
462+
P: Send + Sync + LedgerFinder<Ledger = L>,
463463
{
464464
async fn sign_tx<T: WalletStorageReadUnlocked + Send>(
465465
&mut self,
@@ -1162,4 +1162,4 @@ mod tests;
11621162

11631163
#[cfg(feature = "enable-ledger-device-tests")]
11641164
#[cfg(test)]
1165-
mod speculus;
1165+
mod speculos;
20 KB
Binary file not shown.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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+
//! Podman driver for speculos execution, runs a speculos instance within
17+
//! a Podman container.
18+
19+
use core::fmt::Debug;
20+
use std::net::SocketAddr;
21+
22+
use crate::signer::ledger_signer::speculos::Handle;
23+
24+
use async_trait::async_trait;
25+
26+
/// Handle to a Speculos instance running under Podman
27+
#[derive(Debug)]
28+
pub struct PodmanHandle {
29+
addr: SocketAddr,
30+
}
31+
32+
impl PodmanHandle {
33+
pub fn new(addr: SocketAddr) -> Self {
34+
Self { addr }
35+
}
36+
}
37+
38+
#[async_trait]
39+
impl Handle for PodmanHandle {
40+
fn addr(&self) -> SocketAddr {
41+
self.addr
42+
}
43+
}

wallet/src/signer/ledger_signer/speculus/handle.rs renamed to wallet/src/signer/ledger_signer/speculos/handle.rs

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
use std::net::SocketAddr;
2222

2323
use async_trait::async_trait;
24-
// use image::{io::Reader as ImageReader, DynamicImage};
2524
use reqwest::Client;
2625
use serde::{Deserialize, Serialize};
2726
use strum::Display;
@@ -72,20 +71,6 @@ pub trait Handle {
7271

7372
Ok(())
7473
}
75-
76-
// /// Fetch a screenshot from the simulator
77-
// async fn screenshot(&self) -> anyhow::Result<DynamicImage> {
78-
// // Fetch screenshot from HTTP API
79-
// let r = reqwest::get(format!("http://{}/screenshot", self.addr())).await?;
80-
//
81-
// // Read image bytes
82-
// let b = r.bytes().await?;
83-
//
84-
// // Parse image object
85-
// let i = ImageReader::new(Cursor::new(b)).with_guessed_format()?.decode()?;
86-
//
87-
// Ok(i)
88-
// }
8974
}
9075

9176
#[cfg(test)]
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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+
//! Rust wrapper for executing Speculos via podman,
17+
//! provided to simplify CI/CD with ledger applications.
18+
19+
mod drivers;
20+
pub use drivers::*;
21+
22+
mod handle;
23+
pub use handle::*;

0 commit comments

Comments
 (0)