drive_abci/abci/app/
check_tx.rs1use crate::abci::app::PlatformApplication;
2use crate::abci::handler;
3use crate::error::Error;
4use crate::platform_types::platform::Platform;
5use crate::rpc::core::CoreRPCLike;
6use crate::utils::spawn_blocking_task_with_name_if_supported;
7use async_trait::async_trait;
8use std::fmt::Debug;
9use std::sync::Arc;
10use tenderdash_abci::proto::abci as proto;
11use tenderdash_abci::proto::abci::abci_application_server as grpc_abci_server;
12use tenderdash_abci::proto::tonic;
13
14pub struct CheckTxAbciApplication<C>
19where
20 C: CoreRPCLike + Send + Sync + 'static,
21{
22 platform: Arc<Platform<C>>,
24 core_rpc: Arc<C>,
25}
26
27impl<C> PlatformApplication<C> for CheckTxAbciApplication<C>
28where
29 C: CoreRPCLike + Send + Sync + 'static,
30{
31 fn platform(&self) -> &Platform<C> {
32 self.platform.as_ref()
33 }
34}
35
36impl<C> CheckTxAbciApplication<C>
37where
38 C: CoreRPCLike + Send + Sync + 'static,
39{
40 pub fn new(platform: Arc<Platform<C>>, core_rpc: Arc<C>) -> Self {
42 Self { platform, core_rpc }
43 }
44}
45
46impl<C> Debug for CheckTxAbciApplication<C>
47where
48 C: CoreRPCLike + Send + Sync + 'static,
49{
50 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51 write!(f, "<CheckTxAbciApplication>")
52 }
53}
54
55#[async_trait]
56impl<C> grpc_abci_server::AbciApplication for CheckTxAbciApplication<C>
57where
58 C: CoreRPCLike + Send + Sync + 'static,
59{
60 async fn echo(
61 &self,
62 request: tonic::Request<proto::RequestEcho>,
63 ) -> Result<tonic::Response<proto::ResponseEcho>, tonic::Status> {
64 let response = handler::echo(self, request.into_inner()).map_err(error_into_status)?;
65
66 Ok(tonic::Response::new(response))
67 }
68
69 async fn check_tx(
70 &self,
71 request: tonic::Request<proto::RequestCheckTx>,
72 ) -> Result<tonic::Response<proto::ResponseCheckTx>, tonic::Status> {
73 let platform = Arc::clone(&self.platform);
74 let core_rpc = Arc::clone(&self.core_rpc);
75
76 let proto_request = request.into_inner();
77
78 let check_tx_type = proto::CheckTxType::try_from(proto_request.r#type)
79 .map_err(|_| tonic::Status::invalid_argument("invalid check tx type"))?;
80
81 let thread_name = match check_tx_type {
82 proto::CheckTxType::New => "check_tx",
83 proto::CheckTxType::Recheck => "re_check_tx",
84 };
85
86 spawn_blocking_task_with_name_if_supported(thread_name, move || {
87 let response = handler::check_tx(&platform, &core_rpc, proto_request)
88 .map_err(error_into_status)?;
89
90 Ok(tonic::Response::new(response))
91 })?
92 .await
93 .map_err(|error| tonic::Status::internal(format!("check tx panics: {}", error)))?
94 }
95}
96
97pub fn error_into_status(error: Error) -> tonic::Status {
98 tonic::Status::internal(error.to_string())
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104 use crate::error::execution::ExecutionError;
105 use crate::rpc::core::MockCoreRPCLike;
106
107 #[test]
108 fn error_into_status_produces_internal_status() {
109 let error = Error::Execution(ExecutionError::CorruptedCodeExecution("test error message"));
110 let status = error_into_status(error);
111
112 assert_eq!(status.code(), tonic::Code::Internal);
113 assert!(status.message().contains("test error message"));
114 }
115
116 #[test]
117 fn error_into_status_preserves_error_message() {
118 let error = Error::Execution(ExecutionError::NotInTransaction("no active transaction"));
119 let status = error_into_status(error);
120
121 assert!(status.message().contains("no active transaction"));
122 }
123
124 #[test]
125 fn check_tx_abci_application_debug_format() {
126 let platform =
128 crate::test::helpers::setup::TestPlatformBuilder::new().build_with_mock_rpc();
129
130 let core_rpc = MockCoreRPCLike::new();
131
132 let app = CheckTxAbciApplication::new(Arc::new(platform.platform), Arc::new(core_rpc));
133
134 let debug_str = format!("{:?}", app);
135 assert_eq!(debug_str, "<CheckTxAbciApplication>");
136 }
137
138 #[test]
139 fn check_tx_abci_application_platform_returns_platform() {
140 let platform =
141 crate::test::helpers::setup::TestPlatformBuilder::new().build_with_mock_rpc();
142
143 let core_rpc = MockCoreRPCLike::new();
144
145 let app = CheckTxAbciApplication::new(Arc::new(platform.platform), Arc::new(core_rpc));
146
147 let _platform_ref = app.platform();
149 }
150}