drive_abci/abci/app/
full.rs1use crate::abci::app::{BlockExecutionApplication, PlatformApplication, TransactionalApplication};
2use crate::abci::handler;
3use crate::abci::handler::error::error_into_exception;
4use crate::error::execution::ExecutionError;
5use crate::error::Error;
6use crate::execution::types::block_execution_context::BlockExecutionContext;
7use crate::platform_types::platform::Platform;
8use crate::rpc::core::CoreRPCLike;
9use dpp::version::PlatformVersion;
10use drive::grovedb::Transaction;
11use std::fmt::Debug;
12use std::sync::RwLock;
13use tenderdash_abci::proto::abci as proto;
14
15pub struct FullAbciApplication<'a, C> {
20 pub platform: &'a Platform<C>,
22 pub transaction: RwLock<Option<Transaction<'a>>>,
24 pub block_execution_context: RwLock<Option<BlockExecutionContext>>,
26}
27
28impl<'a, C> FullAbciApplication<'a, C> {
29 pub fn new(platform: &'a Platform<C>) -> Self {
31 Self {
32 platform,
33 transaction: Default::default(),
34 block_execution_context: Default::default(),
35 }
36 }
37}
38
39impl<C> PlatformApplication<C> for FullAbciApplication<'_, C> {
40 fn platform(&self) -> &Platform<C> {
41 self.platform
42 }
43}
44
45impl<C> BlockExecutionApplication for FullAbciApplication<'_, C> {
46 fn block_execution_context(&self) -> &RwLock<Option<BlockExecutionContext>> {
47 &self.block_execution_context
48 }
49}
50
51impl<'a, C> TransactionalApplication<'a> for FullAbciApplication<'a, C> {
52 fn start_transaction(&self) {
54 let transaction = self.platform.drive.grove.start_transaction();
55 self.transaction.write().unwrap().replace(transaction);
56 }
57
58 fn transaction(&self) -> &RwLock<Option<Transaction<'a>>> {
59 &self.transaction
60 }
61
62 fn commit_transaction(&self, platform_version: &PlatformVersion) -> Result<(), Error> {
64 let transaction = self
65 .transaction
66 .write()
67 .unwrap()
68 .take()
69 .ok_or(Error::Execution(ExecutionError::NotInTransaction(
70 "trying to commit a transaction, but we are not in one",
71 )))?;
72
73 self.platform
74 .drive
75 .commit_transaction(transaction, &platform_version.drive)
76 .map_err(Error::Drive)
77 }
78}
79
80impl<C> Debug for FullAbciApplication<'_, C> {
81 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
82 write!(f, "<FullAbciApplication>")
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89 use crate::rpc::core::MockCoreRPCLike;
90
91 #[test]
92 fn full_abci_application_debug_format() {
93 let platform =
94 crate::test::helpers::setup::TestPlatformBuilder::new().build_with_mock_rpc();
95
96 let app = FullAbciApplication::new(&platform.platform);
97
98 let debug_str = format!("{:?}", app);
99 assert_eq!(debug_str, "<FullAbciApplication>");
100 }
101
102 #[test]
103 fn full_abci_application_platform_returns_reference() {
104 let platform =
105 crate::test::helpers::setup::TestPlatformBuilder::new().build_with_mock_rpc();
106
107 let app = FullAbciApplication::<MockCoreRPCLike>::new(&platform.platform);
108 let _platform_ref = app.platform();
109 }
110
111 #[test]
112 fn full_abci_application_block_execution_context_is_initially_none() {
113 let platform =
114 crate::test::helpers::setup::TestPlatformBuilder::new().build_with_mock_rpc();
115
116 let app = FullAbciApplication::<MockCoreRPCLike>::new(&platform.platform);
117
118 let ctx = app.block_execution_context().read().unwrap();
119 assert!(ctx.is_none());
120 }
121
122 #[test]
123 fn full_abci_application_transaction_is_initially_none() {
124 let platform =
125 crate::test::helpers::setup::TestPlatformBuilder::new().build_with_mock_rpc();
126
127 let app = FullAbciApplication::<MockCoreRPCLike>::new(&platform.platform);
128
129 let tx = app.transaction().read().unwrap();
130 assert!(tx.is_none());
131 }
132
133 #[test]
134 fn full_abci_application_start_transaction_creates_transaction() {
135 let platform =
136 crate::test::helpers::setup::TestPlatformBuilder::new().build_with_mock_rpc();
137
138 let app = FullAbciApplication::<MockCoreRPCLike>::new(&platform.platform);
139
140 app.start_transaction();
141
142 let tx = app.transaction().read().unwrap();
143 assert!(tx.is_some());
144 }
145
146 #[test]
147 fn full_abci_application_commit_without_transaction_fails() {
148 let platform =
149 crate::test::helpers::setup::TestPlatformBuilder::new().build_with_mock_rpc();
150
151 let app = FullAbciApplication::<MockCoreRPCLike>::new(&platform.platform);
152 let platform_version = PlatformVersion::latest();
153
154 let result = app.commit_transaction(platform_version);
155 assert!(result.is_err());
156 }
157
158 #[test]
159 fn full_abci_application_start_and_commit_transaction_succeeds() {
160 let platform =
161 crate::test::helpers::setup::TestPlatformBuilder::new().build_with_mock_rpc();
162
163 let app = FullAbciApplication::<MockCoreRPCLike>::new(&platform.platform);
164 let platform_version = PlatformVersion::latest();
165
166 app.start_transaction();
167
168 let result = app.commit_transaction(platform_version);
169 assert!(result.is_ok());
170
171 let tx = app.transaction().read().unwrap();
173 assert!(tx.is_none());
174 }
175}
176
177impl<C> tenderdash_abci::Application for FullAbciApplication<'_, C>
178where
179 C: CoreRPCLike,
180{
181 fn info(
182 &self,
183 request: proto::RequestInfo,
184 ) -> Result<proto::ResponseInfo, proto::ResponseException> {
185 handler::info(self, request).map_err(error_into_exception)
186 }
187
188 fn init_chain(
189 &self,
190 request: proto::RequestInitChain,
191 ) -> Result<proto::ResponseInitChain, proto::ResponseException> {
192 handler::init_chain(self, request).map_err(error_into_exception)
193 }
194
195 fn query(
196 &self,
197 _request: proto::RequestQuery,
198 ) -> Result<proto::ResponseQuery, proto::ResponseException> {
199 unreachable!("query is not supported in full ABCI application")
200 }
201
202 fn check_tx(
203 &self,
204 request: proto::RequestCheckTx,
205 ) -> Result<proto::ResponseCheckTx, proto::ResponseException> {
206 handler::check_tx(self.platform, &self.platform.core_rpc, request)
207 .map_err(error_into_exception)
208 }
209
210 fn extend_vote(
211 &self,
212 request: proto::RequestExtendVote,
213 ) -> Result<proto::ResponseExtendVote, proto::ResponseException> {
214 handler::extend_vote(self, request).map_err(error_into_exception)
215 }
216
217 fn finalize_block(
218 &self,
219 request: proto::RequestFinalizeBlock,
220 ) -> Result<proto::ResponseFinalizeBlock, proto::ResponseException> {
221 handler::finalize_block(self, request).map_err(error_into_exception)
222 }
223
224 fn prepare_proposal(
225 &self,
226 request: proto::RequestPrepareProposal,
227 ) -> Result<proto::ResponsePrepareProposal, proto::ResponseException> {
228 handler::prepare_proposal(self, request).map_err(error_into_exception)
229 }
230
231 fn process_proposal(
232 &self,
233 request: proto::RequestProcessProposal,
234 ) -> Result<proto::ResponseProcessProposal, proto::ResponseException> {
235 handler::process_proposal(self, request).map_err(error_into_exception)
236 }
237
238 fn verify_vote_extension(
239 &self,
240 request: proto::RequestVerifyVoteExtension,
241 ) -> Result<proto::ResponseVerifyVoteExtension, proto::ResponseException> {
242 handler::verify_vote_extension(self, request).map_err(error_into_exception)
243 }
244}