1use anyhow::Result;
9use diem_crypto::{hash::SPARSE_MERKLE_PLACEHOLDER_HASH, HashValue};
10use diem_types::{
11 account_address::AccountAddress,
12 committed_block::CommittedBlock,
13 contract_event::ContractEvent,
14 epoch_change::EpochChangeProof,
15 epoch_state::EpochState,
16 ledger_info::{
17 deserialize_ledger_info_unchecked, LedgerInfoWithSignatures,
18 },
19 proof::{definition::LeafCount, AccumulatorConsistencyProof},
20 reward_distribution_event::RewardDistributionEventV2,
21 term_state::PosState,
22 transaction::{
23 TransactionInfo, TransactionListWithProof, TransactionToCommit,
24 TransactionWithProof, Version,
25 },
26};
27use serde::{Deserialize, Serialize};
28use std::sync::Arc;
29use thiserror::Error;
30
31pub mod mock;
33pub mod state_view;
34
35#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
36pub struct StartupInfo {
37 #[serde(deserialize_with = "deserialize_ledger_info_unchecked")]
40 pub latest_ledger_info: LedgerInfoWithSignatures,
41 pub latest_epoch_state: Option<EpochState>,
44 pub committed_tree_state: TreeState,
45 pub synced_tree_state: Option<TreeState>,
46
47 pub committed_pos_state: PosState,
48}
49
50impl StartupInfo {
51 pub fn new(
52 latest_ledger_info: LedgerInfoWithSignatures,
53 latest_epoch_state: Option<EpochState>,
54 committed_tree_state: TreeState, synced_tree_state: Option<TreeState>,
55 committed_pos_state: PosState,
56 ) -> Self {
57 Self {
58 latest_ledger_info,
59 latest_epoch_state,
60 committed_tree_state,
61 synced_tree_state,
62 committed_pos_state,
63 }
64 }
65
66 #[cfg(any(feature = "fuzzing"))]
67 pub fn new_for_testing() -> Self {
68 use diem_types::on_chain_config::ValidatorSet;
69
70 let latest_ledger_info = LedgerInfoWithSignatures::genesis(
71 HashValue::zero(),
72 ValidatorSet::empty(),
73 );
74 let latest_epoch_state = None;
75 let committed_tree_state = TreeState {
76 num_transactions: 0,
77 ledger_frozen_subtree_hashes: Vec::new(),
78 account_state_root_hash: *SPARSE_MERKLE_PLACEHOLDER_HASH,
79 };
80 let synced_tree_state = None;
81
82 Self {
83 latest_ledger_info,
84 latest_epoch_state,
85 committed_tree_state,
86 synced_tree_state,
87 }
88 }
89
90 pub fn get_epoch_state(&self) -> &EpochState {
91 self.latest_ledger_info
92 .ledger_info()
93 .next_epoch_state()
94 .unwrap_or_else(|| {
95 self.latest_epoch_state
96 .as_ref()
97 .expect("EpochState must exist")
98 })
99 }
100}
101
102#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
103pub struct TreeState {
104 pub num_transactions: LeafCount,
105 pub ledger_frozen_subtree_hashes: Vec<HashValue>,
106 pub account_state_root_hash: HashValue,
107}
108
109impl TreeState {
110 pub fn new(
111 num_transactions: LeafCount,
112 ledger_frozen_subtree_hashes: Vec<HashValue>,
113 account_state_root_hash: HashValue,
114 ) -> Self {
115 Self {
116 num_transactions,
117 ledger_frozen_subtree_hashes,
118 account_state_root_hash,
119 }
120 }
121
122 pub fn describe(&self) -> &'static str {
123 if self.num_transactions != 0 {
124 "DB has been bootstrapped."
125 } else if self.account_state_root_hash
126 != *SPARSE_MERKLE_PLACEHOLDER_HASH
127 {
128 "DB has no transaction, but a non-empty pre-genesis state."
129 } else {
130 "DB is empty, has no transaction or state."
131 }
132 }
133}
134
135#[derive(Debug, Deserialize, Error, PartialEq, Serialize)]
136pub enum Error {
137 #[error("Service error: {:?}", error)]
138 ServiceError { error: String },
139
140 #[error("Serialization error: {0}")]
141 SerializationError(String),
142}
143
144impl From<anyhow::Error> for Error {
145 fn from(error: anyhow::Error) -> Self {
146 Self::ServiceError {
147 error: format!("{}", error),
148 }
149 }
150}
151
152impl From<bcs::Error> for Error {
153 fn from(error: bcs::Error) -> Self {
154 Self::SerializationError(format!("{}", error))
155 }
156}
157
158impl From<diem_secure_net::Error> for Error {
159 fn from(error: diem_secure_net::Error) -> Self {
160 Self::ServiceError {
161 error: format!("{}", error),
162 }
163 }
164}
165
166#[derive(Clone, Copy, Eq, PartialEq)]
167pub enum Order {
168 Ascending,
169 Descending,
170}
171
172pub trait DbReader: Send + Sync {
175 fn get_epoch_ending_ledger_infos(
180 &self, start_epoch: u64, end_epoch: u64,
181 ) -> Result<EpochChangeProof>;
182
183 fn get_transactions(
188 &self, start_version: Version, batch_size: u64,
189 ledger_version: Version, fetch_events: bool,
190 ) -> Result<TransactionListWithProof>;
191
192 fn get_block_timestamp(&self, version: u64) -> Result<u64>;
197
198 fn get_last_version_before_timestamp(
203 &self, _timestamp: u64, _ledger_version: Version,
204 ) -> Result<Version> {
205 unimplemented!()
206 }
207
208 fn get_latest_ledger_info(&self) -> Result<LedgerInfoWithSignatures>;
210
211 fn get_latest_version(&self) -> Result<Version> {
213 Ok(self.get_latest_ledger_info()?.ledger_info().version())
214 }
215
216 fn get_latest_commit_metadata(&self) -> Result<(Version, u64)> {
218 let ledger_info_with_sig = self.get_latest_ledger_info()?;
219 let ledger_info = ledger_info_with_sig.ledger_info();
220 Ok((ledger_info.version(), ledger_info.timestamp_usecs()))
221 }
222
223 fn get_startup_info(
229 &self, need_pos_state: bool,
230 ) -> Result<Option<StartupInfo>>;
231
232 fn get_txn_by_account(
233 &self, address: AccountAddress, seq_num: u64, ledger_version: Version,
234 fetch_events: bool,
235 ) -> Result<Option<TransactionWithProof>>;
236
237 fn get_state_proof_with_ledger_info(
240 &self, known_version: u64, ledger_info: LedgerInfoWithSignatures,
241 ) -> Result<(EpochChangeProof, AccumulatorConsistencyProof)>;
242
243 fn get_state_proof(
245 &self, known_version: u64,
246 ) -> Result<(
247 LedgerInfoWithSignatures,
248 EpochChangeProof,
249 AccumulatorConsistencyProof,
250 )>;
251
252 fn get_latest_tree_state(&self) -> Result<TreeState>;
255
256 fn get_epoch_ending_ledger_info(
258 &self, known_version: u64,
259 ) -> Result<LedgerInfoWithSignatures>;
260
261 fn get_latest_transaction_info_option(
265 &self,
266 ) -> Result<Option<(Version, TransactionInfo)>> {
267 unimplemented!()
268 }
269
270 fn get_accumulator_root_hash(
274 &self, _version: Version,
275 ) -> Result<HashValue> {
276 unimplemented!()
277 }
278
279 fn get_pos_state(&self, _block_id: &HashValue) -> Result<PosState> {
280 unimplemented!()
281 }
282
283 fn get_latest_pos_state(&self) -> Arc<PosState> { unimplemented!() }
284}
285
286pub trait DbWriter: Send + Sync {
289 fn save_transactions(
296 &self, txns_to_commit: &[TransactionToCommit], first_version: Version,
297 ledger_info_with_sigs: Option<&LedgerInfoWithSignatures>,
298 pos_state: Option<PosState>, committed_blocks: Vec<CommittedBlock>,
299 ledger_infos_with_voted_block: Vec<(
300 HashValue,
301 LedgerInfoWithSignatures,
302 )>,
303 ) -> Result<()>;
304
305 fn save_reward_event(
306 &self, epoch: u64, event: &RewardDistributionEventV2,
307 ) -> Result<()>;
308
309 fn delete_pos_state_by_block(&self, block_id: &HashValue) -> Result<()>;
310}
311
312#[derive(Clone)]
313pub struct DbReaderWriter {
314 pub reader: Arc<dyn DbReader>,
315 pub writer: Arc<dyn DbWriter>,
316}
317
318impl DbReaderWriter {
319 pub fn new<D: 'static + DbReader + DbWriter>(db: D) -> Self {
320 let reader = Arc::new(db);
321 let writer = Arc::clone(&reader);
322
323 Self { reader, writer }
324 }
325
326 pub fn from_arc<D: 'static + DbReader + DbWriter>(arc_db: Arc<D>) -> Self {
327 let reader = Arc::clone(&arc_db);
328 let writer = Arc::clone(&arc_db);
329
330 Self { reader, writer }
331 }
332
333 pub fn wrap<D: 'static + DbReader + DbWriter>(db: D) -> (Arc<D>, Self) {
334 let arc_db = Arc::new(db);
335 (Arc::clone(&arc_db), Self::from_arc(arc_db))
336 }
337}
338
339impl<D> From<D> for DbReaderWriter
340where D: 'static + DbReader + DbWriter
341{
342 fn from(db: D) -> Self { Self::new(db) }
343}
344
345#[derive(Clone, Debug, Deserialize, Serialize)]
347pub enum StorageRequest {
348 GetStartupInfoRequest,
349 SaveTransactionsRequest(Box<SaveTransactionsRequest>),
350}
351
352#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
353pub struct SaveTransactionsRequest {
354 pub txns_to_commit: Vec<TransactionToCommit>,
355 pub first_version: Version,
356 pub ledger_info_with_signatures: Option<LedgerInfoWithSignatures>,
357}
358
359impl SaveTransactionsRequest {
360 pub fn new(
362 txns_to_commit: Vec<TransactionToCommit>, first_version: Version,
363 ledger_info_with_signatures: Option<LedgerInfoWithSignatures>,
364 ) -> Self {
365 SaveTransactionsRequest {
366 txns_to_commit,
367 first_version,
368 ledger_info_with_signatures,
369 }
370 }
371}
372
373pub trait DBReaderForPoW: Send + Sync + DbReader {
374 fn get_latest_ledger_info_option(&self)
375 -> Option<LedgerInfoWithSignatures>;
376
377 fn get_block_ledger_info(
379 &self, consensus_block_id: &HashValue,
380 ) -> Result<LedgerInfoWithSignatures>;
381
382 fn get_events_by_version(
383 &self, start_version: u64, end_version: u64,
384 ) -> Result<Vec<ContractEvent>>;
385
386 fn get_epoch_ending_blocks(
387 &self, start_epoch: u64, end_epoch: u64,
388 ) -> Result<Vec<HashValue>>;
389
390 fn get_reward_event(&self, epoch: u64)
391 -> Result<RewardDistributionEventV2>;
392
393 fn get_committed_block_by_hash(
394 &self, block_hash: &HashValue,
395 ) -> Result<CommittedBlock>;
396
397 fn get_committed_block_hash_by_view(&self, view: u64) -> Result<HashValue>;
398
399 fn get_ledger_info_by_voted_block(
400 &self, block_id: &HashValue,
401 ) -> Result<LedgerInfoWithSignatures>;
402
403 fn get_block_hash_by_epoch_and_round(
404 &self, epoch: u64, round: u64,
405 ) -> Result<HashValue>;
406}