1use std::str::FromStr;
2
3use super::clementine::{
4 self, clementine_verifier_server::ClementineVerifier, Empty, NonceGenRequest, NonceGenResponse,
5 OperatorParams, OptimisticPayoutParams, PartialSig, RawTxWithRbfInfo, VergenResponse,
6 VerifierDepositFinalizeParams, VerifierDepositSignParams, VerifierParams,
7};
8use super::error;
9use super::parser::ParserError;
10use crate::builder::transaction::sign::{create_and_sign_txs, TransactionRequestData};
11use crate::builder::transaction::ContractContext;
12use crate::citrea::CitreaClientT;
13use crate::compatibility::ActorWithConfig;
14use crate::constants::RESTART_BACKGROUND_TASKS_TIMEOUT;
15use crate::rpc::clementine::{CompatibilityParamsRpc, VerifierDepositFinalizeResponse};
16#[cfg(feature = "automation")]
17use crate::tx_sender_ext::TxSenderClientExt;
18use crate::utils::{get_vergen_response, monitor_standalone_task, timed_request};
19use crate::verifier::VerifierServer;
20use crate::{constants, fetch_next_optional_message_from_stream};
21use crate::{
22 fetch_next_message_from_stream,
23 rpc::parser::{self},
24};
25use alloy::primitives::PrimitiveSignature;
26use bitcoin::Witness;
27use clementine::verifier_deposit_finalize_params::Params;
28use clementine_errors::ResultExt as _;
29use eyre::Context as _;
30use secp256k1::musig::AggregatedNonce;
31use tokio::sync::mpsc::{self};
32use tokio_stream::wrappers::ReceiverStream;
33use tonic::{async_trait, Request, Response, Status, Streaming};
34
35#[async_trait]
36impl<C> ClementineVerifier for VerifierServer<C>
37where
38 C: CitreaClientT,
39{
40 async fn get_compatibility_params(
41 &self,
42 _request: Request<Empty>,
43 ) -> Result<Response<CompatibilityParamsRpc>, Status> {
44 let params = self.verifier.get_compatibility_params()?;
45 Ok(Response::new(params.try_into().map_to_status()?))
46 }
47
48 async fn vergen(&self, _request: Request<Empty>) -> Result<Response<VergenResponse>, Status> {
49 tracing::info!("Vergen rpc called");
50 Ok(Response::new(get_vergen_response()))
51 }
52
53 async fn restart_background_tasks(
54 &self,
55 _request: tonic::Request<super::Empty>,
56 ) -> std::result::Result<tonic::Response<super::Empty>, tonic::Status> {
57 tracing::info!("Restarting background tasks rpc called");
58 timed_request(
60 RESTART_BACKGROUND_TASKS_TIMEOUT,
61 "Restarting background tasks",
62 self.start_background_tasks(),
63 )
64 .await?;
65 tracing::info!("Restarting background tasks rpc completed");
66 Ok(Response::new(Empty {}))
67 }
68
69 async fn optimistic_payout_sign(
70 &self,
71 request: Request<OptimisticPayoutParams>,
72 ) -> Result<Response<PartialSig>, Status> {
73 tracing::info!("Optimistic payout sign rpc called");
74 let params = request.into_inner();
75 let agg_nonce = AggregatedNonce::from_byte_array(
76 params
77 .agg_nonce
78 .as_slice()
79 .try_into()
80 .map_err(|_| Status::invalid_argument("agg_nonce must be exactly 66 bytes"))?,
81 )
82 .map_err(|e| Status::invalid_argument(format!("Invalid musigagg nonce: {e}")))?;
83 let nonce_session_id = params
84 .nonce_gen
85 .ok_or(Status::invalid_argument(
86 "Nonce params not found for optimistic payout",
87 ))?
88 .id
89 .parse::<u128>()
90 .map_err(|e| Status::invalid_argument(format!("Invalid nonce session id: {e}")))?;
91
92 let opt_withdraw_params = params.opt_withdrawal.ok_or(Status::invalid_argument(
93 "Withdrawal params not found for optimistic payout",
94 ))?;
95
96 tracing::info!(
97 "Parsed optimistic payout rpc params: {:?}",
98 opt_withdraw_params
99 );
100
101 let verification_signature_str = opt_withdraw_params.verification_signature.clone();
102 let withdrawal_params = opt_withdraw_params
103 .withdrawal
104 .ok_or(Status::invalid_argument(
105 "Withdrawal params not found for optimistic payout",
106 ))?;
107 let (withdrawal_id, input_signature, input_outpoint, output_script_pubkey, output_amount) =
108 parser::operator::parse_withdrawal_sig_params(withdrawal_params)?;
109
110 let verification_signature = verification_signature_str
111 .map(|sig| {
112 PrimitiveSignature::from_str(&sig).map_err(|e| {
113 Status::invalid_argument(format!("Invalid verification signature: {e}"))
114 })
115 })
116 .transpose()?;
117
118 let partial_sig = self
119 .verifier
120 .sign_optimistic_payout(
121 nonce_session_id,
122 agg_nonce,
123 withdrawal_id,
124 input_signature,
125 input_outpoint,
126 output_script_pubkey,
127 output_amount,
128 verification_signature,
129 )
130 .await?;
131 tracing::info!("Optimistic payout sign rpc completed successfully");
132 Ok(Response::new(partial_sig.into()))
133 }
134
135 async fn internal_create_watchtower_challenge(
136 &self,
137 request: tonic::Request<super::TransactionRequest>,
138 ) -> std::result::Result<tonic::Response<super::RawTxWithRbfInfo>, tonic::Status> {
139 tracing::warn!(
140 "Internal create watchtower challenge rpc called with request: {:?}",
141 request
142 );
143 let transaction_request = request.into_inner();
144 let transaction_data: TransactionRequestData = transaction_request.try_into()?;
145
146 let (_tx_type, signed_tx, rbf_info) = self
147 .verifier
148 .create_watchtower_challenge(
149 transaction_data,
150 &{
151 let challenge_bytes = self
152 .verifier
153 .config
154 .protocol_paramset()
155 .watchtower_challenge_bytes;
156 let mut challenge = vec![0u8; challenge_bytes];
157 for (step, i) in (0..challenge_bytes).step_by(32).enumerate() {
158 if i < challenge_bytes {
159 challenge[i] = step as u8;
160 }
161 }
162 challenge
163 }, None,
165 )
166 .await?;
167
168 Ok(Response::new(RawTxWithRbfInfo {
169 raw_tx: bitcoin::consensus::serialize(&signed_tx),
170 rbf_info: Some(rbf_info.into()),
171 }))
172 }
173 type NonceGenStream = ReceiverStream<Result<NonceGenResponse, Status>>;
174 type DepositSignStream = ReceiverStream<Result<PartialSig, Status>>;
175
176 async fn get_params(&self, _: Request<Empty>) -> Result<Response<VerifierParams>, Status> {
177 tracing::info!("Verifier get params rpc called");
178 let params: VerifierParams = (&self.verifier).try_into()?;
179
180 Ok(Response::new(params))
181 }
182
183 async fn set_operator(
184 &self,
185 req: Request<Streaming<OperatorParams>>,
186 ) -> Result<Response<Empty>, Status> {
187 let mut in_stream = req.into_inner();
188 tracing::info!("set_operator rpc called");
189 let (collateral_funding_outpoint, operator_xonly_pk, wallet_reimburse_address) =
190 parser::operator::parse_details(&mut in_stream).await?;
191 tracing::info!("Parsed set_operator rpc params for operator xonly pk: {}, collateral funding outpoint: {}, wallet reimburse address: {:?}", operator_xonly_pk, collateral_funding_outpoint, wallet_reimburse_address);
192
193 let wallet_reimburse_address_checked = wallet_reimburse_address
195 .clone()
196 .require_network(self.verifier.config.protocol_paramset().network)
197 .map_err(|e| {
198 Status::invalid_argument(format!(
199 "Invalid operator reimbursement address: {:?} for bitcoin network {:?} for operator {:?}. ParseError: {}",
200 wallet_reimburse_address,
201 self.verifier.config.protocol_paramset().network,
202 operator_xonly_pk,
203 e
204 ))
205 })?;
206
207 let mut operator_kickoff_winternitz_public_keys = Vec::new();
208 for _ in 0..self.verifier.config.get_num_kickoff_winternitz_pks() {
210 operator_kickoff_winternitz_public_keys
211 .push(parser::operator::parse_winternitz_public_keys(&mut in_stream).await?);
212 }
213
214 let mut unspent_kickoff_sigs =
215 Vec::with_capacity(self.verifier.config.get_num_unspent_kickoff_sigs());
216 for _ in 0..self.verifier.config.get_num_unspent_kickoff_sigs() {
217 unspent_kickoff_sigs.push(parser::operator::parse_schnorr_sig(&mut in_stream).await?);
218 }
219
220 if in_stream.message().await?.is_some() {
221 return Err(Status::invalid_argument(
222 "Expected end of stream, got more messages in set_operator",
223 ));
224 }
225
226 self.verifier
227 .set_operator(
228 collateral_funding_outpoint,
229 operator_xonly_pk,
230 wallet_reimburse_address_checked,
231 operator_kickoff_winternitz_public_keys,
232 unspent_kickoff_sigs,
233 )
234 .await?;
235
236 tracing::info!(
237 "Set operator rpc completed successfully for operator xonly pk: {}",
238 operator_xonly_pk
239 );
240 Ok(Response::new(Empty {}))
241 }
242
243 async fn nonce_gen(
244 &self,
245 req: Request<NonceGenRequest>,
246 ) -> Result<Response<Self::NonceGenStream>, Status> {
247 let num_nonces = req.into_inner().num_nonces;
248 tracing::info!(
249 "Verifier nonce gen rpc called with num_nonces: {}",
250 num_nonces
251 );
252 let (session_id, pub_nonces) = self.verifier.nonce_gen(num_nonces).await?;
253
254 let (tx, rx) = mpsc::channel(pub_nonces.len() + 1);
255 let monitor_sender = tx.clone();
256
257 let handle = tokio::spawn(async move {
258 let nonce_gen_first_response = clementine::NonceGenFirstResponse {
259 id: session_id.to_string(),
260 num_nonces,
261 };
262 let session_id: NonceGenResponse = nonce_gen_first_response.into();
263 tx.send(Ok(session_id)).await.map_err(|e| {
264 Status::aborted(format!("Failed to send nonce gen first response: {e}"))
265 })?;
266
267 for pub_nonce in &pub_nonces {
268 let pub_nonce: NonceGenResponse = pub_nonce.into();
269 tx.send(Ok(pub_nonce)).await.map_err(|e| {
270 Status::aborted(format!("Failed to send nonce gen response: {e}"))
271 })?;
272 }
273
274 Ok::<(), Status>(())
275 });
276 monitor_standalone_task(handle, "Verifier nonce_gen", monitor_sender);
277
278 Ok(Response::new(ReceiverStream::new(rx)))
279 }
280
281 async fn deposit_sign(
282 &self,
283 req: Request<Streaming<VerifierDepositSignParams>>,
284 ) -> Result<Response<Self::DepositSignStream>, Status> {
285 let mut in_stream = req.into_inner();
286 let verifier = self.verifier.clone();
287 tracing::info!("Verifier deposit sign rpc called");
288
289 let (tx, rx) = mpsc::channel(constants::DEFAULT_CHANNEL_SIZE);
290 let out_stream: Self::DepositSignStream = ReceiverStream::new(rx);
291
292 let (param_tx, mut param_rx) = mpsc::channel(1);
293 let (agg_nonce_tx, agg_nonce_rx) = mpsc::channel(constants::DEFAULT_CHANNEL_SIZE);
294 let config = self.verifier.config.clone();
295
296 let handle = tokio::spawn(async move {
298 let params = fetch_next_message_from_stream!(in_stream, params)?;
299 let (deposit_data, session_id) = match params {
300 clementine::verifier_deposit_sign_params::Params::DepositSignFirstParam(
301 deposit_sign_session,
302 ) => parser::verifier::parse_deposit_sign_session(
303 deposit_sign_session,
304 &verifier.signer.public_key,
305 )?,
306 _ => return Err(Status::invalid_argument("Expected DepositOutpoint")),
307 };
308
309 let mut received_agg_nonces = 0;
310 let needed_agg_nonces = config.get_num_required_nofn_sigs(&deposit_data);
311
312 param_tx
313 .send((deposit_data, session_id))
314 .await
315 .map_err(error::output_stream_ended_prematurely)?;
316
317 while let Some(result) =
318 fetch_next_optional_message_from_stream!(&mut in_stream, params)
319 {
320 let agg_nonce = match result {
321 clementine::verifier_deposit_sign_params::Params::AggNonce(agg_nonce) => {
322 AggregatedNonce::from_byte_array(
323 agg_nonce.as_slice().try_into().map_err(|_| {
324 ParserError::RPCParamMalformed("AggNonce".to_string())
325 })?,
326 )
327 .map_err(|_| ParserError::RPCParamMalformed("AggNonce".to_string()))?
328 }
329 _ => return Err(Status::invalid_argument("Expected AggNonce")),
330 };
331
332 agg_nonce_tx
333 .send(agg_nonce)
334 .await
335 .map_err(error::output_stream_ended_prematurely)?;
336
337 received_agg_nonces += 1;
338 if received_agg_nonces == needed_agg_nonces {
339 break;
340 }
341 }
342 Ok(())
343 });
344 monitor_standalone_task(handle, "Verifier deposit data receiver", tx.clone());
345
346 let tx_for_monitor = tx.clone();
348 let handle = tokio::spawn(async move {
349 let (deposit_data, session_id) = param_rx
350 .recv()
351 .await
352 .ok_or(error::expected_msg_got_none("parameters")())?;
353
354 tracing::info!("Called deposit_sign for deposit data: {:?}", deposit_data,);
355
356 let mut partial_sig_receiver = verifier
357 .deposit_sign(deposit_data.clone(), session_id, agg_nonce_rx)
358 .await?;
359
360 let mut nonce_idx = 0;
361 let num_required_sigs = verifier.config.get_num_required_nofn_sigs(&deposit_data);
362 while let Some(partial_sig_result) = partial_sig_receiver.recv().await {
363 match partial_sig_result {
364 Ok(partial_sig) => {
365 tx.send(Ok(PartialSig {
366 partial_sig: partial_sig.serialize().to_vec(),
367 }))
368 .await
369 .map_err(|e| {
370 Status::aborted(format!(
371 "Error sending partial sig, stream ended prematurely: {e}"
372 ))
373 })?;
374 }
375 Err(e) => {
376 tx
377 .send(Err(e.into()))
378 .await
379 .map_err(|send_err| {
380 Status::aborted(format!(
381 "Error forwarding partial sig error, stream ended prematurely: {send_err}"
382 ))
383 })?;
384 break;
385 }
386 }
387
388 nonce_idx += 1;
389 tracing::trace!(
390 "Verifier {:?} signed and sent sighash {} of {} through rpc deposit_sign",
391 verifier.signer.public_key,
392 nonce_idx,
393 num_required_sigs
394 );
395 if nonce_idx == num_required_sigs {
396 break;
397 }
398 }
399
400 Ok::<(), Status>(())
401 });
402 monitor_standalone_task(handle, "Verifier deposit signature sender", tx_for_monitor);
403
404 Ok(Response::new(out_stream))
405 }
406
407 async fn deposit_finalize(
411 &self,
412 req: Request<Streaming<VerifierDepositFinalizeParams>>,
413 ) -> Result<Response<VerifierDepositFinalizeResponse>, Status> {
414 let mut in_stream = req.into_inner();
415 tracing::info!("deposit finalize rpc called");
416
417 let (sig_tx, sig_rx) = mpsc::channel(constants::DEFAULT_CHANNEL_SIZE);
418 let (agg_nonce_tx, agg_nonce_rx) = mpsc::channel(1);
419 let (operator_sig_tx, operator_sig_rx) = mpsc::channel(constants::DEFAULT_CHANNEL_SIZE);
420
421 let params = fetch_next_message_from_stream!(in_stream, params)?;
422 let (deposit_data, session_id) = match params {
423 Params::DepositSignFirstParam(deposit_sign_session) => {
424 parser::verifier::parse_deposit_sign_session(
425 deposit_sign_session,
426 &self.verifier.signer.public_key,
427 )?
428 }
429 _ => Err(Status::internal("Expected DepositOutpoint"))?,
430 };
431 tracing::info!(
432 "deposit_data received in deposit_finalize, {:?}",
433 deposit_data
434 );
435 let deposit_outpoint = deposit_data.get_deposit_outpoint();
436
437 let verifier = self.verifier.clone();
439 let mut dep_data = deposit_data.clone();
440 let deposit_finalize_handle = tokio::spawn(async move {
441 verifier
442 .deposit_finalize(
443 &mut dep_data,
444 session_id,
445 sig_rx,
446 agg_nonce_rx,
447 operator_sig_rx,
448 )
449 .await
450 });
451
452 let verifier = self.verifier.clone();
454 let sig_handle = tokio::spawn(async move {
455 let num_required_nofn_sigs = verifier.config.get_num_required_nofn_sigs(&deposit_data);
456 tracing::debug!(
457 "Needed nofn sigs for deposit {:?}: {}",
458 deposit_data,
459 num_required_nofn_sigs
460 );
461 let mut nonce_idx = 0;
462 while let Some(sig) =
463 parser::verifier::parse_next_deposit_finalize_param_schnorr_sig(&mut in_stream)
464 .await
465 .wrap_err_with(|| {
466 format!(
467 "While waiting for the {}th signature out of {}",
468 nonce_idx + 1,
469 num_required_nofn_sigs
470 )
471 })
472 .map_to_status()?
473 {
474 tracing::trace!(
475 "Received full nofn sig {} in deposit_finalize()",
476 nonce_idx + 1
477 );
478 sig_tx
479 .send(sig)
480 .await
481 .map_err(error::output_stream_ended_prematurely)?;
482 tracing::debug!(
483 "Sent full nofn sig {} to src/verifier in deposit_finalize()",
484 nonce_idx + 1
485 );
486 nonce_idx += 1;
487 if nonce_idx == num_required_nofn_sigs {
488 break;
489 }
490 }
491 if nonce_idx < num_required_nofn_sigs {
492 let err_msg = format!(
493 "Insufficient N-of-N signatures received: got {nonce_idx}, expected {num_required_nofn_sigs}",
494 );
495 tracing::error!("{err_msg}");
496 return Err(Status::invalid_argument(err_msg));
497 }
498
499 let move_tx_agg_nonce =
500 parser::verifier::parse_deposit_finalize_param_move_tx_agg_nonce(&mut in_stream)
501 .await?;
502 agg_nonce_tx
503 .send(move_tx_agg_nonce)
504 .await
505 .map_err(error::output_stream_ended_prematurely)?;
506
507 let emergency_stop_agg_nonce =
508 parser::verifier::parse_deposit_finalize_param_emergency_stop_agg_nonce(
509 &mut in_stream,
510 )
511 .await?;
512 agg_nonce_tx
513 .send(emergency_stop_agg_nonce)
514 .await
515 .map_err(error::output_stream_ended_prematurely)?;
516
517 let num_required_op_sigs = verifier
518 .config
519 .get_num_required_operator_sigs(&deposit_data);
520 let num_operators = deposit_data.get_num_operators();
521 let num_required_total_op_sigs = num_required_op_sigs * num_operators;
522 let mut total_op_sig_count = 0;
523 for _ in 0..num_operators {
524 let mut op_sig_count = 0;
525
526 while let Some(operator_sig) =
527 parser::verifier::parse_next_deposit_finalize_param_schnorr_sig(&mut in_stream)
528 .await?
529 {
530 tracing::trace!(
531 "Received full operator sig {} in deposit_finalize()",
532 op_sig_count + 1
533 );
534 operator_sig_tx
535 .send(operator_sig)
536 .await
537 .map_err(error::output_stream_ended_prematurely)?;
538 tracing::trace!(
539 "Sent full operator sig {} to src/verifier in deposit_finalize()",
540 op_sig_count + 1
541 );
542
543 op_sig_count += 1;
544 total_op_sig_count += 1;
545 if op_sig_count == num_required_op_sigs {
546 break;
547 }
548 }
549 }
550
551 if total_op_sig_count < num_required_total_op_sigs {
552 let err_msg = format!(
553 "Insufficient operator signatures received: got {total_op_sig_count}, expected {num_required_total_op_sigs}",
554 );
555 tracing::error!("{err_msg}");
556 return Err(Status::invalid_argument(err_msg));
557 }
558
559 Ok::<(), Status>(())
560 });
561
562 sig_handle.await.map_err(|e| {
563 Status::internal(format!("Deposit sign thread failed to finish: {e}").as_str())
564 })??;
565
566 let partial_sig = deposit_finalize_handle.await.map_err(|e| {
567 Status::internal(format!("Deposit finalize thread failed to finish: {e}").as_str())
568 })??;
569
570 let response = VerifierDepositFinalizeResponse {
571 move_to_vault_partial_sig: partial_sig.0.serialize().to_vec(),
572 emergency_stop_partial_sig: partial_sig.1.serialize().to_vec(),
573 };
574
575 tracing::info!(
576 "deposit finalize rpc completed successfully for deposit outpoint: {:?}",
577 deposit_outpoint
578 );
579
580 Ok(Response::new(response))
581 }
582
583 async fn set_operator_keys(
584 &self,
585 request: tonic::Request<super::OperatorKeysWithDeposit>,
586 ) -> std::result::Result<tonic::Response<super::Empty>, tonic::Status> {
587 tracing::info!("set_operator_keys rpc called");
588 let data = request.into_inner();
589 let (deposit_data, op_keys, operator_xonly_pk) =
590 parser::verifier::parse_op_keys_with_deposit(data)?;
591 tracing::info!(
592 "Parsed set_operator_keys rpc params, operator xonly pk: {:?}, deposit data: {:?}",
593 operator_xonly_pk,
594 deposit_data
595 );
596 self.verifier
597 .set_operator_keys(deposit_data, op_keys, operator_xonly_pk)
598 .await?;
599 Ok(Response::new(Empty {}))
600 }
601
602 async fn internal_create_signed_txs(
603 &self,
604 request: tonic::Request<super::TransactionRequest>,
605 ) -> std::result::Result<tonic::Response<super::SignedTxsWithType>, tonic::Status> {
606 let transaction_request = request.into_inner();
607 let transaction_data: TransactionRequestData = transaction_request.try_into()?;
608 tracing::warn!(
609 "Called internal_create_signed_txs with transaction data: {:?}",
610 transaction_data
611 );
612 let (_, deposit_data) = self
613 .verifier
614 .db
615 .get_deposit_data(None, transaction_data.deposit_outpoint)
616 .await?
617 .ok_or(Status::invalid_argument("Deposit not found in database"))?;
618 let context = ContractContext::new_context_for_kickoff(
619 transaction_data.kickoff_data,
620 deposit_data,
621 self.verifier.config.protocol_paramset(),
622 );
623 let raw_txs = create_and_sign_txs(
624 self.verifier.db.clone(),
625 &self.verifier.signer,
626 self.verifier.config.clone(),
627 context,
628 None, None,
630 )
631 .await?;
632
633 Ok(Response::new(raw_txs.into()))
634 }
635
636 async fn internal_handle_kickoff(
637 &self,
638 request: Request<clementine::Txid>,
639 ) -> Result<Response<Empty>, Status> {
640 let txid = request.into_inner();
641 let txid = bitcoin::Txid::try_from(txid).map_err(|e| {
642 Status::invalid_argument(format!("Failed to convert txid to bitcoin::Txid: {e}"))
643 })?;
644 tracing::warn!(
645 "Called internal_handle_kickoff for kickoff txid: {:?}",
646 txid
647 );
648 let mut dbtx = self.verifier.db.begin_transaction().await?;
649 let kickoff_data = self
650 .verifier
651 .db
652 .get_deposit_data_with_kickoff_txid(None, txid)
653 .await?;
654 if let Some((deposit_data, kickoff_id)) = kickoff_data {
655 self.verifier
656 .handle_kickoff(
657 &mut dbtx,
658 Witness::new(),
659 deposit_data,
660 kickoff_id,
661 false,
662 txid,
663 )
664 .await?;
665 } else {
666 return Err(Status::not_found("Kickoff txid not found"));
667 }
668 dbtx.commit()
669 .await
670 .wrap_err("Failed to commit transaction")
671 .map_to_status()?;
672 Ok(Response::new(Empty {}))
673 }
674
675 async fn debug_tx(
676 &self,
677 request: tonic::Request<super::TxDebugRequest>,
678 ) -> std::result::Result<tonic::Response<super::TxDebugInfo>, tonic::Status> {
679 #[cfg(not(feature = "automation"))]
680 {
681 Err(tonic::Status::unimplemented(
682 "Automation is not enabled, TxSender is not running.",
683 ))
684 }
685
686 #[cfg(feature = "automation")]
688 {
689 let tx_id = request.into_inner().tx_id;
690 tracing::info!("Called debug_tx for tx sender try to send id: {:?}", tx_id);
691 match self.verifier.tx_sender.debug_tx(tx_id).await {
692 Ok(debug_info) => Ok(tonic::Response::new(debug_info)),
693 Err(e) => Err(tonic::Status::internal(format!(
694 "Failed to debug TX {tx_id}: {e}",
695 ))),
696 }
697 }
698 }
699
700 async fn get_current_status(
701 &self,
702 _request: Request<Empty>,
703 ) -> Result<Response<clementine::EntityStatus>, Status> {
704 tracing::debug!("Called get_current_status rpc");
705 let status = self.get_current_status().await?;
706 Ok(Response::new(status))
707 }
708}