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

Revive payments via Budget #3079

Merged
merged 2 commits into from
Mar 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions programs/budget/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ solana-budget-api = { path = "../budget_api", version = "0.12.0" }
solana-logger = { path = "../../logger", version = "0.12.0" }
solana-sdk = { path = "../../sdk", version = "0.12.0" }

[dev-dependencies]
solana-runtime = { path = "../../runtime", version = "0.12.0" }

[lib]
name = "solana_budget_program"
crate-type = ["cdylib"]
Expand Down
5 changes: 3 additions & 2 deletions programs/budget/src/budget_program.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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();
Expand Down
1 change: 0 additions & 1 deletion programs/budget/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
mod budget_program;
mod budget_state;

use crate::budget_program::process_instruction;
use log::*;
Expand Down
32 changes: 32 additions & 0 deletions programs/budget/tests/budget.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use solana_budget_api::budget_transaction::BudgetTransaction;
use solana_runtime::bank::{Bank, Result};
use solana_sdk::genesis_block::GenesisBlock;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil};

struct BudgetBank<'a> {
bank: &'a Bank,
}

impl<'a> BudgetBank<'a> {
fn new(bank: &'a Bank) -> Self {
bank.add_native_program("solana_budget_program", &solana_budget_api::id());
Self { bank }
}

fn pay(&self, from_keypair: &Keypair, to_id: Pubkey, lamports: u64) -> Result<()> {
let blockhash = self.bank.last_blockhash();
let tx = BudgetTransaction::new_payment(from_keypair, to_id, lamports, blockhash, 0);
self.bank.process_transaction(&tx)
}
}

#[test]
fn test_budget_payment_via_bank() {
let (genesis_block, from_keypair) = GenesisBlock::new(10_000);
let bank = Bank::new(&genesis_block);
let budget_bank = BudgetBank::new(&bank);
let to_id = Keypair::new().pubkey();
budget_bank.pay(&from_keypair, to_id, 100).unwrap();
assert_eq!(bank.get_balance(&to_id), 100);
}
13 changes: 8 additions & 5 deletions programs/budget_api/src/budget_instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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()
}
Expand All @@ -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]
Expand Down
18 changes: 14 additions & 4 deletions programs/budget_api/src/budget_transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)
}
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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 {
Expand Down
1 change: 1 addition & 0 deletions programs/budget_api/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub mod budget_expr;
pub mod budget_instruction;
pub mod budget_state;
pub mod budget_transaction;
pub mod payment_plan;

Expand Down
18 changes: 18 additions & 0 deletions sdk/src/system_instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down