From 8c2f7138829071fa36b2b2acde9d6410fb494481 Mon Sep 17 00:00:00 2001 From: Ammar Arif Date: Mon, 13 Jan 2025 21:54:27 -0500 Subject: [PATCH 1/4] fix: deprecated declared classes --- .../src/implementation/blockifier/utils.rs | 29 ++++++++++--------- .../storage/provider/src/providers/db/mod.rs | 29 +++++++++++-------- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/crates/katana/executor/src/implementation/blockifier/utils.rs b/crates/katana/executor/src/implementation/blockifier/utils.rs index 335b44b092..a94dd41b09 100644 --- a/crates/katana/executor/src/implementation/blockifier/utils.rs +++ b/crates/katana/executor/src/implementation/blockifier/utils.rs @@ -1,4 +1,4 @@ -use std::collections::BTreeMap; +use std::collections::{BTreeMap, BTreeSet, HashSet}; use std::num::NonZeroU128; use std::sync::Arc; @@ -432,9 +432,19 @@ pub(super) fn state_update_from_cached_state( katana_primitives::class::ContractClass, > = BTreeMap::new(); - for class_hash in state_diff.compiled_class_hashes.keys() { + let mut declared_classes = BTreeMap::new(); + let mut deprecated_declared_classes = BTreeSet::new(); + + for (class_hash, compiled_hash) in state_diff.compiled_class_hashes { let hash = class_hash.0; let class = state.class(hash).unwrap().expect("must exist if declared"); + + if class.is_legacy() { + deprecated_declared_classes.insert(hash); + } else { + declared_classes.insert(hash, compiled_hash.0); + } + declared_contract_classes.insert(hash, class); } @@ -470,24 +480,15 @@ pub(super) fn state_update_from_cached_state( katana_primitives::class::ClassHash, >>(); - let declared_classes = - state_diff - .compiled_class_hashes - .into_iter() - .map(|(key, value)| (key.0, value.0)) - .collect::>(); - StateUpdatesWithClasses { classes: declared_contract_classes, state_updates: StateUpdates { nonce_updates, storage_updates, - deployed_contracts, declared_classes, - ..Default::default() + deployed_contracts, + deprecated_declared_classes, + replaced_classes: BTreeMap::default(), }, } } diff --git a/crates/katana/storage/provider/src/providers/db/mod.rs b/crates/katana/storage/provider/src/providers/db/mod.rs index 7f7192c259..3fc71f85c4 100644 --- a/crates/katana/storage/provider/src/providers/db/mod.rs +++ b/crates/katana/storage/provider/src/providers/db/mod.rs @@ -1,7 +1,7 @@ pub mod state; pub mod trie; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, BTreeSet}; use std::fmt::Debug; use std::ops::{Range, RangeInclusive}; @@ -301,19 +301,22 @@ impl StateUpdateProvider for DbProvider { Ok((contract_address, class_hash)) })?; - let declared_classes = dup_entries::< - Db, - tables::ClassDeclarations, - BTreeMap, - _, - >(&db_tx, block_num, |entry| { + let mut declared_classes = BTreeMap::new(); + let mut deprecated_declared_classes = BTreeSet::new(); + + dup_entries::(&db_tx, block_num, |entry| { let (_, class_hash) = entry?; - let compiled_hash = db_tx - .get::(class_hash)? - .ok_or(ProviderError::MissingCompiledClassHash(class_hash))?; + match db_tx.get::(class_hash)? { + Some(compiled_hash) => { + declared_classes.insert(class_hash, compiled_hash); + } + None => { + deprecated_declared_classes.insert(class_hash); + } + } - Ok((class_hash, compiled_hash)) + Ok(()) })?; let storage_updates = { @@ -337,12 +340,14 @@ impl StateUpdateProvider for DbProvider { }; db_tx.commit()?; + Ok(Some(StateUpdates { nonce_updates, storage_updates, deployed_contracts, declared_classes, - ..Default::default() + deprecated_declared_classes, + replaced_classes: BTreeMap::default(), })) } else { Ok(None) From 374d5656c279387dfcc2a9550784aa077163a28c Mon Sep 17 00:00:00 2001 From: Ammar Arif Date: Mon, 13 Jan 2025 22:34:10 -0500 Subject: [PATCH 2/4] fix: put geensis class into the correct map --- .../src/implementation/blockifier/utils.rs | 4 ++- crates/katana/primitives/src/chain_spec.rs | 9 ++----- .../katana/rpc/rpc-types/src/state_update.rs | 6 ++++- .../storage/provider/src/providers/db/mod.rs | 25 ++++++++++--------- 4 files changed, 23 insertions(+), 21 deletions(-) diff --git a/crates/katana/executor/src/implementation/blockifier/utils.rs b/crates/katana/executor/src/implementation/blockifier/utils.rs index a94dd41b09..abae3566e6 100644 --- a/crates/katana/executor/src/implementation/blockifier/utils.rs +++ b/crates/katana/executor/src/implementation/blockifier/utils.rs @@ -1,4 +1,4 @@ -use std::collections::{BTreeMap, BTreeSet, HashSet}; +use std::collections::{BTreeMap, BTreeSet}; use std::num::NonZeroU128; use std::sync::Arc; @@ -435,6 +435,8 @@ pub(super) fn state_update_from_cached_state( let mut declared_classes = BTreeMap::new(); let mut deprecated_declared_classes = BTreeSet::new(); + // TODO: Legacy class shouldn't have a compiled class hash. This is a hack we added + // in our fork of `blockifier. Check if it's possible to remove it now. for (class_hash, compiled_hash) in state_diff.compiled_class_hashes { let hash = class_hash.0; let class = state.class(hash).unwrap().expect("must exist if declared"); diff --git a/crates/katana/primitives/src/chain_spec.rs b/crates/katana/primitives/src/chain_spec.rs index f0cac5a1a5..0c2a4ef861 100644 --- a/crates/katana/primitives/src/chain_spec.rs +++ b/crates/katana/primitives/src/chain_spec.rs @@ -14,8 +14,7 @@ use crate::genesis::allocation::{DevAllocationsGenerator, GenesisAllocation}; use crate::genesis::constant::{ get_fee_token_balance_base_storage_address, DEFAULT_ACCOUNT_CLASS_PUBKEY_STORAGE_SLOT, DEFAULT_ETH_FEE_TOKEN_ADDRESS, DEFAULT_LEGACY_ERC20_CLASS, DEFAULT_LEGACY_ERC20_CLASS_HASH, - DEFAULT_LEGACY_UDC_CLASS, DEFAULT_LEGACY_UDC_CLASS_HASH, - DEFAULT_LEGACY_UDC_COMPILED_CLASS_HASH, DEFAULT_PREFUNDED_ACCOUNT_BALANCE, + DEFAULT_LEGACY_UDC_CLASS, DEFAULT_LEGACY_UDC_CLASS_HASH, DEFAULT_PREFUNDED_ACCOUNT_BALANCE, DEFAULT_STRK_FEE_TOKEN_ADDRESS, DEFAULT_UDC_ADDRESS, ERC20_DECIMAL_STORAGE_SLOT, ERC20_NAME_STORAGE_SLOT, ERC20_SYMBOL_STORAGE_SLOT, ERC20_TOTAL_SUPPLY_STORAGE_SLOT, }; @@ -233,11 +232,7 @@ fn add_default_udc(states: &mut StateUpdatesWithClasses) { .entry(DEFAULT_LEGACY_UDC_CLASS_HASH) .or_insert_with(|| DEFAULT_LEGACY_UDC_CLASS.clone()); - states - .state_updates - .declared_classes - .entry(DEFAULT_LEGACY_UDC_CLASS_HASH) - .or_insert(DEFAULT_LEGACY_UDC_COMPILED_CLASS_HASH); + states.state_updates.deprecated_declared_classes.insert(DEFAULT_LEGACY_UDC_CLASS_HASH); // deploy UDC contract states diff --git a/crates/katana/rpc/rpc-types/src/state_update.rs b/crates/katana/rpc/rpc-types/src/state_update.rs index d4248b1a1f..ae9cf1d37c 100644 --- a/crates/katana/rpc/rpc-types/src/state_update.rs +++ b/crates/katana/rpc/rpc-types/src/state_update.rs @@ -1,3 +1,4 @@ +use katana_primitives::class::ClassHash; use serde::{Deserialize, Serialize}; use starknet::core::types::{ ContractStorageDiffItem, DeclaredClassItem, DeployedContractItem, NonceUpdate, StorageEntry, @@ -49,6 +50,9 @@ impl From for StateDiff { .map(|(addr, nonce)| NonceUpdate { nonce, contract_address: addr.into() }) .collect(); + let deprecated_declared_classes: Vec = + value.deprecated_declared_classes.into_iter().collect(); + let declared_classes: Vec = value .declared_classes .into_iter() @@ -81,8 +85,8 @@ impl From for StateDiff { storage_diffs, declared_classes, deployed_contracts, + deprecated_declared_classes, replaced_classes: Default::default(), - deprecated_declared_classes: Default::default(), }) } } diff --git a/crates/katana/storage/provider/src/providers/db/mod.rs b/crates/katana/storage/provider/src/providers/db/mod.rs index 3fc71f85c4..ac93a12b0e 100644 --- a/crates/katana/storage/provider/src/providers/db/mod.rs +++ b/crates/katana/storage/provider/src/providers/db/mod.rs @@ -304,20 +304,21 @@ impl StateUpdateProvider for DbProvider { let mut declared_classes = BTreeMap::new(); let mut deprecated_declared_classes = BTreeSet::new(); - dup_entries::(&db_tx, block_num, |entry| { - let (_, class_hash) = entry?; - - match db_tx.get::(class_hash)? { - Some(compiled_hash) => { - declared_classes.insert(class_hash, compiled_hash); - } - None => { - deprecated_declared_classes.insert(class_hash); + if let Some(block_entries) = + db_tx.cursor_dup::()?.walk_dup(Some(block_num), None)? + { + for entry in block_entries { + let (_, class_hash) = entry?; + match db_tx.get::(class_hash)? { + Some(compiled_hash) => { + declared_classes.insert(class_hash, compiled_hash); + } + None => { + deprecated_declared_classes.insert(class_hash); + } } } - - Ok(()) - })?; + } let storage_updates = { let entries = dup_entries::< From 99d786797aceb8159568110a438128c67bf77bcb Mon Sep 17 00:00:00 2001 From: Ammar Arif Date: Tue, 14 Jan 2025 10:43:32 -0500 Subject: [PATCH 3/4] add test --- crates/katana/rpc/rpc/tests/starknet.rs | 28 +++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/crates/katana/rpc/rpc/tests/starknet.rs b/crates/katana/rpc/rpc/tests/starknet.rs index 251b1760cb..9740ff7d73 100644 --- a/crates/katana/rpc/rpc/tests/starknet.rs +++ b/crates/katana/rpc/rpc/tests/starknet.rs @@ -24,8 +24,9 @@ use starknet::core::types::contract::legacy::LegacyContractClass; use starknet::core::types::{ BlockId, BlockTag, Call, DeclareTransactionReceipt, DeployAccountTransactionReceipt, EventFilter, EventsPage, ExecutionResult, Felt, MaybePendingBlockWithReceipts, - MaybePendingBlockWithTxHashes, MaybePendingBlockWithTxs, StarknetError, - TransactionExecutionStatus, TransactionFinalityStatus, TransactionReceipt, TransactionTrace, + MaybePendingBlockWithTxHashes, MaybePendingBlockWithTxs, MaybePendingStateUpdate, + StarknetError, TransactionExecutionStatus, TransactionFinalityStatus, TransactionReceipt, + TransactionTrace, }; use starknet::core::utils::get_contract_address; use starknet::macros::{felt, selector}; @@ -56,6 +57,20 @@ async fn declare_and_deploy_contract() -> Result<()> { // check that the class is actually declared assert!(provider.get_class(BlockId::Tag(BlockTag::Pending), class_hash).await.is_ok()); + // check state update includes class in declared_classes + let state_update = provider.get_state_update(BlockId::Tag(BlockTag::Latest)).await?; + match state_update { + MaybePendingStateUpdate::Update(update) => { + assert!(update + .state_diff + .declared_classes + .iter() + .any(|item| item.class_hash == class_hash + && item.compiled_class_hash == compiled_class_hash)); + } + _ => panic!("Expected Update, got PendingUpdate"), + } + let ctor_args = vec![Felt::ONE, Felt::TWO]; let calldata = [ vec![ @@ -110,6 +125,15 @@ async fn declare_and_deploy_legacy_contract() -> Result<()> { // check that the class is actually declared assert!(provider.get_class(BlockId::Tag(BlockTag::Pending), class_hash).await.is_ok()); + // check state update includes class in deprecated_declared_classes + let state_update = provider.get_state_update(BlockId::Tag(BlockTag::Latest)).await?; + match state_update { + MaybePendingStateUpdate::Update(update) => { + assert!(update.state_diff.deprecated_declared_classes.contains(&class_hash)); + } + _ => panic!("Expected Update, got PendingUpdate"), + } + let ctor_args = vec![Felt::ONE]; let calldata = [ vec![ From 77fb02aeeadfc1b37d5c03a1a3eb33dfea2755b3 Mon Sep 17 00:00:00 2001 From: Ammar Arif Date: Tue, 14 Jan 2025 10:48:01 -0500 Subject: [PATCH 4/4] fmt --- crates/katana/rpc/rpc/tests/starknet.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/crates/katana/rpc/rpc/tests/starknet.rs b/crates/katana/rpc/rpc/tests/starknet.rs index 9740ff7d73..0dce2e039a 100644 --- a/crates/katana/rpc/rpc/tests/starknet.rs +++ b/crates/katana/rpc/rpc/tests/starknet.rs @@ -61,12 +61,10 @@ async fn declare_and_deploy_contract() -> Result<()> { let state_update = provider.get_state_update(BlockId::Tag(BlockTag::Latest)).await?; match state_update { MaybePendingStateUpdate::Update(update) => { - assert!(update - .state_diff - .declared_classes - .iter() - .any(|item| item.class_hash == class_hash - && item.compiled_class_hash == compiled_class_hash)); + assert!( + update.state_diff.declared_classes.iter().any(|item| item.class_hash == class_hash + && item.compiled_class_hash == compiled_class_hash) + ); } _ => panic!("Expected Update, got PendingUpdate"), }