Skip to content

Commit 1e86fc1

Browse files
committed
refactor: have a structured IndexOutOfBoundsError type
1 parent 234c1ec commit 1e86fc1

File tree

4 files changed

+76
-15
lines changed

4 files changed

+76
-15
lines changed

wallet/src/descriptor/policy.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ use miniscript::{
6161

6262
use crate::descriptor::ExtractPolicy;
6363
use crate::keys::ExtScriptContext;
64+
use crate::types::IndexOutOfBoundsError;
6465
use crate::wallet::signer::{SignerId, SignersContainer};
6566
use crate::wallet::utils::{After, Older, SecpCtx};
6667

@@ -324,7 +325,7 @@ impl Satisfaction {
324325
..
325326
} => {
326327
if inner_index >= *n || items.contains(&inner_index) {
327-
return Err(PolicyError::IndexOutOfRange(inner_index));
328+
return Err(IndexOutOfBoundsError::new(inner_index, *n))?;
328329
}
329330

330331
match inner {
@@ -514,7 +515,7 @@ pub enum PolicyError {
514515
NotEnoughItemsSelected(String),
515516
/// Index out of range for an item to satisfy a [`SatisfiableItem::Thresh`] or a
516517
/// [`SatisfiableItem::Multisig`]
517-
IndexOutOfRange(usize),
518+
IndexOutOfRange(IndexOutOfBoundsError),
518519
/// Can not add to an item that is [`Satisfaction::None`] or [`Satisfaction::Complete`]
519520
AddOnLeaf,
520521
/// Can not add to an item that is [`Satisfaction::PartialComplete`]
@@ -530,7 +531,7 @@ impl fmt::Display for PolicyError {
530531
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
531532
match self {
532533
Self::NotEnoughItemsSelected(err) => write!(f, "Not enough items selected: {err}"),
533-
Self::IndexOutOfRange(index) => write!(f, "Index out of range: {index}"),
534+
Self::IndexOutOfRange(err) => write!(f, "{err}"),
534535
Self::AddOnLeaf => write!(f, "Add on leaf"),
535536
Self::AddOnPartialComplete => write!(f, "Add on partial complete"),
536537
Self::MixedTimelockUnits => write!(f, "Mixed timelock units"),
@@ -539,6 +540,12 @@ impl fmt::Display for PolicyError {
539540
}
540541
}
541542

543+
impl From<IndexOutOfBoundsError> for PolicyError {
544+
fn from(err: IndexOutOfBoundsError) -> Self {
545+
Self::IndexOutOfRange(err)
546+
}
547+
}
548+
542549
#[cfg(feature = "std")]
543550
impl std::error::Error for PolicyError {}
544551

@@ -695,7 +702,7 @@ impl Policy {
695702
// make sure all the indexes in the `selected` list are within range
696703
for index in &selected {
697704
if *index >= items.len() {
698-
return Err(PolicyError::IndexOutOfRange(*index));
705+
return Err(IndexOutOfBoundsError::new(*index, items.len()))?;
699706
}
700707
}
701708

@@ -718,7 +725,7 @@ impl Policy {
718725
return Err(PolicyError::NotEnoughItemsSelected(self.id.clone()));
719726
}
720727
if let Some(item) = selected.into_iter().find(|&i| i >= keys.len()) {
721-
return Err(PolicyError::IndexOutOfRange(item));
728+
return Err(IndexOutOfBoundsError::new(item, keys.len()))?;
722729
}
723730

724731
Ok(Condition::default())
@@ -1570,7 +1577,12 @@ mod test {
15701577
// index out of range
15711578
let out_of_range =
15721579
policy.get_condition(&vec![(policy.id.clone(), vec![5])].into_iter().collect());
1573-
assert_eq!(out_of_range, Err(PolicyError::IndexOutOfRange(5)));
1580+
assert_eq!(
1581+
out_of_range,
1582+
Err(PolicyError::IndexOutOfRange(IndexOutOfBoundsError::new(
1583+
5, 2
1584+
)))
1585+
);
15741586
}
15751587

15761588
const ALICE_TPRV_STR:&str = "tprv8ZgxMBicQKsPf6T5X327efHnvJDr45Xnb8W4JifNWtEoqXu9MRYS4v1oYe6DFcMVETxy5w3bqpubYRqvcVTqovG1LifFcVUuJcbwJwrhYzP";

wallet/src/types.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,3 +144,32 @@ impl Utxo {
144144
}
145145
}
146146
}
147+
148+
/// Index out of bounds error.
149+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
150+
pub struct IndexOutOfBoundsError {
151+
/// The index that is out of range.
152+
pub index: usize,
153+
/// The length of the container.
154+
pub len: usize,
155+
}
156+
157+
impl IndexOutOfBoundsError {
158+
/// Create a new `IndexOutOfBoundsError`.
159+
pub fn new(index: usize, len: usize) -> Self {
160+
Self { index, len }
161+
}
162+
}
163+
164+
impl fmt::Display for IndexOutOfBoundsError {
165+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
166+
write!(
167+
f,
168+
"Index out of bounds: index {} is greater than or equal to length {}",
169+
self.index, self.len
170+
)
171+
}
172+
}
173+
174+
#[cfg(feature = "std")]
175+
impl std::error::Error for IndexOutOfBoundsError {}

wallet/src/wallet/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1997,7 +1997,7 @@ impl Wallet {
19971997
let psbt_input = &psbt
19981998
.inputs
19991999
.get(n)
2000-
.ok_or(SignerError::InputIndexOutOfRange)?;
2000+
.ok_or(IndexOutOfBoundsError::new(n, psbt.inputs.len()))?;
20012001
if psbt_input.final_script_sig.is_some() || psbt_input.final_script_witness.is_some() {
20022002
continue;
20032003
}
@@ -2035,12 +2035,13 @@ impl Wallet {
20352035
),
20362036
) {
20372037
Ok(_) => {
2038+
let length = psbt.inputs.len();
20382039
// Set the UTXO fields, final script_sig and witness
20392040
// and clear everything else.
20402041
let psbt_input = psbt
20412042
.inputs
20422043
.get_mut(n)
2043-
.ok_or(SignerError::InputIndexOutOfRange)?;
2044+
.ok_or(IndexOutOfBoundsError::new(n, length))?;
20442045
let original = mem::take(psbt_input);
20452046
psbt_input.non_witness_utxo = original.non_witness_utxo;
20462047
psbt_input.witness_utxo = original.witness_utxo;

wallet/src/wallet/signer.rs

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ use miniscript::{SigType, ToPublicKey};
106106
use super::utils::SecpCtx;
107107
use crate::descriptor::{DescriptorMeta, XKeyUtils};
108108
use crate::psbt::PsbtUtils;
109+
use crate::types::IndexOutOfBoundsError;
109110
use crate::wallet::error::MiniscriptPsbtError;
110111

111112
/// Identifier of a signer in the `SignersContainers`. Used as a key to find the right signer among
@@ -142,7 +143,7 @@ pub enum SignerError {
142143
/// The user canceled the operation
143144
UserCanceled,
144145
/// Input index is out of range
145-
InputIndexOutOfRange,
146+
InputIndexOutOfRange(IndexOutOfBoundsError),
146147
/// The `non_witness_utxo` field of the transaction is required to sign this input
147148
MissingNonWitnessUtxo,
148149
/// The `non_witness_utxo` specified is invalid
@@ -179,7 +180,7 @@ impl fmt::Display for SignerError {
179180
Self::MissingKey => write!(f, "Missing private key"),
180181
Self::InvalidKey => write!(f, "The private key in use has the right fingerprint but derives differently than expected"),
181182
Self::UserCanceled => write!(f, "The user canceled the operation"),
182-
Self::InputIndexOutOfRange => write!(f, "Input index out of range"),
183+
Self::InputIndexOutOfRange(err) => write!(f, "{err}"),
183184
Self::MissingNonWitnessUtxo => write!(f, "Missing non-witness UTXO"),
184185
Self::InvalidNonWitnessUtxo => write!(f, "Invalid non-witness UTXO"),
185186
Self::MissingWitnessUtxo => write!(f, "Missing witness UTXO"),
@@ -195,6 +196,12 @@ impl fmt::Display for SignerError {
195196
}
196197
}
197198

199+
impl From<IndexOutOfBoundsError> for SignerError {
200+
fn from(err: IndexOutOfBoundsError) -> Self {
201+
Self::InputIndexOutOfRange(err)
202+
}
203+
}
204+
198205
#[cfg(feature = "std")]
199206
impl std::error::Error for SignerError {}
200207

@@ -318,7 +325,7 @@ impl InputSigner for SignerWrapper<DescriptorXKey<Xpriv>> {
318325
secp: &SecpCtx,
319326
) -> Result<(), SignerError> {
320327
if input_index >= psbt.inputs.len() {
321-
return Err(SignerError::InputIndexOutOfRange);
328+
return Err(IndexOutOfBoundsError::new(input_index, psbt.inputs.len()))?;
322329
}
323330

324331
if psbt.inputs[input_index].final_script_sig.is_some()
@@ -442,8 +449,14 @@ impl InputSigner for SignerWrapper<PrivateKey> {
442449
sign_options: &SignOptions,
443450
secp: &SecpCtx,
444451
) -> Result<(), SignerError> {
445-
if input_index >= psbt.inputs.len() || input_index >= psbt.unsigned_tx.input.len() {
446-
return Err(SignerError::InputIndexOutOfRange);
452+
if input_index >= psbt.inputs.len() {
453+
return Err(IndexOutOfBoundsError::new(input_index, psbt.inputs.len()))?;
454+
}
455+
if input_index >= psbt.unsigned_tx.input.len() {
456+
return Err(IndexOutOfBoundsError::new(
457+
input_index,
458+
psbt.unsigned_tx.input.len(),
459+
))?;
447460
}
448461

449462
if psbt.inputs[input_index].final_script_sig.is_some()
@@ -834,8 +847,14 @@ fn compute_tap_sighash(
834847
input_index: usize,
835848
extra: Option<taproot::TapLeafHash>,
836849
) -> Result<(sighash::TapSighash, TapSighashType), SignerError> {
837-
if input_index >= psbt.inputs.len() || input_index >= psbt.unsigned_tx.input.len() {
838-
return Err(SignerError::InputIndexOutOfRange);
850+
if input_index >= psbt.inputs.len() {
851+
Err(IndexOutOfBoundsError::new(input_index, psbt.inputs.len()))?;
852+
}
853+
if input_index >= psbt.unsigned_tx.input.len() {
854+
Err(IndexOutOfBoundsError::new(
855+
input_index,
856+
psbt.unsigned_tx.input.len(),
857+
))?;
839858
}
840859

841860
let psbt_input = &psbt.inputs[input_index];

0 commit comments

Comments
 (0)