1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{DiemDB, Order, MAX_LIMIT};
use anyhow::{ensure, format_err, Result};
use diem_config::config::RocksdbConfig;
use diem_types::{
    account_address::AccountAddress,
    account_state_blob::AccountStateBlob,
    contract_event::ContractEvent,
    event::EventKey,
    transaction::{Transaction, Version},
};
use std::{convert::AsRef, path::Path};
use storage_interface::{DbReader, StartupInfo};

pub struct Diemsum {
    db: DiemDB,
}

impl Diemsum {
    pub fn new<P: AsRef<Path> + Clone>(db_root_path: P) -> Result<Self> {
        let db = DiemDB::open(
            db_root_path,
            true, /* read only */
            None, /* no prune_window */
            RocksdbConfig::default(),
        )?;
        Ok(Diemsum { db })
    }

    pub fn get_startup_info(&self) -> Result<StartupInfo> {
        self.db
            .ledger_store
            .get_startup_info()?
            .ok_or_else(|| format_err!("DB is empty"))
    }

    pub fn get_committed_version(&self) -> Result<Version> {
        Ok(self
            .db
            .get_startup_info()?
            .ok_or_else(|| format_err!("No committed ledger info found."))?
            .latest_ledger_info
            .ledger_info()
            .version())
    }

    pub fn scan_txn_by_version(
        &self,
        from_version: Version,
        to_version: Version,
    ) -> Result<Vec<Transaction>> {
        ensure!(
            to_version >= from_version,
            "'from' version {} > 'to' version {}",
            from_version,
            to_version
        );
        let num_txns = to_version - from_version;
        let txn_iter = self
            .db
            .transaction_store
            .get_transaction_iter(from_version, num_txns as usize)?;
        txn_iter.collect::<Result<Vec<_>>>()
    }

    pub fn get_txn_by_version(&self, version: Version) -> Result<Transaction> {
        self.db.transaction_store.get_transaction(version)
    }

    pub fn get_account_state_by_version(
        &self,
        address: AccountAddress,
        version: Version,
    ) -> Result<Option<AccountStateBlob>> {
        self.db
            .state_store
            .get_account_state_with_proof_by_version(address, version)
            .map(|blob_and_proof| blob_and_proof.0)
    }

    pub fn scan_events_by_seq(
        &self,
        key: &EventKey,
        from_seq: u64,
        to_seq: u64,
    ) -> Result<Vec<(Version, ContractEvent)>> {
        ensure!(
            to_seq >= from_seq,
            "'from' sequence {} > 'to' sequence {}",
            from_seq,
            to_seq
        );
        Ok((from_seq..to_seq)
            .step_by(MAX_LIMIT as usize)
            .map(|seq| self.db.get_events(key, seq, Order::Ascending, MAX_LIMIT))
            .collect::<Result<Vec<_>>>()?
            .into_iter()
            .flatten()
            .collect::<Vec<_>>())
    }

    pub fn get_events_by_version(&self, version: Version) -> Result<Vec<ContractEvent>> {
        self.db.event_store.get_events_by_version(version)
    }
}