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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
use crate::*;
use snarkos_algorithms::merkle_tree::MerkleTree;
use snarkos_errors::storage::StorageError;
use snarkos_models::{
algorithms::LoadableMerkleParameters,
genesis::Genesis,
objects::{LedgerScheme, Transaction},
parameters::Parameters,
};
use snarkos_objects::Block;
use snarkos_parameters::{GenesisBlock, LedgerMerkleTreeParameters};
use snarkos_utilities::bytes::FromBytes;
use parking_lot::RwLock;
use std::{
fs,
marker::PhantomData,
path::{Path, PathBuf},
sync::Arc,
};
pub struct Ledger<T: Transaction, P: LoadableMerkleParameters> {
pub latest_block_height: RwLock<u32>,
pub ledger_parameters: P,
pub cm_merkle_tree: RwLock<MerkleTree<P>>,
pub storage: Arc<Storage>,
pub _transaction: PhantomData<T>,
}
impl<T: Transaction, P: LoadableMerkleParameters> Ledger<T, P> {
pub fn open() -> Result<Self, StorageError> {
let mut path = std::env::current_dir()?;
path.push("../db");
Self::open_at_path(path)
}
pub fn open_at_path<PATH: AsRef<Path>>(path: PATH) -> Result<Self, StorageError> {
fs::create_dir_all(path.as_ref()).map_err(|err| StorageError::Message(err.to_string()))?;
Self::load_ledger_state(path)
}
pub fn is_empty(&self) -> bool {
self.get_latest_block().is_err()
}
pub fn get_latest_block_height(&self) -> u32 {
*self.latest_block_height.read()
}
pub fn get_block_count(&self) -> u32 {
*self.latest_block_height.read() + 1
}
pub fn get_peer_book(&self) -> Result<Vec<u8>, StorageError> {
Ok(self.get(COL_META, &KEY_PEER_BOOK.as_bytes().to_vec())?)
}
pub fn store_to_peer_book(&self, peers_serialized: Vec<u8>) -> Result<(), StorageError> {
let op = Op::Insert {
col: COL_META,
key: KEY_PEER_BOOK.as_bytes().to_vec(),
value: peers_serialized,
};
self.storage.write(DatabaseTransaction(vec![op]))
}
pub fn destroy_storage(path: PathBuf) -> Result<(), StorageError> {
Storage::destroy_storage(path)
}
fn load_ledger_state<PATH: AsRef<Path>>(path: PATH) -> Result<Self, StorageError> {
let latest_block_number = {
let storage = Storage::open_cf(path.as_ref(), NUM_COLS)?;
storage.get(COL_META, KEY_BEST_BLOCK_NUMBER.as_bytes())?
};
let crh = P::H::from(FromBytes::read(&LedgerMerkleTreeParameters::load_bytes()?[..])?);
let ledger_parameters = P::from(crh);
match latest_block_number {
Some(val) => {
let storage = Storage::open_cf(path.as_ref(), NUM_COLS)?;
let mut cm_and_indices = vec![];
for (commitment_key, index_value) in storage.get_iter(COL_COMMITMENT)? {
let commitment: T::Commitment = FromBytes::read(&commitment_key[..])?;
let index = bytes_to_u32(index_value.to_vec()) as usize;
cm_and_indices.push((commitment, index));
}
cm_and_indices.sort_by(|&(_, i), &(_, j)| i.cmp(&j));
let commitments = cm_and_indices.into_iter().map(|(cm, _)| cm).collect::<Vec<_>>();
let merkle_tree = MerkleTree::new(ledger_parameters.clone(), &commitments)?;
Ok(Self {
latest_block_height: RwLock::new(bytes_to_u32(val)),
storage: Arc::new(storage),
cm_merkle_tree: RwLock::new(merkle_tree),
ledger_parameters,
_transaction: PhantomData,
})
}
None => {
let genesis_block: Block<T> = FromBytes::read(GenesisBlock::load_bytes().as_slice())?;
let ledger_storage = Self::new(&path.as_ref().to_path_buf(), ledger_parameters, genesis_block)
.expect("Ledger could not be instantiated");
Ok(ledger_storage)
}
}
}
pub(crate) fn get(&self, col: u32, key: &Vec<u8>) -> Result<Vec<u8>, StorageError> {
match self.storage.get(col, key)? {
Some(data) => Ok(data),
None => Err(StorageError::MissingValue(hex::encode(key))),
}
}
}