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
108
// 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(),
            true, /* account_count_migration, ignored anyway */
        )?;
        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)
    }
}