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