From 13367fd4e00708845b0836fc72262dc42a152da9 Mon Sep 17 00:00:00 2001 From: Ammar Arif Date: Fri, 10 Jan 2025 17:56:23 -0500 Subject: [PATCH 1/6] feat: add special block hash registry contract --- crates/katana/core/src/backend/mod.rs | 30 +++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/crates/katana/core/src/backend/mod.rs b/crates/katana/core/src/backend/mod.rs index a50cf6e384..15f3ac8b37 100644 --- a/crates/katana/core/src/backend/mod.rs +++ b/crates/katana/core/src/backend/mod.rs @@ -11,7 +11,7 @@ use katana_primitives::env::BlockEnv; use katana_primitives::receipt::{Event, ReceiptWithTxHash}; use katana_primitives::state::{compute_state_diff_hash, StateUpdates}; use katana_primitives::transaction::{TxHash, TxWithHash}; -use katana_primitives::Felt; +use katana_primitives::{address, ContractAddress, Felt}; use katana_provider::traits::block::{BlockHashProvider, BlockWriter}; use katana_provider::traits::trie::TrieWriter; use katana_trie::compute_merkle_root; @@ -49,7 +49,7 @@ impl Backend { pub fn do_mine_block( &self, block_env: &BlockEnv, - execution_output: ExecutionOutput, + mut execution_output: ExecutionOutput, ) -> Result { // we optimistically allocate the maximum amount possible let mut txs = Vec::with_capacity(execution_output.transactions.len()); @@ -68,6 +68,9 @@ impl Backend { let tx_count = txs.len() as u32; let tx_hashes = txs.iter().map(|tx| tx.hash).collect::>(); + // Update special contract address 0x1 + self.update_block_hash(&mut execution_output.states.state_updates, block_env.number)?; + // create a new block and compute its commitment let block = self.commit_block( block_env.clone(), @@ -93,6 +96,29 @@ impl Backend { Ok(MinedBlockOutcome { block_number, txs: tx_hashes, stats: execution_output.stats }) } + // https://docs.starknet.io/architecture-and-concepts/network-architecture/starknet-state/#address_0x1 + fn update_block_hash( + &self, + state_updates: &mut StateUpdates, + block_number: u64, + ) -> Result<(), BlockProductionError> { + const STORED_BLOCK_HASH_BUFFER: u64 = 10; + + if block_number >= STORED_BLOCK_HASH_BUFFER { + let block_number = block_number - STORED_BLOCK_HASH_BUFFER; + let block_hash = self + .blockchain + .provider() + .block_hash_by_num(block_number)? + .expect("qed; missing block hash"); + + let storages = state_updates.storage_updates.entry(address!("0x1")).or_default(); + storages.insert(block_number.into(), block_hash); + } + + Ok(()) + } + pub fn update_block_env(&self, block_env: &mut BlockEnv) { let mut context_gen = self.block_context_generator.write(); let current_timestamp_secs = get_current_timestamp().as_secs() as i64; From e9d4bb49d03f26984737ee005ad4abb2f1c35a43 Mon Sep 17 00:00:00 2001 From: Ammar Arif Date: Fri, 10 Jan 2025 18:15:58 -0500 Subject: [PATCH 2/6] rename method --- crates/katana/core/src/backend/mod.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/crates/katana/core/src/backend/mod.rs b/crates/katana/core/src/backend/mod.rs index 15f3ac8b37..bd86fe6b9e 100644 --- a/crates/katana/core/src/backend/mod.rs +++ b/crates/katana/core/src/backend/mod.rs @@ -69,7 +69,10 @@ impl Backend { let tx_hashes = txs.iter().map(|tx| tx.hash).collect::>(); // Update special contract address 0x1 - self.update_block_hash(&mut execution_output.states.state_updates, block_env.number)?; + self.update_block_hash_registry_contract( + &mut execution_output.states.state_updates, + block_env.number, + )?; // create a new block and compute its commitment let block = self.commit_block( @@ -96,8 +99,9 @@ impl Backend { Ok(MinedBlockOutcome { block_number, txs: tx_hashes, stats: execution_output.stats }) } + // TODO: create a dedicated class for this contract. // https://docs.starknet.io/architecture-and-concepts/network-architecture/starknet-state/#address_0x1 - fn update_block_hash( + fn update_block_hash_registry_contract( &self, state_updates: &mut StateUpdates, block_number: u64, From ccf38a6611314aba611498ffae69bc371ce58080 Mon Sep 17 00:00:00 2001 From: Ammar Arif Date: Fri, 10 Jan 2025 18:24:24 -0500 Subject: [PATCH 3/6] type --- crates/katana/core/src/backend/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/katana/core/src/backend/mod.rs b/crates/katana/core/src/backend/mod.rs index bd86fe6b9e..e8f3f049f0 100644 --- a/crates/katana/core/src/backend/mod.rs +++ b/crates/katana/core/src/backend/mod.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use gas_oracle::L1GasOracle; use katana_executor::{ExecutionOutput, ExecutionResult, ExecutorFactory}; use katana_primitives::block::{ - FinalityStatus, Header, PartialHeader, SealedBlock, SealedBlockWithStatus, + BlockNumber, FinalityStatus, Header, PartialHeader, SealedBlock, SealedBlockWithStatus, }; use katana_primitives::chain_spec::ChainSpec; use katana_primitives::da::L1DataAvailabilityMode; @@ -104,7 +104,7 @@ impl Backend { fn update_block_hash_registry_contract( &self, state_updates: &mut StateUpdates, - block_number: u64, + block_number: BlockNumber, ) -> Result<(), BlockProductionError> { const STORED_BLOCK_HASH_BUFFER: u64 = 10; From 775ddf13a5b42928c76164621bd60036cd9a9b9f Mon Sep 17 00:00:00 2001 From: Ammar Arif Date: Fri, 10 Jan 2025 23:17:29 -0500 Subject: [PATCH 4/6] fix: placeholder block hash when in forked mode --- crates/katana/core/src/backend/mod.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/crates/katana/core/src/backend/mod.rs b/crates/katana/core/src/backend/mod.rs index e8f3f049f0..9505762136 100644 --- a/crates/katana/core/src/backend/mod.rs +++ b/crates/katana/core/src/backend/mod.rs @@ -3,7 +3,8 @@ use std::sync::Arc; use gas_oracle::L1GasOracle; use katana_executor::{ExecutionOutput, ExecutionResult, ExecutorFactory}; use katana_primitives::block::{ - BlockNumber, FinalityStatus, Header, PartialHeader, SealedBlock, SealedBlockWithStatus, + BlockHash, BlockNumber, FinalityStatus, Header, PartialHeader, SealedBlock, + SealedBlockWithStatus, }; use katana_primitives::chain_spec::ChainSpec; use katana_primitives::da::L1DataAvailabilityMode; @@ -110,11 +111,16 @@ impl Backend { if block_number >= STORED_BLOCK_HASH_BUFFER { let block_number = block_number - STORED_BLOCK_HASH_BUFFER; - let block_hash = self - .blockchain - .provider() - .block_hash_by_num(block_number)? - .expect("qed; missing block hash"); + let block_hash = self.blockchain.provider().block_hash_by_num(block_number)?; + + // When in forked mode, we might not have the older block hash in the database. This + // could be the case where the `block_number - STORED_BLOCK_HASH_BUFFER` is + // earlier than the forked block, which right now, Katana doesn't + // yet have the ability to fetch older blocks on the database level. So, we default to + // `BlockHash::ZERO` in this case. + // + // TODO: Fix quick! + let block_hash = block_hash.unwrap_or(BlockHash::ZERO); let storages = state_updates.storage_updates.entry(address!("0x1")).or_default(); storages.insert(block_number.into(), block_hash); From 6be9058d794c19b749fa18ceddcfdadca02e6aa5 Mon Sep 17 00:00:00 2001 From: Ammar Arif Date: Fri, 10 Jan 2025 23:38:13 -0500 Subject: [PATCH 5/6] feat: add special check in rpc --- crates/katana/core/src/backend/mod.rs | 2 +- crates/katana/rpc/rpc/src/starknet/mod.rs | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/crates/katana/core/src/backend/mod.rs b/crates/katana/core/src/backend/mod.rs index 9505762136..f2a6d5f906 100644 --- a/crates/katana/core/src/backend/mod.rs +++ b/crates/katana/core/src/backend/mod.rs @@ -100,7 +100,7 @@ impl Backend { Ok(MinedBlockOutcome { block_number, txs: tx_hashes, stats: execution_output.stats }) } - // TODO: create a dedicated class for this contract. + // TODO: create a dedicated struct for this contract. // https://docs.starknet.io/architecture-and-concepts/network-architecture/starknet-state/#address_0x1 fn update_block_hash_registry_contract( &self, diff --git a/crates/katana/rpc/rpc/src/starknet/mod.rs b/crates/katana/rpc/rpc/src/starknet/mod.rs index 520b3d507c..3828b2c332 100644 --- a/crates/katana/rpc/rpc/src/starknet/mod.rs +++ b/crates/katana/rpc/rpc/src/starknet/mod.rs @@ -280,6 +280,12 @@ where contract_address: ContractAddress, ) -> StarknetApiResult { self.on_io_blocking_task(move |this| { + // Contract address 0x1 is special system contract and does not + // have a class. See https://docs.starknet.io/architecture-and-concepts/network-architecture/starknet-state/#address_0x1. + if contract_address.0 == Felt::ONE { + return Ok(ClassHash::ZERO); + } + let state = this.state(&block_id)?; let class_hash = state.class_hash_of_contract(contract_address)?; class_hash.ok_or(StarknetApiError::ContractNotFound) @@ -305,10 +311,14 @@ where ) -> StarknetApiResult { let state = self.state(&block_id)?; - // check that contract exist by checking the class hash of the contract - let Some(_) = state.class_hash_of_contract(contract_address)? else { + // Check that contract exist by checking the class hash of the contract, + // unless its address 0x1 which is special system contract and does not + // have a class. See https://docs.starknet.io/architecture-and-concepts/network-architecture/starknet-state/#address_0x1. + if contract_address.0 != Felt::ONE + && state.class_hash_of_contract(contract_address)?.is_none() + { return Err(StarknetApiError::ContractNotFound); - }; + } let value = state.storage(contract_address, storage_key)?; Ok(value.unwrap_or_default()) From 39e6a7fbeece3ef57b78d340020bdeaff0b07223 Mon Sep 17 00:00:00 2001 From: Ammar Arif Date: Sat, 11 Jan 2025 00:04:55 -0500 Subject: [PATCH 6/6] fix: update test to avoid using special contract address (mainly for forked) --- .../katana/storage/provider/tests/contract.rs | 48 +++++++++---------- .../katana/storage/provider/tests/fixtures.rs | 4 +- .../katana/storage/provider/tests/storage.rs | 44 ++++++++--------- 3 files changed, 48 insertions(+), 48 deletions(-) diff --git a/crates/katana/storage/provider/tests/contract.rs b/crates/katana/storage/provider/tests/contract.rs index 0a7541f5d1..46339dfa5c 100644 --- a/crates/katana/storage/provider/tests/contract.rs +++ b/crates/katana/storage/provider/tests/contract.rs @@ -43,8 +43,8 @@ mod latest { #[rstest::rstest] #[case( vec![ - (ContractAddress::from(felt!("1")), Some(felt!("22")), Some(felt!("3"))), - (ContractAddress::from(felt!("2")), Some(felt!("33")), Some(felt!("2"))), + (ContractAddress::from(felt!("1337")), Some(felt!("22")), Some(felt!("3"))), + (ContractAddress::from(felt!("80085")), Some(felt!("33")), Some(felt!("2"))), ] )] fn test_latest_contract_info_read( @@ -95,31 +95,31 @@ mod historical { #[case::storage_at_block_0( 0, vec![ - (ContractAddress::from(felt!("1")), None, None), - (ContractAddress::from(felt!("2")), None, None) - ]) - ] + (ContractAddress::from(felt!("1337")), None, None), + (ContractAddress::from(felt!("80085")), None, None) + ]) +] #[case::storage_at_block_1( - 1, - vec![ - (ContractAddress::from(felt!("1")), Some(felt!("11")), Some(felt!("1"))), - (ContractAddress::from(felt!("2")), Some(felt!("11")), Some(felt!("1"))), - ]) - ] + 1, + vec![ + (ContractAddress::from(felt!("1337")), Some(felt!("11")), Some(felt!("1"))), + (ContractAddress::from(felt!("80085")), Some(felt!("11")), Some(felt!("1"))), + ]) +] #[case::storage_at_block_4( - 4, - vec![ - (ContractAddress::from(felt!("1")), Some(felt!("11")), Some(felt!("2"))), - (ContractAddress::from(felt!("2")), Some(felt!("22")), Some(felt!("1"))), - ]) - ] + 4, + vec![ + (ContractAddress::from(felt!("1337")), Some(felt!("11")), Some(felt!("2"))), + (ContractAddress::from(felt!("80085")), Some(felt!("22")), Some(felt!("1"))), + ]) +] #[case::storage_at_block_5( - 5, - vec![ - (ContractAddress::from(felt!("1")), Some(felt!("22")), Some(felt!("3"))), - (ContractAddress::from(felt!("2")), Some(felt!("33")), Some(felt!("2"))), - ]) - ] + 5, + vec![ + (ContractAddress::from(felt!("1337")), Some(felt!("22")), Some(felt!("3"))), + (ContractAddress::from(felt!("80085")), Some(felt!("33")), Some(felt!("2"))), + ]) +] fn test_historical_storage_read( #[from(provider_with_states)] provider: BlockchainProvider, #[case] block_num: BlockNumber, diff --git a/crates/katana/storage/provider/tests/fixtures.rs b/crates/katana/storage/provider/tests/fixtures.rs index 918c98975c..44d8e66a89 100644 --- a/crates/katana/storage/provider/tests/fixtures.rs +++ b/crates/katana/storage/provider/tests/fixtures.rs @@ -69,8 +69,8 @@ pub fn db_provider() -> BlockchainProvider { #[rstest::fixture] pub fn mock_state_updates() -> [StateUpdatesWithClasses; 3] { - let address_1 = address!("1"); - let address_2 = address!("2"); + let address_1 = address!("1337"); + let address_2 = address!("80085"); let class_hash_1 = felt!("11"); let compiled_class_hash_1 = felt!("1000"); diff --git a/crates/katana/storage/provider/tests/storage.rs b/crates/katana/storage/provider/tests/storage.rs index f401e189b6..9961d4c6a9 100644 --- a/crates/katana/storage/provider/tests/storage.rs +++ b/crates/katana/storage/provider/tests/storage.rs @@ -39,11 +39,11 @@ mod latest { #[rstest::rstest] #[case( vec![ - (ContractAddress::from(felt!("1")), felt!("1"), Some(felt!("111"))), - (ContractAddress::from(felt!("1")), felt!("2"), Some(felt!("222"))), - (ContractAddress::from(felt!("1")), felt!("3"), Some(felt!("77"))), - (ContractAddress::from(felt!("2")), felt!("1"), Some(felt!("12"))), - (ContractAddress::from(felt!("2")), felt!("2"), Some(felt!("13"))) + (ContractAddress::from(felt!("1337")), felt!("1"), Some(felt!("111"))), + (ContractAddress::from(felt!("1337")), felt!("2"), Some(felt!("222"))), + (ContractAddress::from(felt!("1337")), felt!("3"), Some(felt!("77"))), + (ContractAddress::from(felt!("80085")), felt!("1"), Some(felt!("12"))), + (ContractAddress::from(felt!("80085")), felt!("2"), Some(felt!("13"))) ] )] fn test_latest_storage_read( @@ -95,38 +95,38 @@ mod historical { #[case::storage_at_block_0( 0, vec![ - (ContractAddress::from(felt!("1")), felt!("1"), None), - (ContractAddress::from(felt!("1")), felt!("2"), None), - (ContractAddress::from(felt!("2")), felt!("1"), None), - (ContractAddress::from(felt!("2")), felt!("2"), None) + (ContractAddress::from(felt!("1337")), felt!("1"), None), + (ContractAddress::from(felt!("1337")), felt!("2"), None), + (ContractAddress::from(felt!("80085")), felt!("1"), None), + (ContractAddress::from(felt!("80085")), felt!("2"), None) ]) ] #[case::storage_at_block_1( 1, vec![ - (ContractAddress::from(felt!("1")), felt!("1"), Some(felt!("100"))), - (ContractAddress::from(felt!("1")), felt!("2"), Some(felt!("101"))), - (ContractAddress::from(felt!("2")), felt!("1"), Some(felt!("200"))), - (ContractAddress::from(felt!("2")), felt!("2"), Some(felt!("201"))), + (ContractAddress::from(felt!("1337")), felt!("1"), Some(felt!("100"))), + (ContractAddress::from(felt!("1337")), felt!("2"), Some(felt!("101"))), + (ContractAddress::from(felt!("80085")), felt!("1"), Some(felt!("200"))), + (ContractAddress::from(felt!("80085")), felt!("2"), Some(felt!("201"))), ]) ] #[case::storage_at_block_4( 4, vec![ - (ContractAddress::from(felt!("1")), felt!("1"), Some(felt!("111"))), - (ContractAddress::from(felt!("1")), felt!("2"), Some(felt!("222"))), - (ContractAddress::from(felt!("2")), felt!("1"), Some(felt!("200"))), - (ContractAddress::from(felt!("2")), felt!("2"), Some(felt!("201"))), + (ContractAddress::from(felt!("1337")), felt!("1"), Some(felt!("111"))), + (ContractAddress::from(felt!("1337")), felt!("2"), Some(felt!("222"))), + (ContractAddress::from(felt!("80085")), felt!("1"), Some(felt!("200"))), + (ContractAddress::from(felt!("80085")), felt!("2"), Some(felt!("201"))), ]) ] #[case::storage_at_block_5( 5, vec![ - (ContractAddress::from(felt!("1")), felt!("1"), Some(felt!("111"))), - (ContractAddress::from(felt!("1")), felt!("2"), Some(felt!("222"))), - (ContractAddress::from(felt!("1")), felt!("3"), Some(felt!("77"))), - (ContractAddress::from(felt!("2")), felt!("1"), Some(felt!("12"))), - (ContractAddress::from(felt!("2")), felt!("2"), Some(felt!("13"))), + (ContractAddress::from(felt!("1337")), felt!("1"), Some(felt!("111"))), + (ContractAddress::from(felt!("1337")), felt!("2"), Some(felt!("222"))), + (ContractAddress::from(felt!("1337")), felt!("3"), Some(felt!("77"))), + (ContractAddress::from(felt!("80085")), felt!("1"), Some(felt!("12"))), + (ContractAddress::from(felt!("80085")), felt!("2"), Some(felt!("13"))), ]) ] fn test_historical_storage_read(