Skip to content

Commit 9c4a229

Browse files
committed
Check magic bytes and chain type
1 parent 3128926 commit 9c4a229

File tree

7 files changed

+104
-2
lines changed

7 files changed

+104
-2
lines changed

chainstate/launcher/src/lib.rs

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use std::sync::Arc;
2222
use chainstate::InitializationError;
2323
use chainstate_storage::{BlockchainStorageRead, BlockchainStorageWrite};
2424
use storage_lmdb::resize_callback::MapResizeCallback;
25+
use utils::ensure;
2526

2627
// Some useful reexports
2728
pub use chainstate::{
@@ -47,6 +48,8 @@ fn make_chainstate_and_storage_impl<B: 'static + storage::Backend>(
4748
.map_err(|e| Error::FailedToInitializeChainstate(e.into()))?;
4849

4950
check_storage_version(&mut storage)?;
51+
check_magic_bytes(&mut storage, chain_config.as_ref())?;
52+
check_chain_type(&mut storage, chain_config.as_ref())?;
5053

5154
let chainstate = chainstate::make_chainstate(
5255
chain_config,
@@ -70,7 +73,7 @@ fn check_storage_version<B: 'static + storage::Backend>(
7073
.set_storage_version(CURRENT_CHAINSTATE_STORAGE_VERSION)
7174
.map_err(InitializationError::StorageError)?;
7275
} else {
73-
utils::ensure!(
76+
ensure!(
7477
storage_version == CURRENT_CHAINSTATE_STORAGE_VERSION,
7578
InitializationError::ChainstateStorageVersionMismatch(
7679
storage_version,
@@ -81,6 +84,53 @@ fn check_storage_version<B: 'static + storage::Backend>(
8184
Ok(())
8285
}
8386

87+
fn check_magic_bytes<B: 'static + storage::Backend>(
88+
storage: &mut chainstate_storage::Store<B>,
89+
chain_config: &ChainConfig,
90+
) -> Result<(), Error> {
91+
let storage_magic_bytes =
92+
storage.get_magic_bytes().map_err(InitializationError::StorageError)?;
93+
let chain_config_magic_bytes = chain_config.magic_bytes();
94+
95+
match storage_magic_bytes {
96+
Some(storage_magic_bytes) => ensure!(
97+
&storage_magic_bytes == chain_config_magic_bytes,
98+
InitializationError::ChainConfigMagicBytesMismatch(
99+
storage_magic_bytes,
100+
chain_config_magic_bytes.to_owned()
101+
)
102+
),
103+
None => storage
104+
.set_magic_bytes(chain_config_magic_bytes)
105+
.map_err(InitializationError::StorageError)?,
106+
};
107+
108+
Ok(())
109+
}
110+
111+
fn check_chain_type<B: 'static + storage::Backend>(
112+
storage: &mut chainstate_storage::Store<B>,
113+
chain_config: &ChainConfig,
114+
) -> Result<(), Error> {
115+
let storage_chain_type = storage.get_chain_type().map_err(InitializationError::StorageError)?;
116+
let chain_config_type = chain_config.chain_type().name();
117+
118+
match storage_chain_type {
119+
Some(storage_chain_type) => ensure!(
120+
storage_chain_type == chain_config_type,
121+
InitializationError::ChainTypeMismatch(
122+
storage_chain_type,
123+
chain_config_type.to_owned()
124+
)
125+
),
126+
None => storage
127+
.set_chain_type(chain_config_type)
128+
.map_err(InitializationError::StorageError)?,
129+
};
130+
131+
Ok(())
132+
}
133+
84134
/// Create chainstate together with its storage
85135
pub fn make_chainstate(
86136
datadir: &std::path::Path,

chainstate/src/detail/error.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,12 @@ pub enum InitializationError {
210210
"Node cannot load chainstate database because the versions mismatch: db `{0}`, app `{1}`"
211211
)]
212212
ChainstateStorageVersionMismatch(u32, u32),
213+
#[error(
214+
"Chain's config magic bytes do not match the one from database : expected `{0:?}`, actual `{1:?}`"
215+
)]
216+
ChainConfigMagicBytesMismatch([u8; 4], [u8; 4]),
217+
#[error("Node's chain type doesn't match the one in the database : db `{0}`, app `{1}`")]
218+
ChainTypeMismatch(String, String),
213219
}
214220

215221
impl From<OrphanAddError> for Result<(), OrphanCheckError> {

chainstate/storage/src/internal/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,8 @@ macro_rules! delegate_to_transaction {
202202
impl<B: storage::Backend> BlockchainStorageRead for Store<B> {
203203
delegate_to_transaction! {
204204
fn get_storage_version(&self) -> crate::Result<u32>;
205+
fn get_magic_bytes(&self) -> crate::Result<Option<[u8; 4]>>;
206+
fn get_chain_type(&self) -> crate::Result<Option<String>>;
205207
fn get_best_block_id(&self) -> crate::Result<Option<Id<GenBlock>>>;
206208
fn get_block_index(&self, id: &Id<Block>) -> crate::Result<Option<BlockIndex>>;
207209
fn get_block(&self, id: Id<Block>) -> crate::Result<Option<Block>>;
@@ -355,6 +357,8 @@ impl<B: storage::Backend> PoSAccountingStorageRead<SealedStorageTag> for Store<B
355357
impl<B: storage::Backend> BlockchainStorageWrite for Store<B> {
356358
delegate_to_transaction! {
357359
fn set_storage_version(&mut self, version: u32) -> crate::Result<()>;
360+
fn set_magic_bytes(&mut self, bytes: &[u8; 4]) -> crate::Result<()>;
361+
fn set_chain_type(&mut self, chain: &str) -> crate::Result<()>;
358362
fn set_best_block_id(&mut self, id: &Id<GenBlock>) -> crate::Result<()>;
359363
fn set_block_index(&mut self, block_index: &BlockIndex) -> crate::Result<()>;
360364
fn add_block(&mut self, block: &Block) -> crate::Result<()>;

chainstate/storage/src/internal/store_tx.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ mod well_known {
6565
declare_entry!(BestBlockId: Id<GenBlock>);
6666
declare_entry!(UtxosBestBlockId: Id<GenBlock>);
6767
declare_entry!(TxIndexEnabled: bool);
68+
declare_entry!(MagicBytes: [u8; 4]);
69+
declare_entry!(ChainType: String);
6870
}
6971

7072
/// Read-only chainstate storage transaction
@@ -81,6 +83,14 @@ macro_rules! impl_read_ops {
8183
self.read_value::<well_known::StoreVersion>().map(|v| v.unwrap_or_default())
8284
}
8385

86+
fn get_magic_bytes(&self) -> crate::Result<Option<[u8; 4]>> {
87+
self.read_value::<well_known::MagicBytes>()
88+
}
89+
90+
fn get_chain_type(&self) -> crate::Result<Option<String>> {
91+
self.read_value::<well_known::ChainType>()
92+
}
93+
8494
fn get_block_index(&self, id: &Id<Block>) -> crate::Result<Option<BlockIndex>> {
8595
self.read::<db::DBBlockIndex, _, _>(id)
8696
}
@@ -388,6 +398,14 @@ impl<'st, B: storage::Backend> BlockchainStorageWrite for StoreTxRw<'st, B> {
388398
self.write_value::<well_known::StoreVersion>(&version)
389399
}
390400

401+
fn set_magic_bytes(&mut self, bytes: &[u8; 4]) -> crate::Result<()> {
402+
self.write_value::<well_known::MagicBytes>(bytes)
403+
}
404+
405+
fn set_chain_type(&mut self, chain: &str) -> crate::Result<()> {
406+
self.write_value::<well_known::ChainType>(&chain.to_owned())
407+
}
408+
391409
fn set_best_block_id(&mut self, id: &Id<GenBlock>) -> crate::Result<()> {
392410
self.write_value::<well_known::BestBlockId>(id)
393411
}

chainstate/storage/src/lib.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ pub trait BlockchainStorageRead:
6363
/// Get storage version
6464
fn get_storage_version(&self) -> crate::Result<u32>;
6565

66+
/// Get magic bytes
67+
fn get_magic_bytes(&self) -> crate::Result<Option<[u8; 4]>>;
68+
69+
/// Get chain type name
70+
fn get_chain_type(&self) -> crate::Result<Option<String>>;
71+
6672
/// Get the hash of the best block
6773
fn get_best_block_id(&self) -> crate::Result<Option<Id<GenBlock>>>;
6874

@@ -134,6 +140,12 @@ pub trait BlockchainStorageWrite:
134140
/// Set storage version
135141
fn set_storage_version(&mut self, version: u32) -> Result<()>;
136142

143+
/// Set magic bytes
144+
fn set_magic_bytes(&mut self, bytes: &[u8; 4]) -> Result<()>;
145+
146+
/// Set chain type name
147+
fn set_chain_type(&mut self, chain: &str) -> Result<()>;
148+
137149
/// Set the hash of the best block
138150
fn set_best_block_id(&mut self, id: &Id<GenBlock>) -> Result<()>;
139151

chainstate/storage/src/mock/mock_impl.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ mockall::mock! {
4545

4646
impl crate::BlockchainStorageRead for Store {
4747
fn get_storage_version(&self) -> crate::Result<u32>;
48+
fn get_magic_bytes(&self) -> crate::Result<Option<[u8; 4]>>;
49+
fn get_chain_type(&self) -> crate::Result<Option<String>>;
4850
fn get_best_block_id(&self) -> crate::Result<Option<Id<GenBlock>>>;
4951
fn get_block_index(&self, id: &Id<Block>) -> crate::Result<Option<BlockIndex>>;
5052
fn get_block(&self, id: Id<Block>) -> crate::Result<Option<Block>>;
@@ -148,6 +150,8 @@ mockall::mock! {
148150

149151
impl crate::BlockchainStorageWrite for Store {
150152
fn set_storage_version(&mut self, version: u32) -> crate::Result<()>;
153+
fn set_magic_bytes(&mut self, bytes: &[u8; 4]) -> crate::Result<()>;
154+
fn set_chain_type(&mut self, chain: &str) -> crate::Result<()>;
151155
fn set_best_block_id(&mut self, id: &Id<GenBlock>) -> crate::Result<()>;
152156
fn set_block_index(&mut self, block_index: &BlockIndex) -> crate::Result<()>;
153157
fn add_block(&mut self, block: &Block) -> crate::Result<()>;
@@ -297,6 +301,8 @@ mockall::mock! {
297301

298302
impl crate::BlockchainStorageRead for StoreTxRo {
299303
fn get_storage_version(&self) -> crate::Result<u32>;
304+
fn get_magic_bytes(&self) -> crate::Result<Option<[u8; 4]>>;
305+
fn get_chain_type(&self) -> crate::Result<Option<String>>;
300306
fn get_best_block_id(&self) -> crate::Result<Option<Id<GenBlock>>>;
301307
fn get_block_index(&self, id: &Id<Block>) -> crate::Result<Option<BlockIndex>>;
302308
fn get_block(&self, id: Id<Block>) -> crate::Result<Option<Block>>;
@@ -409,6 +415,8 @@ mockall::mock! {
409415

410416
impl crate::BlockchainStorageRead for StoreTxRw {
411417
fn get_storage_version(&self) -> crate::Result<u32>;
418+
fn get_magic_bytes(&self) -> crate::Result<Option<[u8; 4]>>;
419+
fn get_chain_type(&self) -> crate::Result<Option<String>>;
412420
fn get_best_block_id(&self) -> crate::Result<Option<Id<GenBlock>>>;
413421
fn get_block(&self, id: Id<Block>) -> crate::Result<Option<Block>>;
414422
fn get_block_index(&self, id: &Id<Block>) -> crate::Result<Option<BlockIndex>>;
@@ -511,6 +519,8 @@ mockall::mock! {
511519

512520
impl crate::BlockchainStorageWrite for StoreTxRw {
513521
fn set_storage_version(&mut self, version: u32) -> crate::Result<()>;
522+
fn set_magic_bytes(&mut self, bytes: &[u8; 4]) -> crate::Result<()>;
523+
fn set_chain_type(&mut self, chain: &str) -> crate::Result<()>;
514524
fn set_best_block_id(&mut self, id: &Id<GenBlock>) -> crate::Result<()>;
515525
fn set_block_index(&mut self, block_index: &BlockIndex) -> crate::Result<()>;
516526
fn add_block(&mut self, block: &Block) -> crate::Result<()>;

node-lib/src/runner.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,9 @@ async fn start(
293293
Ok((manager, controller)) => (manager, controller),
294294
Err(error) => match error.downcast_ref::<ChainstateError>() {
295295
Some(ChainstateError::FailedToInitializeChainstate(e)) => match e {
296-
chainstate::InitializationError::ChainstateStorageVersionMismatch(_, _) => {
296+
chainstate::InitializationError::ChainstateStorageVersionMismatch(_, _)
297+
| chainstate::InitializationError::ChainTypeMismatch(_, _)
298+
| chainstate::InitializationError::ChainConfigMagicBytesMismatch(_, _) => {
297299
log::warn!("Failed to init chainstate: {e} \n Cleaning up current db and trying from scratch.");
298300

299301
let storage_config: StorageBackendConfig =

0 commit comments

Comments
 (0)