Revive payments via Budget

This commit is contained in:
Greg Fitzgerald
2019-03-03 15:43:51 -07:00
parent e8ae603a01
commit 2ec9bc9f05
7 changed files with 53 additions and 14 deletions

View File

@ -1,9 +1,9 @@
//! budget program //! budget program
use crate::budget_state::{BudgetError, BudgetState};
use bincode::deserialize; use bincode::deserialize;
use chrono::prelude::{DateTime, Utc}; use chrono::prelude::{DateTime, Utc};
use log::*; use log::*;
use solana_budget_api::budget_instruction::BudgetInstruction; use solana_budget_api::budget_instruction::BudgetInstruction;
use solana_budget_api::budget_state::{BudgetError, BudgetState};
use solana_budget_api::payment_plan::Witness; use solana_budget_api::payment_plan::Witness;
use solana_sdk::account::KeyedAccount; use solana_sdk::account::KeyedAccount;
@ -86,7 +86,8 @@ fn apply_debits(
BudgetInstruction::InitializeAccount(expr) => { BudgetInstruction::InitializeAccount(expr) => {
let expr = expr.clone(); let expr = expr.clone();
if let Some(payment) = expr.final_payment() { 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(()) Ok(())
} else { } else {
let existing = BudgetState::deserialize(&keyed_accounts[1].account.userdata).ok(); let existing = BudgetState::deserialize(&keyed_accounts[1].account.userdata).ok();

View File

@ -1,5 +1,4 @@
mod budget_program; mod budget_program;
mod budget_state;
use crate::budget_program::process_instruction; use crate::budget_program::process_instruction;
use log::*; use log::*;

View File

@ -29,10 +29,13 @@ pub enum BudgetInstruction {
impl BudgetInstruction { impl BudgetInstruction {
pub fn new_initialize_account(contract: Pubkey, expr: BudgetExpr) -> BuilderInstruction { pub fn new_initialize_account(contract: Pubkey, expr: BudgetExpr) -> BuilderInstruction {
BuilderInstruction::new( let mut keys = vec![];
id(), if let BudgetExpr::Pay(payment) = &expr {
&BudgetInstruction::InitializeAccount(expr), keys.push((payment.to, false));
vec![(contract, false)], } else {
) panic!("unsupported Budget instruction");
}
keys.push((contract, false));
BuilderInstruction::new(id(), &BudgetInstruction::InitializeAccount(expr), keys)
} }
} }

View File

@ -1,7 +1,7 @@
//! budget state //! budget state
use crate::budget_expr::BudgetExpr;
use bincode::{self, deserialize, serialize_into}; use bincode::{self, deserialize, serialize_into};
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use solana_budget_api::budget_expr::BudgetExpr;
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub enum BudgetError { pub enum BudgetError {
@ -25,6 +25,13 @@ pub struct BudgetState {
} }
impl BudgetState { impl BudgetState {
pub fn new(budget_expr: BudgetExpr) -> Self {
Self {
initialized: true,
pending_budget: Some(budget_expr),
}
}
pub fn is_pending(&self) -> bool { pub fn is_pending(&self) -> bool {
self.pending_budget.is_some() self.pending_budget.is_some()
} }
@ -43,7 +50,7 @@ impl BudgetState {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use solana_budget_api::id; use crate::id;
use solana_sdk::account::Account; use solana_sdk::account::Account;
#[test] #[test]

View File

@ -2,8 +2,9 @@
use crate::budget_expr::{BudgetExpr, Condition}; use crate::budget_expr::{BudgetExpr, Condition};
use crate::budget_instruction::BudgetInstruction; use crate::budget_instruction::BudgetInstruction;
use crate::budget_state::BudgetState;
use crate::id; use crate::id;
use bincode::deserialize; use bincode::{deserialize, serialized_size};
use chrono::prelude::*; use chrono::prelude::*;
use solana_sdk::hash::Hash; use solana_sdk::hash::Hash;
use solana_sdk::pubkey::Pubkey; use solana_sdk::pubkey::Pubkey;
@ -26,8 +27,15 @@ impl BudgetTransaction {
let contract = Keypair::new().pubkey(); let contract = Keypair::new().pubkey();
let from = from_keypair.pubkey(); let from = from_keypair.pubkey();
let payment = BudgetExpr::new_payment(tokens - fee, to); let payment = BudgetExpr::new_payment(tokens - fee, to);
let space = serialized_size(&BudgetState::new(payment.clone())).unwrap();
TransactionBuilder::new(fee) 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)) .push(BudgetInstruction::new_initialize_account(contract, payment))
.sign(&[from_keypair], recent_blockhash) .sign(&[from_keypair], recent_blockhash)
} }
@ -163,7 +171,9 @@ impl BudgetTransaction {
/// Verify only the payment plan. /// Verify only the payment plan.
pub fn verify_plan(tx: &Transaction) -> bool { 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)) = if let Some(BudgetInstruction::InitializeAccount(expr)) =
BudgetTransaction::instruction(&tx, 1) BudgetTransaction::instruction(&tx, 1)
{ {
@ -226,7 +236,7 @@ mod tests {
let pubkey = keypair.pubkey(); let pubkey = keypair.pubkey();
let mut tx = BudgetTransaction::new(&keypair, pubkey, 42, zero); let mut tx = BudgetTransaction::new(&keypair, pubkey, 42, zero);
let mut system_instruction = BudgetTransaction::system_instruction(&tx, 0).unwrap(); 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! *tokens = 1_000_000; // <-- attack, part 1!
let mut instruction = BudgetTransaction::instruction(&tx, 1).unwrap(); let mut instruction = BudgetTransaction::instruction(&tx, 1).unwrap();
if let BudgetInstruction::InitializeAccount(ref mut expr) = instruction { if let BudgetInstruction::InitializeAccount(ref mut expr) = instruction {

View File

@ -1,5 +1,6 @@
pub mod budget_expr; pub mod budget_expr;
pub mod budget_instruction; pub mod budget_instruction;
pub mod budget_state;
pub mod budget_transaction; pub mod budget_transaction;
pub mod payment_plan; pub mod payment_plan;

View File

@ -25,6 +25,24 @@ pub enum SystemInstruction {
} }
impl 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 { pub fn new_move(from_id: Pubkey, to_id: Pubkey, tokens: u64) -> BuilderInstruction {
BuilderInstruction::new( BuilderInstruction::new(
system_program::id(), system_program::id(),