rpc_tx.rs 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2022 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use std::str::FromStr;
  19. use darkfi_sdk::crypto::{Address, PublicKey, TokenId};
  20. use darkfi_serial::{deserialize, serialize};
  21. use log::{error, warn};
  22. use serde_json::{json, Value};
  23. use darkfi::{
  24. rpc::jsonrpc::{ErrorCode::InvalidParams, JsonError, JsonResponse, JsonResult},
  25. tx::Transaction,
  26. };
  27. use super::Darkfid;
  28. use crate::{server_error, RpcError};
  29. impl Darkfid {
  30. // RPCAPI:
  31. // Transfer a given amount of some token to the given address.
  32. // Returns a transaction ID upon success.
  33. //
  34. // * `dest_addr` -> Recipient's DarkFi address
  35. // * `token_id` -> ID of the token to send
  36. // * `12345` -> Amount in `u64` of the funds to send
  37. //
  38. // --> {"jsonrpc": "2.0", "method": "tx.transfer", "params": ["dest_addr", "token_id", 12345], "id": 1}
  39. // <-- {"jsonrpc": "2.0", "result": "txID...", "id": 1}
  40. pub async fn tx_transfer(&self, id: Value, params: &[Value]) -> JsonResult {
  41. if params.len() != 3 ||
  42. !params[0].is_string() ||
  43. !params[1].is_string() ||
  44. !params[2].is_u64()
  45. {
  46. return JsonError::new(InvalidParams, None, id).into()
  47. }
  48. if !(*self.synced.lock().await) {
  49. error!("[RPC] tx.transfer: Blockchain is not synced");
  50. return server_error(RpcError::NotSynced, id, None)
  51. }
  52. let address = params[0].as_str().unwrap();
  53. let token = params[1].as_str().unwrap();
  54. let amount = params[2].as_u64().unwrap();
  55. let address = match Address::from_str(address) {
  56. Ok(v) => v,
  57. Err(e) => {
  58. error!("[RPC] tx.transfer: Failed parsing address from string: {}", e);
  59. return server_error(RpcError::InvalidAddressParam, id, None)
  60. }
  61. };
  62. let pubkey = match PublicKey::try_from(address) {
  63. Ok(v) => v,
  64. Err(e) => {
  65. error!("[RPC] tx.transfer: Failed parsing PublicKey from Address: {}", e);
  66. return server_error(RpcError::ParseError, id, None)
  67. }
  68. };
  69. let token_id = match TokenId::try_from(token) {
  70. Ok(v) => v,
  71. Err(e) => {
  72. error!("[RPC] tx.transfer: Failed parsing Token ID from string: {}", e);
  73. return server_error(RpcError::ParseError, id, None)
  74. }
  75. };
  76. let tx = match self
  77. .client
  78. .build_transaction(
  79. pubkey,
  80. amount,
  81. token_id,
  82. false,
  83. self.validator_state.read().await.state_machine.clone(),
  84. )
  85. .await
  86. {
  87. Ok(v) => v,
  88. Err(e) => {
  89. error!("tx.transfer: Failed building transaction: {}", e);
  90. return server_error(RpcError::TxBuildFail, id, None)
  91. }
  92. };
  93. if let Some(sync_p2p) = &self.sync_p2p {
  94. if let Err(e) = sync_p2p.broadcast(tx.clone()).await {
  95. error!("[RPC] tx.transfer: Failed broadcasting transaction: {}", e);
  96. return server_error(RpcError::TxBroadcastFail, id, None)
  97. }
  98. } else {
  99. warn!("[RPC] tx.transfer: No sync P2P network, not broadcasting transaction.");
  100. return server_error(RpcError::TxBroadcastFail, id, None)
  101. }
  102. let tx_hash = blake3::hash(&serialize(&tx)).to_hex().as_str().to_string();
  103. JsonResponse::new(json!(tx_hash), id).into()
  104. }
  105. // RPCAPI:
  106. // Simulate a network state transition with the given transaction.
  107. // Returns `true` if the transaction is valid, otherwise, a corresponding
  108. // error.
  109. //
  110. // --> {"jsonrpc": "2.0", "method": "tx.simulate", "params": ["base58encodedTX"], "id": 1}
  111. // <-- {"jsonrpc": "2.0", "result": true, "id": 1}
  112. pub async fn tx_simulate(&self, id: Value, params: &[Value]) -> JsonResult {
  113. if params.len() != 1 || !params[0].is_string() {
  114. return JsonError::new(InvalidParams, None, id).into()
  115. }
  116. if !(*self.synced.lock().await) {
  117. error!("[RPC] tx.simulate: Blockchain is not synced");
  118. return server_error(RpcError::NotSynced, id, None)
  119. }
  120. // Try to deserialize the transaction
  121. let tx_bytes = match bs58::decode(params[0].as_str().unwrap().trim()).into_vec() {
  122. Ok(v) => v,
  123. Err(e) => {
  124. error!("[RPC] tx.simulate: Failed decoding base58 transaction: {}", e);
  125. return server_error(RpcError::ParseError, id, None)
  126. }
  127. };
  128. let tx: Transaction = match deserialize(&tx_bytes) {
  129. Ok(v) => v,
  130. Err(e) => {
  131. error!("[RPC] tx.simulate: Failed deserializing bytes into Transaction: {}", e);
  132. return server_error(RpcError::ParseError, id, None)
  133. }
  134. };
  135. // Simulate state transition
  136. if let Err(e) = self.simulate_transaction(&tx).await {
  137. error!("[RPC] tx.broadcast: Failed to validate state transition: {}", e);
  138. return server_error(RpcError::TxSimulationFail, id, None)
  139. }
  140. JsonResponse::new(json!(true), id).into()
  141. }
  142. // RPCAPI:
  143. // Broadcast a given transaction to the P2P network.
  144. // The function will first simulate the state transition in order to see
  145. // if the transaction is actually valid, and in turn it will return an
  146. // error if this is the case. Otherwise, a transaction ID will be returned.
  147. //
  148. // --> {"jsonrpc": "2.0", "method": "tx.broadcast", "params": ["base58encodedTX"], "id": 1}
  149. // <-- {"jsonrpc": "2.0", "result": "txID...", "id": 1}
  150. pub async fn tx_broadcast(&self, id: Value, params: &[Value]) -> JsonResult {
  151. if params.len() != 1 || !params[0].is_string() {
  152. return JsonError::new(InvalidParams, None, id).into()
  153. }
  154. if !(*self.synced.lock().await) {
  155. error!("[RPC] tx.transfer: Blockchain is not synced");
  156. return server_error(RpcError::NotSynced, id, None)
  157. }
  158. // Try to deserialize the transaction
  159. let tx_bytes = match bs58::decode(params[0].as_str().unwrap().trim()).into_vec() {
  160. Ok(v) => v,
  161. Err(e) => {
  162. error!("[RPC] tx.broadcast: Failed decoding base58 transaction: {}", e);
  163. return server_error(RpcError::ParseError, id, None)
  164. }
  165. };
  166. let tx: Transaction = match deserialize(&tx_bytes) {
  167. Ok(v) => v,
  168. Err(e) => {
  169. error!("[RPC] tx.broadcast: Failed deserializing bytes into Transaction: {}", e);
  170. return server_error(RpcError::ParseError, id, None)
  171. }
  172. };
  173. // Simulate state transition
  174. if let Err(e) = self.simulate_transaction(&tx).await {
  175. error!("[RPC] tx.broadcast: Failed to validate state transition: {}", e);
  176. return server_error(RpcError::TxSimulationFail, id, None)
  177. }
  178. // TODO: Should we apply the state transition locally before broadcasting it?
  179. if let Some(sync_p2p) = &self.sync_p2p {
  180. if let Err(e) = sync_p2p.broadcast(tx.clone()).await {
  181. error!("[RPC] tx.broadcast: Failed broadcasting transaction: {}", e);
  182. return server_error(RpcError::TxBroadcastFail, id, None)
  183. }
  184. // TODO: Mark coin as spent in the wallet
  185. } else {
  186. warn!("[RPC] tx.broadcast: No sync P2P network, not broadcasting transaction.");
  187. return server_error(RpcError::TxBroadcastFail, id, None)
  188. }
  189. let tx_hash = blake3::hash(&serialize(&tx)).to_hex().as_str().to_string();
  190. JsonResponse::new(json!(tx_hash), id).into()
  191. }
  192. }