Skip to content

Commit

Permalink
payment: Detect tx overspending (#2867)
Browse files Browse the repository at this point in the history
A provider will now detect if a transaction will be used for multiple
SendPayment instances exceeding the actual tx amount.
  • Loading branch information
kamirr authored Oct 31, 2023
1 parent 6518402 commit 0531aa5
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 2 deletions.
26 changes: 26 additions & 0 deletions core/payment/src/dao/payment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,32 @@ impl<'c> PaymentDao<'c> {
.await
}

pub async fn get_for_confirmation(&self, details: Vec<u8>) -> DbResult<Vec<Payment>> {
readonly_transaction(self.pool, move |conn| {
let mut result = Vec::new();

let payments: Vec<ReadObj> = dsl::pay_payment
.filter(dsl::details.eq(&details))
.load(conn)?;

for payment in payments {
let activity_payments = activity_pay_dsl::pay_activity_payment
.filter(activity_pay_dsl::payment_id.eq(&payment.id))
.filter(activity_pay_dsl::owner_id.eq(&payment.owner_id))
.load(conn)?;
let agreement_payments = agreement_pay_dsl::pay_agreement_payment
.filter(agreement_pay_dsl::payment_id.eq(&payment.id))
.filter(agreement_pay_dsl::owner_id.eq(&payment.owner_id))
.load(conn)?;

result.push(payment.into_api_model(activity_payments, agreement_payments))
}

Ok(result)
})
.await
}

pub async fn get_for_node_id(
&self,
node_id: NodeId,
Expand Down
4 changes: 4 additions & 0 deletions core/payment/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,10 @@ pub mod processor {
"Transaction balance too low (probably tx hash re-used)".to_owned(),
))
}

pub fn overspending(tx_amount: &BigDecimal, total_amount: &BigDecimal) -> Result<(), Self> {
Err(Self::Validation(format!("Transaction for {tx_amount} used for multiple payments amounting to {total_amount}")))
}
}

#[derive(thiserror::Error, Debug)]
Expand Down
32 changes: 30 additions & 2 deletions core/payment/src/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,7 @@ impl PaymentProcessor {
};
let details: PaymentDetails = driver_endpoint(&driver)
.send(driver::VerifyPayment::new(
confirmation,
confirmation.clone(),
platform.clone(),
payment.clone(),
))
Expand Down Expand Up @@ -623,9 +623,37 @@ impl PaymentProcessor {
}
}

// Insert payment into database (this operation creates and updates all related entities)
// Verify totals for all agreements and activities with the same confirmation
let payment_dao: PaymentDao = self.db_executor.as_dao();
let shared_payments = payment_dao
.get_for_confirmation(confirmation.confirmation)
.await?;
let all_payment_sum = shared_payments
.iter()
.map(|payment| {
let agreement_total = payment
.agreement_payments
.iter()
.map(|ap| &ap.amount)
.sum::<BigDecimal>();

let activity_total = payment
.activity_payments
.iter()
.map(|ap| &ap.amount)
.sum::<BigDecimal>();

agreement_total + activity_total
})
.sum::<BigDecimal>();

if &all_payment_sum + agreement_sum + activity_sum > details.amount {
return VerifyPaymentError::overspending(&details.amount, &all_payment_sum);
}

// Insert payment into database (this operation creates and updates all related entities)
payment_dao.insert_received(payment, payee_id).await?;

Ok(())
}

Expand Down

0 comments on commit 0531aa5

Please sign in to comment.