1use darkfi_serial::deserialize_async;
20use log::{error, warn};
21use tinyjson::JsonValue;
22
23use darkfi::{
24 rpc::jsonrpc::{
25 ErrorCode::{InternalError, InvalidParams},
26 JsonError, JsonResponse, JsonResult,
27 },
28 tx::Transaction,
29 util::encoding::base64,
30};
31
32use super::DarkfiNode;
33use crate::{server_error, RpcError};
34
35impl DarkfiNode {
36 pub async fn tx_simulate(&self, id: u16, params: JsonValue) -> JsonResult {
44 let params = params.get::<Vec<JsonValue>>().unwrap();
45 if params.len() != 1 || !params[0].is_string() {
46 return JsonError::new(InvalidParams, None, id).into()
47 }
48
49 if !*self.validator.synced.read().await {
50 error!(target: "darkfid::rpc::tx_simulate", "Blockchain is not synced");
51 return server_error(RpcError::NotSynced, id, None)
52 }
53
54 let tx_enc = params[0].get::<String>().unwrap().trim();
56 let tx_bytes = match base64::decode(tx_enc) {
57 Some(v) => v,
58 None => {
59 error!(target: "darkfid::rpc::tx_simulate", "Failed decoding base64 transaction");
60 return server_error(RpcError::ParseError, id, None)
61 }
62 };
63
64 let tx: Transaction = match deserialize_async(&tx_bytes).await {
65 Ok(v) => v,
66 Err(e) => {
67 error!(target: "darkfid::rpc::tx_simulate", "Failed deserializing bytes into Transaction: {}", e);
68 return server_error(RpcError::ParseError, id, None)
69 }
70 };
71
72 let result = self.validator.append_tx(&tx, false).await;
74 if result.is_err() {
75 error!(
76 target: "darkfid::rpc::tx_simulate", "Failed to validate state transition: {}",
77 result.err().unwrap()
78 );
79 return server_error(RpcError::TxSimulationFail, id, None)
80 };
81
82 JsonResponse::new(JsonValue::Boolean(true), id).into()
83 }
84
85 pub async fn tx_broadcast(&self, id: u16, params: JsonValue) -> JsonResult {
94 let params = params.get::<Vec<JsonValue>>().unwrap();
95 if params.len() != 1 || !params[0].is_string() {
96 return JsonError::new(InvalidParams, None, id).into()
97 }
98
99 if !*self.validator.synced.read().await {
100 error!(target: "darkfid::rpc::tx_broadcast", "Blockchain is not synced");
101 return server_error(RpcError::NotSynced, id, None)
102 }
103
104 let tx_enc = params[0].get::<String>().unwrap().trim();
106 let tx_bytes = match base64::decode(tx_enc) {
107 Some(v) => v,
108 None => {
109 error!(target: "darkfid::rpc::tx_broadcast", "Failed decoding base64 transaction");
110 return server_error(RpcError::ParseError, id, None)
111 }
112 };
113
114 let tx: Transaction = match deserialize_async(&tx_bytes).await {
115 Ok(v) => v,
116 Err(e) => {
117 error!(target: "darkfid::rpc::tx_broadcast", "Failed deserializing bytes into Transaction: {}", e);
118 return server_error(RpcError::ParseError, id, None)
119 }
120 };
121
122 let error_message = if self.rpc_client.is_some() {
126 "Failed to append transaction to mempool"
127 } else {
128 "Failed to validate state transition"
129 };
130 if let Err(e) = self.validator.append_tx(&tx, self.rpc_client.is_some()).await {
132 error!(target: "darkfid::rpc::tx_broadcast", "{}: {}", error_message, e);
133 return server_error(RpcError::TxSimulationFail, id, None)
134 };
135
136 self.p2p_handler.p2p.broadcast(&tx).await;
137 if !self.p2p_handler.p2p.is_connected() {
138 warn!(target: "darkfid::rpc::tx_broadcast", "No connected channels to broadcast tx");
139 }
140
141 let tx_hash = tx.hash().to_string();
142 JsonResponse::new(JsonValue::String(tx_hash), id).into()
143 }
144
145 pub async fn tx_pending(&self, id: u16, params: JsonValue) -> JsonResult {
152 let params = params.get::<Vec<JsonValue>>().unwrap();
153 if !params.is_empty() {
154 return JsonError::new(InvalidParams, None, id).into()
155 }
156
157 if !*self.validator.synced.read().await {
158 error!(target: "darkfid::rpc::tx_pending", "Blockchain is not synced");
159 return server_error(RpcError::NotSynced, id, None)
160 }
161
162 let pending_txs = match self.validator.blockchain.get_pending_txs() {
163 Ok(v) => v,
164 Err(e) => {
165 error!(target: "darkfid::rpc::tx_pending", "Failed fetching pending txs: {}", e);
166 return JsonError::new(InternalError, None, id).into()
167 }
168 };
169
170 let pending_txs: Vec<JsonValue> =
171 pending_txs.iter().map(|x| JsonValue::String(x.hash().to_string())).collect();
172
173 JsonResponse::new(JsonValue::Array(pending_txs), id).into()
174 }
175
176 pub async fn tx_clean_pending(&self, id: u16, params: JsonValue) -> JsonResult {
183 let params = params.get::<Vec<JsonValue>>().unwrap();
184 if !params.is_empty() {
185 return JsonError::new(InvalidParams, None, id).into()
186 }
187
188 if !*self.validator.synced.read().await {
189 error!(target: "darkfid::rpc::tx_clean_pending", "Blockchain is not synced");
190 return server_error(RpcError::NotSynced, id, None)
191 }
192
193 let pending_txs = match self.validator.blockchain.get_pending_txs() {
194 Ok(v) => v,
195 Err(e) => {
196 error!(target: "darkfid::rpc::tx_clean_pending", "Failed fetching pending txs: {}", e);
197 return JsonError::new(InternalError, None, id).into()
198 }
199 };
200
201 if let Err(e) = self.validator.blockchain.remove_pending_txs(&pending_txs) {
202 error!(target: "darkfid::rpc::tx_clean_pending", "Failed fetching pending txs: {}", e);
203 return JsonError::new(InternalError, None, id).into()
204 };
205
206 let pending_txs: Vec<JsonValue> =
207 pending_txs.iter().map(|x| JsonValue::String(x.hash().to_string())).collect();
208
209 JsonResponse::new(JsonValue::Array(pending_txs), id).into()
210 }
211
212 pub async fn tx_calculate_fee(&self, id: u16, params: JsonValue) -> JsonResult {
220 let params = params.get::<Vec<JsonValue>>().unwrap();
221 if params.len() != 2 || !params[0].is_string() || !params[1].is_bool() {
222 return JsonError::new(InvalidParams, None, id).into()
223 }
224
225 if !*self.validator.synced.read().await {
226 error!(target: "darkfid::rpc::tx_calculate_fee", "Blockchain is not synced");
227 return server_error(RpcError::NotSynced, id, None)
228 }
229
230 let tx_enc = params[0].get::<String>().unwrap().trim();
232 let tx_bytes = match base64::decode(tx_enc) {
233 Some(v) => v,
234 None => {
235 error!(target: "darkfid::rpc::tx_calculate_fee", "Failed decoding base64 transaction");
236 return server_error(RpcError::ParseError, id, None)
237 }
238 };
239
240 let tx: Transaction = match deserialize_async(&tx_bytes).await {
241 Ok(v) => v,
242 Err(e) => {
243 error!(target: "darkfid::rpc::tx_calculate_fee", "Failed deserializing bytes into Transaction: {}", e);
244 return server_error(RpcError::ParseError, id, None)
245 }
246 };
247
248 let include_fee = params[1].get::<bool>().unwrap();
250
251 let result = self.validator.calculate_fee(&tx, *include_fee).await;
253 if result.is_err() {
254 error!(
255 target: "darkfid::rpc::tx_calculate_fee", "Failed to validate state transition: {}",
256 result.err().unwrap()
257 );
258 return server_error(RpcError::TxGasCalculationFail, id, None)
259 };
260
261 JsonResponse::new(JsonValue::Number(result.unwrap() as f64), id).into()
262 }
263}