From 2ec9bc9f05d4627a45270094cfd50d49dd2430df Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Sun, 3 Mar 2019 15:43:51 -0700 Subject: [PATCH] Revive payments via Budget --- programs/budget/src/budget_program.rs | 5 +++-- programs/budget/src/lib.rs | 1 - programs/budget_api/src/budget_instruction.rs | 13 ++++++++----- .../{budget => budget_api}/src/budget_state.rs | 11 +++++++++-- programs/budget_api/src/budget_transaction.rs | 18 ++++++++++++++---- programs/budget_api/src/lib.rs | 1 + sdk/src/system_instruction.rs | 18 ++++++++++++++++++ 7 files changed, 53 insertions(+), 14 deletions(-) rename programs/{budget => budget_api}/src/budget_state.rs (88%) diff --git a/programs/budget/src/budget_program.rs b/programs/budget/src/budget_program.rs index 1f34ccb16..d04c5bc5b 100644 --- a/programs/budget/src/budget_program.rs +++ b/programs/budget/src/budget_program.rs @@ -1,9 +1,9 @@ //! budget program -use crate::budget_state::{BudgetError, BudgetState}; use bincode::deserialize; use chrono::prelude::{DateTime, Utc}; use log::*; use solana_budget_api::budget_instruction::BudgetInstruction; +use solana_budget_api::budget_state::{BudgetError, BudgetState}; use solana_budget_api::payment_plan::Witness; use solana_sdk::account::KeyedAccount; @@ -86,7 +86,8 @@ fn apply_debits( BudgetInstruction::InitializeAccount(expr) => { let expr = expr.clone(); if let Some(payment) = expr.final_payment() { - keyed_accounts[1].account.tokens += payment.tokens; + keyed_accounts[1].account.tokens = 0; + keyed_accounts[0].account.tokens += payment.tokens; Ok(()) } else { let existing = BudgetState::deserialize(&keyed_accounts[1].account.userdata).ok(); diff --git a/programs/budget/src/lib.rs b/programs/budget/src/lib.rs index cf534da74..294ec5b79 100644 --- a/programs/budget/src/lib.rs +++ b/programs/budget/src/lib.rs @@ -1,5 +1,4 @@ mod budget_program; -mod budget_state; use crate::budget_program::process_instruction; use log::*; diff --git a/programs/budget_api/src/budget_instruction.rs b/programs/budget_api/src/budget_instruction.rs index 12c6fdd0e..26b510c15 100644 --- a/programs/budget_api/src/budget_instruction.rs +++ b/programs/budget_api/src/budget_instruction.rs @@ -29,10 +29,13 @@ pub enum BudgetInstruction { impl BudgetInstruction { pub fn new_initialize_account(contract: Pubkey, expr: BudgetExpr) -> BuilderInstruction { - BuilderInstruction::new( - id(), - &BudgetInstruction::InitializeAccount(expr), - vec![(contract, false)], - ) + let mut keys = vec![]; + if let BudgetExpr::Pay(payment) = &expr { + keys.push((payment.to, false)); + } else { + panic!("unsupported Budget instruction"); + } + keys.push((contract, false)); + BuilderInstruction::new(id(), &BudgetInstruction::InitializeAccount(expr), keys) } } diff --git a/programs/budget/src/budget_state.rs b/programs/budget_api/src/budget_state.rs similarity index 88% rename from programs/budget/src/budget_state.rs rename to programs/budget_api/src/budget_state.rs index 2a451ed3a..009361782 100644 --- a/programs/budget/src/budget_state.rs +++ b/programs/budget_api/src/budget_state.rs @@ -1,7 +1,7 @@ //! budget state +use crate::budget_expr::BudgetExpr; use bincode::{self, deserialize, serialize_into}; use serde_derive::{Deserialize, Serialize}; -use solana_budget_api::budget_expr::BudgetExpr; #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub enum BudgetError { @@ -25,6 +25,13 @@ pub struct BudgetState { } impl BudgetState { + pub fn new(budget_expr: BudgetExpr) -> Self { + Self { + initialized: true, + pending_budget: Some(budget_expr), + } + } + pub fn is_pending(&self) -> bool { self.pending_budget.is_some() } @@ -43,7 +50,7 @@ impl BudgetState { #[cfg(test)] mod test { use super::*; - use solana_budget_api::id; + use crate::id; use solana_sdk::account::Account; #[test] diff --git a/programs/budget_api/src/budget_transaction.rs b/programs/budget_api/src/budget_transaction.rs index e8dfc15a7..4f50bd179 100644 --- a/programs/budget_api/src/budget_transaction.rs +++ b/programs/budget_api/src/budget_transaction.rs @@ -2,8 +2,9 @@ use crate::budget_expr::{BudgetExpr, Condition}; use crate::budget_instruction::BudgetInstruction; +use crate::budget_state::BudgetState; use crate::id; -use bincode::deserialize; +use bincode::{deserialize, serialized_size}; use chrono::prelude::*; use solana_sdk::hash::Hash; use solana_sdk::pubkey::Pubkey; @@ -26,8 +27,15 @@ impl BudgetTransaction { let contract = Keypair::new().pubkey(); let from = from_keypair.pubkey(); let payment = BudgetExpr::new_payment(tokens - fee, to); + let space = serialized_size(&BudgetState::new(payment.clone())).unwrap(); TransactionBuilder::new(fee) - .push(SystemInstruction::new_move(from, contract, tokens)) + .push(SystemInstruction::new_program_account( + from, + contract, + tokens, + space, + id(), + )) .push(BudgetInstruction::new_initialize_account(contract, payment)) .sign(&[from_keypair], recent_blockhash) } @@ -163,7 +171,9 @@ impl BudgetTransaction { /// Verify only the payment plan. pub fn verify_plan(tx: &Transaction) -> bool { - if let Some(SystemInstruction::Move { tokens }) = Self::system_instruction(tx, 0) { + if let Some(SystemInstruction::CreateAccount { tokens, .. }) = + Self::system_instruction(tx, 0) + { if let Some(BudgetInstruction::InitializeAccount(expr)) = BudgetTransaction::instruction(&tx, 1) { @@ -226,7 +236,7 @@ mod tests { let pubkey = keypair.pubkey(); let mut tx = BudgetTransaction::new(&keypair, pubkey, 42, zero); let mut system_instruction = BudgetTransaction::system_instruction(&tx, 0).unwrap(); - if let SystemInstruction::Move { ref mut tokens } = system_instruction { + if let SystemInstruction::CreateAccount { ref mut tokens, .. } = system_instruction { *tokens = 1_000_000; // <-- attack, part 1! let mut instruction = BudgetTransaction::instruction(&tx, 1).unwrap(); if let BudgetInstruction::InitializeAccount(ref mut expr) = instruction { diff --git a/programs/budget_api/src/lib.rs b/programs/budget_api/src/lib.rs index e3469c19d..df03126e5 100644 --- a/programs/budget_api/src/lib.rs +++ b/programs/budget_api/src/lib.rs @@ -1,5 +1,6 @@ pub mod budget_expr; pub mod budget_instruction; +pub mod budget_state; pub mod budget_transaction; pub mod payment_plan; diff --git a/sdk/src/system_instruction.rs b/sdk/src/system_instruction.rs index e66c0a4f1..60a308991 100644 --- a/sdk/src/system_instruction.rs +++ b/sdk/src/system_instruction.rs @@ -25,6 +25,24 @@ pub enum SystemInstruction { } impl SystemInstruction { + pub fn new_program_account( + from_id: Pubkey, + to_id: Pubkey, + tokens: u64, + space: u64, + program_id: Pubkey, + ) -> BuilderInstruction { + BuilderInstruction::new( + system_program::id(), + &SystemInstruction::CreateAccount { + tokens, + space, + program_id, + }, + vec![(from_id, true), (to_id, false)], + ) + } + pub fn new_move(from_id: Pubkey, to_id: Pubkey, tokens: u64) -> BuilderInstruction { BuilderInstruction::new( system_program::id(),