From b3f09300fa5fe35b3fda6f9798d543d6c5af8a87 Mon Sep 17 00:00:00 2001 From: Eval Exec Date: Wed, 17 Jun 2026 04:52:15 -0400 Subject: [PATCH 1/4] fix: replace H160::from_slice().unwrap() with proper error handling Replace all 32 instances of H160::from_slice(...).unwrap() across the codebase with proper error handling: - For functions returning Result: use .map_err(|e| format!(...))? - For closures inside .map() on Result: convert to .and_then() - For closures inside .map() on Option: convert to .and_then().ok() - For format!() calls: extract H160 to a variable first - For guarded/safe sites in signer.rs: use .expect() with clear message - For [0..20] slicing: add bounds check via .get(0..20) before H160 Fixes the highest-frequency panic pattern in the codebase (~30 sites that could crash from malformed address data from RPC/user input). --- src/subcommands/account.rs | 4 +++- src/subcommands/dao/command.rs | 4 +++- src/subcommands/deploy/mod.rs | 10 +++++--- src/subcommands/sudt.rs | 43 +++++++++++++++++++++++++++------- src/subcommands/tx.rs | 25 +++++++++++++------- src/subcommands/util.rs | 15 ++++++------ src/subcommands/wallet.rs | 17 ++++++++++---- src/utils/signer.rs | 19 +++++++++++---- src/utils/tx_helper.rs | 14 +++++++---- 9 files changed, 108 insertions(+), 43 deletions(-) diff --git a/src/subcommands/account.rs b/src/subcommands/account.rs index b26ea69f..b7f25332 100644 --- a/src/subcommands/account.rs +++ b/src/subcommands/account.rs @@ -493,8 +493,10 @@ impl CliSubCommand for AccountSubCommand<'_> { .keystore_handler() .extended_pubkey(lock_arg, &path, password)?; let address_payload = AddressPayload::from_pubkey(&extended_pubkey); + let lock_arg = H160::from_slice(address_payload.args().as_ref()) + .map_err(|err| format!("invalid H160 from address payload: {}", err))?; let resp = serde_json::json!({ - "lock_arg": format!("{:#x}", H160::from_slice(address_payload.args().as_ref()).unwrap()), + "lock_arg": format!("{:#x}", lock_arg), "address(deprecated)": address_json(address_payload.clone(), false), "address": address_json(address_payload, true), }); diff --git a/src/subcommands/dao/command.rs b/src/subcommands/dao/command.rs index 4094d9a7..485f5124 100644 --- a/src/subcommands/dao/command.rs +++ b/src/subcommands/dao/command.rs @@ -130,7 +130,9 @@ impl TransactArgs { result .map(|address_opt| { address_opt - .map(|address| H160::from_slice(&address.payload().args()).unwrap()) + .and_then(|address| { + H160::from_slice(address.payload().args().as_ref()).ok() + }) }) .map_err(|_| format!("Invalid value for '--from-account': {}", err)) })? diff --git a/src/subcommands/deploy/mod.rs b/src/subcommands/deploy/mod.rs index ebb2036a..3d1750bc 100644 --- a/src/subcommands/deploy/mod.rs +++ b/src/subcommands/deploy/mod.rs @@ -309,7 +309,8 @@ impl CliSubCommand for DeploySubCommand<'_> { // Sign if required if m.is_present("sign-now") { - let account = H160::from_slice(from_address.payload().args().as_ref()).unwrap(); + let account = H160::from_slice(from_address.payload().args().as_ref()) + .map_err(|err| format!("invalid H160 from from-address: {}", err))?; let signer = { let handler = self.plugin_mgr.keystore_handler(); let change_path = handler.root_key_path(account.clone())?; @@ -380,8 +381,11 @@ impl CliSubCommand for DeploySubCommand<'_> { } let result: Result = parser.parse(input); result - .map(|address| { - H160::from_slice(&address.payload().args()).unwrap() + .and_then(|address| { + H160::from_slice(address.payload().args().as_ref()) + .map_err(|e| { + format!("invalid H160 from address: {}", e) + }) }) .map_err(|_| err) }) diff --git a/src/subcommands/sudt.rs b/src/subcommands/sudt.rs index 0ebf1895..97af5409 100644 --- a/src/subcommands/sudt.rs +++ b/src/subcommands/sudt.rs @@ -244,7 +244,8 @@ impl<'a> SudtSubCommand<'a> { } else { None }; - let owner_account = H160::from_slice(owner.payload().args().as_ref()).unwrap(); + let owner_account = H160::from_slice(owner.payload().args().as_ref()) + .map_err(|err| format!("invalid H160 from owner address: {}", err))?; let owner_script = Script::from(&owner); let owner_script_hash = owner_script.calc_script_hash(); let receivers = udt_to_vec @@ -368,7 +369,14 @@ impl<'a> SudtSubCommand<'a> { }; let owner_script_hash = Script::from(&owner).calc_script_hash(); - let sender_account = H160::from_slice(&sender.payload().args().as_ref()[0..20]).unwrap(); + let sender_args = sender.payload().args(); + let args_bytes: &[u8] = sender_args.as_ref(); + let sender_account = H160::from_slice( + args_bytes + .get(0..20) + .ok_or_else(|| "sender address payload too short for H160".to_string())?, + ) + .map_err(|err| format!("invalid H160 from sender address: {}", err))?; let sender_script = Script::from(&sender); let type_script = udt_type.build_script(&udt_script_id, &owner_script_hash); let cheque_sender_script_hash = Script::new_builder() @@ -426,7 +434,8 @@ impl<'a> SudtSubCommand<'a> { let mut accounts = vec![(format!("sender({})", sender_sighash), sender_account)]; if let Some(addr) = capacity_provider.as_ref() { if *addr != sender { - let account = H160::from_slice(addr.payload().args().as_ref()).unwrap(); + let account = H160::from_slice(addr.payload().args().as_ref()) + .map_err(|err| format!("invalid H160 from address: {}", err))?; accounts.push((format!("capacity provider({})", addr), account)); } } @@ -550,7 +559,8 @@ impl<'a> SudtSubCommand<'a> { let owner_script_hash = Script::from(&owner).calc_script_hash(); let capacity_provider = capacity_provider.unwrap_or_else(|| to.clone()); let capacity_provider_account = - H160::from_slice(capacity_provider.payload().args().as_ref()).unwrap(); + H160::from_slice(capacity_provider.payload().args().as_ref()) + .map_err(|err| format!("invalid H160 from capacity provider: {}", err))?; let acp_lock = Script::new_builder() .code_hash(acp_script_id.code_hash.pack()) .hash_type(acp_script_id.hash_type) @@ -702,12 +712,19 @@ impl<'a> SudtSubCommand<'a> { sender_lock_script: sender_script, }; - let receiver_account = - H160::from_slice(&receiver.payload().args().as_ref()[0..20]).unwrap(); + let receiver_args = receiver.payload().args(); + let args_bytes: &[u8] = receiver_args.as_ref(); + let receiver_account = H160::from_slice( + args_bytes + .get(0..20) + .ok_or_else(|| "receiver address payload too short for H160".to_string())?, + ) + .map_err(|err| format!("invalid H160 from receiver address: {}", err))?; let mut accounts = vec![("receiver".to_string(), receiver_account)]; if let Some(addr) = capacity_provider.as_ref() { if *addr != receiver { - let account = H160::from_slice(addr.payload().args().as_ref()).unwrap(); + let account = H160::from_slice(addr.payload().args().as_ref()) + .map_err(|err| format!("invalid H160 from address: {}", err))?; accounts.push(("capacity provider".to_string(), account)); } } @@ -818,11 +835,19 @@ impl<'a> SudtSubCommand<'a> { acp_script_id: acp_script_id.clone(), }; - let sender_account = H160::from_slice(&sender.payload().args().as_ref()[0..20]).unwrap(); + let sender_args = sender.payload().args(); + let args_bytes: &[u8] = sender_args.as_ref(); + let sender_account = H160::from_slice( + args_bytes + .get(0..20) + .ok_or_else(|| "sender address payload too short for H160".to_string())?, + ) + .map_err(|err| format!("invalid H160 from sender address: {}", err))?; let mut accounts = vec![("sender".to_string(), sender_account)]; if let Some(addr) = capacity_provider.as_ref() { if *addr != receiver { - let account = H160::from_slice(addr.payload().args().as_ref()).unwrap(); + let account = H160::from_slice(addr.payload().args().as_ref()) + .map_err(|err| format!("invalid H160 from address: {}", err))?; accounts.push(("capacity provider".to_string(), account)); } } diff --git a/src/subcommands/tx.rs b/src/subcommands/tx.rs index f6745836..da72aec8 100644 --- a/src/subcommands/tx.rs +++ b/src/subcommands/tx.rs @@ -397,10 +397,13 @@ impl CliSubCommand for TxSubCommand<'_> { FromStrParser::::default().from_matches(m, "require-first-n")?; let threshold: u8 = FromStrParser::::default().from_matches(m, "threshold")?; - let sighash_addresses = sighash_addresses + let sighash_addresses: Vec = sighash_addresses .into_iter() - .map(|address| H160::from_slice(address.payload().args().as_ref()).unwrap()) - .collect::>(); + .map(|address| { + H160::from_slice(address.payload().args().as_ref()) + .map_err(|e| format!("invalid H160 from sighash address: {}", e)) + }) + .collect::, _>>()?; let cfg = MultisigConfig::new_with( multisig_script, sighash_addresses, @@ -501,8 +504,11 @@ impl CliSubCommand for TxSubCommand<'_> { .set_network(network) .parse(input); result - .map(|address| { - H160::from_slice(&address.payload().args()).unwrap() + .and_then(|address| { + H160::from_slice(address.payload().args().as_ref()) + .map_err(|e| { + format!("invalid H160 from address: {}", e) + }) }) .map_err(|_| err) }) @@ -624,10 +630,13 @@ impl CliSubCommand for TxSubCommand<'_> { let since_absolute_epoch_opt: Option = FromStrParser::::default().from_matches_opt(m, "since-absolute-epoch")?; - let sighash_addresses = sighash_addresses + let sighash_addresses: Vec = sighash_addresses .into_iter() - .map(|address| H160::from_slice(address.payload().args().as_ref()).unwrap()) - .collect::>(); + .map(|address| { + H160::from_slice(address.payload().args().as_ref()) + .map_err(|e| format!("invalid H160 from sighash address: {}", e)) + }) + .collect::, _>>()?; let cfg = MultisigConfig::new_with( multisig_script, sighash_addresses, diff --git a/src/subcommands/util.rs b/src/subcommands/util.rs index 1203ddae..61accdcb 100644 --- a/src/subcommands/util.rs +++ b/src/subcommands/util.rs @@ -328,7 +328,8 @@ impl CliSubCommand for UtilSubCommand<'_> { Some(pubkey) => AddressPayload::from_pubkey(&pubkey), None => get_address(None, m)?, }; - let lock_arg = H160::from_slice(address_payload.args().as_ref()).unwrap(); + let lock_arg = H160::from_slice(address_payload.args().as_ref()) + .map_err(|err| format!("invalid H160 from address payload: {}", err))?; let old_address = OldAddress::new_default(lock_arg.clone()); eprintln!( @@ -369,8 +370,8 @@ message = "0x" AddressParser::new_sighash().from_matches_opt(m, "from-account"); result .map(|address_opt| { - address_opt.map(|address| { - H160::from_slice(&address.payload().args()).unwrap() + address_opt.and_then(|address| { + H160::from_slice(address.payload().args().as_ref()).ok() }) }) .map_err(|_| err) @@ -444,8 +445,8 @@ message = "0x" AddressParser::new_sighash().from_matches_opt(m, "from-account"); result .map(|address_opt| { - address_opt.map(|address| { - H160::from_slice(&address.payload().args()).unwrap() + address_opt.and_then(|address| { + H160::from_slice(address.payload().args().as_ref()).ok() }) }) .map_err(|_| err) @@ -505,8 +506,8 @@ message = "0x" AddressParser::new_sighash().from_matches_opt(m, "from-account"); result .map(|address_opt| { - address_opt.map(|address| { - H160::from_slice(&address.payload().args()).unwrap() + address_opt.and_then(|address| { + H160::from_slice(address.payload().args().as_ref()).ok() }) }) .map_err(|_| err) diff --git a/src/subcommands/wallet.rs b/src/subcommands/wallet.rs index 58381bf4..2891338b 100644 --- a/src/subcommands/wallet.rs +++ b/src/subcommands/wallet.rs @@ -162,7 +162,10 @@ impl<'a> WalletSubCommand<'a> { .set_network(network_type) .parse(&input); result - .map(|address| H160::from_slice(&address.payload().args()).unwrap()) + .and_then(|address| { + H160::from_slice(address.payload().args().as_ref()) + .map_err(|e| format!("invalid H160 from address: {}", e)) + }) .map_err(|_| err) }) }) @@ -272,13 +275,15 @@ impl<'a> WalletSubCommand<'a> { SinceSource::default(), )]; - let from_lock_arg = H160::from_slice(from_address.payload().args().as_ref()).unwrap(); + let from_lock_arg = H160::from_slice(from_address.payload().args().as_ref()) + .map_err(|err| format!("invalid H160 from from-address: {}", err))?; let mut path_map: HashMap = Default::default(); let (change_address_payload, change_path) = if let Some(last_change_address) = last_change_address_opt.as_ref() { // Behave like HD wallet let change_last = - H160::from_slice(last_change_address.payload().args().as_ref()).unwrap(); + H160::from_slice(last_change_address.payload().args().as_ref()) + .map_err(|err| format!("invalid H160 from change-address: {}", err))?; let key_set = self.plugin_mgr.keystore_handler().derived_key_set( from_lock_arg.clone(), receiving_address_length, @@ -326,7 +331,8 @@ impl<'a> WalletSubCommand<'a> { } if let Some(last_change_address) = last_change_address_opt.as_ref() { let change_last = - H160::from_slice(last_change_address.payload().args().as_ref()).unwrap(); + H160::from_slice(last_change_address.payload().args().as_ref()) + .map_err(|err| format!("invalid H160 from change-address: {}", err))?; signer.cache_key_set( from_lock_arg.clone(), receiving_address_length, @@ -624,7 +630,8 @@ impl CliSubCommand for WalletSubCommand<'_> { }; let mut lock_scripts = vec![Script::from(&address_payload)]; if m.is_present("derived") { - let lock_arg = H160::from_slice(address_payload.args().as_ref()).unwrap(); + let lock_arg = H160::from_slice(address_payload.args().as_ref()) + .map_err(|err| format!("invalid H160 from address payload: {}", err))?; let key_set = self .plugin_mgr diff --git a/src/utils/signer.rs b/src/utils/signer.rs index 19b6282d..dba38f1f 100644 --- a/src/utils/signer.rs +++ b/src/utils/signer.rs @@ -77,7 +77,9 @@ impl PrivkeySigner { pub fn add_privkey(&mut self, privkey: PrivkeyWrapper) { let pubkey = secp256k1::PublicKey::from_secret_key(&SECP256K1, &privkey); - let id = H160::from_slice(&blake2b_256(&pubkey.serialize()[..])[0..20]).unwrap(); + // Safe: blake2b_256 always produces 32 bytes, [0..20] is always exactly 20 bytes + let id = H160::from_slice(&blake2b_256(&pubkey.serialize()[..])[0..20]) + .expect("H160::from_slice on 20-byte hash output should never fail"); self.privkeys.insert(id.clone(), privkey); self.ids.insert(id.clone(), id); } @@ -90,7 +92,9 @@ impl PrivkeySigner { .args(Bytes::from(account.as_bytes().to_vec()).pack()) .build() .calc_script_hash(); - let lock_hash160 = H160::from_slice(&script_hash.as_slice()[0..20]).unwrap(); + // Safe: script_hash is always 32 bytes, [0..20] is always exactly 20 bytes + let lock_hash160 = H160::from_slice(&script_hash.as_slice()[0..20]) + .expect("H160::from_slice on 20-byte script hash should never fail"); self.ids.insert(lock_hash160, account); true } else { @@ -104,7 +108,8 @@ impl Signer for PrivkeySigner { if id.len() != 20 { return false; } - self.ids.contains_key(&H160::from_slice(id).unwrap()) + // Safe: guarded by id.len() != 20 check above + self.ids.contains_key(&H160::from_slice(id).expect("H160::from_slice on 20-byte id should never fail")) } fn sign( @@ -117,7 +122,9 @@ impl Signer for PrivkeySigner { if id.len() != 20 { return Err(SignerError::IdNotFound); } - let hash160 = H160::from_slice(id).unwrap(); + // Safe: guarded by id.len() != 20 check above + let hash160 = H160::from_slice(id) + .map_err(|_| SignerError::IdNotFound)?; let account = self.ids.get(&hash160).ok_or(SignerError::IdNotFound)?; let privkey = self.privkeys.get(account).expect("no privkey found"); privkey.sign(id, message, recoverable, tx) @@ -165,7 +172,9 @@ impl KeyStoreHandlerSigner { .args(Bytes::from(account.as_bytes().to_vec()).pack()) .build() .calc_script_hash(); - let lock_hash160 = H160::from_slice(&script_hash.as_slice()[0..20]).unwrap(); + // Safe: script_hash is always 32 bytes, [0..20] is always exactly 20 bytes + let lock_hash160 = H160::from_slice(&script_hash.as_slice()[0..20]) + .expect("H160::from_slice on 20-byte script hash should never fail"); self.ids .insert(lock_hash160, (DerivationPath::default(), None, account)); true diff --git a/src/utils/tx_helper.rs b/src/utils/tx_helper.rs index eeb2c14f..de802602 100644 --- a/src/utils/tx_helper.rs +++ b/src/utils/tx_helper.rs @@ -198,7 +198,8 @@ impl TxHelper { ] .contains(&code_hash) { - let hash160 = H160::from_slice(&lock_arg[..20]).unwrap(); + let hash160 = H160::from_slice(&lock_arg[..20]) + .map_err(|err| format!("invalid H160 from lock_arg: {}", err))?; if !self.multisig_configs.contains_key(&hash160) { return Err(format!( "No mutisig config found for input(no.{}) lock_arg prefix: {:#x}", @@ -260,7 +261,8 @@ impl TxHelper { continue; } - let multisig_hash160 = H160::from_slice(&lock_arg[..20]).unwrap(); + let multisig_hash160 = H160::from_slice(&lock_arg[..20]) + .map_err(|err| format!("invalid multisig H160 from lock_arg: {}", err))?; let lock_args = if [ MultisigScript::Legacy.script_id().code_hash.pack(), MultisigScript::V2.script_id().code_hash.pack(), @@ -273,7 +275,10 @@ impl TxHelper { .clone() } else { let mut lock_args = HashSet::default(); - lock_args.insert(H160::from_slice(lock_arg.as_ref()).unwrap()); + lock_args.insert( + H160::from_slice(lock_arg.as_ref()) + .map_err(|err| format!("invalid H160 from lock_arg: {}", err))?, + ); lock_args }; if signer(&lock_args, &h256!("0x0"), &Transaction::default().into())?.is_some() { @@ -324,7 +329,8 @@ impl TxHelper { ] .contains(&code_hash) { - let hash160 = H160::from_slice(&lock_arg[..20]).unwrap(); + let hash160 = H160::from_slice(&lock_arg[..20]) + .map_err(|err| format!("invalid H160 from lock_arg: {}", err))?; let multisig_config = self.multisig_configs.get(&hash160).unwrap(); let threshold = multisig_config.threshold() as usize; let mut data = BytesMut::from(&multisig_config.to_witness_data()[..]); From a7ace081799215e7d94bb5b644325eb80e8aaa51 Mon Sep 17 00:00:00 2001 From: Eval Exec Date: Wed, 17 Jun 2026 23:17:29 -0400 Subject: [PATCH 2/4] style: apply cargo fmt --- src/subcommands/dao/command.rs | 7 ++-- src/subcommands/deploy/mod.rs | 7 ++-- src/subcommands/tx.rs | 7 ++-- src/subcommands/wallet.rs | 70 +++++++++++++++++----------------- src/utils/signer.rs | 7 ++-- 5 files changed, 48 insertions(+), 50 deletions(-) diff --git a/src/subcommands/dao/command.rs b/src/subcommands/dao/command.rs index 485f5124..0034514d 100644 --- a/src/subcommands/dao/command.rs +++ b/src/subcommands/dao/command.rs @@ -129,10 +129,9 @@ impl TransactArgs { .from_matches_opt(m, "from-account"); result .map(|address_opt| { - address_opt - .and_then(|address| { - H160::from_slice(address.payload().args().as_ref()).ok() - }) + address_opt.and_then(|address| { + H160::from_slice(address.payload().args().as_ref()).ok() + }) }) .map_err(|_| format!("Invalid value for '--from-account': {}", err)) })? diff --git a/src/subcommands/deploy/mod.rs b/src/subcommands/deploy/mod.rs index 3d1750bc..b88e3fe2 100644 --- a/src/subcommands/deploy/mod.rs +++ b/src/subcommands/deploy/mod.rs @@ -382,10 +382,9 @@ impl CliSubCommand for DeploySubCommand<'_> { let result: Result = parser.parse(input); result .and_then(|address| { - H160::from_slice(address.payload().args().as_ref()) - .map_err(|e| { - format!("invalid H160 from address: {}", e) - }) + H160::from_slice(address.payload().args().as_ref()).map_err( + |e| format!("invalid H160 from address: {}", e), + ) }) .map_err(|_| err) }) diff --git a/src/subcommands/tx.rs b/src/subcommands/tx.rs index da72aec8..a6eb5c3d 100644 --- a/src/subcommands/tx.rs +++ b/src/subcommands/tx.rs @@ -505,10 +505,9 @@ impl CliSubCommand for TxSubCommand<'_> { .parse(input); result .and_then(|address| { - H160::from_slice(address.payload().args().as_ref()) - .map_err(|e| { - format!("invalid H160 from address: {}", e) - }) + H160::from_slice(address.payload().args().as_ref()).map_err( + |e| format!("invalid H160 from address: {}", e), + ) }) .map_err(|_| err) }) diff --git a/src/subcommands/wallet.rs b/src/subcommands/wallet.rs index 2891338b..8fef28fe 100644 --- a/src/subcommands/wallet.rs +++ b/src/subcommands/wallet.rs @@ -278,42 +278,42 @@ impl<'a> WalletSubCommand<'a> { let from_lock_arg = H160::from_slice(from_address.payload().args().as_ref()) .map_err(|err| format!("invalid H160 from from-address: {}", err))?; let mut path_map: HashMap = Default::default(); - let (change_address_payload, change_path) = - if let Some(last_change_address) = last_change_address_opt.as_ref() { - // Behave like HD wallet - let change_last = - H160::from_slice(last_change_address.payload().args().as_ref()) - .map_err(|err| format!("invalid H160 from change-address: {}", err))?; - let key_set = self.plugin_mgr.keystore_handler().derived_key_set( - from_lock_arg.clone(), - receiving_address_length, - change_last.clone(), - DERIVE_CHANGE_ADDRESS_MAX_LEN, - None, - )?; - let mut change_path_opt = None; - for (path, hash160) in key_set.external.into_iter().chain(key_set.change) { - if hash160 == change_last { - change_path_opt = Some(path.clone()); - } - path_map.insert(hash160.clone(), path); - let payload = AddressPayload::from_pubkey_hash(hash160); - lock_scripts.push(( - Script::from(&payload), - sighash_placeholder_witness.clone(), - Default::default(), - )); + let (change_address_payload, change_path) = if let Some(last_change_address) = + last_change_address_opt.as_ref() + { + // Behave like HD wallet + let change_last = H160::from_slice(last_change_address.payload().args().as_ref()) + .map_err(|err| format!("invalid H160 from change-address: {}", err))?; + let key_set = self.plugin_mgr.keystore_handler().derived_key_set( + from_lock_arg.clone(), + receiving_address_length, + change_last.clone(), + DERIVE_CHANGE_ADDRESS_MAX_LEN, + None, + )?; + let mut change_path_opt = None; + for (path, hash160) in key_set.external.into_iter().chain(key_set.change) { + if hash160 == change_last { + change_path_opt = Some(path.clone()); } - ( - last_change_address.payload().clone(), - change_path_opt.expect("change path not exists"), - ) - } else { - ( - from_address.payload().clone(), - self.plugin_mgr.root_key_path(from_lock_arg.clone())?, - ) - }; + path_map.insert(hash160.clone(), path); + let payload = AddressPayload::from_pubkey_hash(hash160); + lock_scripts.push(( + Script::from(&payload), + sighash_placeholder_witness.clone(), + Default::default(), + )); + } + ( + last_change_address.payload().clone(), + change_path_opt.expect("change path not exists"), + ) + } else { + ( + from_address.payload().clone(), + self.plugin_mgr.root_key_path(from_lock_arg.clone())?, + ) + }; let get_signer = || -> Result, String> { if let Some(privkey) = from_privkey.as_ref() { diff --git a/src/utils/signer.rs b/src/utils/signer.rs index dba38f1f..0aaa36e3 100644 --- a/src/utils/signer.rs +++ b/src/utils/signer.rs @@ -109,7 +109,9 @@ impl Signer for PrivkeySigner { return false; } // Safe: guarded by id.len() != 20 check above - self.ids.contains_key(&H160::from_slice(id).expect("H160::from_slice on 20-byte id should never fail")) + self.ids.contains_key( + &H160::from_slice(id).expect("H160::from_slice on 20-byte id should never fail"), + ) } fn sign( @@ -123,8 +125,7 @@ impl Signer for PrivkeySigner { return Err(SignerError::IdNotFound); } // Safe: guarded by id.len() != 20 check above - let hash160 = H160::from_slice(id) - .map_err(|_| SignerError::IdNotFound)?; + let hash160 = H160::from_slice(id).map_err(|_| SignerError::IdNotFound)?; let account = self.ids.get(&hash160).ok_or(SignerError::IdNotFound)?; let privkey = self.privkeys.get(account).expect("no privkey found"); privkey.sign(id, message, recoverable, tx) From 738674ac9705873178028b93247ceb6297e39cd6 Mon Sep 17 00:00:00 2001 From: Eval Exec Date: Thu, 18 Jun 2026 00:26:56 -0400 Subject: [PATCH 3/4] refactor: add h160_from_slice / h160_from_slice_prefix helpers Extract the repeated pattern of H160::from_slice(x).map_err(...) into two helper functions in src/utils/other.rs: - h160_from_slice(data, context) -> Result - h160_from_slice_prefix(data, context) -> Result (takes first 20 bytes, with bounds check) Replace all inline H160::from_slice error handling across 8 files with calls to these helpers. Net reduction of 7 lines while making error messages consistent and code more readable. --- src/subcommands/account.rs | 5 +- src/subcommands/dao/command.rs | 4 +- src/subcommands/deploy/mod.rs | 11 +++-- src/subcommands/sudt.rs | 54 ++++++++-------------- src/subcommands/tx.rs | 15 +++--- src/subcommands/util.rs | 20 ++++---- src/subcommands/wallet.rs | 84 +++++++++++++++++----------------- src/utils/other.rs | 13 ++++++ src/utils/tx_helper.rs | 15 ++---- 9 files changed, 107 insertions(+), 114 deletions(-) diff --git a/src/subcommands/account.rs b/src/subcommands/account.rs index b7f25332..bfe51c6f 100644 --- a/src/subcommands/account.rs +++ b/src/subcommands/account.rs @@ -20,7 +20,7 @@ use crate::utils::{ ArgParser, ExtendedPrivkeyPathParser, FilePathParser, FixedHashParser, FromStrParser, HexParser, PrivkeyPathParser, PrivkeyWrapper, }, - other::{address_json, read_password}, + other::{address_json, h160_from_slice, read_password}, }; pub struct AccountSubCommand<'a> { @@ -493,8 +493,7 @@ impl CliSubCommand for AccountSubCommand<'_> { .keystore_handler() .extended_pubkey(lock_arg, &path, password)?; let address_payload = AddressPayload::from_pubkey(&extended_pubkey); - let lock_arg = H160::from_slice(address_payload.args().as_ref()) - .map_err(|err| format!("invalid H160 from address payload: {}", err))?; + let lock_arg = h160_from_slice(address_payload.args().as_ref(), "address payload")?; let resp = serde_json::json!({ "lock_arg": format!("{:#x}", lock_arg), "address(deprecated)": address_json(address_payload.clone(), false), diff --git a/src/subcommands/dao/command.rs b/src/subcommands/dao/command.rs index 0034514d..74b1d222 100644 --- a/src/subcommands/dao/command.rs +++ b/src/subcommands/dao/command.rs @@ -6,7 +6,7 @@ use crate::utils::{ AddressParser, ArgParser, CapacityParser, FixedHashParser, FromStrParser, OutPointParser, PrivkeyPathParser, PrivkeyWrapper, }, - other::{get_address, get_network_type}, + other::{get_address, get_network_type, h160_from_slice}, }; use ckb_crypto::secp::SECP256K1; use ckb_sdk::{Address, AddressPayload, HumanCapacity, NetworkType}; @@ -130,7 +130,7 @@ impl TransactArgs { result .map(|address_opt| { address_opt.and_then(|address| { - H160::from_slice(address.payload().args().as_ref()).ok() + h160_from_slice(address.payload().args().as_ref(), "address").ok() }) }) .map_err(|_| format!("Invalid value for '--from-account': {}", err)) diff --git a/src/subcommands/deploy/mod.rs b/src/subcommands/deploy/mod.rs index b88e3fe2..2288e8d6 100644 --- a/src/subcommands/deploy/mod.rs +++ b/src/subcommands/deploy/mod.rs @@ -27,7 +27,7 @@ use crate::utils::{ PrivkeyPathParser, PrivkeyWrapper, }, genesis_info::GenesisInfo, - other::{get_live_cell_with_cache, get_network_type, read_password}, + other::{get_live_cell_with_cache, get_network_type, h160_from_slice, read_password}, rpc::HttpRpcClient, signer::KeyStoreHandlerSigner, tx_helper::{SignerFn, ZERO_HASH}, @@ -309,8 +309,8 @@ impl CliSubCommand for DeploySubCommand<'_> { // Sign if required if m.is_present("sign-now") { - let account = H160::from_slice(from_address.payload().args().as_ref()) - .map_err(|err| format!("invalid H160 from from-address: {}", err))?; + let account = + h160_from_slice(from_address.payload().args().as_ref(), "from-address")?; let signer = { let handler = self.plugin_mgr.keystore_handler(); let change_path = handler.root_key_path(account.clone())?; @@ -382,8 +382,9 @@ impl CliSubCommand for DeploySubCommand<'_> { let result: Result = parser.parse(input); result .and_then(|address| { - H160::from_slice(address.payload().args().as_ref()).map_err( - |e| format!("invalid H160 from address: {}", e), + h160_from_slice( + address.payload().args().as_ref(), + "address", ) }) .map_err(|_| err) diff --git a/src/subcommands/sudt.rs b/src/subcommands/sudt.rs index 97af5409..ba199944 100644 --- a/src/subcommands/sudt.rs +++ b/src/subcommands/sudt.rs @@ -44,7 +44,10 @@ use crate::{ }, cell_dep::{CellDepName, CellDeps}, genesis_info::GenesisInfo, - other::{get_network_type, map_tx_builder_error_2_str, read_password}, + other::{ + get_network_type, h160_from_slice, h160_from_slice_prefix, map_tx_builder_error_2_str, + read_password, + }, rpc::HttpRpcClient, signer::{CommonSigner, KeyStoreHandlerSigner, PrivkeySigner}, }, @@ -244,8 +247,7 @@ impl<'a> SudtSubCommand<'a> { } else { None }; - let owner_account = H160::from_slice(owner.payload().args().as_ref()) - .map_err(|err| format!("invalid H160 from owner address: {}", err))?; + let owner_account = h160_from_slice(owner.payload().args().as_ref(), "owner address")?; let owner_script = Script::from(&owner); let owner_script_hash = owner_script.calc_script_hash(); let receivers = udt_to_vec @@ -369,14 +371,8 @@ impl<'a> SudtSubCommand<'a> { }; let owner_script_hash = Script::from(&owner).calc_script_hash(); - let sender_args = sender.payload().args(); - let args_bytes: &[u8] = sender_args.as_ref(); - let sender_account = H160::from_slice( - args_bytes - .get(0..20) - .ok_or_else(|| "sender address payload too short for H160".to_string())?, - ) - .map_err(|err| format!("invalid H160 from sender address: {}", err))?; + let sender_account = + h160_from_slice_prefix(sender.payload().args().as_ref(), "sender address")?; let sender_script = Script::from(&sender); let type_script = udt_type.build_script(&udt_script_id, &owner_script_hash); let cheque_sender_script_hash = Script::new_builder() @@ -434,8 +430,7 @@ impl<'a> SudtSubCommand<'a> { let mut accounts = vec![(format!("sender({})", sender_sighash), sender_account)]; if let Some(addr) = capacity_provider.as_ref() { if *addr != sender { - let account = H160::from_slice(addr.payload().args().as_ref()) - .map_err(|err| format!("invalid H160 from address: {}", err))?; + let account = h160_from_slice(addr.payload().args().as_ref(), "address")?; accounts.push((format!("capacity provider({})", addr), account)); } } @@ -558,9 +553,10 @@ impl<'a> SudtSubCommand<'a> { let acp_script_id = get_script_id(&cell_deps, CellDepName::Acp)?; let owner_script_hash = Script::from(&owner).calc_script_hash(); let capacity_provider = capacity_provider.unwrap_or_else(|| to.clone()); - let capacity_provider_account = - H160::from_slice(capacity_provider.payload().args().as_ref()) - .map_err(|err| format!("invalid H160 from capacity provider: {}", err))?; + let capacity_provider_account = h160_from_slice( + capacity_provider.payload().args().as_ref(), + "capacity provider", + )?; let acp_lock = Script::new_builder() .code_hash(acp_script_id.code_hash.pack()) .hash_type(acp_script_id.hash_type) @@ -712,19 +708,12 @@ impl<'a> SudtSubCommand<'a> { sender_lock_script: sender_script, }; - let receiver_args = receiver.payload().args(); - let args_bytes: &[u8] = receiver_args.as_ref(); - let receiver_account = H160::from_slice( - args_bytes - .get(0..20) - .ok_or_else(|| "receiver address payload too short for H160".to_string())?, - ) - .map_err(|err| format!("invalid H160 from receiver address: {}", err))?; + let receiver_account = + h160_from_slice_prefix(receiver.payload().args().as_ref(), "receiver address")?; let mut accounts = vec![("receiver".to_string(), receiver_account)]; if let Some(addr) = capacity_provider.as_ref() { if *addr != receiver { - let account = H160::from_slice(addr.payload().args().as_ref()) - .map_err(|err| format!("invalid H160 from address: {}", err))?; + let account = h160_from_slice(addr.payload().args().as_ref(), "address")?; accounts.push(("capacity provider".to_string(), account)); } } @@ -835,19 +824,12 @@ impl<'a> SudtSubCommand<'a> { acp_script_id: acp_script_id.clone(), }; - let sender_args = sender.payload().args(); - let args_bytes: &[u8] = sender_args.as_ref(); - let sender_account = H160::from_slice( - args_bytes - .get(0..20) - .ok_or_else(|| "sender address payload too short for H160".to_string())?, - ) - .map_err(|err| format!("invalid H160 from sender address: {}", err))?; + let sender_account = + h160_from_slice_prefix(sender.payload().args().as_ref(), "sender address")?; let mut accounts = vec![("sender".to_string(), sender_account)]; if let Some(addr) = capacity_provider.as_ref() { if *addr != receiver { - let account = H160::from_slice(addr.payload().args().as_ref()) - .map_err(|err| format!("invalid H160 from address: {}", err))?; + let account = h160_from_slice(addr.payload().args().as_ref(), "address")?; accounts.push(("capacity provider".to_string(), account)); } } diff --git a/src/subcommands/tx.rs b/src/subcommands/tx.rs index a6eb5c3d..5dba04bb 100644 --- a/src/subcommands/tx.rs +++ b/src/subcommands/tx.rs @@ -38,7 +38,7 @@ use crate::utils::{ genesis_info::GenesisInfo, other::{ check_capacity, get_genesis_info, get_live_cell, get_live_cell_with_cache, - get_network_type, get_privkey_signer, get_to_data, read_password, + get_network_type, get_privkey_signer, get_to_data, h160_from_slice, read_password, }, rpc::HttpRpcClient, tx_helper::{SignerFn, TxHelper}, @@ -400,8 +400,7 @@ impl CliSubCommand for TxSubCommand<'_> { let sighash_addresses: Vec = sighash_addresses .into_iter() .map(|address| { - H160::from_slice(address.payload().args().as_ref()) - .map_err(|e| format!("invalid H160 from sighash address: {}", e)) + h160_from_slice(address.payload().args().as_ref(), "sighash address") }) .collect::, _>>()?; let cfg = MultisigConfig::new_with( @@ -505,8 +504,9 @@ impl CliSubCommand for TxSubCommand<'_> { .parse(input); result .and_then(|address| { - H160::from_slice(address.payload().args().as_ref()).map_err( - |e| format!("invalid H160 from address: {}", e), + h160_from_slice( + address.payload().args().as_ref(), + "address", ) }) .map_err(|_| err) @@ -632,8 +632,7 @@ impl CliSubCommand for TxSubCommand<'_> { let sighash_addresses: Vec = sighash_addresses .into_iter() .map(|address| { - H160::from_slice(address.payload().args().as_ref()) - .map_err(|e| format!("invalid H160 from sighash address: {}", e)) + h160_from_slice(address.payload().args().as_ref(), "sighash address") }) .collect::, _>>()?; let cfg = MultisigConfig::new_with( @@ -893,7 +892,7 @@ impl TryFrom for MultisigConfig { .into_iter() .map(|address_string| { Address::from_str(&address_string) - .map(|addr| H160::from_slice(addr.payload().args().as_ref()))? + .map(|addr| h160_from_slice(addr.payload().args().as_ref(), "address"))? .map_err(|err| format!("invalid address: {address_string} error: {err:?}")) }) .collect::, String>>()?; diff --git a/src/subcommands/util.rs b/src/subcommands/util.rs index 61accdcb..4d692ed7 100644 --- a/src/subcommands/util.rs +++ b/src/subcommands/util.rs @@ -36,7 +36,7 @@ use crate::utils::{ PrivkeyPathParser, PrivkeyWrapper, PubkeyHexParser, }, genesis_info::GenesisInfo, - other::{address_json, get_address, get_network_type, read_password}, + other::{address_json, get_address, get_network_type, h160_from_slice, read_password}, rpc::{ChainInfo, HttpRpcClient}, }; use crate::{build_cli, get_version}; @@ -328,8 +328,7 @@ impl CliSubCommand for UtilSubCommand<'_> { Some(pubkey) => AddressPayload::from_pubkey(&pubkey), None => get_address(None, m)?, }; - let lock_arg = H160::from_slice(address_payload.args().as_ref()) - .map_err(|err| format!("invalid H160 from address payload: {}", err))?; + let lock_arg = h160_from_slice(address_payload.args().as_ref(), "address payload")?; let old_address = OldAddress::new_default(lock_arg.clone()); eprintln!( @@ -371,7 +370,8 @@ message = "0x" result .map(|address_opt| { address_opt.and_then(|address| { - H160::from_slice(address.payload().args().as_ref()).ok() + h160_from_slice(address.payload().args().as_ref(), "address") + .ok() }) }) .map_err(|_| err) @@ -446,7 +446,8 @@ message = "0x" result .map(|address_opt| { address_opt.and_then(|address| { - H160::from_slice(address.payload().args().as_ref()).ok() + h160_from_slice(address.payload().args().as_ref(), "address") + .ok() }) }) .map_err(|_| err) @@ -507,7 +508,8 @@ message = "0x" result .map(|address_opt| { address_opt.and_then(|address| { - H160::from_slice(address.payload().args().as_ref()).ok() + h160_from_slice(address.payload().args().as_ref(), "address") + .ok() }) }) .map_err(|_| err) @@ -859,8 +861,10 @@ fn search_path( extended_address: Address, password: Option, ) -> Result { - let target = H160::from_slice(extended_address.payload().args().as_ref()) - .map_err(|err| format!("parse extended address lock args error: {}", err))?; + let target = h160_from_slice( + extended_address.payload().args().as_ref(), + "extended address", + )?; let key_set = plugin_mgr .keystore_handler() .derived_key_set_by_index(hash160, 0, 2000, 0, 2000, password)?; diff --git a/src/subcommands/wallet.rs b/src/subcommands/wallet.rs index 8fef28fe..6b5f71aa 100644 --- a/src/subcommands/wallet.rs +++ b/src/subcommands/wallet.rs @@ -46,7 +46,7 @@ use crate::utils::{ genesis_info::GenesisInfo, other::{ check_capacity, get_address, get_arg_value, get_genesis_info, get_network_type, - get_to_data, map_tx_builder_error_2_str, read_password, to_live_cell_info, + get_to_data, h160_from_slice, map_tx_builder_error_2_str, read_password, to_live_cell_info, }, rpc::HttpRpcClient, signer::KeyStoreHandlerSigner, @@ -163,8 +163,7 @@ impl<'a> WalletSubCommand<'a> { .parse(&input); result .and_then(|address| { - H160::from_slice(address.payload().args().as_ref()) - .map_err(|e| format!("invalid H160 from address: {}", e)) + h160_from_slice(address.payload().args().as_ref(), "address") }) .map_err(|_| err) }) @@ -275,45 +274,46 @@ impl<'a> WalletSubCommand<'a> { SinceSource::default(), )]; - let from_lock_arg = H160::from_slice(from_address.payload().args().as_ref()) - .map_err(|err| format!("invalid H160 from from-address: {}", err))?; + let from_lock_arg = + h160_from_slice(from_address.payload().args().as_ref(), "from-address")?; let mut path_map: HashMap = Default::default(); - let (change_address_payload, change_path) = if let Some(last_change_address) = - last_change_address_opt.as_ref() - { - // Behave like HD wallet - let change_last = H160::from_slice(last_change_address.payload().args().as_ref()) - .map_err(|err| format!("invalid H160 from change-address: {}", err))?; - let key_set = self.plugin_mgr.keystore_handler().derived_key_set( - from_lock_arg.clone(), - receiving_address_length, - change_last.clone(), - DERIVE_CHANGE_ADDRESS_MAX_LEN, - None, - )?; - let mut change_path_opt = None; - for (path, hash160) in key_set.external.into_iter().chain(key_set.change) { - if hash160 == change_last { - change_path_opt = Some(path.clone()); + let (change_address_payload, change_path) = + if let Some(last_change_address) = last_change_address_opt.as_ref() { + // Behave like HD wallet + let change_last = h160_from_slice( + last_change_address.payload().args().as_ref(), + "change-address", + )?; + let key_set = self.plugin_mgr.keystore_handler().derived_key_set( + from_lock_arg.clone(), + receiving_address_length, + change_last.clone(), + DERIVE_CHANGE_ADDRESS_MAX_LEN, + None, + )?; + let mut change_path_opt = None; + for (path, hash160) in key_set.external.into_iter().chain(key_set.change) { + if hash160 == change_last { + change_path_opt = Some(path.clone()); + } + path_map.insert(hash160.clone(), path); + let payload = AddressPayload::from_pubkey_hash(hash160); + lock_scripts.push(( + Script::from(&payload), + sighash_placeholder_witness.clone(), + Default::default(), + )); } - path_map.insert(hash160.clone(), path); - let payload = AddressPayload::from_pubkey_hash(hash160); - lock_scripts.push(( - Script::from(&payload), - sighash_placeholder_witness.clone(), - Default::default(), - )); - } - ( - last_change_address.payload().clone(), - change_path_opt.expect("change path not exists"), - ) - } else { - ( - from_address.payload().clone(), - self.plugin_mgr.root_key_path(from_lock_arg.clone())?, - ) - }; + ( + last_change_address.payload().clone(), + change_path_opt.expect("change path not exists"), + ) + } else { + ( + from_address.payload().clone(), + self.plugin_mgr.root_key_path(from_lock_arg.clone())?, + ) + }; let get_signer = || -> Result, String> { if let Some(privkey) = from_privkey.as_ref() { @@ -630,8 +630,8 @@ impl CliSubCommand for WalletSubCommand<'_> { }; let mut lock_scripts = vec![Script::from(&address_payload)]; if m.is_present("derived") { - let lock_arg = H160::from_slice(address_payload.args().as_ref()) - .map_err(|err| format!("invalid H160 from address payload: {}", err))?; + let lock_arg = + h160_from_slice(address_payload.args().as_ref(), "address payload")?; let key_set = self .plugin_mgr diff --git a/src/utils/other.rs b/src/utils/other.rs index 044da459..9038b148 100644 --- a/src/utils/other.rs +++ b/src/utils/other.rs @@ -383,3 +383,16 @@ pub(crate) fn map_tx_builder_error_2_str(no_max_tx_fee: bool, err: TxBuilderErro } err.to_string() } + +/// Convert a byte slice to H160 with a context-specific error message. +pub(crate) fn h160_from_slice(data: &[u8], context: &str) -> Result { + H160::from_slice(data).map_err(|e| format!("invalid H160 from {}: {}", context, e)) +} + +/// Take the first 20 bytes of a slice and convert to H160 with context error. +pub(crate) fn h160_from_slice_prefix(data: &[u8], context: &str) -> Result { + let bytes = data + .get(0..20) + .ok_or_else(|| format!("{} payload too short for H160", context))?; + H160::from_slice(bytes).map_err(|e| format!("invalid H160 from {}: {}", context, e)) +} diff --git a/src/utils/tx_helper.rs b/src/utils/tx_helper.rs index de802602..3aa20d9d 100644 --- a/src/utils/tx_helper.rs +++ b/src/utils/tx_helper.rs @@ -17,6 +17,7 @@ use ckb_sdk::constants::{MultisigScript, SECP_SIGNATURE_SIZE, SIGHASH_TYPE_HASH} use ckb_sdk::{unlock::MultisigConfig, Since}; use crate::utils::genesis_info::GenesisInfo; +use crate::utils::other::{h160_from_slice, h160_from_slice_prefix}; // TODO: Add dao support @@ -198,8 +199,7 @@ impl TxHelper { ] .contains(&code_hash) { - let hash160 = H160::from_slice(&lock_arg[..20]) - .map_err(|err| format!("invalid H160 from lock_arg: {}", err))?; + let hash160 = h160_from_slice_prefix(&lock_arg, "lock_arg")?; if !self.multisig_configs.contains_key(&hash160) { return Err(format!( "No mutisig config found for input(no.{}) lock_arg prefix: {:#x}", @@ -261,8 +261,7 @@ impl TxHelper { continue; } - let multisig_hash160 = H160::from_slice(&lock_arg[..20]) - .map_err(|err| format!("invalid multisig H160 from lock_arg: {}", err))?; + let multisig_hash160 = h160_from_slice_prefix(&lock_arg, "lock_arg")?; let lock_args = if [ MultisigScript::Legacy.script_id().code_hash.pack(), MultisigScript::V2.script_id().code_hash.pack(), @@ -275,10 +274,7 @@ impl TxHelper { .clone() } else { let mut lock_args = HashSet::default(); - lock_args.insert( - H160::from_slice(lock_arg.as_ref()) - .map_err(|err| format!("invalid H160 from lock_arg: {}", err))?, - ); + lock_args.insert(h160_from_slice(lock_arg.as_ref(), "lock_arg")?); lock_args }; if signer(&lock_args, &h256!("0x0"), &Transaction::default().into())?.is_some() { @@ -329,8 +325,7 @@ impl TxHelper { ] .contains(&code_hash) { - let hash160 = H160::from_slice(&lock_arg[..20]) - .map_err(|err| format!("invalid H160 from lock_arg: {}", err))?; + let hash160 = h160_from_slice_prefix(&lock_arg, "lock_arg")?; let multisig_config = self.multisig_configs.get(&hash160).unwrap(); let threshold = multisig_config.threshold() as usize; let mut data = BytesMut::from(&multisig_config.to_witness_data()[..]); From b64dcc5d751c96d772b07ed72a8b5e314f331e3d Mon Sep 17 00:00:00 2001 From: Eval Exec Date: Sun, 28 Jun 2026 04:09:37 -0400 Subject: [PATCH 4/4] ci: use actions-rust-lang/setup-rust-toolchain@v1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace dtolnay/rust-toolchain@stable with the official actions-rust-lang/setup-rust-toolchain@v1 which auto-discovers rust-toolchain.toml from the repo root. Fixes integration-test failure caused by dtolnay/rust-toolchain@stable breaking change. - No hardcoded toolchain version in CI — reads from rust-toolchain.toml - Built-in caching via Swatinem/rust-cache - Built-in problem matchers - Removes redundant rustup component add commands --- .github/workflows/ci.yaml | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 4dff25a7..9aa01f3f 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -21,9 +21,7 @@ jobs: os: [ ubuntu-latest, macos-15-intel, windows-latest ] steps: - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@stable - with: - toolchain: 1.95.0 + - uses: actions-rust-lang/setup-rust-toolchain@v1 - if: matrix.os == 'windows-latest' name: Windows Dependencies shell: pwsh @@ -42,9 +40,7 @@ jobs: os: [ ubuntu-latest, macos-15-intel ] steps: - uses: actions/checkout@v2 - - uses: dtolnay/rust-toolchain@stable - with: - toolchain: 1.95.0 + - uses: actions-rust-lang/setup-rust-toolchain@v1 - name: Integration_Test run: make integration @@ -55,13 +51,11 @@ jobs: os: [ ubuntu-latest, macos-15-intel ] steps: - uses: actions/checkout@v2 - - uses: dtolnay/rust-toolchain@stable + - uses: actions-rust-lang/setup-rust-toolchain@v1 with: - toolchain: 1.95.0 + components: rustfmt, clippy - name: Linters run: | - cargo fmt --version || rustup component add rustfmt - cargo clippy --version || rustup component add clippy make fmt make clippy git diff --exit-code Cargo.lock @@ -76,9 +70,7 @@ jobs: - --hide-inclusion-graph --show-stats licenses steps: - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@stable - with: - toolchain: 1.95.0 + - uses: actions-rust-lang/setup-rust-toolchain@v1 - name: cargo-deny uses: EmbarkStudios/cargo-deny-action@v2 with: