Skip to content

Commit afef891

Browse files
committed
wip
1 parent fda66f5 commit afef891

File tree

3 files changed

+135
-14
lines changed

3 files changed

+135
-14
lines changed

crates/storage/db/src/models/contract.rs

Lines changed: 83 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,30 +12,108 @@ pub struct ContractInfoChangeList {
1212
pub nonce_change_list: BlockList,
1313
}
1414

15+
/// The type of event that triggered the class change.
16+
#[derive(Debug, Default, PartialEq, Eq)]
17+
#[cfg_attr(test, derive(::arbitrary::Arbitrary))]
18+
pub enum ContractClassChangeType {
19+
/// The contract was deployed with the given class hash.
20+
#[default]
21+
Deployed,
22+
/// The class change is made using the `replace_class` syscall.
23+
Replaced,
24+
}
25+
1526
#[derive(Debug, Default, PartialEq, Eq)]
1627
#[cfg_attr(test, derive(::arbitrary::Arbitrary))]
1728
pub struct ContractClassChange {
29+
/// The type of class change.
30+
pub r#type: ContractClassChangeType,
31+
/// The address of the contract whose class has changed.
1832
pub contract_address: ContractAddress,
1933
/// The updated class hash of `contract_address`.
2034
pub class_hash: ClassHash,
2135
}
2236

37+
impl ContractClassChange {
38+
/// Creates a new `ContractClassChange` instance representing a deployed contract.
39+
pub fn deployed(contract_address: ContractAddress, class_hash: ClassHash) -> Self {
40+
Self { r#type: ContractClassChangeType::Deployed, contract_address, class_hash }
41+
}
42+
43+
/// Creates a new `ContractClassChange` instance representing a replaced class
44+
pub fn replaced(contract_address: ContractAddress, new_class_hash: ClassHash) -> Self {
45+
Self {
46+
r#type: ContractClassChangeType::Replaced,
47+
contract_address,
48+
class_hash: new_class_hash,
49+
}
50+
}
51+
52+
fn decompress_current(bytes: &[u8]) -> Result<Self, CodecError> {
53+
let r#type = ContractClassChangeType::decompress(&bytes[0..1])?;
54+
let contract_address = ContractAddress::decode(&bytes[1..33])?;
55+
let class_hash = ClassHash::decompress(&bytes[33..])?;
56+
Ok(Self { r#type, contract_address, class_hash })
57+
}
58+
59+
/// Backward compatibility purposes.
60+
///
61+
/// For old format, ContractClassChangeType::Deployed type is assumed.
62+
#[cold]
63+
fn decompress_legacy(bytes: &[u8]) -> Result<Self, CodecError> {
64+
let contract_address = ContractAddress::decode(&bytes[0..32])?;
65+
let class_hash = ClassHash::decompress(&bytes[32..])?;
66+
Ok(Self { r#type: ContractClassChangeType::Deployed, contract_address, class_hash })
67+
}
68+
}
69+
70+
impl Compress for ContractClassChangeType {
71+
type Compressed = Vec<u8>;
72+
fn compress(self) -> Result<Self::Compressed, CodecError> {
73+
let byte: u8 = match self {
74+
ContractClassChangeType::Deployed => 0,
75+
ContractClassChangeType::Replaced => 1,
76+
};
77+
Ok(vec![byte])
78+
}
79+
}
80+
81+
impl Decompress for ContractClassChangeType {
82+
fn decompress<B: AsRef<[u8]>>(bytes: B) -> Result<Self, CodecError> {
83+
let bytes = bytes.as_ref();
84+
if bytes.is_empty() {
85+
return Err(CodecError::Decompress("can't decompress empty bytes".to_string()));
86+
}
87+
88+
match bytes[0] {
89+
0 => Ok(ContractClassChangeType::Deployed),
90+
1 => Ok(ContractClassChangeType::Replaced),
91+
_ => Err(CodecError::Decompress("unknown ContractClassChangeType variant".to_string())),
92+
}
93+
}
94+
}
95+
2396
impl Compress for ContractClassChange {
2497
type Compressed = Vec<u8>;
98+
2599
fn compress(self) -> Result<Self::Compressed, CodecError> {
26100
let mut buf = Vec::new();
27-
buf.extend_from_slice(self.contract_address.encode().as_ref());
28-
buf.extend_from_slice(self.class_hash.compress()?.as_ref());
101+
buf.extend(self.r#type.compress()?);
102+
buf.extend(self.contract_address.encode());
103+
buf.extend(self.class_hash.compress()?);
29104
Ok(buf)
30105
}
31106
}
32107

33108
impl Decompress for ContractClassChange {
34109
fn decompress<B: AsRef<[u8]>>(bytes: B) -> Result<Self, crate::error::CodecError> {
35110
let bytes = bytes.as_ref();
36-
let contract_address = ContractAddress::decode(&bytes[0..32])?;
37-
let class_hash = ClassHash::decompress(&bytes[32..])?;
38-
Ok(Self { contract_address, class_hash })
111+
112+
if let Ok(result) = Self::decompress_current(bytes) {
113+
return Ok(result);
114+
}
115+
116+
ContractClassChange::decompress_legacy(bytes)
39117
}
40118
}
41119

crates/storage/provider/provider/src/providers/db/mod.rs

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use katana_db::abstraction::{Database, DbCursor, DbCursorMut, DbDupSortCursor, D
99
use katana_db::error::DatabaseError;
1010
use katana_db::models::block::StoredBlockBodyIndices;
1111
use katana_db::models::contract::{
12-
ContractClassChange, ContractInfoChangeList, ContractNonceChange,
12+
ContractClassChange, ContractClassChangeType, ContractInfoChangeList, ContractNonceChange,
1313
};
1414
use katana_db::models::list::BlockList;
1515
use katana_db::models::stage::StageCheckpoint;
@@ -301,8 +301,28 @@ impl<Db: Database> StateUpdateProvider for DbProvider<Db> {
301301
BTreeMap<ContractAddress, ClassHash>,
302302
_,
303303
>(&db_tx, block_num, |entry| {
304-
let (_, ContractClassChange { contract_address, class_hash }) = entry?;
305-
Ok(Some((contract_address, class_hash)))
304+
let (_, ContractClassChange { r#type, contract_address, class_hash }) = entry?;
305+
306+
if r#type == ContractClassChangeType::Deployed {
307+
Ok(Some((contract_address, class_hash)))
308+
} else {
309+
Ok(None)
310+
}
311+
})?;
312+
313+
let replaced_classes = dup_entries::<
314+
Db,
315+
tables::ClassChangeHistory,
316+
BTreeMap<ContractAddress, ClassHash>,
317+
_,
318+
>(&db_tx, block_num, |entry| {
319+
let (_, ContractClassChange { r#type, contract_address, class_hash }) = entry?;
320+
321+
if r#type == ContractClassChangeType::Replaced {
322+
Ok(Some((contract_address, class_hash)))
323+
} else {
324+
Ok(None)
325+
}
306326
})?;
307327

308328
let mut declared_classes = BTreeMap::new();
@@ -351,8 +371,8 @@ impl<Db: Database> StateUpdateProvider for DbProvider<Db> {
351371
storage_updates,
352372
deployed_contracts,
353373
declared_classes,
374+
replaced_classes,
354375
deprecated_declared_classes,
355-
replaced_classes: BTreeMap::default(),
356376
}))
357377
} else {
358378
Ok(None)
@@ -431,8 +451,12 @@ impl<Db: Database> StateUpdateProvider for DbProvider<Db> {
431451
BTreeMap<ContractAddress, ClassHash>,
432452
_,
433453
>(&db_tx, block_num, |entry| {
434-
let (_, ContractClassChange { contract_address, class_hash }) = entry?;
435-
Ok(Some((contract_address, class_hash)))
454+
let (_, ContractClassChange { r#type, contract_address, class_hash }) = entry?;
455+
if r#type == ContractClassChangeType::Deployed {
456+
Ok(Some((contract_address, class_hash)))
457+
} else {
458+
Ok(None)
459+
}
436460
})?;
437461

438462
db_tx.commit()?;
@@ -835,11 +859,24 @@ impl<Db: Database> BlockWriter for DbProvider<Db> {
835859

836860
db_tx.put::<tables::ContractInfo>(addr, value)?;
837861

838-
let class_change_key = ContractClassChange { contract_address: addr, class_hash };
862+
let class_change_key = ContractClassChange::deployed(addr, class_hash);
839863
db_tx.put::<tables::ClassChangeHistory>(block_number, class_change_key)?;
840864
db_tx.put::<tables::ContractInfoChangeSet>(addr, new_change_set)?;
841865
}
842866

867+
for (addr, new_class_hash) in states.state_updates.replaced_classes {
868+
let mut info = db_tx.get::<tables::ContractInfo>(addr)?.unwrap();
869+
info.class_hash = new_class_hash;
870+
db_tx.put::<tables::ContractInfo>(addr, info)?;
871+
872+
let mut change_set = db_tx.get::<tables::ContractInfoChangeSet>(addr)?.unwrap();
873+
change_set.class_change_list.insert(block_number);
874+
db_tx.put::<tables::ContractInfoChangeSet>(addr, change_set)?;
875+
876+
let class_change_key = ContractClassChange::replaced(addr, new_class_hash);
877+
db_tx.put::<tables::ClassChangeHistory>(block_number, class_change_key)?;
878+
}
879+
843880
for (addr, nonce) in states.state_updates.nonce_updates {
844881
let value = if let Some(info) = db_tx.get::<tables::ContractInfo>(addr)? {
845882
GenericContractInfo { nonce, ..info }

crates/storage/provider/provider/src/providers/fork/state.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ use std::cmp::Ordering;
22
use std::sync::Arc;
33

44
use katana_db::abstraction::{Database, DbTx, DbTxMut};
5-
use katana_db::models::contract::{ContractClassChange, ContractNonceChange};
5+
use katana_db::models::contract::{
6+
ContractClassChange, ContractClassChangeType, ContractNonceChange,
7+
};
68
use katana_db::models::storage::{ContractStorageEntry, ContractStorageKey, StorageEntry};
79
use katana_db::tables;
810
use katana_fork::BackendClient;
@@ -270,7 +272,11 @@ impl<Db: Database> StateProvider for HistoricalStateProvider<Db> {
270272
Ok(res)
271273
} else if let res @ Some(class_hash) = self.backend.get_class_hash_at(address)? {
272274
let block = self.provider.block();
273-
let entry = ContractClassChange { contract_address: address, class_hash };
275+
let entry = ContractClassChange {
276+
r#type: ContractClassChangeType::Deployed,
277+
contract_address: address,
278+
class_hash,
279+
};
274280

275281
self.db.db().tx_mut()?.put::<tables::ClassChangeHistory>(block, entry)?;
276282
Ok(res)

0 commit comments

Comments
 (0)