ledger.rs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. use crate::{
  2. amount::AmountCents, config::Config, status::StatusManager, storage::Storage,
  3. transaction::Type, AccountId, Amount, Error, PaymentFrom, PaymentId, Status, Transaction, TxId,
  4. };
  5. use std::{cmp::Ordering, collections::HashMap, sync::Arc};
  6. /// The Verax ledger
  7. #[derive(Debug)]
  8. pub struct Ledger<S>
  9. where
  10. S: Storage + Sync + Send,
  11. {
  12. config: Arc<Config<S>>,
  13. }
  14. impl<S> Clone for Ledger<S>
  15. where
  16. S: Storage + Sync + Send,
  17. {
  18. fn clone(&self) -> Self {
  19. Self {
  20. config: self.config.clone(),
  21. }
  22. }
  23. }
  24. impl<S> Ledger<S>
  25. where
  26. S: Storage + Sync + Send,
  27. {
  28. /// Creates a new ledger instance
  29. pub fn new(config: Config<S>) -> Self {
  30. Self {
  31. config: Arc::new(config),
  32. }
  33. }
  34. /// The internal usage is to select unspent payments for each account to
  35. /// create new transactions. The external API however does not expose that
  36. /// level of usage, instead it exposes a simple API to move funds using
  37. /// accounts to debit from and accounts to credit to. A single transaction
  38. /// can use multiple accounts to debit and credit, instead of a single
  39. /// account.
  40. ///
  41. /// This function selects the unspent payments to be used in a transaction,
  42. /// in a descending order (making sure to include any negative deposit).
  43. ///
  44. /// This function returns a vector of payments to be used as inputs and
  45. /// optionally a dependent transaction to be executed first. This
  46. /// transaction is an internal transaction and it settles immediately. It is
  47. /// used to split an existing payment into two payments, one to be used as
  48. /// input and the other to be used as change. This is done to avoid locking
  49. /// any change amount until the main transaction settles.
  50. async fn select_payments_from_accounts(
  51. &self,
  52. payments: Vec<(AccountId, Amount)>,
  53. ) -> Result<(Option<Transaction>, Vec<PaymentFrom>), Error> {
  54. let mut to_spend = HashMap::<_, AmountCents>::new();
  55. for (account_id, amount) in payments.into_iter() {
  56. let id = (account_id, amount.asset().clone());
  57. if let Some(value) = to_spend.get_mut(&id) {
  58. *value = value
  59. .checked_add(amount.cents())
  60. .ok_or(Error::Overflow("cents".to_owned()))?;
  61. } else {
  62. to_spend.insert(id, amount.cents());
  63. }
  64. }
  65. let mut change_input = vec![];
  66. let mut change_output = vec![];
  67. let mut payments: Vec<PaymentFrom> = vec![];
  68. for ((account, asset), mut to_spend_cents) in to_spend.into_iter() {
  69. let iterator = self
  70. .config
  71. .storage
  72. .get_unspent_payments(&account, &asset, to_spend_cents)
  73. .await?;
  74. for payment in iterator.into_iter() {
  75. let cents = payment.amount.cents();
  76. to_spend_cents = to_spend_cents
  77. .checked_sub(cents)
  78. .ok_or(Error::Underflow("cents".to_owned()))?;
  79. payments.push(payment);
  80. match to_spend_cents.cmp(&0) {
  81. Ordering::Equal => {
  82. // No change amount, we are done with this input
  83. break;
  84. }
  85. Ordering::Less => {
  86. // There is a change amount, we need to split the last
  87. // input into two payment_ids into the same accounts in
  88. // a transaction that will settle immediately, otherwise
  89. // the change amount will be unspendable until this
  90. // transaction settles. By doing so the current
  91. // operation will have no change and it can safely take
  92. // its time to settle without making any change amount
  93. // unspendable.
  94. let to_spend_cents = to_spend_cents.abs();
  95. let input = payments
  96. .pop()
  97. .ok_or(Error::InsufficientBalance(account.clone(), asset.clone()))?;
  98. change_input.push(input);
  99. change_output.push((
  100. account.clone(),
  101. asset.new_amount(
  102. cents
  103. .checked_sub(to_spend_cents)
  104. .ok_or(Error::Underflow("change cents".to_owned()))?,
  105. ),
  106. ));
  107. change_output.push((account.clone(), asset.new_amount(to_spend_cents)));
  108. // Go to the next payment
  109. break;
  110. }
  111. _ => {
  112. // We need more funds, continue to the selecting the
  113. // available payment if any
  114. }
  115. }
  116. }
  117. if to_spend_cents > 0 {
  118. // We don't have enough payment to cover the to_spend_cents
  119. // Return an insufficient balance error
  120. return Err(Error::InsufficientBalance(account, asset.clone()));
  121. }
  122. }
  123. let exchange_tx = if change_input.is_empty() {
  124. None
  125. } else {
  126. let total =
  127. u16::try_from(change_input.len()).map_err(|e| Error::Overflow(e.to_string()))?;
  128. let split_input = Transaction::new(
  129. "Exchange transaction".to_owned(),
  130. // Set the change transaction as settled. This is an
  131. // internal transaction to split existing payments
  132. // into exact new payments, so the main transaction has no
  133. // change.
  134. self.config.status.default_spendable(),
  135. Type::Exchange,
  136. change_input,
  137. change_output,
  138. )
  139. .await?;
  140. let creates = &split_input.creates;
  141. for i in 0..total {
  142. // Spend the new payment
  143. let index = i
  144. .checked_mul(2)
  145. .ok_or(Error::Overflow("index overflow".to_owned()))?;
  146. let uindex: usize = index.into();
  147. payments.push(PaymentFrom {
  148. id: PaymentId {
  149. transaction: split_input.id.clone(),
  150. position: index,
  151. },
  152. from: creates[uindex].to.clone(),
  153. amount: creates[uindex].amount.clone(),
  154. });
  155. }
  156. Some(split_input)
  157. };
  158. Ok((exchange_tx, payments))
  159. }
  160. /// Creates a new transaction and returns it.
  161. ///
  162. /// The input is pretty simple, take this amounts from these given accounts
  163. /// and send them to these accounts (and amounts). The job of this function
  164. /// is to figure it out how to do it. This function will make sure that each
  165. /// account has enough balance, selecting the unspent payments from each
  166. /// account that will be spent. It will also return a list of transactions
  167. /// that will be used to return the change to the accounts, these accounts
  168. /// can be settled immediately so no other funds required to perform the
  169. /// transaction are locked.
  170. ///
  171. /// This functions performs read only operations on top of the storage layer
  172. /// and it will guarantee execution (meaning that it will not lock any
  173. /// funds, so these transactions may fail if any selected payment is spent
  174. /// between the time the transaction is created and executed).
  175. ///
  176. /// A NewTransaction struct is returned, the change_transactions should be
  177. /// executed and set as settled before the transaction is executed,
  178. /// otherwise it will fail. A failure in any execution will render the
  179. /// entire operation as failed but no funds will be locked.
  180. pub async fn new_transaction(
  181. &self,
  182. reference: String,
  183. status: Status,
  184. from: Vec<(AccountId, Amount)>,
  185. to: Vec<(AccountId, Amount)>,
  186. ) -> Result<Transaction, Error> {
  187. let (change_transaction, payments) = self.select_payments_from_accounts(from).await?;
  188. if let Some(mut change_tx) = change_transaction {
  189. change_tx.persist(&self.config).await?;
  190. }
  191. let mut transaction =
  192. Transaction::new(reference, status, Type::Transaction, payments, to).await?;
  193. transaction.persist(&self.config).await?;
  194. Ok(transaction)
  195. }
  196. /// Return the balances from a given account
  197. ///
  198. /// The balance is a vector of Amounts, one for each asset. The balance will
  199. /// return only spendable amounts, meaning that any amount that is locked in
  200. /// a transaction will not be returned.
  201. ///
  202. /// TODO: Return locked funds as well.
  203. pub async fn get_balance(&self, account: &AccountId) -> Result<Vec<Amount>, Error> {
  204. Ok(self.config.storage.get_balance(account).await?)
  205. }
  206. /// Creates an external deposit
  207. ///
  208. /// Although a deposit can have multiple output payments, to different
  209. /// accounts and amounts, to keep the upstream API simple, this function
  210. /// only accepts a single account and amount to credit
  211. pub async fn deposit(
  212. &self,
  213. account: &AccountId,
  214. amount: Amount,
  215. status: Status,
  216. reference: String,
  217. ) -> Result<Transaction, Error> {
  218. let mut transaction =
  219. Transaction::new_external_deposit(reference, status, vec![(account.clone(), amount)])?;
  220. transaction.persist(&self.config).await?;
  221. Ok(transaction)
  222. }
  223. /// Creates a new withdrawal transaction and returns it.
  224. ///
  225. /// Although a transaction supports multiple inputs to be burned, from
  226. /// different accounts, to keep things simple, this function only supports a
  227. /// single input (single account and single amount). This is because the
  228. /// natural behaviour is to have withdrawals from a single account.
  229. pub async fn withdrawal(
  230. &self,
  231. account: &AccountId,
  232. amount: Amount,
  233. status: Status,
  234. reference: String,
  235. ) -> Result<Transaction, Error> {
  236. let (change_transactions, payments) = self
  237. .select_payments_from_accounts(vec![(account.clone(), amount)])
  238. .await?;
  239. for mut change_tx in change_transactions.into_iter() {
  240. change_tx.persist(&self.config).await?;
  241. }
  242. let mut transaction = Transaction::new_external_withdrawal(reference, status, payments)?;
  243. transaction.persist(&self.config).await?;
  244. Ok(transaction)
  245. }
  246. /// Returns the payment object by a given payment id
  247. pub async fn get_payment_info(&self, _payment_id: &PaymentId) -> Result<PaymentFrom, Error> {
  248. todo!()
  249. }
  250. /// Returns the transaction object by a given transaction id
  251. pub async fn get_transaction(&self, transaction_id: &TxId) -> Result<Transaction, Error> {
  252. Ok(self.config.storage.get_transaction(transaction_id).await?)
  253. }
  254. /// Returns all transactions from a given account. It can be optionally be
  255. /// sorted by transaction type. The transactions are sorted from newest to
  256. /// oldest.
  257. pub async fn get_transactions(
  258. &self,
  259. account_id: &AccountId,
  260. types: Vec<Type>,
  261. ) -> Result<Vec<Transaction>, Error> {
  262. let types = if types.is_empty() {
  263. vec![Type::Transaction, Type::Deposit, Type::Withdrawal]
  264. } else {
  265. types
  266. };
  267. Ok(self
  268. .config
  269. .storage
  270. .get_transactions(account_id, &types, &[])
  271. .await?)
  272. }
  273. /// Returns the status manager
  274. pub fn get_status_manager(&self) -> &StatusManager {
  275. &self.config.status
  276. }
  277. /// Attempts to change the status of a given transaction id. On success the
  278. /// new transaction object is returned, otherwise an error is returned.
  279. pub async fn change_status(
  280. &self,
  281. transaction_id: &TxId,
  282. new_status: Status,
  283. reason: String,
  284. ) -> Result<Transaction, Error> {
  285. Ok(self
  286. .config
  287. .storage
  288. .get_transaction(transaction_id)
  289. .await?
  290. .change_status(&self.config, new_status, reason)
  291. .await?)
  292. }
  293. }