1use darkfi_serial::deserialize_async;
20use tinyjson::JsonValue;
21use tracing::{error, warn};
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 {
95 let params = params.get::<Vec<JsonValue>>().unwrap();
96 if params.len() != 1 || !params[0].is_string() {
97 return JsonError::new(InvalidParams, None, id).into()
98 }
99
100 if !*self.validator.synced.read().await {
101 error!(target: "darkfid::rpc::tx_broadcast", "Blockchain is not synced");
102 return server_error(RpcError::NotSynced, id, None)
103 }
104
105 let tx_enc = params[0].get::<String>().unwrap().trim();
107 let tx_bytes = match base64::decode(tx_enc) {
108 Some(v) => v,
109 None => {
110 error!(target: "darkfid::rpc::tx_broadcast", "Failed decoding base64 transaction");
111 return server_error(RpcError::ParseError, id, None)
112 }
113 };
114
115 let tx: Transaction = match deserialize_async(&tx_bytes).await {
116 Ok(v) => v,
117 Err(e) => {
118 error!(target: "darkfid::rpc::tx_broadcast", "Failed deserializing bytes into Transaction: {e}");
119 return server_error(RpcError::ParseError, id, None)
120 }
121 };
122
123 if let Err(e) = self.validator.append_tx(&tx, true).await {
125 error!(target: "darkfid::rpc::tx_broadcast", "Failed to append transaction to mempool: {e}");
126 return server_error(RpcError::TxSimulationFail, id, None)
127 };
128
129 self.p2p_handler.p2p.broadcast(&tx).await;
130 if !self.p2p_handler.p2p.is_connected() {
131 warn!(target: "darkfid::rpc::tx_broadcast", "No connected channels to broadcast tx");
132 }
133
134 let tx_hash = tx.hash().to_string();
135 JsonResponse::new(JsonValue::String(tx_hash), id).into()
136 }
137
138 pub async fn tx_pending(&self, id: u16, params: JsonValue) -> JsonResult {
145 let params = params.get::<Vec<JsonValue>>().unwrap();
146 if !params.is_empty() {
147 return JsonError::new(InvalidParams, None, id).into()
148 }
149
150 if !*self.validator.synced.read().await {
151 error!(target: "darkfid::rpc::tx_pending", "Blockchain is not synced");
152 return server_error(RpcError::NotSynced, id, None)
153 }
154
155 let pending_txs = match self.validator.blockchain.get_pending_txs() {
156 Ok(v) => v,
157 Err(e) => {
158 error!(target: "darkfid::rpc::tx_pending", "Failed fetching pending txs: {e}");
159 return JsonError::new(InternalError, None, id).into()
160 }
161 };
162
163 let pending_txs: Vec<JsonValue> =
164 pending_txs.iter().map(|x| JsonValue::String(x.hash().to_string())).collect();
165
166 JsonResponse::new(JsonValue::Array(pending_txs), id).into()
167 }
168
169 pub async fn tx_clean_pending(&self, id: u16, params: JsonValue) -> JsonResult {
176 let params = params.get::<Vec<JsonValue>>().unwrap();
177 if !params.is_empty() {
178 return JsonError::new(InvalidParams, None, id).into()
179 }
180
181 if !*self.validator.synced.read().await {
182 error!(target: "darkfid::rpc::tx_clean_pending", "Blockchain is not synced");
183 return server_error(RpcError::NotSynced, id, None)
184 }
185
186 let pending_txs = match self.validator.blockchain.get_pending_txs() {
187 Ok(v) => v,
188 Err(e) => {
189 error!(target: "darkfid::rpc::tx_clean_pending", "Failed fetching pending txs: {e}");
190 return JsonError::new(InternalError, None, id).into()
191 }
192 };
193
194 if let Err(e) = self.validator.blockchain.remove_pending_txs(&pending_txs) {
195 error!(target: "darkfid::rpc::tx_clean_pending", "Failed fetching pending txs: {e}");
196 return JsonError::new(InternalError, None, id).into()
197 };
198
199 let pending_txs: Vec<JsonValue> =
200 pending_txs.iter().map(|x| JsonValue::String(x.hash().to_string())).collect();
201
202 JsonResponse::new(JsonValue::Array(pending_txs), id).into()
203 }
204
205 pub async fn tx_calculate_fee(&self, id: u16, params: JsonValue) -> JsonResult {
213 let params = params.get::<Vec<JsonValue>>().unwrap();
214 if params.len() != 2 || !params[0].is_string() || !params[1].is_bool() {
215 return JsonError::new(InvalidParams, None, id).into()
216 }
217
218 if !*self.validator.synced.read().await {
219 error!(target: "darkfid::rpc::tx_calculate_fee", "Blockchain is not synced");
220 return server_error(RpcError::NotSynced, id, None)
221 }
222
223 let tx_enc = params[0].get::<String>().unwrap().trim();
225 let tx_bytes = match base64::decode(tx_enc) {
226 Some(v) => v,
227 None => {
228 error!(target: "darkfid::rpc::tx_calculate_fee", "Failed decoding base64 transaction");
229 return server_error(RpcError::ParseError, id, None)
230 }
231 };
232
233 let tx: Transaction = match deserialize_async(&tx_bytes).await {
234 Ok(v) => v,
235 Err(e) => {
236 error!(target: "darkfid::rpc::tx_calculate_fee", "Failed deserializing bytes into Transaction: {e}");
237 return server_error(RpcError::ParseError, id, None)
238 }
239 };
240
241 let include_fee = params[1].get::<bool>().unwrap();
243
244 let result = self.validator.calculate_fee(&tx, *include_fee).await;
246 if result.is_err() {
247 error!(
248 target: "darkfid::rpc::tx_calculate_fee", "Failed to validate state transition: {}",
249 result.err().unwrap()
250 );
251 return server_error(RpcError::TxGasCalculationFail, id, None)
252 };
253
254 JsonResponse::new(JsonValue::Number(result.unwrap() as f64), id).into()
255 }
256}