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::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 ConsensusAbciApplication<'a, C> {
21 platform: &'a Platform<C>,
23 transaction: RwLock<Option<Transaction<'a>>>,
25 block_execution_context: RwLock<Option<BlockExecutionContext>>,
27 unsigned_withdrawal_txs_by_round: RwLock<UnsignedWithdrawalTxsByRound>,
29}
30
31impl<'a, C> ConsensusAbciApplication<'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 ConsensusAbciApplication<'_, C> {
44 fn platform(&self) -> &Platform<C> {
45 self.platform
46 }
47}
48
49impl<C> BlockExecutionApplication for ConsensusAbciApplication<'_, 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 ConsensusAbciApplication<'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 ConsensusAbciApplication<'_, C> {
89 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90 write!(f, "<ConsensusAbciApplication>")
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97 use crate::rpc::core::MockCoreRPCLike;
98
99 #[test]
100 fn consensus_abci_application_debug_format() {
101 let platform =
102 crate::test::helpers::setup::TestPlatformBuilder::new().build_with_mock_rpc();
103
104 let app = ConsensusAbciApplication::new(&platform.platform);
105
106 let debug_str = format!("{:?}", app);
107 assert_eq!(debug_str, "<ConsensusAbciApplication>");
108 }
109
110 #[test]
111 fn consensus_abci_application_platform_returns_reference() {
112 let platform =
113 crate::test::helpers::setup::TestPlatformBuilder::new().build_with_mock_rpc();
114
115 let app = ConsensusAbciApplication::<MockCoreRPCLike>::new(&platform.platform);
116 let _platform_ref = app.platform();
117 }
118
119 #[test]
120 fn consensus_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 = ConsensusAbciApplication::<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 consensus_abci_application_transaction_is_initially_none() {
132 let platform =
133 crate::test::helpers::setup::TestPlatformBuilder::new().build_with_mock_rpc();
134
135 let app = ConsensusAbciApplication::<MockCoreRPCLike>::new(&platform.platform);
136
137 let tx = app.transaction().read().unwrap();
138 assert!(tx.is_none());
139 }
140
141 #[test]
142 fn consensus_abci_application_start_transaction_creates_transaction() {
143 let platform =
144 crate::test::helpers::setup::TestPlatformBuilder::new().build_with_mock_rpc();
145
146 let app = ConsensusAbciApplication::<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 consensus_abci_application_commit_without_transaction_fails() {
156 let platform =
157 crate::test::helpers::setup::TestPlatformBuilder::new().build_with_mock_rpc();
158
159 let app = ConsensusAbciApplication::<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
167impl<C> tenderdash_abci::Application for ConsensusAbciApplication<'_, C>
168where
169 C: CoreRPCLike,
170{
171 fn info(
172 &self,
173 request: proto::RequestInfo,
174 ) -> Result<proto::ResponseInfo, proto::ResponseException> {
175 handler::info(self, request).map_err(error_into_exception)
176 }
177
178 fn init_chain(
179 &self,
180 request: proto::RequestInitChain,
181 ) -> Result<proto::ResponseInitChain, proto::ResponseException> {
182 handler::init_chain(self, request).map_err(error_into_exception)
183 }
184
185 fn query(
186 &self,
187 _request: proto::RequestQuery,
188 ) -> Result<proto::ResponseQuery, proto::ResponseException> {
189 unreachable!("query is not implemented for consensus ABCI application")
190 }
191
192 fn check_tx(
193 &self,
194 _request: proto::RequestCheckTx,
195 ) -> Result<proto::ResponseCheckTx, proto::ResponseException> {
196 unreachable!("check_tx is not implemented for consensus ABCI application")
197 }
198
199 fn extend_vote(
200 &self,
201 request: proto::RequestExtendVote,
202 ) -> Result<proto::ResponseExtendVote, proto::ResponseException> {
203 handler::extend_vote(self, request).map_err(error_into_exception)
204 }
205
206 fn finalize_block(
207 &self,
208 request: proto::RequestFinalizeBlock,
209 ) -> Result<proto::ResponseFinalizeBlock, proto::ResponseException> {
210 handler::finalize_block(self, request).map_err(error_into_exception)
211 }
212
213 fn prepare_proposal(
214 &self,
215 request: proto::RequestPrepareProposal,
216 ) -> Result<proto::ResponsePrepareProposal, proto::ResponseException> {
217 handler::prepare_proposal(self, request).map_err(error_into_exception)
218 }
219
220 fn process_proposal(
221 &self,
222 request: proto::RequestProcessProposal,
223 ) -> Result<proto::ResponseProcessProposal, proto::ResponseException> {
224 handler::process_proposal(self, request).map_err(error_into_exception)
225 }
226
227 fn verify_vote_extension(
228 &self,
229 request: proto::RequestVerifyVoteExtension,
230 ) -> Result<proto::ResponseVerifyVoteExtension, proto::ResponseException> {
231 handler::verify_vote_extension(self, request).map_err(error_into_exception)
232 }
233}