Skip to content

Commit

Permalink
feat(storage)!: store deprecated classes in a file (#1309)
Browse files Browse the repository at this point in the history
  • Loading branch information
dan-starkware authored Oct 25, 2023
1 parent f4885fe commit 61f0b23
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 15 deletions.
53 changes: 52 additions & 1 deletion crates/papyrus_storage/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam};
use serde::{Deserialize, Serialize};
use starknet_api::block::{BlockHash, BlockHeader, BlockNumber};
use starknet_api::core::{ClassHash, ContractAddress, Nonce};
use starknet_api::deprecated_contract_class::ContractClass as DeprecatedContractClass;
use starknet_api::hash::StarkFelt;
use starknet_api::state::{ContractClass, StorageKey, ThinStateDiff};
use starknet_api::transaction::{EventContent, Transaction, TransactionHash};
Expand Down Expand Up @@ -607,6 +608,41 @@ impl FileAccess {
}
}

// Appends a deprecated contract class to the corresponding file and returns its location.
fn append_deprecated_contract_class(
&self,
deprecated_contract_class: &DeprecatedContractClass,
) -> LocationInFile {
match self.clone() {
FileAccess::Readers(_) => panic!("Cannot write to storage in read only mode."),
FileAccess::Writers(mut file_writers) => {
file_writers.deprecated_contract_class.append(deprecated_contract_class)
}
}
}

// Returns the deprecated contract class at the given location or an error in case it doesn't
// exist.
fn get_deprecated_contract_class_unchecked(
&self,
location: LocationInFile,
) -> StorageResult<DeprecatedContractClass> {
match self {
FileAccess::Readers(file_readers) => Ok(file_readers
.deprecated_contract_class
.get(location)?
.ok_or(StorageError::DBInconsistency {
msg: format!("DeprecatedContractClass at location {:?} not found.", location),
})?),
FileAccess::Writers(file_writers) => Ok(file_writers
.deprecated_contract_class
.get(location)?
.ok_or(StorageError::DBInconsistency {
msg: format!("DeprecatedContractClass at location {:?} not found.", location),
})?),
}
}

fn flush(&self) {
// TODO(dan): Consider 1. flushing only the relevant files, 2. flushing concurrently.
match self {
Expand All @@ -615,6 +651,7 @@ impl FileAccess {
file_writers.thin_state_diff.flush();
file_writers.contract_class.flush();
file_writers.casm.flush();
file_writers.deprecated_contract_class.flush();
}
}
}
Expand All @@ -625,13 +662,15 @@ struct FileWriters {
thin_state_diff: FileWriter<ThinStateDiff>,
contract_class: FileWriter<ContractClass>,
casm: FileWriter<CasmContractClass>,
deprecated_contract_class: FileWriter<DeprecatedContractClass>,
}

#[derive(Clone, Debug)]
struct FileReaders {
thin_state_diff: FileReader<ThinStateDiff>,
contract_class: FileReader<ContractClass>,
casm: FileReader<CasmContractClass>,
deprecated_contract_class: FileReader<DeprecatedContractClass>,
}

fn open_storage_files(
Expand Down Expand Up @@ -661,18 +700,28 @@ fn open_storage_files(

let casm_offset = table.get(&db_transaction, &OffsetKind::Casm)?.unwrap_or_default();
let (casm_writer, casm_reader) =
open_file(mmap_file_config, db_config.path().join("casm"), casm_offset)?;
open_file(mmap_file_config.clone(), db_config.path().join("casm.dat"), casm_offset)?;

let deprecated_contract_class_offset =
table.get(&db_transaction, &OffsetKind::DeprecatedContractClass)?.unwrap_or_default();
let (deprecated_contract_class_writer, deprecated_contract_class_reader) = open_file(
mmap_file_config,
db_config.path().join("deprecated_contract_class.dat"),
deprecated_contract_class_offset,
)?;

Ok((
FileWriters {
thin_state_diff: thin_state_diff_writer,
contract_class: contract_class_writer,
casm: casm_writer,
deprecated_contract_class: deprecated_contract_class_writer,
},
FileReaders {
thin_state_diff: thin_state_diff_reader,
contract_class: contract_class_reader,
casm: casm_reader,
deprecated_contract_class: deprecated_contract_class_reader,
},
))
}
Expand All @@ -686,4 +735,6 @@ pub enum OffsetKind {
ContractClass,
/// A CASM file.
Casm,
/// A deprecated contract class file.
DeprecatedContractClass,
}
4 changes: 3 additions & 1 deletion crates/papyrus_storage/src/serializers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ use crate::compression_utils::{
};
use crate::db::serialization::{StorageSerde, StorageSerdeError};
use crate::header::StarknetVersion;
use crate::mmap_file::LocationInFile;
use crate::ommer::{OmmerEventKey, OmmerTransactionKey};
#[cfg(test)]
use crate::serializers::serializers_test::{create_storage_serde_test, StorageSerdeTest};
Expand Down Expand Up @@ -279,7 +280,7 @@ auto_storage_serde! {
pub struct H160(pub [u8; 20]);
pub struct IndexedDeprecatedContractClass {
pub block_number: BlockNumber,
pub contract_class: DeprecatedContractClass,
pub location_in_file: LocationInFile,
}
pub enum InvokeTransaction {
V0(InvokeTransactionV0) = 0,
Expand Down Expand Up @@ -335,6 +336,7 @@ auto_storage_serde! {
ThinStateDiff = 0,
ContractClass = 1,
Casm = 2,
DeprecatedContractClass = 3,
}
struct OmmerTransactionKey(pub BlockHash, pub TransactionOffsetInBlock);
struct OmmerEventKey(pub OmmerTransactionKey, pub EventIndexInTransactionOutput);
Expand Down
7 changes: 4 additions & 3 deletions crates/papyrus_storage/src/state/data.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
use starknet_api::block::BlockNumber;
use starknet_api::core::ClassHash;
use starknet_api::deprecated_contract_class::ContractClass as DeprecatedContractClass;
use starknet_api::state::ContractClass;

use crate::mmap_file::LocationInFile;

pub type DeclaredClasses = IndexMap<ClassHash, ContractClass>;
pub type DeprecatedDeclaredClasses = IndexMap<ClassHash, DeprecatedContractClass>;

/// Data structs that are serialized into the database.

#[derive(Debug, Default, Clone, Eq, PartialEq, Deserialize, Serialize)]
#[derive(Debug, Clone, Eq, PartialEq)]
pub(crate) struct IndexedDeprecatedContractClass {
pub block_number: BlockNumber,
pub contract_class: DeprecatedContractClass,
pub location_in_file: LocationInFile,
}
32 changes: 24 additions & 8 deletions crates/papyrus_storage/src/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ impl<'env, Mode: TransactionKind> StateReader<'env, Mode> {
if state_number.is_before(value.block_number) {
return Ok(None);
}
Ok(Some(value.contract_class))
Ok(Some(self.file_access.get_deprecated_contract_class_unchecked(value.location_in_file)?))
}
}

Expand Down Expand Up @@ -477,13 +477,17 @@ impl<'env> StateStorageWriter for StorageTxn<'env, RW> {
&self.txn,
block_number,
&deprecated_declared_classes_table,
&self.file_access,
&file_offset_table,
)?;
} else {
write_deprecated_declared_classes(
deprecated_declared_classes,
&self.txn,
block_number,
&deprecated_declared_classes_table,
&self.file_access,
&file_offset_table,
)?;
}

Expand Down Expand Up @@ -539,6 +543,7 @@ impl<'env> StateStorageWriter for StorageTxn<'env, RW> {
block_number,
&thin_state_diff,
&deprecated_declared_classes_table,
&self.file_access,
)?;
let deleted_compiled_classes = delete_compiled_classes(
&self.txn,
Expand Down Expand Up @@ -650,19 +655,26 @@ fn write_deprecated_declared_classes<'env>(
txn: &DbTransaction<'env, RW>,
block_number: BlockNumber,
deprecated_declared_classes_table: &'env DeprecatedDeclaredClassesTable<'env>,
file_access: &FileAccess,
file_offset_table: &'env FileOffsetTable<'env>,
) -> StorageResult<()> {
for (class_hash, deprecated_contract_class) in deprecated_declared_classes {
// TODO(dan): remove this check after regenesis, in favor of insert().
if let Some(value) = deprecated_declared_classes_table.get(txn, &class_hash)? {
if value.contract_class != deprecated_contract_class {
if file_access.get_deprecated_contract_class_unchecked(value.location_in_file)?
!= deprecated_contract_class
{
return Err(StorageError::ClassAlreadyExists { class_hash });
}
continue;
}
let value = IndexedDeprecatedContractClass {
block_number,
contract_class: deprecated_contract_class,
};
let location = file_access.append_deprecated_contract_class(&deprecated_contract_class);
let value = IndexedDeprecatedContractClass { block_number, location_in_file: location };
file_offset_table.upsert(
txn,
&OffsetKind::DeprecatedContractClass,
&location.next_offset(),
)?;
let res = deprecated_declared_classes_table.insert(txn, &class_hash, &value);
match res {
Ok(()) => continue,
Expand Down Expand Up @@ -771,6 +783,7 @@ fn delete_deprecated_declared_classes<'env>(
block_number: BlockNumber,
thin_state_diff: &ThinStateDiff,
deprecated_declared_classes_table: &'env DeprecatedDeclaredClassesTable<'env>,
file_access: &FileAccess,
) -> StorageResult<IndexMap<ClassHash, DeprecatedContractClass>> {
// Class hashes of the contracts that were deployed in this block.
let deployed_contracts_class_hashes = thin_state_diff.deployed_contracts.values();
Expand All @@ -791,12 +804,15 @@ fn delete_deprecated_declared_classes<'env>(
// don't find in the deprecated classes table.
if let Some(IndexedDeprecatedContractClass {
block_number: declared_block_number,
contract_class,
location_in_file,
}) = deprecated_declared_classes_table.get(txn, class_hash)?
{
// If the class was declared in a different block then we should'nt delete it.
if block_number == declared_block_number {
deleted_data.insert(*class_hash, contract_class);
deleted_data.insert(
*class_hash,
file_access.get_deprecated_contract_class_unchecked(location_in_file)?,
);
deprecated_declared_classes_table.delete(txn, class_hash)?;
}
}
Expand Down
5 changes: 3 additions & 2 deletions crates/papyrus_storage/src/test_instances.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use starknet_api::block::{BlockHash, BlockNumber};
use starknet_api::core::ContractAddress;
use starknet_api::deprecated_contract_class::ContractClass as DeprecatedContractClass;
use starknet_api::transaction::{
EventIndexInTransactionOutput,
Fee,
Expand All @@ -20,6 +19,7 @@ use crate::body::events::{
};
use crate::body::TransactionIndex;
use crate::header::StarknetVersion;
use crate::mmap_file::LocationInFile;
use crate::state::data::IndexedDeprecatedContractClass;
use crate::version::Version;
use crate::{EventIndex, MarkerKind, OffsetKind, OmmerEventKey, OmmerTransactionKey};
Expand All @@ -28,7 +28,7 @@ auto_impl_get_test_instance! {
struct EventIndex(pub TransactionIndex, pub EventIndexInTransactionOutput);
pub struct IndexedDeprecatedContractClass {
pub block_number: BlockNumber,
pub contract_class: DeprecatedContractClass,
pub location_in_file: LocationInFile,
}
enum MarkerKind {
Header = 0,
Expand All @@ -40,6 +40,7 @@ auto_impl_get_test_instance! {
ThinStateDiff = 0,
ContractClass = 1,
Casm = 2,
DeprecatedContractClass = 3,
}
struct OmmerTransactionKey(pub BlockHash, pub TransactionOffsetInBlock);
struct OmmerEventKey(pub OmmerTransactionKey, pub EventIndexInTransactionOutput);
Expand Down

0 comments on commit 61f0b23

Please sign in to comment.