diff --git a/CHANGELOG.md b/CHANGELOG.md index 13b7ac8715f..ba93d7806de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Fixed +- [2106](https://github.com/FuelLabs/fuel-core/pull/2106): Handle the case when nodes with overriding start on the fresh network. - [2105](https://github.com/FuelLabs/fuel-core/pull/2105): Fixed the rollback functionality to work with empty gas price database. ## [Version 0.33.0] diff --git a/crates/fuel-core/src/database.rs b/crates/fuel-core/src/database.rs index 766f9b16db8..4249a1d0add 100644 --- a/crates/fuel-core/src/database.rs +++ b/crates/fuel-core/src/database.rs @@ -126,10 +126,14 @@ pub type ReyalerIterableKeyValueView = IterableKeyValueView> pub type GenesisDatabase = Database; impl OnChainIterableKeyValueView { - pub fn latest_height(&self) -> StorageResult { + pub fn maybe_latest_height(&self) -> StorageResult> { self.iter_all_keys::(Some(IterDirection::Reverse)) .next() - .ok_or(not_found!("BlockHeight"))? + .transpose() + } + + pub fn latest_height(&self) -> StorageResult { + self.maybe_latest_height()?.ok_or(not_found!("BlockHeight")) } pub fn latest_block(&self) -> StorageResult { diff --git a/crates/fuel-core/src/service.rs b/crates/fuel-core/src/service.rs index 851b59eb48f..43a6be09049 100644 --- a/crates/fuel-core/src/service.rs +++ b/crates/fuel-core/src/service.rs @@ -227,7 +227,11 @@ impl FuelService { let on_chain_view = combined_database.on_chain().latest_view()?; for override_height in poa.get_all_overrides().keys() { - let current_height = on_chain_view.latest_height()?; + let Some(current_height) = on_chain_view.maybe_latest_height()? + else { + // Database is empty, nothing to rollback + return Ok(()); + }; if override_height > ¤t_height { return Ok(()); diff --git a/tests/tests/regenesis.rs b/tests/tests/regenesis.rs index 145883ddbd9..94d67d241ff 100644 --- a/tests/tests/regenesis.rs +++ b/tests/tests/regenesis.rs @@ -693,6 +693,47 @@ async fn starting_node_with_overwritten_old_poa_key_doesnt_rollback_the_state( Ok(()) } +#[tokio::test(flavor = "multi_thread")] +async fn starting_empty_node_with_overwritten_poa_works() -> anyhow::Result<()> { + let mut rng = StdRng::seed_from_u64(1234); + let state_config = StateConfig::local_testnet(); + let mut original_chain_config = ChainConfig::local_testnet(); + let tmp_dir = tempdir()?; + let tmp_path: PathBuf = tmp_dir.path().into(); + let snapshot_writer = SnapshotWriter::json(tmp_path.clone()); + + // Given + let (original_secret_key, original_address) = random_key(&mut rng); + original_chain_config.consensus = + ConsensusConfig::PoAV2(PoAV2::new(original_address, { + let mut overrides = BTreeMap::default(); + overrides.insert(123.into(), original_address); + overrides + })); + snapshot_writer.write_state_config(state_config.clone(), &original_chain_config)?; + + // When + let result = FuelCoreDriver::spawn_with_directory( + tmp_dir, + &[ + "--debug", + "--poa-instant", + "true", + "--snapshot", + tmp_path.to_str().unwrap(), + "--consensus-key", + original_secret_key.to_string().as_str(), + ], + ) + .await; + + // Then + let core = result.expect("Failed to start the node"); + produce_block_with_tx(&mut rng, &core.client).await; + + Ok(()) +} + #[tokio::test(flavor = "multi_thread")] async fn starting_node_with_overwritten_new_poa_key_rollbacks_the_state( ) -> anyhow::Result<()> {