Skip to content

Commit 702936c

Browse files
committed
Init storage with version
1 parent b106edd commit 702936c

File tree

10 files changed

+136
-86
lines changed

10 files changed

+136
-86
lines changed

chainstate/launcher/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,10 @@ fn make_chainstate_and_storage_impl<B: 'static + storage::Backend>(
3939
chain_config: Arc<ChainConfig>,
4040
chainstate_config: ChainstateConfig,
4141
) -> Result<Box<dyn ChainstateInterface>, Error> {
42-
let mut storage = chainstate_storage::Store::new(storage_backend)
42+
let storage = chainstate_storage::Store::new(storage_backend, &chain_config)
4343
.map_err(|e| Error::FailedToInitializeChainstate(e.into()))?;
4444

45-
storage_compatibility::check_storage_compatibility(&mut storage, chain_config.as_ref())
45+
storage_compatibility::check_storage_compatibility(&storage, chain_config.as_ref())
4646
.map_err(InitializationError::StorageCompatibilityCheckError)?;
4747

4848
let chainstate = chainstate::make_chainstate(

chainstate/launcher/src/storage_compatibility.rs

Lines changed: 41 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,12 @@
1414
// limitations under the License.
1515

1616
use chainstate::StorageCompatibilityCheckError;
17-
use chainstate_storage::{BlockchainStorageRead, BlockchainStorageWrite};
17+
use chainstate_storage::{BlockchainStorageRead, ChainstateStorageVersion};
1818
use common::chain::ChainConfig;
1919
use utils::ensure;
2020

21-
const CHAINSTATE_STORAGE_VERSION_UNINITIALIZED: u32 = 0;
22-
const CHAINSTATE_STORAGE_VERSION_V1: u32 = 1;
23-
const CURRENT_CHAINSTATE_STORAGE_VERSION: u32 = CHAINSTATE_STORAGE_VERSION_V1;
24-
25-
pub fn check_storage_compatibility<B: 'static + storage::Backend>(
26-
storage: &mut chainstate_storage::Store<B>,
21+
pub fn check_storage_compatibility(
22+
storage: &impl BlockchainStorageRead,
2723
chain_config: &ChainConfig,
2824
) -> Result<(), StorageCompatibilityCheckError> {
2925
check_storage_version(storage)?;
@@ -33,74 +29,64 @@ pub fn check_storage_compatibility<B: 'static + storage::Backend>(
3329
Ok(())
3430
}
3531

36-
fn check_storage_version<B: 'static + storage::Backend>(
37-
storage: &mut chainstate_storage::Store<B>,
32+
fn check_storage_version(
33+
storage: &impl BlockchainStorageRead,
3834
) -> Result<(), StorageCompatibilityCheckError> {
3935
let storage_version = storage
4036
.get_storage_version()
41-
.map_err(StorageCompatibilityCheckError::StorageError)?;
37+
.map_err(StorageCompatibilityCheckError::StorageError)?
38+
.ok_or(StorageCompatibilityCheckError::StorageVersionMissing)?;
39+
let storage_version = ChainstateStorageVersion::new(storage_version)
40+
.ok_or(StorageCompatibilityCheckError::StorageVersionConversionError)?;
41+
42+
ensure!(
43+
storage_version == ChainstateStorageVersion::CURRENT,
44+
StorageCompatibilityCheckError::ChainstateStorageVersionMismatch(
45+
storage_version,
46+
ChainstateStorageVersion::CURRENT
47+
)
48+
);
4249

43-
if storage_version == CHAINSTATE_STORAGE_VERSION_UNINITIALIZED {
44-
storage
45-
.set_storage_version(CURRENT_CHAINSTATE_STORAGE_VERSION)
46-
.map_err(StorageCompatibilityCheckError::StorageError)?;
47-
} else {
48-
ensure!(
49-
storage_version == CURRENT_CHAINSTATE_STORAGE_VERSION,
50-
StorageCompatibilityCheckError::ChainstateStorageVersionMismatch(
51-
storage_version,
52-
CURRENT_CHAINSTATE_STORAGE_VERSION
53-
)
54-
);
55-
}
5650
Ok(())
5751
}
5852

59-
fn check_magic_bytes<B: 'static + storage::Backend>(
60-
storage: &mut chainstate_storage::Store<B>,
53+
fn check_magic_bytes(
54+
storage: &impl BlockchainStorageRead,
6155
chain_config: &ChainConfig,
6256
) -> Result<(), StorageCompatibilityCheckError> {
6357
let storage_magic_bytes = storage
6458
.get_magic_bytes()
65-
.map_err(StorageCompatibilityCheckError::StorageError)?;
66-
let chain_config_magic_bytes = chain_config.magic_bytes();
59+
.map_err(StorageCompatibilityCheckError::StorageError)?
60+
.ok_or(StorageCompatibilityCheckError::MagicBytesMissing)?;
6761

68-
match storage_magic_bytes {
69-
Some(storage_magic_bytes) => ensure!(
70-
&storage_magic_bytes == chain_config_magic_bytes,
71-
StorageCompatibilityCheckError::ChainConfigMagicBytesMismatch(
72-
storage_magic_bytes,
73-
chain_config_magic_bytes.to_owned()
74-
)
75-
),
76-
None => storage
77-
.set_magic_bytes(chain_config_magic_bytes)
78-
.map_err(StorageCompatibilityCheckError::StorageError)?,
79-
};
62+
ensure!(
63+
&storage_magic_bytes == chain_config.magic_bytes(),
64+
StorageCompatibilityCheckError::ChainConfigMagicBytesMismatch(
65+
storage_magic_bytes,
66+
chain_config.magic_bytes().to_owned()
67+
)
68+
);
8069

8170
Ok(())
8271
}
8372

84-
fn check_chain_type<B: 'static + storage::Backend>(
85-
storage: &mut chainstate_storage::Store<B>,
73+
fn check_chain_type(
74+
storage: &impl BlockchainStorageRead,
8675
chain_config: &ChainConfig,
8776
) -> Result<(), StorageCompatibilityCheckError> {
88-
let storage_chain_type =
89-
storage.get_chain_type().map_err(StorageCompatibilityCheckError::StorageError)?;
77+
let storage_chain_type = storage
78+
.get_chain_type()
79+
.map_err(StorageCompatibilityCheckError::StorageError)?
80+
.ok_or(StorageCompatibilityCheckError::ChainTypeMissing)?;
9081
let chain_config_type = chain_config.chain_type().name();
9182

92-
match storage_chain_type {
93-
Some(storage_chain_type) => ensure!(
94-
storage_chain_type == chain_config_type,
95-
StorageCompatibilityCheckError::ChainTypeMismatch(
96-
storage_chain_type,
97-
chain_config_type.to_owned()
98-
)
99-
),
100-
None => storage
101-
.set_chain_type(chain_config_type)
102-
.map_err(StorageCompatibilityCheckError::StorageError)?,
103-
};
83+
ensure!(
84+
storage_chain_type == chain_config_type,
85+
StorageCompatibilityCheckError::ChainTypeMismatch(
86+
storage_chain_type,
87+
chain_config_type.to_owned()
88+
)
89+
);
10490

10591
Ok(())
10692
}

chainstate/src/detail/error.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use super::{
2121
storage::TransactionVerifierStorageError,
2222
},
2323
};
24+
use chainstate_storage::ChainstateStorageVersion;
2425
use chainstate_types::{GetAncestorError, PropertyQueryError};
2526
use common::{
2627
chain::{
@@ -214,10 +215,18 @@ pub enum InitializationError {
214215
pub enum StorageCompatibilityCheckError {
215216
#[error("Block storage error: `{0}`")]
216217
StorageError(#[from] chainstate_storage::Error),
218+
#[error("Storage version is missing in the db")]
219+
StorageVersionMissing,
220+
#[error("Failed to convert storage error")]
221+
StorageVersionConversionError,
222+
#[error("Magic bytes are missing in the db")]
223+
MagicBytesMissing,
224+
#[error("Chain type is missing in the db")]
225+
ChainTypeMissing,
217226
#[error(
218-
"Node cannot load chainstate database because the versions mismatch: db `{0}`, app `{1}`"
227+
"Node cannot load chainstate database because the versions mismatch: db `{0:?}`, app `{1:?}`"
219228
)]
220-
ChainstateStorageVersionMismatch(u32, u32),
229+
ChainstateStorageVersionMismatch(ChainstateStorageVersion, ChainstateStorageVersion),
221230
#[error(
222231
"Chain's config magic bytes do not match the one from database : expected `{0:?}`, actual `{1:?}`"
223232
)]

chainstate/storage/src/internal/mod.rs

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ use common::{
2222
config::EpochIndex,
2323
tokens::{TokenAuxiliaryData, TokenId},
2424
transaction::{Transaction, TxMainChainIndex, TxMainChainPosition},
25-
AccountNonce, AccountType, Block, DelegationId, GenBlock, OutPointSourceId, PoolId,
26-
UtxoOutPoint,
25+
AccountNonce, AccountType, Block, ChainConfig, DelegationId, GenBlock, OutPointSourceId,
26+
PoolId, UtxoOutPoint,
2727
},
2828
primitives::{Amount, BlockHeight, Id},
2929
};
@@ -42,12 +42,35 @@ use crate::{
4242
mod store_tx;
4343
pub use store_tx::{StoreTxRo, StoreTxRw};
4444

45+
mod version;
46+
pub use version::ChainstateStorageVersion;
47+
4548
/// Store for blockchain data, parametrized over the backend B
4649
pub struct Store<B: storage::Backend>(storage::Storage<B, Schema>);
4750

4851
impl<B: storage::Backend> Store<B> {
4952
/// Create a new chainstate storage
50-
pub fn new(backend: B) -> crate::Result<Self> {
53+
pub fn new(backend: B, chain_config: &ChainConfig) -> crate::Result<Self> {
54+
let mut storage = Self::from_backend(backend)?;
55+
56+
// Set defaults if missing
57+
58+
if storage.get_storage_version()?.is_none() {
59+
storage.set_storage_version(ChainstateStorageVersion::CURRENT as u32)?;
60+
}
61+
62+
if storage.get_magic_bytes()?.is_none() {
63+
storage.set_magic_bytes(chain_config.magic_bytes())?;
64+
}
65+
66+
if storage.get_chain_type()?.is_none() {
67+
storage.set_chain_type(chain_config.chain_type().name())?;
68+
}
69+
70+
Ok(storage)
71+
}
72+
73+
fn from_backend(backend: B) -> crate::Result<Self> {
5174
let storage = Self(storage::Storage::new(backend).map_err(crate::Error::from)?);
5275
Ok(storage)
5376
}
@@ -146,7 +169,7 @@ impl<B: storage::Backend> Store<B> {
146169
impl<B: Default + storage::Backend> Store<B> {
147170
/// Create a default storage (mostly for testing, may want to remove this later)
148171
pub fn new_empty() -> crate::Result<Self> {
149-
Self::new(B::default())
172+
Self::from_backend(B::default())
150173
}
151174
}
152175

@@ -201,7 +224,7 @@ macro_rules! delegate_to_transaction {
201224

202225
impl<B: storage::Backend> BlockchainStorageRead for Store<B> {
203226
delegate_to_transaction! {
204-
fn get_storage_version(&self) -> crate::Result<u32>;
227+
fn get_storage_version(&self) -> crate::Result<Option<u32>>;
205228
fn get_magic_bytes(&self) -> crate::Result<Option<[u8; 4]>>;
206229
fn get_chain_type(&self) -> crate::Result<Option<String>>;
207230
fn get_best_block_id(&self) -> crate::Result<Option<Id<GenBlock>>>;

chainstate/storage/src/internal/store_tx.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ macro_rules! impl_read_ops {
7979
($TxType:ident) => {
8080
/// Blockchain data storage transaction
8181
impl<'st, B: storage::Backend> BlockchainStorageRead for $TxType<'st, B> {
82-
fn get_storage_version(&self) -> crate::Result<u32> {
83-
self.read_value::<well_known::StoreVersion>().map(|v| v.unwrap_or_default())
82+
fn get_storage_version(&self) -> crate::Result<Option<u32>> {
83+
self.read_value::<well_known::StoreVersion>()
8484
}
8585

8686
fn get_magic_bytes(&self) -> crate::Result<Option<[u8; 4]>> {

chainstate/storage/src/internal/test.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ fn test_storage_get_default_version_in_tx() {
3333
let store = TestStore::new_empty().unwrap();
3434
let vtx = store.transaction_ro().unwrap().get_storage_version().unwrap();
3535
let vst = store.get_storage_version().unwrap();
36-
assert_eq!(vtx, 0, "Default storage version wrong");
36+
assert_eq!(vtx, None, "Default storage version wrong");
3737
assert_eq!(vtx, vst, "Transaction and non-transaction inconsistency");
3838
})
3939
}
@@ -73,9 +73,9 @@ fn test_storage_manipulation() {
7373
let mut store = TestStore::new_empty().unwrap();
7474

7575
// Storage version manipulation
76-
assert_eq!(store.get_storage_version(), Ok(0));
76+
assert_eq!(store.get_storage_version(), Ok(None));
7777
assert_eq!(store.set_storage_version(2), Ok(()));
78-
assert_eq!(store.get_storage_version(), Ok(2));
78+
assert_eq!(store.get_storage_version(), Ok(Some(2)));
7979

8080
// Store is now empty, the block is not there
8181
assert_eq!(store.get_block(block0.get_id()), Ok(None));
@@ -159,7 +159,7 @@ fn get_set_transactions() {
159159
let store = Store::clone(&store);
160160
utils::thread::spawn(move || {
161161
let mut tx = store.transaction_rw(None).unwrap();
162-
let v = tx.get_storage_version().unwrap();
162+
let v = tx.get_storage_version().unwrap().unwrap();
163163
tx.set_storage_version(v + 1).unwrap();
164164
tx.commit().unwrap();
165165
})
@@ -168,16 +168,16 @@ fn get_set_transactions() {
168168
let store = Store::clone(&store);
169169
utils::thread::spawn(move || {
170170
let tx = store.transaction_ro().unwrap();
171-
let v1 = tx.get_storage_version().unwrap();
172-
let v2 = tx.get_storage_version().unwrap();
171+
let v1 = tx.get_storage_version().unwrap().unwrap();
172+
let v2 = tx.get_storage_version().unwrap().unwrap();
173173
assert!([2, 3].contains(&v1));
174174
assert_eq!(v1, v2, "Version query in a transaction inconsistent");
175175
})
176176
};
177177

178178
let _ = thr0.join();
179179
let _ = thr1.join();
180-
assert_eq!(store.get_storage_version(), Ok(3));
180+
assert_eq!(store.get_storage_version(), Ok(Some(3)));
181181
})
182182
}
183183

@@ -193,7 +193,7 @@ fn test_storage_transactions() {
193193
let store = Store::clone(&store);
194194
utils::thread::spawn(move || {
195195
let mut tx = store.transaction_rw(None).unwrap();
196-
let v = tx.get_storage_version().unwrap();
196+
let v = tx.get_storage_version().unwrap().unwrap();
197197
tx.set_storage_version(v + 3).unwrap();
198198
tx.commit().unwrap();
199199
})
@@ -202,15 +202,15 @@ fn test_storage_transactions() {
202202
let store = Store::clone(&store);
203203
utils::thread::spawn(move || {
204204
let mut tx = store.transaction_rw(None).unwrap();
205-
let v = tx.get_storage_version().unwrap();
205+
let v = tx.get_storage_version().unwrap().unwrap();
206206
tx.set_storage_version(v + 5).unwrap();
207207
tx.commit().unwrap();
208208
})
209209
};
210210

211211
let _ = thr0.join();
212212
let _ = thr1.join();
213-
assert_eq!(store.get_storage_version(), Ok(10));
213+
assert_eq!(store.get_storage_version(), Ok(Some(10)));
214214
})
215215
}
216216

@@ -226,7 +226,7 @@ fn test_storage_transactions_with_result_check() {
226226
let store = Store::clone(&store);
227227
utils::thread::spawn(move || {
228228
let mut tx = store.transaction_rw(None).unwrap();
229-
let v = tx.get_storage_version().unwrap();
229+
let v = tx.get_storage_version().unwrap().unwrap();
230230
assert!(tx.set_storage_version(v + 3).is_ok());
231231
assert!(tx.commit().is_ok());
232232
})
@@ -235,15 +235,15 @@ fn test_storage_transactions_with_result_check() {
235235
let store = Store::clone(&store);
236236
utils::thread::spawn(move || {
237237
let mut tx = store.transaction_rw(None).unwrap();
238-
let v = tx.get_storage_version().unwrap();
238+
let v = tx.get_storage_version().unwrap().unwrap();
239239
assert!(tx.set_storage_version(v + 5).is_ok());
240240
assert!(tx.commit().is_ok());
241241
})
242242
};
243243

244244
let _ = thr0.join();
245245
let _ = thr1.join();
246-
assert_eq!(store.get_storage_version(), Ok(10));
246+
assert_eq!(store.get_storage_version(), Ok(Some(10)));
247247
})
248248
}
249249

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright (c) 2023 RBB S.r.l
2+
3+
// SPDX-License-Identifier: MIT
4+
// Licensed under the MIT License;
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// https://github.com/mintlayer/mintlayer-core/blob/master/LICENSE
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
17+
#[repr(u32)]
18+
pub enum ChainstateStorageVersion {
19+
// skipping 0 for historical reasons
20+
V1 = 1,
21+
}
22+
23+
impl ChainstateStorageVersion {
24+
pub const CURRENT: Self = Self::V1;
25+
26+
pub fn new(value: u32) -> Option<Self> {
27+
match value {
28+
1 => Some(ChainstateStorageVersion::V1),
29+
_ => None,
30+
}
31+
}
32+
}

0 commit comments

Comments
 (0)