Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

Commit

Permalink
Do Budget verification in BudgetScript
Browse files Browse the repository at this point in the history
  • Loading branch information
garious authored and solana-grimes committed Mar 18, 2019
1 parent ce6257a commit a54854a
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 68 deletions.
36 changes: 36 additions & 0 deletions programs/budget_api/src/budget_script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ impl BudgetScript {
lamports: u64,
expr: BudgetExpr,
) -> Script {
if !expr.verify(lamports) {
panic!("invalid budget expression");
}
let space = serialized_size(&BudgetState::new(expr.clone())).unwrap();
let instructions = vec![
SystemInstruction::new_program_account(&from, contract, lamports, space, &id()),
Expand Down Expand Up @@ -70,3 +73,36 @@ impl BudgetScript {
Self::new_account(from, contract, lamports, expr)
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::budget_expr::BudgetExpr;

#[test]
fn test_budget_script_verify() {
let alice_pubkey = Keypair::new().pubkey();
let bob_pubkey = Keypair::new().pubkey();
BudgetScript::pay(&alice_pubkey, &bob_pubkey, 1); // No panic! indicates success.
}

#[test]
#[should_panic]
fn test_budget_script_overspend() {
let alice_pubkey = Keypair::new().pubkey();
let bob_pubkey = Keypair::new().pubkey();
let budget_pubkey = Keypair::new().pubkey();
let expr = BudgetExpr::new_payment(2, &bob_pubkey);
BudgetScript::new_account(&alice_pubkey, &budget_pubkey, 1, expr);
}

#[test]
#[should_panic]
fn test_budget_script_underspend() {
let alice_pubkey = Keypair::new().pubkey();
let bob_pubkey = Keypair::new().pubkey();
let budget_pubkey = Keypair::new().pubkey();
let expr = BudgetExpr::new_payment(1, &bob_pubkey);
BudgetScript::new_account(&alice_pubkey, &budget_pubkey, 2, expr);
}
}
68 changes: 0 additions & 68 deletions programs/budget_api/src/budget_transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,71 +109,3 @@ impl BudgetTransaction {
Self::new_signed(from_keypair, script, recent_blockhash, 0)
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::budget_expr::BudgetExpr;
use bincode::{deserialize, serialize};
use solana_sdk::system_instruction::SystemInstruction;

fn deserialize_system_instruction(tx: &Transaction, index: usize) -> Option<SystemInstruction> {
deserialize(&tx.data(index)).ok()
}

fn deserialize_budget_instruction(tx: &Transaction, index: usize) -> Option<BudgetInstruction> {
deserialize(&tx.data(index)).ok()
}

/// Verify only the payment plan.
fn verify_plan(tx: &Transaction) -> bool {
if let Some(SystemInstruction::CreateAccount { lamports, .. }) =
deserialize_system_instruction(tx, 0)
{
if let Some(BudgetInstruction::InitializeAccount(expr)) =
deserialize_budget_instruction(&tx, 1)
{
if !expr.verify(lamports) {
return false;
}
}
}
true
}

#[test]
fn test_payment() {
let zero = Hash::default();
let keypair0 = Keypair::new();
let keypair1 = Keypair::new();
let pubkey1 = keypair1.pubkey();
let tx0 = BudgetTransaction::new_payment(&keypair0, &pubkey1, 42, zero, 0);
assert!(verify_plan(&tx0));
}

#[test]
fn test_overspend_attack() {
let keypair0 = Keypair::new();
let keypair1 = Keypair::new();
let zero = Hash::default();
let mut tx = BudgetTransaction::new_payment(&keypair0, &keypair1.pubkey(), 1, zero, 0);
let mut instruction = deserialize_budget_instruction(&tx, 1).unwrap();
if let BudgetInstruction::InitializeAccount(ref mut expr) = instruction {
if let BudgetExpr::Pay(ref mut payment) = expr {
payment.lamports = 2; // <-- attack!
}
}
tx.instructions[1].data = serialize(&instruction).unwrap();
assert!(!verify_plan(&tx));

// Also, ensure all branchs of the plan spend all lamports
let mut instruction = deserialize_budget_instruction(&tx, 1).unwrap();
if let BudgetInstruction::InitializeAccount(ref mut expr) = instruction {
if let BudgetExpr::Pay(ref mut payment) = expr {
payment.lamports = 0; // <-- whoops!
}
}
tx.instructions[1].data = serialize(&instruction).unwrap();
assert!(!verify_plan(&tx));
}
}

0 comments on commit a54854a

Please sign in to comment.