Add Budget::And element, and supporting functions (#1329)
This commit is contained in:
parent
88a609ade5
commit
db310a044c
|
@ -44,6 +44,9 @@ pub enum Budget {
|
||||||
/// Either make a payment after one condition or a different payment after another
|
/// Either make a payment after one condition or a different payment after another
|
||||||
/// condition, which ever condition is satisfied first.
|
/// condition, which ever condition is satisfied first.
|
||||||
Or((Condition, Payment), (Condition, Payment)),
|
Or((Condition, Payment), (Condition, Payment)),
|
||||||
|
|
||||||
|
/// Make a payment after both of two conditions are satisfied
|
||||||
|
And(Condition, Condition, Payment),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Budget {
|
impl Budget {
|
||||||
|
@ -57,6 +60,15 @@ impl Budget {
|
||||||
Budget::After(Condition::Signature(from), Payment { tokens, to })
|
Budget::After(Condition::Signature(from), Payment { tokens, to })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a budget that pays tokens` to `to` after being witnessed by 2x `from`s
|
||||||
|
pub fn new_2_2_multisig_payment(from0: Pubkey, from1: Pubkey, tokens: i64, to: Pubkey) -> Self {
|
||||||
|
Budget::And(
|
||||||
|
Condition::Signature(from0),
|
||||||
|
Condition::Signature(from1),
|
||||||
|
Payment { tokens, to },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a budget that pays `tokens` to `to` after the given DateTime.
|
/// Create a budget that pays `tokens` to `to` after the given DateTime.
|
||||||
pub fn new_future_payment(dt: DateTime<Utc>, from: Pubkey, tokens: i64, to: Pubkey) -> Self {
|
pub fn new_future_payment(dt: DateTime<Utc>, from: Pubkey, tokens: i64, to: Pubkey) -> Self {
|
||||||
Budget::After(Condition::Timestamp(dt, from), Payment { tokens, to })
|
Budget::After(Condition::Timestamp(dt, from), Payment { tokens, to })
|
||||||
|
@ -87,7 +99,9 @@ impl Budget {
|
||||||
/// Return true if the budget spends exactly `spendable_tokens`.
|
/// Return true if the budget spends exactly `spendable_tokens`.
|
||||||
pub fn verify(&self, spendable_tokens: i64) -> bool {
|
pub fn verify(&self, spendable_tokens: i64) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Budget::Pay(payment) | Budget::After(_, payment) => payment.tokens == spendable_tokens,
|
Budget::Pay(payment) | Budget::After(_, payment) | Budget::And(_, _, payment) => {
|
||||||
|
payment.tokens == spendable_tokens
|
||||||
|
}
|
||||||
Budget::Or(a, b) => a.1.tokens == spendable_tokens && b.1.tokens == spendable_tokens,
|
Budget::Or(a, b) => a.1.tokens == spendable_tokens && b.1.tokens == spendable_tokens,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,15 +109,29 @@ impl Budget {
|
||||||
/// Apply a witness to the budget to see if the budget can be reduced.
|
/// Apply a witness to the budget to see if the budget can be reduced.
|
||||||
/// If so, modify the budget in-place.
|
/// If so, modify the budget in-place.
|
||||||
pub fn apply_witness(&mut self, witness: &Witness, from: &Pubkey) {
|
pub fn apply_witness(&mut self, witness: &Witness, from: &Pubkey) {
|
||||||
let new_payment = match self {
|
let new_budget = match self {
|
||||||
Budget::After(cond, payment) if cond.is_satisfied(witness, from) => Some(payment),
|
Budget::After(cond, payment) if cond.is_satisfied(witness, from) => {
|
||||||
Budget::Or((cond, payment), _) if cond.is_satisfied(witness, from) => Some(payment),
|
Some(Budget::Pay(payment.clone()))
|
||||||
Budget::Or(_, (cond, payment)) if cond.is_satisfied(witness, from) => Some(payment),
|
}
|
||||||
|
Budget::Or((cond, payment), _) if cond.is_satisfied(witness, from) => {
|
||||||
|
Some(Budget::Pay(payment.clone()))
|
||||||
|
}
|
||||||
|
Budget::Or(_, (cond, payment)) if cond.is_satisfied(witness, from) => {
|
||||||
|
Some(Budget::Pay(payment.clone()))
|
||||||
|
}
|
||||||
|
Budget::And(cond0, cond1, payment) => {
|
||||||
|
if cond0.is_satisfied(witness, from) {
|
||||||
|
Some(Budget::After(cond1.clone(), payment.clone()))
|
||||||
|
} else if cond1.is_satisfied(witness, from) {
|
||||||
|
Some(Budget::After(cond0.clone(), payment.clone()))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}.cloned();
|
};
|
||||||
|
if let Some(budget) = new_budget {
|
||||||
if let Some(payment) = new_payment {
|
mem::replace(self, budget);
|
||||||
mem::replace(self, Budget::Pay(payment));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -189,4 +217,14 @@ mod tests {
|
||||||
budget.apply_witness(&Witness::Signature, &from);
|
budget.apply_witness(&Witness::Signature, &from);
|
||||||
assert_eq!(budget, Budget::new_payment(42, from));
|
assert_eq!(budget, Budget::new_payment(42, from));
|
||||||
}
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_2_2_multisig_payment() {
|
||||||
|
let from0 = Keypair::new().pubkey();
|
||||||
|
let from1 = Keypair::new().pubkey();
|
||||||
|
let to = Pubkey::default();
|
||||||
|
|
||||||
|
let mut budget = Budget::new_2_2_multisig_payment(from0, from1, 42, to);
|
||||||
|
budget.apply_witness(&Witness::Signature, &from0);
|
||||||
|
assert_eq!(budget, Budget::new_authorized_payment(from1, 42, to));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue