Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(genesis): set salt of contract on execution of genesis state configuration #2322

Merged
merged 13 commits into from
Oct 11, 2024
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

## Fixed
### Fixed
- [2320](https://github.com/FuelLabs/fuel-core/issues/2320): Prevent `/health` and `/v1/health` from being throttled by the concurrency limiter.
- [2322](https://github.com/FuelLabs/fuel-core/issues/2322): Set the salt of genesis contracts to zero on execution.

## [Version 0.38.0]

Expand Down
11 changes: 11 additions & 0 deletions crates/client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1085,6 +1085,17 @@ impl FuelClient {
Ok(messages)
}

pub async fn contract_info(
&self,
contract: &ContractId,
) -> io::Result<Option<types::Contract>> {
let query = schema::contract::ContractByIdQuery::build(ContractByIdArgs {
id: (*contract).into(),
});
let contract_info = self.query(query).await?.contract.map(Into::into);
Ok(contract_info)
}

pub async fn message_status(&self, nonce: &Nonce) -> io::Result<MessageStatus> {
let query = schema::message::MessageStatusQuery::build(MessageStatusArgs {
nonce: (*nonce).into(),
Expand Down
10 changes: 10 additions & 0 deletions crates/fuel-core/src/combined_database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,16 @@ impl CombinedDatabase {
}
}

/// Converts the combined database into a genesis combined database without
/// checking the height of the databases.
pub fn unsafe_into_genesis(self) -> CombinedGenesisDatabase {
CombinedGenesisDatabase {
on_chain: self.on_chain.unsafe_into_genesis(),
off_chain: self.off_chain.unsafe_into_genesis(),
relayer: self.relayer.unsafe_into_genesis(),
}
}

/// Rollbacks the state of the blockchain to a specific block height.
pub fn rollback_to<S>(
&self,
Expand Down
7 changes: 7 additions & 0 deletions crates/fuel-core/src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,13 @@ where
);
GenesisDatabase::new(self.into_inner().data)
}

/// !!!! WARNING !!!!
/// This method is unsafe because it doesn't check if the height is already set.
/// This allows overriding the genesis state with a new one.
pub fn unsafe_into_genesis(self) -> GenesisDatabase<Description> {
GenesisDatabase::new(self.into_inner().data)
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to add a todo to rework this. It breaks all procession that we have for database right now.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

already done #2329

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant in the code itself

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}

impl<Description, Stage> Database<Description, Stage>
Expand Down
22 changes: 21 additions & 1 deletion crates/fuel-core/src/graphql_api/storage/contracts.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
use fuel_core_chain_config::{
AsTable,
StateConfig,
TableEntry,
};
use fuel_core_storage::{
blueprint::plain::Plain,
codec::{
Expand All @@ -9,7 +14,10 @@ use fuel_core_storage::{
};
use fuel_core_types::{
entities::contract::ContractsInfoType,
fuel_tx::ContractId,
fuel_tx::{
ContractId,
Salt,
},
};

/// Contract info
Expand All @@ -31,6 +39,18 @@ impl TableWithBlueprint for ContractsInfo {
}
}

impl AsTable<ContractsInfo> for StateConfig {
fn as_table(&self) -> Vec<TableEntry<ContractsInfo>> {
self.contracts
.iter()
.map(|contracts_config| TableEntry {
key: contracts_config.contract_id,
value: ContractsInfoType::V1(Salt::zeroed().into()),
})
.collect()
}
}

#[cfg(test)]
mod test {
use super::*;
Expand Down
8 changes: 8 additions & 0 deletions crates/fuel-core/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,14 @@ impl FuelService {
}
}

// repopulate missing tables
genesis::recover_missing_tables_from_genesis_state_config(
watcher.clone(),
&self.shared.config,
&self.shared.database,
)
.await?;

self.override_chain_config_if_needed()
}
}
Expand Down
22 changes: 20 additions & 2 deletions crates/fuel-core/src/service/genesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,10 @@ mod importer;
mod progress;
mod task_manager;

use self::importer::SnapshotImporter;
pub use exporter::Exporter;
pub use task_manager::NotifyCancel;

use self::importer::SnapshotImporter;

/// Performs the importing of the genesis block from the snapshot.
pub async fn execute_genesis_block(
watcher: StateWatcher,
Expand Down Expand Up @@ -150,6 +149,25 @@ pub async fn execute_genesis_block(
Ok(result)
}

// todo: https://github.com/FuelLabs/fuel-core/issues/2329
pub async fn recover_missing_tables_from_genesis_state_config(
watcher: StateWatcher,
config: &Config,
db: &CombinedDatabase,
) -> anyhow::Result<()> {
let genesis_block = create_genesis_block(config);
let db = db.clone().unsafe_into_genesis();
rymnc marked this conversation as resolved.
Show resolved Hide resolved

// todo: https://github.com/FuelLabs/fuel-core/issues/2326
SnapshotImporter::repopulate_maybe_missing_tables(
xgreenx marked this conversation as resolved.
Show resolved Hide resolved
db.clone(),
rymnc marked this conversation as resolved.
Show resolved Hide resolved
genesis_block.clone(),
config.snapshot_reader.clone(),
watcher,
)
.await
}

#[cfg(feature = "test-helpers")]
pub async fn execute_and_commit_genesis_block(
config: &Config,
Expand Down
16 changes: 16 additions & 0 deletions crates/fuel-core/src/service/genesis/importer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,21 @@ impl SnapshotImporter {
.await
}

pub async fn repopulate_maybe_missing_tables(
db: CombinedGenesisDatabase,
genesis_block: Block,
snapshot_reader: SnapshotReader,
watcher: StateWatcher,
) -> anyhow::Result<()> {
let mut importer = Self::new(db, genesis_block, snapshot_reader, watcher);

// the below tables were not populated from the genesis snapshot on older versions
importer.spawn_worker_off_chain::<ContractsInfo, ContractsInfo>()?;
rymnc marked this conversation as resolved.
Show resolved Hide resolved

importer.task_manager.wait().await?;
Ok(())
}

async fn run_workers(mut self) -> anyhow::Result<()> {
tracing::info!("Running imports");
self.spawn_worker_on_chain::<Coins>()?;
Expand All @@ -130,6 +145,7 @@ impl SnapshotImporter {
self.spawn_worker_off_chain::<FuelBlocks, OldFuelBlocks>()?;
self.spawn_worker_off_chain::<Transactions, OldTransactions>()?;
self.spawn_worker_off_chain::<SealedBlockConsensus, OldFuelBlockConsensus>()?;
self.spawn_worker_off_chain::<ContractsInfo, ContractsInfo>()?;
self.spawn_worker_off_chain::<Transactions, ContractsInfo>()?;
self.spawn_worker_off_chain::<OldTransactions, ContractsInfo>()?;
self.spawn_worker_off_chain::<OldFuelBlocks, OldFuelBlocks>()?;
Expand Down
21 changes: 19 additions & 2 deletions crates/fuel-core/src/service/genesis/importer/off_chain.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::borrow::Cow;

use crate::{
database::{
database_description::off_chain::OffChain,
Expand Down Expand Up @@ -38,6 +36,7 @@ use fuel_core_storage::{
StorageAsMut,
};
use fuel_core_types::services::executor::Event;
use std::borrow::Cow;

use super::{
import_task::ImportTable,
Expand Down Expand Up @@ -134,6 +133,24 @@ impl ImportTable for Handler<OwnedCoins, Coins> {
}
}

impl ImportTable for Handler<ContractsInfo, ContractsInfo> {
type TableInSnapshot = ContractsInfo;
type TableBeingWritten = ContractsInfo;
type DbDesc = OffChain;

fn process(
&mut self,
group: Vec<TableEntry<Self::TableInSnapshot>>,
tx: &mut StorageTransaction<&mut GenesisDatabase<Self::DbDesc>>,
) -> anyhow::Result<()> {
for entry in group {
tx.storage::<ContractsInfo>()
.insert(&entry.key, &entry.value)?;
}
Ok(())
}
}

impl ImportTable for Handler<ContractsInfo, Transactions> {
type TableInSnapshot = Transactions;
type TableBeingWritten = ContractsInfo;
Expand Down
24 changes: 24 additions & 0 deletions tests/tests/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ use rand::SeedableRng;

use fuel_core::chain_config::{
CoinConfig,
ContractConfig,
StateConfig,
};
use rstest::rstest;
Expand Down Expand Up @@ -414,3 +415,26 @@ async fn can_get_message_proof() {
assert_eq!(log[1].rb().unwrap(), 1);
assert_eq!(logd.data().unwrap(), db_data);
}

#[tokio::test]
async fn can_get_genesis_contract_salt() {
// given
let contract = ContractConfig::default();
let contract_id = contract.contract_id;
let service_config = Config::local_node_with_state_config(StateConfig {
contracts: vec![contract],
..Default::default()
});

// when
let node =
FuelService::from_database(Database::<OnChain>::in_memory(), service_config)
.await
.unwrap();
let client = FuelClient::from(node.bound_address);

// then
let ret = client.contract_info(&contract_id).await.unwrap().unwrap();

assert_eq!(ret.salt, Salt::zeroed());
}
Loading