drive_abci/abci/app/
consensus.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 ConsensusAbciApplication<'a, C> {
20 platform: &'a Platform<C>,
22 transaction: RwLock<Option<Transaction<'a>>>,
24 block_execution_context: RwLock<Option<BlockExecutionContext>>,
26}
27
28impl<'a, C> ConsensusAbciApplication<'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 ConsensusAbciApplication<'_, C> {
40 fn platform(&self) -> &Platform<C> {
41 self.platform
42 }
43}
44
45impl<C> BlockExecutionApplication for ConsensusAbciApplication<'_, C> {
46 fn block_execution_context(&self) -> &RwLock<Option<BlockExecutionContext>> {
47 &self.block_execution_context
48 }
49}
50
51impl<'a, C> TransactionalApplication<'a> for ConsensusAbciApplication<'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 ConsensusAbciApplication<'_, C> {
81 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
82 write!(f, "<ConsensusAbciApplication>")
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89 use crate::rpc::core::MockCoreRPCLike;
90
91 #[test]
92 fn consensus_abci_application_debug_format() {
93 let platform =
94 crate::test::helpers::setup::TestPlatformBuilder::new().build_with_mock_rpc();
95
96 let app = ConsensusAbciApplication::new(&platform.platform);
97
98 let debug_str = format!("{:?}", app);
99 assert_eq!(debug_str, "<ConsensusAbciApplication>");
100 }
101
102 #[test]
103 fn consensus_abci_application_platform_returns_reference() {
104 let platform =
105 crate::test::helpers::setup::TestPlatformBuilder::new().build_with_mock_rpc();
106
107 let app = ConsensusAbciApplication::<MockCoreRPCLike>::new(&platform.platform);
108 let _platform_ref = app.platform();
109 }
110
111 #[test]
112 fn consensus_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 = ConsensusAbciApplication::<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 consensus_abci_application_transaction_is_initially_none() {
124 let platform =
125 crate::test::helpers::setup::TestPlatformBuilder::new().build_with_mock_rpc();
126
127 let app = ConsensusAbciApplication::<MockCoreRPCLike>::new(&platform.platform);
128
129 let tx = app.transaction().read().unwrap();
130 assert!(tx.is_none());
131 }
132
133 #[test]
134 fn consensus_abci_application_start_transaction_creates_transaction() {
135 let platform =
136 crate::test::helpers::setup::TestPlatformBuilder::new().build_with_mock_rpc();
137
138 let app = ConsensusAbciApplication::<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 consensus_abci_application_commit_without_transaction_fails() {
148 let platform =
149 crate::test::helpers::setup::TestPlatformBuilder::new().build_with_mock_rpc();
150
151 let app = ConsensusAbciApplication::<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
159impl<C> tenderdash_abci::Application for ConsensusAbciApplication<'_, C>
160where
161 C: CoreRPCLike,
162{
163 fn info(
164 &self,
165 request: proto::RequestInfo,
166 ) -> Result<proto::ResponseInfo, proto::ResponseException> {
167 handler::info(self, request).map_err(error_into_exception)
168 }
169
170 fn init_chain(
171 &self,
172 request: proto::RequestInitChain,
173 ) -> Result<proto::ResponseInitChain, proto::ResponseException> {
174 handler::init_chain(self, request).map_err(error_into_exception)
175 }
176
177 fn query(
178 &self,
179 _request: proto::RequestQuery,
180 ) -> Result<proto::ResponseQuery, proto::ResponseException> {
181 unreachable!("query is not implemented for consensus ABCI application")
182 }
183
184 fn check_tx(
185 &self,
186 _request: proto::RequestCheckTx,
187 ) -> Result<proto::ResponseCheckTx, proto::ResponseException> {
188 unreachable!("check_tx is not implemented for consensus ABCI application")
189 }
190
191 fn extend_vote(
192 &self,
193 request: proto::RequestExtendVote,
194 ) -> Result<proto::ResponseExtendVote, proto::ResponseException> {
195 handler::extend_vote(self, request).map_err(error_into_exception)
196 }
197
198 fn finalize_block(
199 &self,
200 request: proto::RequestFinalizeBlock,
201 ) -> Result<proto::ResponseFinalizeBlock, proto::ResponseException> {
202 handler::finalize_block(self, request).map_err(error_into_exception)
203 }
204
205 fn prepare_proposal(
206 &self,
207 request: proto::RequestPrepareProposal,
208 ) -> Result<proto::ResponsePrepareProposal, proto::ResponseException> {
209 handler::prepare_proposal(self, request).map_err(error_into_exception)
210 }
211
212 fn process_proposal(
213 &self,
214 request: proto::RequestProcessProposal,
215 ) -> Result<proto::ResponseProcessProposal, proto::ResponseException> {
216 handler::process_proposal(self, request).map_err(error_into_exception)
217 }
218
219 fn verify_vote_extension(
220 &self,
221 request: proto::RequestVerifyVoteExtension,
222 ) -> Result<proto::ResponseVerifyVoteExtension, proto::ResponseException> {
223 handler::verify_vote_extension(self, request).map_err(error_into_exception)
224 }
225}