Revive payments via Budget
This commit is contained in:
parent
e8ae603a01
commit
2ec9bc9f05
|
@ -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();
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
mod budget_program;
|
||||
mod budget_state;
|
||||
|
||||
use crate::budget_program::process_instruction;
|
||||
use log::*;
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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]
|
|
@ -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 {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
pub mod budget_expr;
|
||||
pub mod budget_instruction;
|
||||
pub mod budget_state;
|
||||
pub mod budget_transaction;
|
||||
pub mod payment_plan;
|
||||
|
||||
|
|
|
@ -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(),
|
||||
|
|
Loading…
Reference in New Issue