Merge debits and credits
Debits no longer need to be applied before credits. Instead, we lock any accounts we'd debit and so error out on the second attempt to lock the same account.
This commit is contained in:
@ -100,43 +100,16 @@ impl BudgetState {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deduct tokens from the source account if it has sufficient funds and the contract isn't
|
|
||||||
/// pending
|
|
||||||
fn apply_debits_to_budget_state(
|
fn apply_debits_to_budget_state(
|
||||||
accounts: &mut [&mut Account],
|
|
||||||
instruction: &Instruction,
|
|
||||||
) -> Result<(), BudgetError> {
|
|
||||||
{
|
|
||||||
// if the source account userdata is not empty, this is a pending contract
|
|
||||||
if !accounts[0].userdata.is_empty() {
|
|
||||||
trace!("source is pending");
|
|
||||||
return Err(BudgetError::SourceIsPendingContract);
|
|
||||||
}
|
|
||||||
if let Instruction::NewBudget(tokens, _) = instruction {
|
|
||||||
if *tokens < 0 {
|
|
||||||
trace!("negative tokens");
|
|
||||||
return Err(BudgetError::NegativeTokens);
|
|
||||||
}
|
|
||||||
|
|
||||||
if accounts[0].tokens < *tokens {
|
|
||||||
trace!("insufficient funds");
|
|
||||||
return Err(BudgetError::InsufficientFunds);
|
|
||||||
} else {
|
|
||||||
accounts[0].tokens -= *tokens;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Apply only a transaction's credits.
|
|
||||||
/// Note: It is safe to apply credits from multiple transactions in parallel.
|
|
||||||
fn apply_credits_to_budget_state(
|
|
||||||
tx: &Transaction,
|
tx: &Transaction,
|
||||||
instruction_index: usize,
|
instruction_index: usize,
|
||||||
accounts: &mut [&mut Account],
|
accounts: &mut [&mut Account],
|
||||||
instruction: &Instruction,
|
instruction: &Instruction,
|
||||||
) -> Result<(), BudgetError> {
|
) -> Result<(), BudgetError> {
|
||||||
|
if !accounts[0].userdata.is_empty() {
|
||||||
|
trace!("source is pending");
|
||||||
|
return Err(BudgetError::SourceIsPendingContract);
|
||||||
|
}
|
||||||
match instruction {
|
match instruction {
|
||||||
Instruction::NewBudget(tokens, budget) => {
|
Instruction::NewBudget(tokens, budget) => {
|
||||||
let budget = budget.clone();
|
let budget = budget.clone();
|
||||||
@ -151,6 +124,7 @@ impl BudgetState {
|
|||||||
} else {
|
} else {
|
||||||
let mut state = BudgetState::default();
|
let mut state = BudgetState::default();
|
||||||
state.pending_budget = Some(budget);
|
state.pending_budget = Some(budget);
|
||||||
|
accounts[0].tokens -= tokens;
|
||||||
accounts[1].tokens += tokens;
|
accounts[1].tokens += tokens;
|
||||||
state.initialized = true;
|
state.initialized = true;
|
||||||
state.serialize(&mut accounts[1].userdata)
|
state.serialize(&mut accounts[1].userdata)
|
||||||
@ -246,9 +220,7 @@ impl BudgetState {
|
|||||||
) -> Result<(), BudgetError> {
|
) -> Result<(), BudgetError> {
|
||||||
if let Ok(instruction) = deserialize(tx.userdata(instruction_index)) {
|
if let Ok(instruction) = deserialize(tx.userdata(instruction_index)) {
|
||||||
trace!("process_transaction: {:?}", instruction);
|
trace!("process_transaction: {:?}", instruction);
|
||||||
Self::apply_debits_to_budget_state(accounts, &instruction).and_then(|_| {
|
Self::apply_debits_to_budget_state(tx, instruction_index, accounts, &instruction)
|
||||||
Self::apply_credits_to_budget_state(tx, instruction_index, accounts, &instruction)
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
info!(
|
info!(
|
||||||
"Invalid transaction userdata: {:?}",
|
"Invalid transaction userdata: {:?}",
|
||||||
|
Reference in New Issue
Block a user