Rename Budget to BudgetExpr
This commit is contained in:
		| @@ -1,4 +1,4 @@ | ||||
| //! The `budget` module provides a domain-specific language for payment plans. Users create Budget objects that
 | ||||
| //! The `budget_expr` module provides a domain-specific language for payment plans. Users create BudgetExpr objects that
 | ||||
| //! are given to an interpreter. The interpreter listens for `Witness` transactions,
 | ||||
| //! which it uses to reduce the payment plan. When the budget is reduced to a
 | ||||
| //! `Payment`, the payment is executed.
 | ||||
| @@ -34,7 +34,7 @@ impl Condition { | ||||
| /// A data type representing a payment plan.
 | ||||
| #[repr(C)] | ||||
| #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] | ||||
| pub enum Budget { | ||||
| pub enum BudgetExpr { | ||||
|     /// Make a payment.
 | ||||
|     Pay(Payment), | ||||
| 
 | ||||
| @@ -49,20 +49,20 @@ pub enum Budget { | ||||
|     And(Condition, Condition, Payment), | ||||
| } | ||||
| 
 | ||||
| impl Budget { | ||||
| impl BudgetExpr { | ||||
|     /// Create the simplest budget - one that pays `tokens` to Pubkey.
 | ||||
|     pub fn new_payment(tokens: i64, to: Pubkey) -> Self { | ||||
|         Budget::Pay(Payment { tokens, to }) | ||||
|         BudgetExpr::Pay(Payment { tokens, to }) | ||||
|     } | ||||
| 
 | ||||
|     /// Create a budget that pays `tokens` to `to` after being witnessed by `from`.
 | ||||
|     pub fn new_authorized_payment(from: Pubkey, tokens: i64, to: Pubkey) -> Self { | ||||
|         Budget::After(Condition::Signature(from), Payment { tokens, to }) | ||||
|         BudgetExpr::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( | ||||
|         BudgetExpr::And( | ||||
|             Condition::Signature(from0), | ||||
|             Condition::Signature(from1), | ||||
|             Payment { tokens, to }, | ||||
| @@ -71,7 +71,7 @@ impl Budget { | ||||
| 
 | ||||
|     /// 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 { | ||||
|         Budget::After(Condition::Timestamp(dt, from), Payment { tokens, to }) | ||||
|         BudgetExpr::After(Condition::Timestamp(dt, from), Payment { tokens, to }) | ||||
|     } | ||||
| 
 | ||||
|     /// Create a budget that pays `tokens` to `to` after the given DateTime
 | ||||
| @@ -82,7 +82,7 @@ impl Budget { | ||||
|         tokens: i64, | ||||
|         to: Pubkey, | ||||
|     ) -> Self { | ||||
|         Budget::Or( | ||||
|         BudgetExpr::Or( | ||||
|             (Condition::Timestamp(dt, from), Payment { tokens, to }), | ||||
|             (Condition::Signature(from), Payment { tokens, to: from }), | ||||
|         ) | ||||
| @@ -91,7 +91,7 @@ impl Budget { | ||||
|     /// Return Payment if the budget requires no additional Witnesses.
 | ||||
|     pub fn final_payment(&self) -> Option<Payment> { | ||||
|         match self { | ||||
|             Budget::Pay(payment) => Some(payment.clone()), | ||||
|             BudgetExpr::Pay(payment) => Some(payment.clone()), | ||||
|             _ => None, | ||||
|         } | ||||
|     } | ||||
| @@ -99,39 +99,39 @@ impl Budget { | ||||
|     /// Return true if the budget spends exactly `spendable_tokens`.
 | ||||
|     pub fn verify(&self, spendable_tokens: i64) -> bool { | ||||
|         match self { | ||||
|             Budget::Pay(payment) | Budget::After(_, payment) | Budget::And(_, _, payment) => { | ||||
|             BudgetExpr::Pay(payment) | BudgetExpr::After(_, payment) | BudgetExpr::And(_, _, payment) => { | ||||
|                 payment.tokens == spendable_tokens | ||||
|             } | ||||
|             Budget::Or(a, b) => a.1.tokens == spendable_tokens && b.1.tokens == spendable_tokens, | ||||
|             BudgetExpr::Or(a, b) => a.1.tokens == spendable_tokens && b.1.tokens == spendable_tokens, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// Apply a witness to the budget to see if the budget can be reduced.
 | ||||
|     /// If so, modify the budget in-place.
 | ||||
|     pub fn apply_witness(&mut self, witness: &Witness, from: &Pubkey) { | ||||
|         let new_budget = match self { | ||||
|             Budget::After(cond, payment) if cond.is_satisfied(witness, from) => { | ||||
|                 Some(Budget::Pay(payment.clone())) | ||||
|         let new_expr = match self { | ||||
|             BudgetExpr::After(cond, payment) if cond.is_satisfied(witness, from) => { | ||||
|                 Some(BudgetExpr::Pay(payment.clone())) | ||||
|             } | ||||
|             Budget::Or((cond, payment), _) if cond.is_satisfied(witness, from) => { | ||||
|                 Some(Budget::Pay(payment.clone())) | ||||
|             BudgetExpr::Or((cond, payment), _) if cond.is_satisfied(witness, from) => { | ||||
|                 Some(BudgetExpr::Pay(payment.clone())) | ||||
|             } | ||||
|             Budget::Or(_, (cond, payment)) if cond.is_satisfied(witness, from) => { | ||||
|                 Some(Budget::Pay(payment.clone())) | ||||
|             BudgetExpr::Or(_, (cond, payment)) if cond.is_satisfied(witness, from) => { | ||||
|                 Some(BudgetExpr::Pay(payment.clone())) | ||||
|             } | ||||
|             Budget::And(cond0, cond1, payment) => { | ||||
|             BudgetExpr::And(cond0, cond1, payment) => { | ||||
|                 if cond0.is_satisfied(witness, from) { | ||||
|                     Some(Budget::After(cond1.clone(), payment.clone())) | ||||
|                     Some(BudgetExpr::After(cond1.clone(), payment.clone())) | ||||
|                 } else if cond1.is_satisfied(witness, from) { | ||||
|                     Some(Budget::After(cond0.clone(), payment.clone())) | ||||
|                     Some(BudgetExpr::After(cond0.clone(), payment.clone())) | ||||
|                 } else { | ||||
|                     None | ||||
|                 } | ||||
|             } | ||||
|             _ => None, | ||||
|         }; | ||||
|         if let Some(budget) = new_budget { | ||||
|             mem::replace(self, budget); | ||||
|         if let Some(expr) = new_expr { | ||||
|             mem::replace(self, expr); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -162,10 +162,10 @@ mod tests { | ||||
|         let dt = Utc.ymd(2014, 11, 14).and_hms(8, 9, 10); | ||||
|         let from = Pubkey::default(); | ||||
|         let to = Pubkey::default(); | ||||
|         assert!(Budget::new_payment(42, to).verify(42)); | ||||
|         assert!(Budget::new_authorized_payment(from, 42, to).verify(42)); | ||||
|         assert!(Budget::new_future_payment(dt, from, 42, to).verify(42)); | ||||
|         assert!(Budget::new_cancelable_future_payment(dt, from, 42, to).verify(42)); | ||||
|         assert!(BudgetExpr::new_payment(42, to).verify(42)); | ||||
|         assert!(BudgetExpr::new_authorized_payment(from, 42, to).verify(42)); | ||||
|         assert!(BudgetExpr::new_future_payment(dt, from, 42, to).verify(42)); | ||||
|         assert!(BudgetExpr::new_cancelable_future_payment(dt, from, 42, to).verify(42)); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
| @@ -173,9 +173,9 @@ mod tests { | ||||
|         let from = Pubkey::default(); | ||||
|         let to = Pubkey::default(); | ||||
| 
 | ||||
|         let mut budget = Budget::new_authorized_payment(from, 42, to); | ||||
|         budget.apply_witness(&Witness::Signature, &from); | ||||
|         assert_eq!(budget, Budget::new_payment(42, to)); | ||||
|         let mut expr = BudgetExpr::new_authorized_payment(from, 42, to); | ||||
|         expr.apply_witness(&Witness::Signature, &from); | ||||
|         assert_eq!(expr, BudgetExpr::new_payment(42, to)); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
| @@ -184,9 +184,9 @@ mod tests { | ||||
|         let from = Keypair::new().pubkey(); | ||||
|         let to = Keypair::new().pubkey(); | ||||
| 
 | ||||
|         let mut budget = Budget::new_future_payment(dt, from, 42, to); | ||||
|         budget.apply_witness(&Witness::Timestamp(dt), &from); | ||||
|         assert_eq!(budget, Budget::new_payment(42, to)); | ||||
|         let mut expr = BudgetExpr::new_future_payment(dt, from, 42, to); | ||||
|         expr.apply_witness(&Witness::Timestamp(dt), &from); | ||||
|         assert_eq!(expr, BudgetExpr::new_payment(42, to)); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
| @@ -197,10 +197,10 @@ mod tests { | ||||
|         let from = Keypair::new().pubkey(); | ||||
|         let to = Keypair::new().pubkey(); | ||||
| 
 | ||||
|         let mut budget = Budget::new_future_payment(dt, from, 42, to); | ||||
|         let orig_budget = budget.clone(); | ||||
|         budget.apply_witness(&Witness::Timestamp(dt), &to); // <-- Attack!
 | ||||
|         assert_eq!(budget, orig_budget); | ||||
|         let mut expr = BudgetExpr::new_future_payment(dt, from, 42, to); | ||||
|         let orig_expr = expr.clone(); | ||||
|         expr.apply_witness(&Witness::Timestamp(dt), &to); // <-- Attack!
 | ||||
|         assert_eq!(expr, orig_expr); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
| @@ -209,13 +209,13 @@ mod tests { | ||||
|         let from = Pubkey::default(); | ||||
|         let to = Pubkey::default(); | ||||
| 
 | ||||
|         let mut budget = Budget::new_cancelable_future_payment(dt, from, 42, to); | ||||
|         budget.apply_witness(&Witness::Timestamp(dt), &from); | ||||
|         assert_eq!(budget, Budget::new_payment(42, to)); | ||||
|         let mut expr = BudgetExpr::new_cancelable_future_payment(dt, from, 42, to); | ||||
|         expr.apply_witness(&Witness::Timestamp(dt), &from); | ||||
|         assert_eq!(expr, BudgetExpr::new_payment(42, to)); | ||||
| 
 | ||||
|         let mut budget = Budget::new_cancelable_future_payment(dt, from, 42, to); | ||||
|         budget.apply_witness(&Witness::Signature, &from); | ||||
|         assert_eq!(budget, Budget::new_payment(42, from)); | ||||
|         let mut expr = BudgetExpr::new_cancelable_future_payment(dt, from, 42, to); | ||||
|         expr.apply_witness(&Witness::Signature, &from); | ||||
|         assert_eq!(expr, BudgetExpr::new_payment(42, from)); | ||||
|     } | ||||
|     #[test] | ||||
|     fn test_2_2_multisig_payment() { | ||||
| @@ -223,8 +223,8 @@ mod tests { | ||||
|         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)); | ||||
|         let mut expr = BudgetExpr::new_2_2_multisig_payment(from0, from1, 42, to); | ||||
|         expr.apply_witness(&Witness::Signature, &from0); | ||||
|         assert_eq!(expr, BudgetExpr::new_authorized_payment(from1, 42, to)); | ||||
|     } | ||||
| } | ||||
| @@ -1,19 +1,19 @@ | ||||
| use budget::Budget; | ||||
| use budget_expr::BudgetExpr; | ||||
| use chrono::prelude::{DateTime, Utc}; | ||||
|  | ||||
| /// A smart contract. | ||||
| #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] | ||||
| pub struct Contract { | ||||
|     /// The number of tokens allocated to the `Budget` and any transaction fees. | ||||
|     /// The number of tokens allocated to the `BudgetExpr` and any transaction fees. | ||||
|     pub tokens: i64, | ||||
|     pub budget: Budget, | ||||
|     pub budget_expr: BudgetExpr, | ||||
| } | ||||
|  | ||||
| /// An instruction to progress the smart contract. | ||||
| #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] | ||||
| pub enum Instruction { | ||||
|     /// Declare and instantiate `Budget`. | ||||
|     NewBudget(Budget), | ||||
|     /// Declare and instantiate `BudgetExpr`. | ||||
|     NewBudget(BudgetExpr), | ||||
|  | ||||
|     /// Tell a payment plan acknowledge the given `DateTime` has past. | ||||
|     ApplyTimestamp(DateTime<Utc>), | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| //! budget program | ||||
| use bincode::{self, deserialize, serialize_into, serialized_size}; | ||||
| use budget::Budget; | ||||
| use budget_expr::BudgetExpr; | ||||
| use budget_instruction::Instruction; | ||||
| use chrono::prelude::{DateTime, Utc}; | ||||
| use payment_plan::Witness; | ||||
| @@ -27,7 +27,7 @@ pub enum BudgetError { | ||||
| #[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)] | ||||
| pub struct BudgetState { | ||||
|     pub initialized: bool, | ||||
|     pub pending_budget: Option<Budget>, | ||||
|     pub pending_budget: Option<BudgetExpr>, | ||||
| } | ||||
|  | ||||
| const BUDGET_PROGRAM_ID: [u8; 32] = [ | ||||
| @@ -55,13 +55,13 @@ impl BudgetState { | ||||
|         accounts: &mut [&mut Account], | ||||
|     ) -> Result<(), BudgetError> { | ||||
|         let mut final_payment = None; | ||||
|         if let Some(ref mut budget) = self.pending_budget { | ||||
|         if let Some(ref mut expr) = self.pending_budget { | ||||
|             let key = match tx.signed_key(instruction_index, 0) { | ||||
|                 None => return Err(BudgetError::UnsignedKey), | ||||
|                 Some(key) => key, | ||||
|             }; | ||||
|             budget.apply_witness(&Witness::Signature, key); | ||||
|             final_payment = budget.final_payment(); | ||||
|             expr.apply_witness(&Witness::Signature, key); | ||||
|             final_payment = expr.final_payment(); | ||||
|         } | ||||
|  | ||||
|         if let Some(payment) = final_payment { | ||||
| @@ -88,13 +88,13 @@ impl BudgetState { | ||||
|         // Check to see if any timelocked transactions can be completed. | ||||
|         let mut final_payment = None; | ||||
|  | ||||
|         if let Some(ref mut budget) = self.pending_budget { | ||||
|         if let Some(ref mut expr) = self.pending_budget { | ||||
|             let key = match tx.signed_key(instruction_index, 0) { | ||||
|                 None => return Err(BudgetError::UnsignedKey), | ||||
|                 Some(key) => key, | ||||
|             }; | ||||
|             budget.apply_witness(&Witness::Timestamp(dt), key); | ||||
|             final_payment = budget.final_payment(); | ||||
|             expr.apply_witness(&Witness::Timestamp(dt), key); | ||||
|             final_payment = expr.final_payment(); | ||||
|         } | ||||
|  | ||||
|         if let Some(payment) = final_payment { | ||||
| @@ -120,9 +120,9 @@ impl BudgetState { | ||||
|             return Err(BudgetError::SourceIsPendingContract); | ||||
|         } | ||||
|         match instruction { | ||||
|             Instruction::NewBudget(budget) => { | ||||
|                 let budget = budget.clone(); | ||||
|                 if let Some(payment) = budget.final_payment() { | ||||
|             Instruction::NewBudget(expr) => { | ||||
|                 let expr = expr.clone(); | ||||
|                 if let Some(payment) = expr.final_payment() { | ||||
|                     accounts[1].tokens += payment.tokens; | ||||
|                     Ok(()) | ||||
|                 } else { | ||||
| @@ -132,7 +132,7 @@ impl BudgetState { | ||||
|                         Err(BudgetError::ContractAlreadyExists) | ||||
|                     } else { | ||||
|                         let mut state = BudgetState::default(); | ||||
|                         state.pending_budget = Some(budget); | ||||
|                         state.pending_budget = Some(expr); | ||||
|                         accounts[1].tokens += accounts[0].tokens; | ||||
|                         accounts[0].tokens = 0; | ||||
|                         state.initialized = true; | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| //! The `budget_transaction` module provides functionality for creating Budget transactions. | ||||
|  | ||||
| use bincode::{deserialize, serialize}; | ||||
| use budget::{Budget, Condition}; | ||||
| use budget_expr::{BudgetExpr, Condition}; | ||||
| use budget_instruction::Instruction; | ||||
| use budget_program::BudgetState; | ||||
| use chrono::prelude::*; | ||||
| @@ -84,7 +84,7 @@ impl BudgetTransaction for Transaction { | ||||
|             tokens: tokens - fee, | ||||
|             to, | ||||
|         }; | ||||
|         let budget_instruction = Instruction::NewBudget(Budget::Pay(payment)); | ||||
|         let budget_instruction = Instruction::NewBudget(BudgetExpr::Pay(payment)); | ||||
|         let pay_userdata = serialize(&budget_instruction).unwrap(); | ||||
|  | ||||
|         let program_ids = vec![SystemProgram::id(), BudgetState::id()]; | ||||
| @@ -160,15 +160,15 @@ impl BudgetTransaction for Transaction { | ||||
|         tokens: i64, | ||||
|         last_id: Hash, | ||||
|     ) -> Self { | ||||
|         let budget = if let Some(from) = cancelable { | ||||
|             Budget::Or( | ||||
|         let expr = if let Some(from) = cancelable { | ||||
|             BudgetExpr::Or( | ||||
|                 (Condition::Timestamp(dt, dt_pubkey), Payment { tokens, to }), | ||||
|                 (Condition::Signature(from), Payment { tokens, to: from }), | ||||
|             ) | ||||
|         } else { | ||||
|             Budget::After(Condition::Timestamp(dt, dt_pubkey), Payment { tokens, to }) | ||||
|             BudgetExpr::After(Condition::Timestamp(dt, dt_pubkey), Payment { tokens, to }) | ||||
|         }; | ||||
|         let instruction = Instruction::NewBudget(budget); | ||||
|         let instruction = Instruction::NewBudget(expr); | ||||
|         let userdata = serialize(&instruction).expect("serialize instruction"); | ||||
|         Self::new( | ||||
|             from_keypair, | ||||
| @@ -189,15 +189,15 @@ impl BudgetTransaction for Transaction { | ||||
|         tokens: i64, | ||||
|         last_id: Hash, | ||||
|     ) -> Self { | ||||
|         let budget = if let Some(from) = cancelable { | ||||
|             Budget::Or( | ||||
|         let expr = if let Some(from) = cancelable { | ||||
|             BudgetExpr::Or( | ||||
|                 (Condition::Signature(witness), Payment { tokens, to }), | ||||
|                 (Condition::Signature(from), Payment { tokens, to: from }), | ||||
|             ) | ||||
|         } else { | ||||
|             Budget::After(Condition::Signature(witness), Payment { tokens, to }) | ||||
|             BudgetExpr::After(Condition::Signature(witness), Payment { tokens, to }) | ||||
|         }; | ||||
|         let instruction = Instruction::NewBudget(budget); | ||||
|         let instruction = Instruction::NewBudget(expr); | ||||
|         let userdata = serialize(&instruction).expect("serialize instruction"); | ||||
|         Self::new( | ||||
|             from_keypair, | ||||
| @@ -220,8 +220,8 @@ impl BudgetTransaction for Transaction { | ||||
|     /// Verify only the payment plan. | ||||
|     fn verify_plan(&self) -> bool { | ||||
|         if let Some(SystemProgram::Move { tokens }) = self.system_instruction(0) { | ||||
|             if let Some(Instruction::NewBudget(budget)) = self.instruction(1) { | ||||
|                 if !(self.fee >= 0 && self.fee <= tokens && budget.verify(tokens - self.fee)) { | ||||
|             if let Some(Instruction::NewBudget(expr)) = self.instruction(1) { | ||||
|                 if !(self.fee >= 0 && self.fee <= tokens && expr.verify(tokens - self.fee)) { | ||||
|                     return false; | ||||
|                 } | ||||
|             } | ||||
| @@ -267,11 +267,11 @@ mod tests { | ||||
|  | ||||
|     #[test] | ||||
|     fn test_serialize_claim() { | ||||
|         let budget = Budget::Pay(Payment { | ||||
|         let expr = BudgetExpr::Pay(Payment { | ||||
|             tokens: 0, | ||||
|             to: Default::default(), | ||||
|         }); | ||||
|         let instruction = Instruction::NewBudget(budget); | ||||
|         let instruction = Instruction::NewBudget(expr); | ||||
|         let userdata = serialize(&instruction).unwrap(); | ||||
|         let instructions = vec![transaction::Instruction { | ||||
|             program_ids_index: 0, | ||||
| @@ -301,8 +301,8 @@ mod tests { | ||||
|         if let SystemProgram::Move { ref mut tokens } = system_instruction { | ||||
|             *tokens = 1_000_000; // <-- attack, part 1! | ||||
|             let mut instruction = tx.instruction(1).unwrap(); | ||||
|             if let Instruction::NewBudget(ref mut budget) = instruction { | ||||
|                 if let Budget::Pay(ref mut payment) = budget { | ||||
|             if let Instruction::NewBudget(ref mut expr) = instruction { | ||||
|                 if let BudgetExpr::Pay(ref mut payment) = expr { | ||||
|                     payment.tokens = *tokens; // <-- attack, part 2! | ||||
|                 } | ||||
|             } | ||||
| @@ -322,8 +322,8 @@ mod tests { | ||||
|         let zero = Hash::default(); | ||||
|         let mut tx = Transaction::budget_new(&keypair0, pubkey1, 42, zero); | ||||
|         let mut instruction = tx.instruction(1); | ||||
|         if let Some(Instruction::NewBudget(ref mut budget)) = instruction { | ||||
|             if let Budget::Pay(ref mut payment) = budget { | ||||
|         if let Some(Instruction::NewBudget(ref mut expr)) = instruction { | ||||
|             if let BudgetExpr::Pay(ref mut payment) = expr { | ||||
|                 payment.to = thief_keypair.pubkey(); // <-- attack! | ||||
|             } | ||||
|         } | ||||
| @@ -339,8 +339,8 @@ mod tests { | ||||
|         let zero = Hash::default(); | ||||
|         let mut tx = Transaction::budget_new(&keypair0, keypair1.pubkey(), 1, zero); | ||||
|         let mut instruction = tx.instruction(1).unwrap(); | ||||
|         if let Instruction::NewBudget(ref mut budget) = instruction { | ||||
|             if let Budget::Pay(ref mut payment) = budget { | ||||
|         if let Instruction::NewBudget(ref mut expr) = instruction { | ||||
|             if let BudgetExpr::Pay(ref mut payment) = expr { | ||||
|                 payment.tokens = 2; // <-- attack! | ||||
|             } | ||||
|         } | ||||
| @@ -349,8 +349,8 @@ mod tests { | ||||
|  | ||||
|         // Also, ensure all branchs of the plan spend all tokens | ||||
|         let mut instruction = tx.instruction(1).unwrap(); | ||||
|         if let Instruction::NewBudget(ref mut budget) = instruction { | ||||
|             if let Budget::Pay(ref mut payment) = budget { | ||||
|         if let Instruction::NewBudget(ref mut expr) = instruction { | ||||
|             if let BudgetExpr::Pay(ref mut payment) = expr { | ||||
|                 payment.tokens = 0; // <-- whoops! | ||||
|             } | ||||
|         } | ||||
|   | ||||
| @@ -14,7 +14,7 @@ pub mod banking_stage; | ||||
| pub mod blob_fetch_stage; | ||||
| pub mod bpf_loader; | ||||
| pub mod broadcast_stage; | ||||
| pub mod budget; | ||||
| pub mod budget_expr; | ||||
| pub mod budget_instruction; | ||||
| pub mod budget_transaction; | ||||
| #[cfg(feature = "chacha")] | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| //! The `plan` module provides a domain-specific language for payment plans. Users create Budget objects that | ||||
| //! The `plan` module provides a domain-specific language for payment plans. Users create BudgetExpr objects that | ||||
| //! are given to an interpreter. The interpreter listens for `Witness` transactions, | ||||
| //! which it uses to reduce the payment plan. When the plan is reduced to a | ||||
| //! `Payment`, the payment is executed. | ||||
|   | ||||
		Reference in New Issue
	
	Block a user