[policy] Allow specifying a policy path for Multisig
While technically it's not required since there are no timelocks inside, it's still less confusing for the end user if we allow this instead of failing like we do currently.
This commit is contained in:
parent
fa2610538f
commit
b61427c07b
@ -506,11 +506,11 @@ impl Condition {
|
||||
}
|
||||
|
||||
/// Errors that can happen while extracting and manipulating policies
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum PolicyError {
|
||||
/// Not enough items are selected to satisfy a [`SatisfiableItem::Thresh`]
|
||||
/// Not enough items are selected to satisfy a [`SatisfiableItem::Thresh`] or a [`SatisfiableItem::Multisig`]
|
||||
NotEnoughItemsSelected(String),
|
||||
/// Index out of range for an item to satisfy a [`SatisfiableItem::Thresh`]
|
||||
/// Index out of range for an item to satisfy a [`SatisfiableItem::Thresh`] or a [`SatisfiableItem::Multisig`]
|
||||
IndexOutOfRange(usize),
|
||||
/// Can not add to an item that is [`Satisfaction::None`] or [`Satisfaction::Complete`]
|
||||
AddOnLeaf,
|
||||
@ -642,10 +642,10 @@ impl Policy {
|
||||
SatisfiableItem::Thresh { items, threshold } if items.len() == *threshold => {
|
||||
(0..*threshold).collect()
|
||||
}
|
||||
SatisfiableItem::Multisig { keys, .. } => (0..keys.len()).collect(),
|
||||
_ => vec![],
|
||||
};
|
||||
let selected = match path.get(&self.id) {
|
||||
_ if !default.is_empty() => &default,
|
||||
Some(arr) => arr,
|
||||
_ => &default,
|
||||
};
|
||||
@ -682,7 +682,16 @@ impl Policy {
|
||||
|
||||
Ok(requirements)
|
||||
}
|
||||
_ if !selected.is_empty() => Err(PolicyError::TooManyItemsSelected(self.id.clone())),
|
||||
SatisfiableItem::Multisig { keys, threshold } => {
|
||||
if selected.len() < *threshold {
|
||||
return Err(PolicyError::NotEnoughItemsSelected(self.id.clone()));
|
||||
}
|
||||
if let Some(item) = selected.iter().find(|i| **i >= keys.len()) {
|
||||
return Err(PolicyError::IndexOutOfRange(*item));
|
||||
}
|
||||
|
||||
Ok(Condition::default())
|
||||
}
|
||||
SatisfiableItem::AbsoluteTimelock { value } => Ok(Condition {
|
||||
csv: None,
|
||||
timelock: Some(*value),
|
||||
@ -1249,4 +1258,50 @@ mod test {
|
||||
//
|
||||
// // TODO how should this merge timelocks?
|
||||
// }
|
||||
|
||||
#[test]
|
||||
fn test_get_condition_multisig() {
|
||||
let secp = Secp256k1::gen_new();
|
||||
|
||||
let (_, pk0, _) = setup_keys(TPRV0_STR);
|
||||
let (_, pk1, _) = setup_keys(TPRV1_STR);
|
||||
|
||||
let desc = descriptor!(wsh(multi(1, pk0, pk1))).unwrap();
|
||||
let (wallet_desc, keymap) = desc
|
||||
.into_wallet_descriptor(&secp, Network::Testnet)
|
||||
.unwrap();
|
||||
let signers = keymap.into();
|
||||
|
||||
let policy = wallet_desc
|
||||
.extract_policy(&signers, &secp)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
// no args, choose the default
|
||||
let no_args = policy.get_condition(&vec![].into_iter().collect());
|
||||
assert_eq!(no_args, Ok(Condition::default()));
|
||||
|
||||
// enough args
|
||||
let eq_thresh =
|
||||
policy.get_condition(&vec![(policy.id.clone(), vec![0])].into_iter().collect());
|
||||
assert_eq!(eq_thresh, Ok(Condition::default()));
|
||||
|
||||
// more args, it doesn't really change anything
|
||||
let gt_thresh =
|
||||
policy.get_condition(&vec![(policy.id.clone(), vec![0, 1])].into_iter().collect());
|
||||
assert_eq!(gt_thresh, Ok(Condition::default()));
|
||||
|
||||
// not enough args, error
|
||||
let lt_thresh =
|
||||
policy.get_condition(&vec![(policy.id.clone(), vec![])].into_iter().collect());
|
||||
assert_eq!(
|
||||
lt_thresh,
|
||||
Err(PolicyError::NotEnoughItemsSelected(policy.id.clone()))
|
||||
);
|
||||
|
||||
// index out of range
|
||||
let out_of_range =
|
||||
policy.get_condition(&vec![(policy.id.clone(), vec![5])].into_iter().collect());
|
||||
assert_eq!(out_of_range, Err(PolicyError::IndexOutOfRange(5)));
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user