safety_rules/
persistent_safety_storage.rs1use crate::Error;
9use consensus_types::{common::Author, safety_data::SafetyData};
10use diem_crypto::{
11 hash::CryptoHash, PrivateKey, SigningKey, ValidCryptoMaterial,
12};
13use diem_global_constants::{
14 CONSENSUS_KEY, EXECUTION_KEY, OWNER_ACCOUNT, SAFETY_DATA,
15};
16use diem_logger::prelude::*;
17use diem_secure_storage::{CryptoStorage, KVStorage, OnDiskStorage};
18use diem_types::validator_config::{
19 ConsensusPrivateKey, ConsensusPublicKey, ConsensusSignature,
20};
21use serde::Serialize;
22use std::{convert::TryFrom, fs};
23
24pub struct PersistentSafetyStorage {
33 enable_cached_safety_data: bool,
34 cached_safety_data: Option<SafetyData>,
35 internal_store: OnDiskStorage,
36 private_key: ConsensusPrivateKey,
37}
38
39impl PersistentSafetyStorage {
40 pub fn initialize(
43 mut internal_store: OnDiskStorage, author: Author,
44 private_key: ConsensusPrivateKey, enable_cached_safety_data: bool,
45 ) -> Self {
46 let geneisis_safety_data = SafetyData::new(1, 0, 0, None);
47 let safety_data = Self::initialize_(
48 &mut internal_store,
49 geneisis_safety_data,
50 author,
51 )
52 .expect("Unable to initialize backend storage");
53
54 Self {
55 enable_cached_safety_data,
56 cached_safety_data: Some(safety_data),
57 internal_store,
58 private_key,
59 }
60 }
61
62 pub fn replace_with_suffix(
63 &mut self, new_storage_suffix: &str,
64 ) -> Result<(), Error> {
65 let current_path = self.internal_store.file_path().clone();
66 let new_path = current_path.with_extension(new_storage_suffix);
67 if !new_path.exists() {
68 return Err(Error::SecureStorageUnexpectedError(format!(
69 "new secure storage path incorrect: {:?}",
70 new_path
71 )));
72 }
73 let new_disk_storage = OnDiskStorage::new(new_path.clone());
74 let old_account: Author = self.internal_store.get(OWNER_ACCOUNT)?.value;
75 let new_account: Author = new_disk_storage.get(OWNER_ACCOUNT)?.value;
76 if old_account != new_account {
77 return Err(Error::SecureStorageUnexpectedError(format!(
78 "current: {}, new: {}",
79 old_account, new_account
80 )));
81 }
82 fs::rename(&new_path, ¤t_path)
83 .map_err(|e| Error::InternalError(e.to_string()))?;
84 self.internal_store = OnDiskStorage::new(current_path);
85 self.cached_safety_data = self.internal_store.get(SAFETY_DATA)?.value;
86 Ok(())
87 }
88
89 pub fn save_to_suffix(
90 &mut self, new_storage_suffix: &str,
91 ) -> Result<(), Error> {
92 let current_path = self.internal_store.file_path();
93 let new_path = current_path.with_extension(new_storage_suffix);
94 fs::rename(current_path, &new_path)
95 .map_err(|e| Error::InternalError(e.to_string()))?;
96 Ok(())
97 }
98
99 fn initialize_(
100 internal_store: &mut OnDiskStorage, safety_data: SafetyData,
101 author: Author,
102 ) -> Result<SafetyData, Error> {
103 if let Ok(safety_data) = internal_store.get::<SafetyData>(SAFETY_DATA) {
112 diem_warn!("Attempted to re-initialize existing storage");
113 return Ok(safety_data.value);
114 }
115
116 internal_store.set(SAFETY_DATA, safety_data.clone())?;
117 internal_store.set(OWNER_ACCOUNT, author)?;
118 Ok(safety_data)
119 }
120
121 pub fn author(&self) -> Result<Author, Error> {
122 Ok(self.internal_store.get(OWNER_ACCOUNT).map(|v| v.value)?)
123 }
124
125 pub fn consensus_key_for_version(
126 &self, version: ConsensusPublicKey,
127 ) -> Result<ConsensusPrivateKey, Error> {
128 if self.private_key.public_key() == version {
129 let serialized: &[u8] = &(self.private_key.to_bytes());
130 let cloned = ConsensusPrivateKey::try_from(serialized).unwrap();
131 Ok(cloned)
132 } else {
133 Ok(self
134 .internal_store
135 .export_private_key_for_version(CONSENSUS_KEY, version)?)
136 }
137 }
138
139 pub fn sign<T: Serialize + CryptoHash>(
140 &self, key_name: String, key_version: ConsensusPublicKey, message: &T,
141 ) -> Result<ConsensusSignature, Error> {
142 if key_name == CONSENSUS_KEY || key_name == EXECUTION_KEY {
143 Ok(self.private_key.sign(message))
144 } else {
145 Ok(self.internal_store.sign_using_version(
146 &key_name,
147 key_version,
148 message,
149 )?)
150 }
151 }
152
153 pub fn safety_data(&mut self) -> Result<SafetyData, Error> {
154 if !self.enable_cached_safety_data {
155 return self.internal_store.get(SAFETY_DATA).map(|v| v.value)?;
156 }
157
158 if let Some(cached_safety_data) = self.cached_safety_data.clone() {
159 Ok(cached_safety_data)
160 } else {
161 let safety_data: SafetyData =
162 self.internal_store.get(SAFETY_DATA).map(|v| v.value)?;
163 self.cached_safety_data = Some(safety_data.clone());
164 Ok(safety_data)
165 }
166 }
167
168 pub fn set_safety_data(&mut self, data: SafetyData) -> Result<(), Error> {
169 match self.internal_store.set(SAFETY_DATA, data.clone()) {
170 Ok(_) => {
171 self.cached_safety_data = Some(data);
172 Ok(())
173 }
174 Err(error) => {
175 self.cached_safety_data = None;
176 Err(Error::SecureStorageUnexpectedError(error.to_string()))
177 }
178 }
179 }
180
181 #[cfg(any(test, feature = "testing"))]
182 pub fn internal_store(&mut self) -> &mut OnDiskStorage {
183 &mut self.internal_store
184 }
185}
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190 use crate::test_utils::test_storage;
191 use diem_types::validator_signer::ValidatorSigner;
192
193 #[test]
194 fn test() {
195 let signer = ValidatorSigner::from_int(0);
196 let mut safety_storage = test_storage(&signer);
197
198 let safety_data = safety_storage.safety_data().unwrap();
199 assert_eq!(safety_data.epoch, 1);
200 assert_eq!(safety_data.last_voted_round, 0);
201 assert_eq!(safety_data.preferred_round, 0);
202
203 safety_storage
204 .set_safety_data(SafetyData::new(9, 8, 1, None))
205 .unwrap();
206
207 let safety_data = safety_storage.safety_data().unwrap();
208 assert_eq!(safety_data.epoch, 9);
209 assert_eq!(safety_data.last_voted_round, 8);
210 assert_eq!(safety_data.preferred_round, 1);
211 }
212}