ledger.rs 13 KB

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