Revive payments via Budget
This commit is contained in:
@ -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();
|
||||||
|
@ -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::*;
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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]
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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(),
|
||||||
|
Reference in New Issue
Block a user